-
Notifications
You must be signed in to change notification settings - Fork 829
/
lib.rs
151 lines (129 loc) · 4.75 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#[cfg(all(test, any(feature = "singlepass", feature = "llvm")))]
mod tests {
use wabt::wat2wasm;
use wasmer_middleware_common::metering::*;
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
use wasmer_runtime_core::{backend::Compiler, compile_with, imports, Func};
#[cfg(feature = "llvm")]
fn get_compiler(limit: u64) -> impl Compiler {
use wasmer_llvm_backend::ModuleCodeGenerator as LLVMMCG;
let c: StreamingCompiler<LLVMMCG, _, _, _, _> = StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
chain.push(Metering::new(limit));
chain
});
c
}
#[cfg(feature = "singlepass")]
fn get_compiler(limit: u64) -> impl Compiler {
use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG;
let c: StreamingCompiler<SinglePassMCG, _, _, _, _> = StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
chain.push(Metering::new(limit));
chain
});
c
}
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
compile_error!("compiler not specified, activate a compiler via features");
#[cfg(feature = "clif")]
fn get_compiler(_limit: u64) -> impl Compiler {
compile_error!("cranelift does not implement metering");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
// Assemblyscript
// export function add_to(x: i32, y: i32): i32 {
// for(var i = 0; i < x; i++){
// if(i % 1 == 0){
// y += i;
// } else {
// y *= i
// }
// }
// return y;
// }
static WAT: &'static str = r#"
(module
(type $t0 (func (param i32 i32) (result i32)))
(type $t1 (func))
(func $add_to (export "add_to") (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
(local $l0 i32)
block $B0
i32.const 0
set_local $l0
loop $L1
get_local $l0
get_local $p0
i32.lt_s
i32.eqz
br_if $B0
get_local $l0
i32.const 1
i32.rem_s
i32.const 0
i32.eq
if $I2
get_local $p1
get_local $l0
i32.add
set_local $p1
else
get_local $p1
get_local $l0
i32.mul
set_local $p1
end
get_local $l0
i32.const 1
i32.add
set_local $l0
br $L1
unreachable
end
unreachable
end
get_local $p1)
(func $f1 (type $t1))
(table $table (export "table") 1 anyfunc)
(memory $memory (export "memory") 0)
(global $g0 i32 (i32.const 8))
(elem (i32.const 0) $f1))
"#;
#[test]
fn test_points_reduced_after_call() {
let wasm_binary = wat2wasm(WAT).unwrap();
let limit = 100u64;
let module = compile_with(&wasm_binary, &get_compiler(limit)).unwrap();
let import_object = imports! {};
let mut instance = module.instantiate(&import_object).unwrap();
set_points_used(&mut instance, 0u64);
let add_to: Func<(i32, i32), i32> = instance.func("add_to").unwrap();
let value = add_to.call(3, 4).unwrap();
// verify it returns the correct value
assert_eq!(value, 7);
// verify it used the correct number of points
assert_eq!(get_points_used(&instance), 74);
}
#[test]
fn test_traps_after_costly_call() {
use wasmer_runtime_core::error::RuntimeError;
let wasm_binary = wat2wasm(WAT).unwrap();
let limit = 100u64;
let module = compile_with(&wasm_binary, &get_compiler(limit)).unwrap();
let import_object = imports! {};
let mut instance = module.instantiate(&import_object).unwrap();
set_points_used(&mut instance, 0u64);
let add_to: Func<(i32, i32), i32> = instance.func("add_to").unwrap();
let result = add_to.call(10_000_000, 4);
let err = result.unwrap_err();
match err {
RuntimeError::Error { data } => {
assert!(data.downcast_ref::<ExecutionLimitExceededError>().is_some());
}
_ => unreachable!(),
}
// verify it used the correct number of points
assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking.
}
}