def test_early_exit(): store = Store() module = Module( store, """ (module (type $run_t (func (param i32 i32) (result i32))) (type $early_exit_t (func (param) (result))) (import "env" "early_exit" (func $early_exit (type $early_exit_t))) (func $run (type $run_t) (param $x i32) (param $y i32) (result i32) (call $early_exit) (i32.add local.get $x local.get $y)) (export "run" (func $run))) """) def early_exit(): raise Exception('oops') import_object = ImportObject() import_object.register("env", { "early_exit": Function(store, early_exit), }) instance = Instance(module, import_object) try: instance.exports.run(1, 2) except RuntimeError as err: assert 'oops' in str(err) else: assert False
def test_import_memory(): store = Store() module = Module( store, """ (module (import "env" "memory" (memory $memory 1)) (func (export "increment") i32.const 0 i32.const 0 i32.load ;; load 0 i32.const 1 i32.add ;; add 1 i32.store ;; store at 0 )) """) memory = Memory(store, MemoryType(minimum=1)) view = memory.uint8_view(offset=0) import_object = defaultdict(dict) import_object["env"]["memory"] = memory instance = Instance(module, import_object) assert view[0] == 0 instance.exports.increment() assert view[0] == 1 instance.exports.increment() assert view[0] == 2
def run_code(wasm_code): # Define the engine that will drive everything. # # In this case, the engine is `wasmer.engine.JIT` which roughly # means that the executable code will live in memory. wasmer_engine = engine.JIT(Compiler) # Create a store, that holds the engine. store = Store(wasmer_engine) # Here we go. # # Let's compile the Wasm module. It is at this step that the Wasm text # is transformed into Wasm bytes (if necessary), and then compiled to # executable code by the compiler, which is then stored in memory by # the engine. module = Module(store, wasm_code) # Provide an "abort()" host function. import_object = host_functions(store) # Congrats, the Wasm module is compiled! Now let's execute it for the # sake of having a complete example. # # Let's instantiate the Wasm module. instance = Instance(module, import_object) # The Wasm module exports a function called `sum`. add = instance.exports.add results = add(1, 2) print(results)
def test_import_memory(): store = Store() module = Module( store, """ (module (import "env" "memory" (memory $memory 1)) (func (export "increment") i32.const 0 i32.const 0 i32.load ;; load 0 i32.const 1 i32.add ;; add 1 i32.store ;; store at 0 )) """) memory = Memory(store, MemoryType(1, shared=False)) view = memory.uint8_view(offset=0) import_object = ImportObject() import_object.register("env", {"memory": memory}) instance = Instance(module, import_object) assert view[0] == 0 instance.exports.increment() assert view[0] == 1 instance.exports.increment() assert view[0] == 2
def test_get_index(): memory = Instance(TEST_BYTES).memory.uint8_view() index = 7 value = 42 memory[index] = value assert memory[index] == value
def test_import_global(): store = Store() module = Module( store, """ (module (import "env" "global" (global $global (mut i32))) (func (export "read_g") (result i32) global.get $global) (func (export "write_g") (param i32) local.get 0 global.set $global)) """) global_ = Global(store, Value.i32(7), mutable=True) import_object = ImportObject() import_object.register("env", {"global": global_}) instance = Instance(module, import_object) assert instance.exports.read_g() == 7 global_.value = 153 assert instance.exports.read_g() == 153 instance.exports.write_g(11) assert global_.value == 11
def test_return_multiple_values_from_host_function(): store = Store() module = Module( store, """ (module (type $swap_t (func (param i32 i64) (result i64 i32))) (type $test_t (func (param i32 i64) (result i64 i32))) (import "env" "swap" (func $swap (type $swap_t))) (func $test (type $test_t) (param $x i32) (param $y i64) (result i64 i32) local.get $x local.get $y call $swap) (export "test" (func $test))) """ ) def swap(x: 'i32', y: 'i64') -> ('i64', 'i32'): return (y, x) import_object = ImportObject() import_object.register( "env", { "swap": Function(store, swap), } ) instance = Instance(module, import_object) assert instance.exports.test(41, 42) == (42, 41)
def run_test(): with open(path, 'rb') as bytecode: wasm_bytes = bytecode.read() instance = Instance(wasm_bytes) # print exported functions print("Modules exported from Rust: ") print(instance.exports) # assign functions simple_add = instance.exports.simple_add fibo = instance.exports.fibo loop_str = instance.exports.loop_str rust_geo_convex_hull = instance.exports.rust_geo_convex_hull reverse_string = instance.exports.reverse_string # try a simple addition result = simple_add(12, 12) print("call simple_add(12, 12): ") print(result) test_str = b'Test sTRing' result = test_reverse(instance, reverse_string, test_str) print(f'Reversing {test_str} >>>') print(result)
def test_get_slice_out_of_range_empty(): with pytest.raises(IndexError) as context_manager: memory = Instance(TEST_BYTES).memory.uint8_view() memory[2:1] exception = context_manager.value assert str(exception) == ('Slice `2:1` cannot be empty.')
def test_get_integer_out_of_range_negative(): with pytest.raises(IndexError) as context_manager: memory = Instance(TEST_BYTES).memory.uint8_view() memory[-1] exception = context_manager.value assert str(exception) == ('Out of bound: Index cannot be negative.')
def test_get_slice_out_of_range_invalid_step(): with pytest.raises(IndexError) as context_manager: memory = Instance(TEST_BYTES).memory.uint8_view() memory[1:7:2] exception = context_manager.value assert str(exception) == ('Slice must have a step of 1 for now; given 2.')
def test_get(self): memory = Instance(TEST_BYTES).uint8_memory_view() index = 7 value = 42 memory[index] = value self.assertEqual(memory[index], value)
def test_failed_to_instantiate(): with pytest.raises(RuntimeError) as context_manager: Instance(INVALID_TEST_BYTES) exception = context_manager.value assert str(exception) == ( 'Failed to compile the module:\n Validation error "Invalid type"')
def test_store_with_various_engines_and_compilers(): engines = [engine.JIT, engine.Native] compilers = [ None, wasmer_compiler_cranelift.Compiler, #wasmer_compiler_llvm.Compiler, wasmer_compiler_singlepass.Compiler ] results = [ ('jit', None), ('jit', 'cranelift'), #('jit', 'llvm'), ('jit', 'singlepass'), ('native', None), ('native', 'cranelift'), #('native', 'llvm'), ('native', 'singlepass'), ] for ((engine_, compiler), expected) in itertools.zip_longest( itertools.product(engines, compilers), results): store = Store(engine_(compiler)) assert store.engine_name == expected[0] assert store.compiler_name == expected[1] if compiler != None: module = Module(store, TEST_BYTES) instance = Instance(module) assert instance.exports.sum(1, 2)
def test_wasi_env_memory(): store = Store() wasi_env = wasi.StateBuilder("foo").finalize() import_object = wasi_env.generate_import_object(store, wasi.Version.LATEST) instance = Instance(Module(store, TEST_BYTES), import_object) wasi_env.memory = instance.exports.memory
def main(): sfip_start = time.time() # expects you to run wasm-pack build before with open(os.path.join("pkg", "slow_function_demo_bg.wasm"), "rb") as instance_bytes: instance = Instance(instance_bytes.read()) instance.exports.slow_func() sfip_end = time.time() print(f"Time taken for slow function using WASM is {sfip_end - sfip_start} seconds")
def test_global_read_write(): y = Instance(TEST_BYTES).globals.y assert y.value == 7 y.value = 8 assert y.value == 8
def test_get_invalid_index(): with pytest.raises(ValueError) as context_manager: memory = Instance(TEST_BYTES).memory.uint8_view() memory['a'] exception = context_manager.value assert str(exception) == ( 'Only integers and slices are valid to represent an index.')
def test_memory_grow_too_much(): with pytest.raises(RuntimeError) as context_manager: Instance(TEST_BYTES).memory.grow(100000) exception = context_manager.value assert str(exception) == ( 'Failed to grow the memory: Grow Error: Failed to add pages because would exceed maximum number of pages. Left: 17, Right: 100000, Pages added: 100017.' )
def test_get_slice(): memory = Instance(TEST_BYTES).memory.uint8_view() index = 7 memory[index] = 1 memory[index + 1] = 2 memory[index + 2] = 3 assert memory[index:index + 3] == [1, 2, 3]
def test_benchmark_execution_time_nbody_llvm_jit(benchmark): store = Store(engine.JIT(LLVM)) module = Module(store, TEST_BYTES) instance = Instance(module) main = instance.exports.main @benchmark def bench(): _ = main(N)
def test_failed_to_instantiate(self): with self.assertRaises(RuntimeError) as context_manager: Instance(INVALID_TEST_BYTES) exception = context_manager.exception self.assertEqual( str(exception), 'Failed to instantiate the module:\n compile error: Validation error "Invalid type"' )
def test_call_i32_i64_f32_f64_f64(self): self.assertEqual( round( Instance(TEST_BYTES).call('i32_i64_f32_f64_f64', [ Value.i32(1), Value.i64(2), Value.f32(3.4), Value.f64(5.6) ]), 6), 1 + 2 + 3.4 + 5.6)
def test_get_integer_out_of_range_too_large(): with pytest.raises(IndexError) as context_manager: memory = Instance(TEST_BYTES).memory.uint8_view() memory[len(memory) + 1] exception = context_manager.value assert str(exception) == ( 'Out of bound: Maximum index 1114113 is larger than the memory size 1114112.' )
def test_benchmark_execution_time_nbody_singlepass_native(benchmark): store = Store(engine.Native(Singlepass)) module = Module(store, TEST_BYTES) instance = Instance(module) main = instance.exports.main @benchmark def bench(): _ = main(N)
def test_set_out_of_range(self): with self.assertRaises(RuntimeError) as context_manager: memory = Instance(TEST_BYTES).uint8_memory_view() memory[len(memory) + 1] = 42 exception = context_manager.exception self.assertEqual( str(exception), 'Out of bound: Absolute index 1114113 is larger than the memory size 1114112.' )
def test_benchmark_memory_view_bytearray_get(benchmark): store = Store(engine.JIT(Compiler)) module = Module(store, TEST_BYTES) instance = Instance(module) memory = bytearray(instance.exports.memory.buffer) def bench(): _ = memory[0] benchmark(bench)
def test_benchmark_memory_view_int8_get(benchmark): store = Store(engine.JIT(Compiler)) module = Module(store, TEST_BYTES) instance = Instance(module) memory = instance.exports.memory.uint8_view() def bench(): _ = memory[0] benchmark(bench)
def run_timing(): with open(path, 'rb') as bytecode: wasm_bytes = bytecode.read() instance = Instance(wasm_bytes) # assign functions simple_add = instance.exports.simple_add fibo = instance.exports.fibo rust_geo_convex_hull = instance.exports.rust_geo_convex_hull # print exported functions print("Modules exported from Rust: ") print(instance.exports) # define metadata in results from collections import OrderedDict results = OrderedDict() results['timestap'] = str(datetime.now()) results['python_wasmer_v'] = f'{wasmer.__version__}|{wasmer.__core_version__}' import subprocess rustc_v = subprocess.check_output(['rustc', '--version']).decode().rstrip() results['rustc_v'] = rustc_v results['data'] = {} t_py = timeit.timeit('[py_simple_add(n-1, n) for n in range(100, 1000)]', number=10000, setup='from examples.scientific import py_simple_add') print('py add', t_py) t_wasm = timeit.timeit('[simple_add(n-1, n) for n in range(100, 1000)]', number=10000, setup=context+'simple_add = instance.exports.simple_add') print('t_wasm add', t_wasm) results['data']['simple_add'] = { 'py': t_py, 'wasm': t_wasm } t_py = timeit.timeit('[py_fibonacci(n) for n in range(100, 1000)]', number=1000, setup='from examples.scientific import py_fibonacci') print('py fibo', t_py) t_wasm = timeit.timeit('[fibo(n) for n in range(100, 1000)]', number=1000, setup=context+'fibo = instance.exports.fibo') print('t_wasm fibo', t_wasm) results['data']['fibonacci'] = { 'py': t_py, 'wasm': t_wasm } t_py = timeit.timeit('[py_shapely_convex_hull() for n in range(100, 1000)]', number=1000, setup='from examples.scientific import py_shapely_convex_hull') print('py shapely convex hull', t_py) t_wasm = timeit.timeit('[rust_geo_convex_hull() for n in range(100, 1000)]', number=1000, setup=context+'rust_geo_convex_hull = instance.exports.rust_geo_convex_hull') print('t_wasm rust-geo convex hull', t_wasm) results['data']['convex_hull'] = { 'py': t_py, 'wasm': t_wasm } # CSV file csv_file = join(dirname(__file__), 'timing', 'data', 'timing.csv') file_exists = os.path.isfile(csv_file) with open(csv_file, 'a') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=results.keys()) if not file_exists: writer.writeheader() file_exists = True writer.writerow(results)
def test_global_read_write_constant(): z = Instance(TEST_BYTES).globals.z assert z.value == 42 with pytest.raises(RuntimeError) as context_manager: z.value = 153 exception = context_manager.value assert str(exception) == ( 'The global variable `z` is not mutable, cannot set a new value.')