├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── benches ├── benches.rs └── wat │ ├── fac_iter.wat │ ├── fac_rec.wat │ ├── fib_iter.wat │ ├── fib_rec.wat │ ├── fill.wat │ └── sum.wat ├── coremark ├── Cargo.toml └── src │ ├── coremark-minimal.wasm │ └── main.rs ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzz_targets │ └── differential.rs ├── src ├── aliasable_box.rs ├── code.rs ├── compile.rs ├── config.rs ├── const_expr.rs ├── data.rs ├── decode.rs ├── downcast.rs ├── elem.rs ├── engine.rs ├── error.rs ├── exec.rs ├── extern_.rs ├── extern_ref.rs ├── extern_val.rs ├── func.rs ├── func_ref.rs ├── global.rs ├── instance.rs ├── into_func.rs ├── lib.rs ├── limits.rs ├── linker.rs ├── main.rs ├── mem.rs ├── module.rs ├── ops.rs ├── ref_.rs ├── stack.rs ├── store.rs ├── table.rs ├── trap.rs ├── val.rs └── validate.rs └── tests ├── testsuite.rs ├── testsuite ├── Contributing.md ├── LICENSE ├── README.md ├── address.wast ├── align.wast ├── binary-leb128.wast ├── binary.wast ├── block.wast ├── br.wast ├── br_if.wast ├── br_table.wast ├── bulk.wast ├── call.wast ├── call_indirect.wast ├── comments.wast ├── const.wast ├── conversions.wast ├── custom.wast ├── data.wast ├── elem.wast ├── endianness.wast ├── exports.wast ├── extract-parts.sh ├── f32.wast ├── f32_bitwise.wast ├── f32_cmp.wast ├── f64.wast ├── f64_bitwise.wast ├── f64_cmp.wast ├── fac.wast ├── float_exprs.wast ├── float_literals.wast ├── float_memory.wast ├── float_misc.wast ├── forward.wast ├── func.wast ├── func_ptrs.wast ├── global.wast ├── i32.wast ├── i64.wast ├── if.wast ├── imports.wast ├── inline-module.wast ├── int_exprs.wast ├── int_literals.wast ├── labels.wast ├── left-to-right.wast ├── linking.wast ├── load.wast ├── local_get.wast ├── local_set.wast ├── local_tee.wast ├── loop.wast ├── memory.wast ├── memory_copy.wast ├── memory_fill.wast ├── memory_grow.wast ├── memory_init.wast ├── memory_redundancy.wast ├── memory_size.wast ├── memory_trap.wast ├── names.wast ├── nop.wast ├── obsolete-keywords.wast ├── proposals │ ├── annotations │ │ └── annotations.wast │ ├── exception-handling │ │ ├── binary.wast │ │ ├── exports.wast │ │ ├── imports.wast │ │ ├── ref_null.wast │ │ ├── tag.wast │ │ ├── throw.wast │ │ ├── throw_ref.wast │ │ └── try_table.wast │ ├── extended-const │ │ ├── data.wast │ │ ├── elem.wast │ │ └── global.wast │ ├── function-references │ │ ├── binary.wast │ │ ├── br_on_non_null.wast │ │ ├── br_on_null.wast │ │ ├── br_table.wast │ │ ├── call_ref.wast │ │ ├── custom.wast │ │ ├── data.wast │ │ ├── elem.wast │ │ ├── func.wast │ │ ├── global.wast │ │ ├── if.wast │ │ ├── linking.wast │ │ ├── local_get.wast │ │ ├── local_init.wast │ │ ├── ref.wast │ │ ├── ref_as_non_null.wast │ │ ├── ref_func.wast │ │ ├── ref_is_null.wast │ │ ├── ref_null.wast │ │ ├── return_call.wast │ │ ├── return_call_indirect.wast │ │ ├── return_call_ref.wast │ │ ├── select.wast │ │ ├── table-sub.wast │ │ ├── table.wast │ │ ├── type-equivalence.wast │ │ ├── unreached-invalid.wast │ │ └── unreached-valid.wast │ ├── gc │ │ ├── array.wast │ │ ├── array_copy.wast │ │ ├── array_fill.wast │ │ ├── array_init_data.wast │ │ ├── array_init_elem.wast │ │ ├── binary-gc.wast │ │ ├── binary.wast │ │ ├── br_on_cast.wast │ │ ├── br_on_cast_fail.wast │ │ ├── br_on_non_null.wast │ │ ├── br_on_null.wast │ │ ├── br_table.wast │ │ ├── call_ref.wast │ │ ├── data.wast │ │ ├── elem.wast │ │ ├── extern.wast │ │ ├── func.wast │ │ ├── global.wast │ │ ├── i31.wast │ │ ├── if.wast │ │ ├── linking.wast │ │ ├── local_get.wast │ │ ├── local_init.wast │ │ ├── ref.wast │ │ ├── ref_as_non_null.wast │ │ ├── ref_cast.wast │ │ ├── ref_eq.wast │ │ ├── ref_is_null.wast │ │ ├── ref_null.wast │ │ ├── ref_test.wast │ │ ├── return_call.wast │ │ ├── return_call_indirect.wast │ │ ├── return_call_ref.wast │ │ ├── select.wast │ │ ├── struct.wast │ │ ├── table-sub.wast │ │ ├── table.wast │ │ ├── type-canon.wast │ │ ├── type-equivalence.wast │ │ ├── type-rec.wast │ │ ├── type-subtyping.wast │ │ ├── unreached-invalid.wast │ │ └── unreached-valid.wast │ ├── memory64 │ │ ├── address.wast │ │ ├── address64.wast │ │ ├── align64.wast │ │ ├── binary-leb128.wast │ │ ├── binary.wast │ │ ├── endianness64.wast │ │ ├── float_memory64.wast │ │ ├── load64.wast │ │ ├── memory.wast │ │ ├── memory64.wast │ │ ├── memory_grow64.wast │ │ ├── memory_redundancy64.wast │ │ ├── memory_trap64.wast │ │ └── simd_address.wast │ ├── multi-memory │ │ ├── address0.wast │ │ ├── address1.wast │ │ ├── align0.wast │ │ ├── binary.wast │ │ ├── binary0.wast │ │ ├── data.wast │ │ ├── data0.wast │ │ ├── data1.wast │ │ ├── data_drop0.wast │ │ ├── exports0.wast │ │ ├── float_exprs0.wast │ │ ├── float_exprs1.wast │ │ ├── float_memory0.wast │ │ ├── imports.wast │ │ ├── imports0.wast │ │ ├── imports1.wast │ │ ├── imports2.wast │ │ ├── imports3.wast │ │ ├── imports4.wast │ │ ├── linking0.wast │ │ ├── linking1.wast │ │ ├── linking2.wast │ │ ├── linking3.wast │ │ ├── load.wast │ │ ├── load0.wast │ │ ├── load1.wast │ │ ├── load2.wast │ │ ├── memory-multi.wast │ │ ├── memory.wast │ │ ├── memory_copy0.wast │ │ ├── memory_copy1.wast │ │ ├── memory_fill0.wast │ │ ├── memory_grow.wast │ │ ├── memory_init0.wast │ │ ├── memory_size.wast │ │ ├── memory_size0.wast │ │ ├── memory_size1.wast │ │ ├── memory_size2.wast │ │ ├── memory_size3.wast │ │ ├── memory_trap0.wast │ │ ├── memory_trap1.wast │ │ ├── simd_memory-multi.wast │ │ ├── start0.wast │ │ ├── store.wast │ │ ├── store0.wast │ │ ├── store1.wast │ │ └── traps0.wast │ ├── relaxed-simd │ │ ├── i16x8_relaxed_q15mulr_s.wast │ │ ├── i32x4_relaxed_trunc.wast │ │ ├── i8x16_relaxed_swizzle.wast │ │ ├── relaxed_dot_product.wast │ │ ├── relaxed_laneselect.wast │ │ ├── relaxed_madd_nmadd.wast │ │ └── relaxed_min_max.wast │ ├── tail-call │ │ ├── return_call.wast │ │ └── return_call_indirect.wast │ └── threads │ │ ├── atomic.wast │ │ ├── exports.wast │ │ ├── imports.wast │ │ └── memory.wast ├── ref_func.wast ├── ref_is_null.wast ├── ref_null.wast ├── repos │ └── README.md ├── return.wast ├── select.wast ├── simd_address.wast ├── simd_align.wast ├── simd_bit_shift.wast ├── simd_bitwise.wast ├── simd_boolean.wast ├── simd_const.wast ├── simd_conversions.wast ├── simd_f32x4.wast ├── simd_f32x4_arith.wast ├── simd_f32x4_cmp.wast ├── simd_f32x4_pmin_pmax.wast ├── simd_f32x4_rounding.wast ├── simd_f64x2.wast ├── simd_f64x2_arith.wast ├── simd_f64x2_cmp.wast ├── simd_f64x2_pmin_pmax.wast ├── simd_f64x2_rounding.wast ├── simd_i16x8_arith.wast ├── simd_i16x8_arith2.wast ├── simd_i16x8_cmp.wast ├── simd_i16x8_extadd_pairwise_i8x16.wast ├── simd_i16x8_extmul_i8x16.wast ├── simd_i16x8_q15mulr_sat_s.wast ├── simd_i16x8_sat_arith.wast ├── simd_i32x4_arith.wast ├── simd_i32x4_arith2.wast ├── simd_i32x4_cmp.wast ├── simd_i32x4_dot_i16x8.wast ├── simd_i32x4_extadd_pairwise_i16x8.wast ├── simd_i32x4_extmul_i16x8.wast ├── simd_i32x4_trunc_sat_f32x4.wast ├── simd_i32x4_trunc_sat_f64x2.wast ├── simd_i64x2_arith.wast ├── simd_i64x2_arith2.wast ├── simd_i64x2_cmp.wast ├── simd_i64x2_extmul_i32x4.wast ├── simd_i8x16_arith.wast ├── simd_i8x16_arith2.wast ├── simd_i8x16_cmp.wast ├── simd_i8x16_sat_arith.wast ├── simd_int_to_int_extend.wast ├── simd_lane.wast ├── simd_linking.wast ├── simd_load.wast ├── simd_load16_lane.wast ├── simd_load32_lane.wast ├── simd_load64_lane.wast ├── simd_load8_lane.wast ├── simd_load_extend.wast ├── simd_load_splat.wast ├── simd_load_zero.wast ├── simd_splat.wast ├── simd_store.wast ├── simd_store16_lane.wast ├── simd_store32_lane.wast ├── simd_store64_lane.wast ├── simd_store8_lane.wast ├── skip-stack-guard-page.wast ├── stack.wast ├── start.wast ├── store.wast ├── switch.wast ├── table-sub.wast ├── table.wast ├── table_copy.wast ├── table_fill.wast ├── table_get.wast ├── table_grow.wast ├── table_init.wast ├── table_set.wast ├── table_size.wast ├── token.wast ├── traps.wast ├── type.wast ├── unreachable.wast ├── unreached-invalid.wast ├── unreached-valid.wast ├── unwind.wast ├── update-testsuite.sh ├── utf8-custom-section-id.wast ├── utf8-import-field.wast ├── utf8-import-module.wast └── utf8-invalid-encoding.wast └── wast_runner.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "makepad-stitch" 3 | version = "0.1.0" 4 | edition = "2021" 5 | description = "An experimental Wasm interpreter written in Rust that is designed to be very fast and lightweight." 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/makepad/stitch" 9 | 10 | [profile.dev] 11 | opt-level = 1 12 | 13 | [dev-dependencies] 14 | criterion = "0.5.1" 15 | wast = "200.0.0" 16 | 17 | [[bench]] 18 | name = "benches" 19 | harness = false 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 makepad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /benches/wat/fac_iter.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func $fac_iter (export "fac_iter") (param $n i64) (result i64) 3 | (local $acc i64) 4 | (local.set $acc 5 | (i64.const 1) 6 | ) 7 | 8 | (block $break 9 | (br_if $break 10 | (i64.lt_u 11 | (local.get $n) 12 | (i64.const 2) 13 | ) 14 | ) 15 | (loop $continue 16 | (local.set 17 | $acc 18 | (i64.mul 19 | (local.get $acc) 20 | (local.get $n) 21 | ) 22 | ) 23 | (local.set $n 24 | (i64.sub 25 | (local.get $n) 26 | (i64.const 1) 27 | ) 28 | ) 29 | (br_if $continue 30 | (i64.gt_s 31 | (local.get $n) 32 | (i64.const 1) 33 | ) 34 | ) 35 | ) 36 | ) 37 | (local.get $acc) 38 | ) 39 | ) -------------------------------------------------------------------------------- /benches/wat/fac_rec.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func $fac_rec (export "fac_rec") (param $n i64) (result i64) 3 | (if (result i64) 4 | (i64.eq 5 | (local.get $n) 6 | (i64.const 0) 7 | ) 8 | (then 9 | (i64.const 1) 10 | ) 11 | (else 12 | (i64.mul 13 | (local.get $n) 14 | (call $fac_rec 15 | (i64.sub 16 | (local.get $n) 17 | (i64.const 1) 18 | ) 19 | ) 20 | ) 21 | ) 22 | ) 23 | ) 24 | ) 25 | -------------------------------------------------------------------------------- /benches/wat/fib_iter.wat: -------------------------------------------------------------------------------- 1 | (func $fib_iter (export "fib_iter") (param $n i64) (result i64) 2 | (local $n1 i64) 3 | (local $n2 i64) 4 | (local $i i64) 5 | (local $tmp i64) 6 | 7 | (if 8 | (i64.lt_u 9 | (local.get $n) 10 | (i64.const 2) 11 | ) 12 | (then 13 | (return 14 | (local.get $n) 15 | ) 16 | ) 17 | ) 18 | (local.set $n1 19 | (i64.const 0) 20 | ) 21 | (local.set $n2 22 | (i64.const 1) 23 | ) 24 | (local.set $i 25 | (i64.const 2) 26 | ) 27 | (block $break 28 | (loop $continue 29 | (local.set $tmp 30 | (i64.add 31 | (local.get $n1) 32 | (local.get $n2) 33 | ) 34 | ) 35 | (local.set $n1 36 | (local.get $n2) 37 | ) 38 | (local.set $n2 39 | (local.get $tmp) 40 | ) 41 | (br_if $break 42 | (i64.eq 43 | (local.get $i) 44 | (local.get $n) 45 | ) 46 | ) 47 | (local.set $i 48 | (i64.add 49 | (local.get $i) 50 | (i64.const 1) 51 | ) 52 | ) 53 | (br $continue) 54 | ) 55 | ) 56 | (local.get $n2) 57 | ) -------------------------------------------------------------------------------- /benches/wat/fib_rec.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func $fib_rec (export "fib_rec") (param $n i64) (result i64) 3 | (if 4 | (i64.lt_u 5 | (local.get $n) 6 | (i64.const 2) 7 | ) 8 | (then 9 | (return 10 | (local.get $n) 11 | ) 12 | ) 13 | ) 14 | (return 15 | (i64.add 16 | (call $fib_rec 17 | (i64.sub 18 | (local.get $n) 19 | (i64.const 2) 20 | ) 21 | ) 22 | (call $fib_rec 23 | (i64.sub 24 | (local.get $n) 25 | (i64.const 1) 26 | ) 27 | ) 28 | ) 29 | ) 30 | ) 31 | ) 32 | -------------------------------------------------------------------------------- /benches/wat/fill.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (memory (export "memory") 16) 3 | (func (export "fill") (param $idx i32) (param $val i32) (param $count i32) 4 | (block $break 5 | (loop $loop 6 | (br_if 7 | $break 8 | (i32.eqz 9 | (local.get $count) 10 | ) 11 | ) 12 | (i32.store8 offset=0 13 | (local.get $idx) 14 | (local.get $val) 15 | ) 16 | (local.set $idx 17 | (i32.add 18 | (local.get $idx) 19 | (i32.const 1) 20 | ) 21 | ) 22 | (local.set $count 23 | (i32.sub 24 | (local.get $count) 25 | (i32.const 1) 26 | ) 27 | ) 28 | (br $loop) 29 | ) 30 | ) 31 | (return) 32 | ) 33 | ) -------------------------------------------------------------------------------- /benches/wat/sum.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (memory (export "memory") 16) 3 | (func (export "sum") (param $idx i32) (param $count i32) (result i64) 4 | (local $acc i64) 5 | 6 | (block $break 7 | (loop $continue 8 | (br_if 9 | $break 10 | (i32.eqz 11 | (local.get $count) 12 | ) 13 | ) 14 | (local.set $acc 15 | (i64.add 16 | (local.get $acc) 17 | (i64.load8_u offset=0 18 | (local.get $idx) 19 | ) 20 | ) 21 | ) 22 | (local.set $idx 23 | (i32.add 24 | (local.get $idx) 25 | (i32.const 1) 26 | ) 27 | ) 28 | (local.set $count 29 | (i32.sub 30 | (local.get $count) 31 | (i32.const 1) 32 | ) 33 | ) 34 | (br $continue) 35 | ) 36 | ) 37 | (return 38 | (local.get $acc) 39 | ) 40 | ) 41 | ) -------------------------------------------------------------------------------- /coremark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "makepad-stitch-coremark" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | makepad-stitch = { path = ".." } 8 | wasm3 = { version = "0.3.1", features = ["build-bindgen"] } 9 | wasmi = "0.31.2" 10 | wasmtime = "20.0.1" 11 | -------------------------------------------------------------------------------- /coremark/src/coremark-minimal.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makepad/stitch/1a5b5d8ae104f37264d94f418a3009fcb77ce4ed/coremark/src/coremark-minimal.wasm -------------------------------------------------------------------------------- /coremark/src/main.rs: -------------------------------------------------------------------------------- 1 | fn clock_ms() -> u64 { 2 | use std::time::{SystemTime, UNIX_EPOCH}; 3 | 4 | SystemTime::now() 5 | .duration_since(UNIX_EPOCH) 6 | .unwrap() 7 | .as_millis() as u64 8 | } 9 | 10 | fn stitch(bytes: &[u8]) -> f32 { 11 | use makepad_stitch::*; 12 | 13 | let engine = Engine::new(); 14 | let mut store = Store::new(engine); 15 | let module = Module::new(store.engine(), bytes).unwrap(); 16 | let mut linker = Linker::new(); 17 | let clock_ms = Func::wrap(&mut store, clock_ms); 18 | linker.define("env", "clock_ms", clock_ms); 19 | let instance = linker.instantiate(&mut store, &module).unwrap(); 20 | let run = instance.exported_func("run").unwrap(); 21 | let mut results = [Val::F32(0.0)]; 22 | run.call(&mut store, &[], &mut results).unwrap(); 23 | results[0].to_f32().unwrap() 24 | } 25 | 26 | fn wasm3(bytes: &[u8]) -> f32 { 27 | use wasm3::Environment; 28 | 29 | wasm3::make_func_wrapper!(clock_ms_wrap: clock_ms() -> u64); 30 | 31 | let environment = Environment::new().unwrap(); 32 | let runtime = environment.create_runtime(1024 * 1024).unwrap(); 33 | let mut module = runtime.parse_and_load_module(bytes).unwrap(); 34 | module 35 | .link_function::<(), u64>("env", "clock_ms", clock_ms_wrap) 36 | .unwrap(); 37 | let run = module.find_function::<(), f32>("run").unwrap(); 38 | run.call().unwrap() 39 | } 40 | 41 | fn wasmi(bytes: &[u8]) -> f32 { 42 | use wasmi::{core::F32, *}; 43 | 44 | let config = Config::default(); 45 | let engine = Engine::new(&config); 46 | let mut store = Store::new(&engine, ()); 47 | let module = Module::new(&engine, bytes).unwrap(); 48 | let mut linker = Linker::new(&engine); 49 | let clock_ms = Func::wrap(&mut store, clock_ms); 50 | linker.define("env", "clock_ms", clock_ms).unwrap(); 51 | let instance = linker.instantiate(&mut store, &module).unwrap(); 52 | let instance = instance.start(&mut store).unwrap(); 53 | let run = instance.get_func(&store, "run").unwrap(); 54 | let mut results = [Value::F32(F32::from_float(0.0))]; 55 | run.call(&mut store, &[], &mut results).unwrap(); 56 | results[0].f32().unwrap().to_float() 57 | } 58 | 59 | fn wasmtime(bytes: &[u8]) -> f32 { 60 | use wasmtime::*; 61 | 62 | let config = Config::default(); 63 | let engine = Engine::new(&config).unwrap(); 64 | let mut store = Store::new(&engine, ()); 65 | let module = Module::new(&engine, bytes).unwrap(); 66 | let mut linker = Linker::new(&engine); 67 | let clock_ms = Func::wrap(&mut store, clock_ms); 68 | linker 69 | .define(&mut store, "env", "clock_ms", clock_ms) 70 | .unwrap(); 71 | let instance = linker.instantiate(&mut store, &module).unwrap(); 72 | let run = instance.get_func(&mut store, "run").unwrap(); 73 | let mut results = [Val::F32(0)]; 74 | run.call(&mut store, &[], &mut results).unwrap(); 75 | results[0].f32().unwrap() 76 | } 77 | 78 | fn main() { 79 | let bytes = include_bytes!("coremark-minimal.wasm"); 80 | println!("stitch {}", stitch(bytes)); 81 | println!("wasm3 {}", wasm3(bytes)); 82 | println!("wasmi {}", wasmi(bytes)); 83 | println!("wasmtime {}", wasmtime(bytes)); 84 | } 85 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "makepad-stitch-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = "0.4" 12 | wasm-smith = "0.200.0" 13 | wasmtime = "19.0.2" 14 | 15 | [dependencies.makepad-stitch] 16 | path = ".." 17 | 18 | [[bin]] 19 | name = "differential" 20 | path = "fuzz_targets/differential.rs" 21 | test = false 22 | doc = false 23 | bench = false 24 | -------------------------------------------------------------------------------- /src/aliasable_box.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fmt, 3 | mem::ManuallyDrop, 4 | ops::{Deref, DerefMut}, 5 | ptr::NonNull, 6 | }; 7 | 8 | pub(crate) struct AliasableBox 9 | where 10 | T: ?Sized, 11 | { 12 | ptr: NonNull, 13 | } 14 | 15 | impl AliasableBox 16 | where 17 | T: ?Sized, 18 | { 19 | pub(crate) fn from_box(boxed: Box) -> Self { 20 | Self { 21 | ptr: unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) }, 22 | } 23 | } 24 | 25 | pub(crate) fn as_raw(&self) -> NonNull { 26 | self.ptr 27 | } 28 | } 29 | 30 | impl fmt::Debug for AliasableBox 31 | where 32 | T: ?Sized + fmt::Debug, 33 | { 34 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 35 | (**self).fmt(f) 36 | } 37 | } 38 | 39 | impl Deref for AliasableBox 40 | where 41 | T: ?Sized, 42 | { 43 | type Target = T; 44 | 45 | fn deref(&self) -> &Self::Target { 46 | unsafe { self.ptr.as_ref() } 47 | } 48 | } 49 | 50 | impl DerefMut for AliasableBox 51 | where 52 | T: ?Sized, 53 | { 54 | fn deref_mut(&mut self) -> &mut Self::Target { 55 | unsafe { self.ptr.as_mut() } 56 | } 57 | } 58 | 59 | impl Drop for AliasableBox 60 | where 61 | T: ?Sized, 62 | { 63 | fn drop(&mut self) { 64 | let this = ManuallyDrop::new(self); 65 | drop(unsafe { Box::from_raw(this.ptr.as_ptr()) }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | pub(crate) const MAX_TYPE_COUNT: usize = 1_000_000; 2 | pub(crate) const MAX_IMPORT_COUNT: usize = 100_000; 3 | pub(crate) const MAX_FUNC_COUNT: usize = 1_000_000; 4 | pub(crate) const MAX_FUNC_PARAM_COUNT: usize = 1_000; 5 | pub(crate) const MAX_FUNC_RESULT_COUNT: usize = 1_000; 6 | pub(crate) const MAX_TABLE_COUNT: usize = 100; 7 | pub(crate) const MAX_MEMORY_COUNT: usize = 1; 8 | pub(crate) const MAX_GLOBAL_COUNT: usize = 1_000_000; 9 | pub(crate) const MAX_EXPORT_COUNT: usize = 100_000; 10 | pub(crate) const MAX_ELEM_COUNT: usize = 100_000; 11 | pub(crate) const MAX_ELEM_SIZE: usize = 1_000_000; 12 | pub(crate) const MAX_FUNC_LOCAL_COUNT: usize = 50_000; 13 | pub(crate) const MAX_FUNC_BODY_SIZE: usize = 128 * 1_024; 14 | pub(crate) const MAX_DATA_COUNT: usize = 100_000; 15 | pub(crate) const MAX_DATA_SIZE: usize = 1_000_000; 16 | -------------------------------------------------------------------------------- /src/const_expr.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | decode::{Decode, DecodeError, Decoder}, 3 | func::Func, 4 | func_ref::FuncRef, 5 | global::{Global, Mut}, 6 | module::ModuleBuilder, 7 | ref_::{Ref, RefType}, 8 | store::Store, 9 | val::{Val, ValType}, 10 | }; 11 | 12 | #[derive(Clone, Debug)] 13 | pub(crate) struct ConstExpr { 14 | instr: ConstInstr, 15 | } 16 | 17 | impl ConstExpr { 18 | pub(crate) fn new_ref_func(func_idx: u32) -> Self { 19 | Self { 20 | instr: ConstInstr::RefFunc(func_idx), 21 | } 22 | } 23 | 24 | pub(crate) fn func_idx(&self) -> Option { 25 | match self.instr { 26 | ConstInstr::RefFunc(func_idx) => Some(func_idx), 27 | _ => None, 28 | } 29 | } 30 | 31 | pub(crate) fn validate(&self, module: &ModuleBuilder) -> Result { 32 | match self.instr { 33 | ConstInstr::I32Const(_) => Ok(ValType::I32), 34 | ConstInstr::I64Const(_) => Ok(ValType::I64), 35 | ConstInstr::F32Const(_) => Ok(ValType::F32), 36 | ConstInstr::F64Const(_) => Ok(ValType::F64), 37 | ConstInstr::RefNull(type_) => Ok(type_.into()), 38 | ConstInstr::RefFunc(func_idx) => { 39 | module.func(func_idx)?; 40 | Ok(ValType::FuncRef) 41 | } 42 | ConstInstr::GlobalGet(global_idx) => { 43 | let type_ = module.imported_global(global_idx)?; 44 | if type_.mut_ != Mut::Const { 45 | return Err(DecodeError::new("global is immutable")); 46 | } 47 | Ok(type_.val) 48 | } 49 | } 50 | } 51 | 52 | pub(crate) fn evaluate(&self, store: &Store, context: &impl EvaluationContext) -> Val { 53 | match self.instr { 54 | ConstInstr::I32Const(val) => val.into(), 55 | ConstInstr::I64Const(val) => val.into(), 56 | ConstInstr::F32Const(val) => val.into(), 57 | ConstInstr::F64Const(val) => val.into(), 58 | ConstInstr::RefNull(ref_ty) => Ref::null(ref_ty).into(), 59 | ConstInstr::RefFunc(func_idx) => FuncRef::new(context.func(func_idx).unwrap()).into(), 60 | ConstInstr::GlobalGet(global_idx) => { 61 | context.global(global_idx).unwrap().get(store).into() 62 | } 63 | } 64 | } 65 | } 66 | 67 | impl Decode for ConstExpr { 68 | fn decode(decoder: &mut Decoder<'_>) -> Result { 69 | let instr = decoder.decode()?; 70 | if decoder.read_byte()? != 0x0B { 71 | return Err(DecodeError::new("expected end opcode")); 72 | } 73 | Ok(Self { instr }) 74 | } 75 | } 76 | 77 | pub(crate) trait EvaluationContext { 78 | fn func(&self, idx: u32) -> Option; 79 | fn global(&self, idx: u32) -> Option; 80 | } 81 | 82 | #[derive(Clone, Copy, Debug)] 83 | enum ConstInstr { 84 | I32Const(i32), 85 | I64Const(i64), 86 | F32Const(f32), 87 | F64Const(f64), 88 | RefNull(RefType), 89 | RefFunc(u32), 90 | GlobalGet(u32), 91 | } 92 | 93 | impl Decode for ConstInstr { 94 | fn decode(decoder: &mut Decoder<'_>) -> Result { 95 | match decoder.read_byte()? { 96 | 0x23 => Ok(Self::GlobalGet(decoder.decode()?)), 97 | 0x41 => Ok(Self::I32Const(decoder.decode()?)), 98 | 0x42 => Ok(Self::I64Const(decoder.decode()?)), 99 | 0x43 => Ok(Self::F32Const(decoder.decode()?)), 100 | 0x44 => Ok(Self::F64Const(decoder.decode()?)), 101 | 0xD0 => Ok(Self::RefNull(decoder.decode()?)), 102 | 0xD2 => Ok(Self::RefFunc(decoder.decode()?)), 103 | _ => Err(DecodeError::new("illegal const opcode")), 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/data.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::store::{Handle, Store, StoreId, UnguardedHandle}, 3 | std::sync::Arc, 4 | }; 5 | 6 | /// A Wasm data segment. 7 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 8 | #[repr(transparent)] 9 | pub(crate) struct Data(pub(crate) Handle); 10 | 11 | impl Data { 12 | pub(crate) fn new(store: &mut Store, bytes: Arc<[u8]>) -> Self { 13 | Self(store.insert_data(DataEntity::new(bytes))) 14 | } 15 | 16 | pub(crate) fn drop_bytes(self, store: &mut Store) { 17 | self.0.as_mut(store).drop_bytes(); 18 | } 19 | 20 | pub(crate) unsafe fn from_unguarded(data: UnguardedData, store_id: StoreId) -> Self { 21 | Self(Handle::from_unguarded(data, store_id)) 22 | } 23 | 24 | pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedData { 25 | self.0.to_unguarded(store_id) 26 | } 27 | } 28 | 29 | /// An unguarded [`Data`]. 30 | pub(crate) type UnguardedData = UnguardedHandle; 31 | 32 | /// The representation of a [`Data`] in the store. 33 | #[derive(Debug)] 34 | pub(crate) struct DataEntity { 35 | bytes: Option>, 36 | } 37 | 38 | impl DataEntity { 39 | fn new(bytes: Arc<[u8]>) -> Self { 40 | Self { bytes: Some(bytes) } 41 | } 42 | 43 | pub(crate) fn bytes(&self) -> &[u8] { 44 | self.bytes.as_ref().map_or(&[], |bytes| &bytes) 45 | } 46 | 47 | pub(crate) fn drop_bytes(&mut self) { 48 | self.bytes = None; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/downcast.rs: -------------------------------------------------------------------------------- 1 | pub(crate) trait DowncastRef { 2 | fn downcast_ref(from: &T) -> Option<&Self>; 3 | } 4 | 5 | pub(crate) trait DowncastMut { 6 | fn downcast_mut(from: &mut T) -> Option<&mut Self>; 7 | } 8 | -------------------------------------------------------------------------------- /src/elem.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | downcast::{DowncastMut, DowncastRef}, 3 | extern_ref::UnguardedExternRef, 4 | func_ref::UnguardedFuncRef, 5 | ref_::RefType, 6 | store::{Handle, Store, StoreId, UnguardedHandle}, 7 | }; 8 | 9 | /// A Wasm element segment. 10 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 11 | #[repr(transparent)] 12 | pub(crate) struct Elem(pub(crate) Handle); 13 | 14 | impl Elem { 15 | pub(crate) unsafe fn new_unguarded(store: &mut Store, elems: UnguardedElems) -> Self { 16 | Self(store.insert_elem(match elems { 17 | UnguardedElems::FuncRef(elems) => ElemEntity::FuncRef(ElemEntityT { 18 | elems: elems.into(), 19 | }), 20 | UnguardedElems::ExternRef(elems) => ElemEntity::ExternRef(ElemEntityT { 21 | elems: elems.into(), 22 | }), 23 | })) 24 | } 25 | 26 | pub(crate) fn type_(self, store: &Store) -> RefType { 27 | match self.0.as_ref(store) { 28 | ElemEntity::FuncRef(_) => RefType::FuncRef, 29 | ElemEntity::ExternRef(_) => RefType::ExternRef, 30 | } 31 | } 32 | 33 | pub(crate) fn drop_elems(self, store: &mut Store) { 34 | match self.0.as_mut(store) { 35 | ElemEntity::FuncRef(elem) => elem.drop_elems(), 36 | ElemEntity::ExternRef(elem) => elem.drop_elems(), 37 | } 38 | } 39 | 40 | pub(crate) unsafe fn from_unguarded(elem: UnguardedElem, store_id: StoreId) -> Self { 41 | Self(Handle::from_unguarded(elem, store_id)) 42 | } 43 | 44 | pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedElem { 45 | self.0.to_unguarded(store_id).into() 46 | } 47 | } 48 | 49 | pub(crate) type UnguardedElem = UnguardedHandle; 50 | 51 | #[derive(Clone, Debug)] 52 | pub(crate) enum UnguardedElems { 53 | FuncRef(Vec), 54 | ExternRef(Vec), 55 | } 56 | 57 | #[derive(Debug)] 58 | pub(crate) enum ElemEntity { 59 | FuncRef(ElemEntityT), 60 | ExternRef(ElemEntityT), 61 | } 62 | 63 | impl ElemEntity { 64 | pub(crate) fn downcast_ref(&self) -> Option<&ElemEntityT> 65 | where 66 | ElemEntityT: DowncastRef, 67 | { 68 | ElemEntityT::downcast_ref(self) 69 | } 70 | 71 | pub(crate) fn downcast_mut(&mut self) -> Option<&mut ElemEntityT> 72 | where 73 | ElemEntityT: DowncastMut, 74 | { 75 | ElemEntityT::downcast_mut(self) 76 | } 77 | } 78 | 79 | #[derive(Debug)] 80 | pub(crate) struct ElemEntityT { 81 | elems: Box<[T]>, 82 | } 83 | 84 | impl ElemEntityT { 85 | pub(crate) fn elems(&self) -> &[T] { 86 | &self.elems 87 | } 88 | 89 | pub(crate) fn drop_elems(&mut self) { 90 | self.elems = Box::new([]); 91 | } 92 | } 93 | 94 | impl DowncastRef for ElemEntityT { 95 | fn downcast_ref(elem: &ElemEntity) -> Option<&Self> { 96 | match elem { 97 | ElemEntity::FuncRef(elem) => Some(elem), 98 | _ => None, 99 | } 100 | } 101 | } 102 | 103 | impl DowncastMut for ElemEntityT { 104 | fn downcast_mut(elem: &mut ElemEntity) -> Option<&mut Self> { 105 | match elem { 106 | ElemEntity::ExternRef(elem) => Some(elem), 107 | _ => None, 108 | } 109 | } 110 | } 111 | 112 | impl DowncastRef for ElemEntityT { 113 | fn downcast_ref(elem: &ElemEntity) -> Option<&Self> { 114 | match elem { 115 | ElemEntity::ExternRef(elem) => Some(elem), 116 | _ => None, 117 | } 118 | } 119 | } 120 | 121 | impl DowncastMut for ElemEntityT { 122 | fn downcast_mut(elem: &mut ElemEntity) -> Option<&mut Self> { 123 | match elem { 124 | ElemEntity::FuncRef(elem) => Some(elem), 125 | _ => None, 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/engine.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{ 3 | code::{CompiledCode, UncompiledCode}, 4 | compile::Compiler, 5 | decode::DecodeError, 6 | func::{Func, FuncType}, 7 | instance::Instance, 8 | module::ModuleBuilder, 9 | store::Store, 10 | validate::Validator, 11 | }, 12 | std::sync::{Arc, Mutex}, 13 | }; 14 | 15 | /// A Wasm engine. 16 | #[derive(Clone, Debug)] 17 | pub struct Engine { 18 | inner: Arc, 19 | } 20 | 21 | impl Engine { 22 | /// Creates a new [`Engine`]. 23 | pub fn new() -> Engine { 24 | Engine { 25 | inner: Arc::new(EngineInner { 26 | validators: Mutex::new(Pool::new()), 27 | compilers: Mutex::new(Pool::new()), 28 | }), 29 | } 30 | } 31 | 32 | pub(crate) fn validate( 33 | &self, 34 | type_: &FuncType, 35 | module: &ModuleBuilder, 36 | code: &UncompiledCode, 37 | ) -> Result<(), DecodeError> { 38 | let mut validator = self.inner.validators.lock().unwrap().pop_or_default(); 39 | let result = validator.validate(type_, module, code); 40 | self.inner.validators.lock().unwrap().push(validator); 41 | result 42 | } 43 | 44 | pub(crate) fn compile( 45 | &self, 46 | store: &mut Store, 47 | func: Func, 48 | instance: &Instance, 49 | code: &UncompiledCode, 50 | ) -> CompiledCode { 51 | let mut compiler = self.inner.compilers.lock().unwrap().pop_or_default(); 52 | let result = compiler.compile(store, func, instance, code); 53 | self.inner.compilers.lock().unwrap().push(compiler); 54 | result 55 | } 56 | } 57 | 58 | impl Default for Engine { 59 | fn default() -> Self { 60 | Self::new() 61 | } 62 | } 63 | 64 | #[derive(Debug)] 65 | struct EngineInner { 66 | validators: Mutex>, 67 | compilers: Mutex>, 68 | } 69 | 70 | #[derive(Debug)] 71 | struct Pool { 72 | items: Vec, 73 | } 74 | 75 | impl Pool 76 | where 77 | T: Default, 78 | { 79 | fn new() -> Self { 80 | Self { items: Vec::new() } 81 | } 82 | 83 | fn pop_or_default(&mut self) -> T { 84 | self.items.pop().unwrap_or_default() 85 | } 86 | 87 | fn push(&mut self, item: T) { 88 | self.items.push(item); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{ 3 | decode::DecodeError, func::FuncError, global::GlobalError, linker::InstantiateError, 4 | mem::MemError, table::TableError, trap::Trap, 5 | }, 6 | std::{error, fmt}, 7 | }; 8 | 9 | /// An error that can occur when operating on a [`Module`](crate::Module) or [`Func`](crate::Func). 10 | #[derive(Debug)] 11 | pub enum Error { 12 | Decode(DecodeError), 13 | Instantiate(InstantiateError), 14 | Func(FuncError), 15 | Table(TableError), 16 | Memory(MemError), 17 | Global(GlobalError), 18 | Trap(Trap), 19 | } 20 | 21 | impl error::Error for Error { 22 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { 23 | match self { 24 | Error::Decode(error) => Some(error), 25 | Error::Instantiate(error) => Some(error), 26 | Error::Func(error) => Some(error), 27 | Error::Table(error) => Some(error), 28 | Error::Memory(error) => Some(error), 29 | Error::Global(error) => Some(error), 30 | Error::Trap(error) => Some(error), 31 | } 32 | } 33 | } 34 | 35 | impl fmt::Display for Error { 36 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 37 | match self { 38 | Error::Decode(_) => write!(f, "decode error"), 39 | Error::Instantiate(_) => write!(f, "instantiate error"), 40 | Error::Func(_) => write!(f, "function error"), 41 | Error::Table(_) => write!(f, "table error"), 42 | Error::Memory(_) => write!(f, "memory error"), 43 | Error::Global(_) => write!(f, "global error"), 44 | Error::Trap(_) => write!(f, "trap"), 45 | } 46 | } 47 | } 48 | 49 | impl From for Error { 50 | fn from(error: DecodeError) -> Self { 51 | Error::Decode(error) 52 | } 53 | } 54 | 55 | impl From for Error { 56 | fn from(error: InstantiateError) -> Self { 57 | Error::Instantiate(error) 58 | } 59 | } 60 | 61 | impl From for Error { 62 | fn from(error: FuncError) -> Self { 63 | Error::Func(error) 64 | } 65 | } 66 | 67 | impl From for Error { 68 | fn from(error: TableError) -> Self { 69 | Error::Table(error) 70 | } 71 | } 72 | 73 | impl From for Error { 74 | fn from(error: MemError) -> Self { 75 | Error::Memory(error) 76 | } 77 | } 78 | 79 | impl From for Error { 80 | fn from(error: GlobalError) -> Self { 81 | Error::Global(error) 82 | } 83 | } 84 | 85 | impl From for Error { 86 | fn from(trap: Trap) -> Self { 87 | Error::Trap(trap) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/extern_.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::store::{Handle, Store, StoreId, UnguardedHandle}, 3 | std::any::Any, 4 | }; 5 | 6 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 7 | pub(crate) struct Extern(Handle); 8 | 9 | impl Extern { 10 | pub(crate) fn new(store: &mut Store, object: impl Any + Send + Sync + 'static) -> Self { 11 | Self(store.insert_extern(ExternEntity::new(object))) 12 | } 13 | 14 | pub(crate) fn get(self, store: &Store) -> &dyn Any { 15 | self.0.as_ref(store).get() 16 | } 17 | 18 | pub(crate) unsafe fn from_unguarded(extern_: UnguardedExtern, store_id: StoreId) -> Self { 19 | Self(Handle::from_unguarded(extern_, store_id)) 20 | } 21 | 22 | pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedExtern { 23 | self.0.to_unguarded(store_id) 24 | } 25 | } 26 | 27 | pub(crate) type UnguardedExtern = UnguardedHandle; 28 | 29 | #[derive(Debug)] 30 | pub(crate) struct ExternEntity { 31 | object: Box, 32 | } 33 | 34 | impl ExternEntity { 35 | fn new(object: impl Any + Send + Sync + 'static) -> Self { 36 | Self { 37 | object: Box::new(object), 38 | } 39 | } 40 | 41 | fn get(&self) -> &dyn Any { 42 | &*self.object 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/extern_ref.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{ 3 | extern_::{Extern, UnguardedExtern}, 4 | store::{Store, StoreId}, 5 | }, 6 | std::any::Any, 7 | }; 8 | 9 | /// A nullable reference to an external object. 10 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 11 | pub struct ExternRef(Option); 12 | 13 | impl ExternRef { 14 | /// Creates a new [`ExternRef`] wrapping the given underlying object. 15 | pub fn new(store: &mut Store, object: impl Into>) -> Self 16 | where 17 | T: Any + Send + Sync + 'static, 18 | { 19 | Self(object.into().map(|object| Extern::new(store, object))) 20 | } 21 | 22 | /// Creates a null [`ExternRef`]. 23 | pub fn null() -> Self { 24 | Self(None) 25 | } 26 | 27 | /// Returns `true` if this [`ExternRef`] is null. 28 | pub fn is_null(self) -> bool { 29 | self.0.is_none() 30 | } 31 | 32 | /// Returns a reference to the underlying object if this `ExternRef` is not null. 33 | pub fn get(self, store: &Store) -> Option<&dyn Any> { 34 | self.0.as_ref().map(|extern_| extern_.get(store)) 35 | } 36 | 37 | /// Converts the given [`UnguardedExternRef`] to a [`ExternRef`]. 38 | /// 39 | /// # Safety 40 | /// 41 | /// The given [`UnguardedExternRef`] must be owned by the [`Store`] with the given [`StoreId`]. 42 | pub(crate) unsafe fn from_unguarded(extern_: UnguardedExternRef, store_id: StoreId) -> Self { 43 | Self(extern_.map(|extern_| unsafe { Extern::from_unguarded(extern_, store_id) })) 44 | } 45 | 46 | /// Converts this [`ExternRef`] to an [`UnguardedExternRef`]. 47 | /// 48 | /// # Panics 49 | /// 50 | /// This [`FuncRef`] is not owned by the [`Store`] with the given [`StoreId`]. 51 | pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedExternRef { 52 | self.0.map(|extern_| extern_.to_unguarded(store_id)) 53 | } 54 | } 55 | 56 | /// An unguarded [`ExternRef`]. 57 | pub(crate) type UnguardedExternRef = Option; 58 | -------------------------------------------------------------------------------- /src/func_ref.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | func::{Func, UnguardedFunc}, 3 | store::{Handle, StoreId}, 4 | }; 5 | 6 | /// A nullable reference to a [`Func`]. 7 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 8 | pub struct FuncRef(pub(crate) Option); 9 | 10 | impl FuncRef { 11 | /// Creates a new [`FuncRef`]. 12 | pub fn new(func: impl Into>) -> Self { 13 | Self(func.into()) 14 | } 15 | 16 | /// Creates a null [`FuncRef`]. 17 | pub fn null() -> Self { 18 | Self(None) 19 | } 20 | 21 | /// Returns `true` if this [`FuncRef`] is null. 22 | pub fn is_null(self) -> bool { 23 | self.0.is_none() 24 | } 25 | 26 | /// Returns the underlying [`Func`] if this [`FuncRef`] is not null. 27 | pub fn get(self) -> Option { 28 | self.0 29 | } 30 | 31 | /// Converts the given [`UnguardedFuncRef`] to a [`FuncRef`]. 32 | /// 33 | /// # Safety 34 | /// 35 | /// The [[`UnguardedFuncRef`] must be owned by the [`Store`] with the given [`StoreId`]. 36 | pub(crate) unsafe fn from_unguarded(func: UnguardedFuncRef, store_id: StoreId) -> Self { 37 | Self(func.map(|func| unsafe { Func(Handle::from_unguarded(func, store_id)) })) 38 | } 39 | 40 | /// Converts this [`FuncRef`] to an [`UnguardedFuncRef`]. 41 | /// 42 | /// # Panics 43 | /// 44 | /// This [`FuncRef`] is not owned by the [`Store`] with the given [`StoreId`]. 45 | pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedFuncRef { 46 | self.0.map(|func| func.0.to_unguarded(store_id)) 47 | } 48 | } 49 | 50 | impl From for FuncRef { 51 | fn from(func: Func) -> Self { 52 | Self::new(func) 53 | } 54 | } 55 | 56 | /// An unguarded [`FuncRef`]. 57 | pub(crate) type UnguardedFuncRef = Option; 58 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod aliasable_box; 2 | mod code; 3 | mod compile; 4 | mod config; 5 | mod const_expr; 6 | mod data; 7 | mod decode; 8 | mod downcast; 9 | mod elem; 10 | mod engine; 11 | mod error; 12 | mod exec; 13 | mod extern_; 14 | mod extern_ref; 15 | mod extern_val; 16 | mod func; 17 | mod func_ref; 18 | mod global; 19 | mod instance; 20 | mod into_func; 21 | mod limits; 22 | mod linker; 23 | mod mem; 24 | mod module; 25 | mod ops; 26 | mod ref_; 27 | mod stack; 28 | mod store; 29 | mod table; 30 | mod trap; 31 | mod val; 32 | mod validate; 33 | 34 | pub use self::{ 35 | decode::DecodeError, 36 | engine::Engine, 37 | error::Error, 38 | extern_ref::ExternRef, 39 | extern_val::{ExternType, ExternVal}, 40 | func::{Func, FuncError, FuncType}, 41 | func_ref::FuncRef, 42 | global::{Global, GlobalError, GlobalType, Mut}, 43 | instance::{Instance, InstanceExports}, 44 | limits::Limits, 45 | linker::{InstantiateError, Linker}, 46 | mem::{Mem, MemError, MemType}, 47 | module::{Module, ModuleExports, ModuleImports}, 48 | ref_::{Ref, RefType}, 49 | store::Store, 50 | table::{Table, TableError, TableType}, 51 | val::{Val, ValType}, 52 | }; 53 | -------------------------------------------------------------------------------- /src/limits.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::{Decode, DecodeError, Decoder}; 2 | 3 | /// A size range. 4 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 5 | pub struct Limits { 6 | pub min: u32, 7 | pub max: Option, 8 | } 9 | 10 | impl Limits { 11 | /// Returns `true` if this [`Limits`] is valid within the range `0..=limit`. 12 | /// 13 | /// A [`Limits`] is valid within the range `0..=limit` if its minimum is not greater than 14 | /// `limit` and its maximum, if it exists, is neither less than its minimum nor greater than 15 | /// `limit`. 16 | pub fn is_valid(self, limit: u32) -> bool { 17 | if self.min > limit { 18 | return false; 19 | } 20 | if self.max.map_or(false, |max| max < self.min || max > limit) { 21 | return false; 22 | } 23 | true 24 | } 25 | 26 | /// Returns `true` if this [`Limits`] is a sublimit of the given [`Limits`]. 27 | /// 28 | /// A [`Limits`] is a sublimit of another [`Limits`] if its minimum is not less than the 29 | /// other's, and its maximum, if it exists, is not greater than the other's. 30 | pub fn is_sublimit_of(self, other: Self) -> bool { 31 | if self.min < other.min { 32 | return false; 33 | } 34 | if let Some(other_max) = other.max { 35 | let Some(self_max) = self.max else { 36 | return false; 37 | }; 38 | if self_max > other_max { 39 | return false; 40 | } 41 | } 42 | true 43 | } 44 | } 45 | 46 | impl Decode for Limits { 47 | fn decode(decoder: &mut Decoder<'_>) -> Result { 48 | match decoder.read_byte()? { 49 | 0x00 => Ok(Limits { 50 | min: decoder.decode()?, 51 | max: None, 52 | }), 53 | 0x01 => Ok(Limits { 54 | min: decoder.decode()?, 55 | max: Some(decoder.decode()?), 56 | }), 57 | _ => Err(DecodeError::new("invalid limits")), 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/linker.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{ 3 | error::Error, extern_val::ExternVal, instance::Instance, module::Module, store::Store, 4 | }, 5 | std::{collections::HashMap, fmt, sync::Arc}, 6 | }; 7 | 8 | /// A linker for defining imports and instantiating [`Module`]s. 9 | #[derive(Clone, Debug)] 10 | pub struct Linker { 11 | strings: StringInterner, 12 | defs: HashMap<(InternedString, InternedString), ExternVal>, 13 | } 14 | 15 | impl Linker { 16 | /// Creates a new [`Linker`]. 17 | pub fn new() -> Self { 18 | Linker { 19 | strings: StringInterner::new(), 20 | defs: HashMap::new(), 21 | } 22 | } 23 | 24 | pub fn define(&mut self, module: &str, name: &str, val: impl Into) { 25 | let module = self.strings.get_or_intern(module); 26 | let name = self.strings.get_or_intern(name); 27 | assert!( 28 | self.defs.insert((module, name), val.into()).is_none(), 29 | "duplicate definition" 30 | ); 31 | } 32 | 33 | pub fn instantiate(&self, store: &mut Store, module: &Module) -> Result { 34 | module.instantiate(store, self) 35 | } 36 | 37 | pub(crate) fn lookup(&self, module: &str, name: &str) -> Option { 38 | let module = self.strings.get(module)?; 39 | let name = self.strings.get(name)?; 40 | self.defs.get(&(module, name)).copied() 41 | } 42 | } 43 | 44 | /// An error that can occur when instantiating a module. 45 | #[derive(Clone, Copy, Debug)] 46 | #[non_exhaustive] 47 | pub enum InstantiateError { 48 | DefNotFound, 49 | ImportKindMismatch, 50 | FuncTypeMismatch, 51 | GlobalTypeMismatch, 52 | TableTypeMismatch, 53 | MemTypeMismatch, 54 | } 55 | 56 | impl fmt::Display for InstantiateError { 57 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 58 | match self { 59 | Self::DefNotFound => write!(f, "definition not found"), 60 | Self::ImportKindMismatch => write!(f, "import kind mismatch"), 61 | Self::FuncTypeMismatch => write!(f, "function type mismatch"), 62 | Self::GlobalTypeMismatch => write!(f, "global type mismatch"), 63 | Self::TableTypeMismatch => write!(f, "table type mismatch"), 64 | Self::MemTypeMismatch => write!(f, "memory type mismatch"), 65 | } 66 | } 67 | } 68 | 69 | impl std::error::Error for InstantiateError {} 70 | 71 | #[derive(Clone, Debug)] 72 | struct StringInterner { 73 | strings: Vec>, 74 | indices: HashMap, usize>, 75 | } 76 | 77 | impl StringInterner { 78 | fn new() -> Self { 79 | StringInterner { 80 | strings: Vec::new(), 81 | indices: HashMap::new(), 82 | } 83 | } 84 | 85 | fn get(&self, string: &str) -> Option { 86 | let index = self.indices.get(string).copied()?; 87 | Some(InternedString(index)) 88 | } 89 | 90 | fn get_or_intern(&mut self, string: &str) -> InternedString { 91 | match self.indices.get(string).copied() { 92 | Some(index) => InternedString(index), 93 | None => { 94 | let index = self.strings.len(); 95 | let string: Arc = string.into(); 96 | self.strings.push(string.clone()); 97 | self.indices.insert(string, index); 98 | InternedString(index) 99 | } 100 | } 101 | } 102 | } 103 | 104 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 105 | struct InternedString(usize); 106 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use { 2 | makepad_stitch::{Engine, Linker, Module, Store, Val, ValType}, 3 | std::{env, fs}, 4 | }; 5 | 6 | fn main() { 7 | let mut args = env::args(); 8 | args.next().unwrap(); 9 | let wasm_file = args.next().unwrap(); 10 | let func_name = args.next().unwrap(); 11 | let args: Vec<_> = args.collect(); 12 | let engine = Engine::new(); 13 | let mut store = Store::new(engine); 14 | let bytes = fs::read(wasm_file).unwrap(); 15 | let module = Module::new(store.engine(), &bytes).unwrap(); 16 | let linker = Linker::new(); 17 | let instance = linker.instantiate(&mut store, &module).unwrap(); 18 | let func = instance.exported_func(&func_name).unwrap(); 19 | let args: Vec<_> = func 20 | .type_(&store) 21 | .params() 22 | .iter() 23 | .zip(args) 24 | .map(|(type_, string)| parse_val(*type_, &string)) 25 | .collect(); 26 | let mut results: Vec<_> = func 27 | .type_(&store) 28 | .results() 29 | .iter() 30 | .map(|type_| Val::default(*type_)) 31 | .collect(); 32 | func.call(&mut store, &args, &mut results).unwrap(); 33 | for result in results { 34 | print_val(result); 35 | } 36 | } 37 | 38 | fn parse_val(type_: ValType, string: &str) -> Val { 39 | match type_ { 40 | ValType::I32 => string.parse::().unwrap().into(), 41 | ValType::I64 => string.parse::().unwrap().into(), 42 | ValType::F32 => string.parse::().unwrap().into(), 43 | ValType::F64 => string.parse::().unwrap().into(), 44 | ValType::FuncRef => unimplemented!(), 45 | ValType::ExternRef => unimplemented!(), 46 | } 47 | } 48 | 49 | fn print_val(val: Val) { 50 | match val { 51 | Val::I32(val) => println!("{}", val), 52 | Val::I64(val) => println!("{}", val), 53 | Val::F32(val) => println!("{}", val), 54 | Val::F64(val) => println!("{}", val), 55 | Val::FuncRef(_) => unimplemented!(), 56 | Val::ExternRef(_) => unimplemented!(), 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/ref_.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | decode::{Decode, DecodeError, Decoder}, 3 | extern_ref::{ExternRef, UnguardedExternRef}, 4 | func_ref::{FuncRef, UnguardedFuncRef}, 5 | store::StoreId, 6 | }; 7 | 8 | /// A Wasm reference. 9 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 10 | pub enum Ref { 11 | FuncRef(FuncRef), 12 | ExternRef(ExternRef), 13 | } 14 | 15 | impl Ref { 16 | /// Returns a null [`Ref`] of the given [`RefType`]. 17 | pub fn null(type_: RefType) -> Self { 18 | match type_ { 19 | RefType::FuncRef => FuncRef::null().into(), 20 | RefType::ExternRef => ExternRef::null().into(), 21 | } 22 | } 23 | 24 | /// Returns the [`RefType`] of this [`Ref`]. 25 | pub fn type_(self) -> RefType { 26 | match self { 27 | Ref::FuncRef(_) => RefType::FuncRef, 28 | Ref::ExternRef(_) => RefType::ExternRef, 29 | } 30 | } 31 | 32 | /// Returns `true` if this [`Ref`] is a [`FuncRef`]. 33 | pub fn is_func_ref(self) -> bool { 34 | self.to_func_ref().is_some() 35 | } 36 | 37 | /// Returns `true` if this [`Ref`] is an [`ExternRef`]. 38 | pub fn is_extern_ref(self) -> bool { 39 | self.to_extern_ref().is_some() 40 | } 41 | 42 | /// Converts this [`Ref`] to a [`FuncRef`], if it is one. 43 | pub fn to_func_ref(self) -> Option { 44 | match self { 45 | Ref::FuncRef(val) => Some(val), 46 | _ => None, 47 | } 48 | } 49 | 50 | /// Converts this [`Ref`] to an [`ExternRef`], if it is one. 51 | pub fn to_extern_ref(self) -> Option { 52 | match self { 53 | Ref::ExternRef(val) => Some(val), 54 | _ => None, 55 | } 56 | } 57 | 58 | /// Converts the given [`UnguardedRef`] to a [`Ref`]. 59 | /// 60 | /// # Safety 61 | /// 62 | /// The [`UnguardedRef`] must be owned by the [`Store`] with the given [`StoreId`]. 63 | pub(crate) unsafe fn from_unguarded(val: UnguardedRef, store_id: StoreId) -> Self { 64 | match val { 65 | UnguardedRef::FuncRef(val) => FuncRef::from_unguarded(val, store_id).into(), 66 | UnguardedRef::ExternRef(val) => ExternRef::from_unguarded(val, store_id).into(), 67 | } 68 | } 69 | 70 | /// Converts this [`Ref`] to an [`UnguardedRef`]. 71 | /// 72 | /// # Panics 73 | /// 74 | /// This [`Ref`] is not owned by the [`Store`] with the given [`StoreId`]. 75 | pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedRef { 76 | match self { 77 | Ref::FuncRef(val) => val.to_unguarded(store_id).into(), 78 | Ref::ExternRef(val) => val.to_unguarded(store_id).into(), 79 | } 80 | } 81 | } 82 | 83 | impl From for Ref { 84 | fn from(val: FuncRef) -> Self { 85 | Ref::FuncRef(val) 86 | } 87 | } 88 | 89 | impl From for Ref { 90 | fn from(val: ExternRef) -> Self { 91 | Ref::ExternRef(val) 92 | } 93 | } 94 | 95 | /// An unguarded [`Ref`]. 96 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 97 | pub(crate) enum UnguardedRef { 98 | FuncRef(UnguardedFuncRef), 99 | ExternRef(UnguardedExternRef), 100 | } 101 | 102 | impl From for UnguardedRef { 103 | fn from(val: UnguardedFuncRef) -> Self { 104 | UnguardedRef::FuncRef(val) 105 | } 106 | } 107 | 108 | impl From for UnguardedRef { 109 | fn from(val: UnguardedExternRef) -> Self { 110 | UnguardedRef::ExternRef(val) 111 | } 112 | } 113 | 114 | /// The type of a [`Ref`]. 115 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 116 | pub enum RefType { 117 | FuncRef, 118 | ExternRef, 119 | } 120 | 121 | impl Decode for RefType { 122 | fn decode(decoder: &mut Decoder<'_>) -> Result { 123 | match decoder.read_byte()? { 124 | 0x6F => Ok(Self::ExternRef), 125 | 0x70 => Ok(Self::FuncRef), 126 | _ => Err(DecodeError::new("malformed reference type")), 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/stack.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::aliasable_box::AliasableBox, 3 | std::{ 4 | cell::Cell, 5 | mem::ManuallyDrop, 6 | ops::{Deref, DerefMut}, 7 | ptr, 8 | }, 9 | }; 10 | 11 | /// A stack for executing threaded code. 12 | /// 13 | /// There is exactly one stack per thread. To obtain a mutable reference to the stack for the 14 | /// current thread, call [`Stack::lock`]. 15 | /// 16 | /// Each stack consists of an array of [`StackSlot`]s with a pointer to the top of the stack, 17 | /// and contains both [`UnguardedVal`](crate::val::UnguardedVal)s and call frames. An 18 | /// [`UnguardedVal`](crate::val::UnguardedVal) takes up a single [`StackSlot`], while a call frame 19 | /// takes up multiple stack slots. 20 | #[derive(Debug)] 21 | pub struct Stack { 22 | slots: AliasableBox<[StackSlot]>, 23 | ptr: *mut StackSlot, 24 | } 25 | 26 | impl Stack { 27 | /// The size of the stack in bytes. 28 | pub(crate) const SIZE: usize = 1024 * 1024; 29 | 30 | /// Locks the [`Stack`] for the current thread, returning a [`StackGuard`]. 31 | pub fn lock() -> StackGuard { 32 | StackGuard { 33 | stack: ManuallyDrop::new(STACK.take().unwrap()), 34 | } 35 | } 36 | 37 | /// Returns a pointer to the base of the stack. 38 | pub(crate) fn base_ptr(&mut self) -> *mut StackSlot { 39 | self.slots.as_mut_ptr() as *mut _ 40 | } 41 | 42 | /// Returns a pointer to the top of the stack. 43 | pub fn ptr(&mut self) -> *mut StackSlot { 44 | self.ptr 45 | } 46 | 47 | /// Sets the pointer to the top of the stack. 48 | /// 49 | /// # Safety 50 | /// 51 | /// The pointer must be within bounds. 52 | pub(crate) unsafe fn set_ptr(&mut self, ptr: *mut StackSlot) { 53 | self.ptr = ptr; 54 | } 55 | 56 | /// Creates a new, zero-initialized [`Stack`]. 57 | fn new() -> Self { 58 | let mut stack = Self { 59 | slots: AliasableBox::from_box(Box::from(vec![0; Self::SIZE])), 60 | ptr: ptr::null_mut(), 61 | }; 62 | stack.ptr = stack.slots.as_mut_ptr(); 63 | stack 64 | } 65 | } 66 | 67 | /// An RAII implementation of a "scoped lock" of a [`Stack`]. 68 | /// 69 | /// When this structure is dropped (falls out of scope), the lock will be unlocked. 70 | #[derive(Debug)] 71 | pub struct StackGuard { 72 | stack: ManuallyDrop, 73 | } 74 | 75 | impl Deref for StackGuard { 76 | type Target = Stack; 77 | 78 | fn deref(&self) -> &Self::Target { 79 | &self.stack 80 | } 81 | } 82 | 83 | impl DerefMut for StackGuard { 84 | fn deref_mut(&mut self) -> &mut Self::Target { 85 | &mut self.stack 86 | } 87 | } 88 | 89 | impl Drop for StackGuard { 90 | fn drop(&mut self) { 91 | STACK.set(Some(unsafe { ManuallyDrop::take(&mut self.stack) })); 92 | } 93 | } 94 | 95 | pub(crate) type StackSlot = u64; 96 | 97 | thread_local! { 98 | static STACK: Cell> = Cell::new(Some(Stack::new())); 99 | } 100 | -------------------------------------------------------------------------------- /src/trap.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | #[derive(Clone, Copy, Debug)] 4 | pub enum Trap { 5 | Unreachable, 6 | TypeMismatch, 7 | ElemUninited, 8 | IntDivByZero, 9 | IntOverflow, 10 | InvalidConversionToInt, 11 | TableAccessOutOfBounds, 12 | MemAccessOutOfBounds, 13 | StackOverflow, 14 | } 15 | 16 | impl Trap { 17 | pub(crate) fn from_usize(val: usize) -> Option { 18 | match val { 19 | 0 => Some(Self::Unreachable), 20 | 1 => Some(Self::TypeMismatch), 21 | 2 => Some(Self::ElemUninited), 22 | 3 => Some(Self::IntDivByZero), 23 | 4 => Some(Self::IntOverflow), 24 | 5 => Some(Self::InvalidConversionToInt), 25 | 6 => Some(Self::TableAccessOutOfBounds), 26 | 7 => Some(Self::MemAccessOutOfBounds), 27 | 8 => Some(Self::StackOverflow), 28 | _ => None, 29 | } 30 | } 31 | 32 | pub(crate) fn to_usize(self) -> usize { 33 | self as usize 34 | } 35 | } 36 | 37 | impl fmt::Display for Trap { 38 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 39 | match self { 40 | Self::Unreachable => write!(f, "unreachable"), 41 | Self::TypeMismatch => write!(f, "type mismatch"), 42 | Self::ElemUninited => write!(f, "element uninitialized"), 43 | Self::IntDivByZero => write!(f, "integer divide by zero"), 44 | Self::IntOverflow => write!(f, "integer overflow"), 45 | Self::InvalidConversionToInt => write!(f, "invalid conversion to integer"), 46 | Self::TableAccessOutOfBounds => write!(f, "table access out of bounds"), 47 | Self::MemAccessOutOfBounds => write!(f, "memory access out of bounds"), 48 | Self::StackOverflow => write!(f, "stack overflow"), 49 | } 50 | } 51 | } 52 | 53 | impl Error for Trap {} 54 | -------------------------------------------------------------------------------- /tests/testsuite/Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to WebAssembly 2 | 3 | Interested in participating? Please follow 4 | [the same contributing guidelines as the design repository][]. 5 | 6 | [the same contributing guidelines as the design repository]: https://github.com/WebAssembly/design/blob/main/Contributing.md 7 | 8 | Also, please be sure to read [the README.md](README.md) for this repository. 9 | -------------------------------------------------------------------------------- /tests/testsuite/README.md: -------------------------------------------------------------------------------- 1 | Amalgamated WebAssembly Test Suite 2 | ================================== 3 | 4 | This repository holds a mirror of the WebAssembly core testsuite which is 5 | maintained [here](https://github.com/WebAssembly/spec/tree/main/test/core), 6 | as well as the tests from the various [proposals 7 | repositories](https://github.com/WebAssembly/proposals/blob/master/README.md). 8 | 9 | In addition it also contains tests from various proposals which are currently 10 | forks of the primary spec repo. 11 | 12 | To add new tests or report problems in existing tests, please file issues and 13 | PRs within the spec or individual proposal repositories rather than within this 14 | mirror repository. 15 | 16 | To update the tests in this repo from their upstream sources: 17 | 18 | 1. Run `update-testsuite.sh` 19 | -------------------------------------------------------------------------------- /tests/testsuite/comments.wast: -------------------------------------------------------------------------------- 1 | ;; Test comment syntax 2 | 3 | ;;comment 4 | 5 | ;;;;;;;;;;; 6 | 7 | ;;comment 8 | 9 | ( ;;comment 10 | module;;comment 11 | );;comment 12 | 13 | ;;) 14 | ;;;) 15 | ;; ;) 16 | ;; (; 17 | 18 | (;;) 19 | 20 | (;comment;) 21 | 22 | (;;comment;) 23 | 24 | (;;;comment;) 25 | 26 | (;;;;;;;;;;;;;;) 27 | 28 | (;(((((((((( ;) 29 | 30 | (;)))))))))));) 31 | 32 | (;comment";) 33 | 34 | (;comment"";) 35 | 36 | (;comment""";) 37 | 38 | ;; ASCII 00-1F, 7F 39 | (; 40 | 41 | ;) 42 | 43 | ;; null-byte followed immediately by end-of-comment delimiter 44 | (;;) 45 | 46 | 47 | (;Heiße Würstchen;) 48 | 49 | (;;) 50 | 51 | (;comment 52 | comment;) 53 | 54 | (;comment;) 55 | 56 | (;comment;)((;comment;) 57 | (;comment;)module(;comment;) 58 | (;comment;))(;comment;) 59 | 60 | (;comment(;nested;)comment;) 61 | 62 | (;comment 63 | (;nested 64 | ;)comment 65 | ;) 66 | 67 | (module 68 | (;comment(;nested(;further;)nested;)comment;) 69 | ) 70 | 71 | (;comment;;comment;) 72 | 73 | (;comment;;comment 74 | ;) 75 | 76 | (module 77 | (;comment;;comment(;nested;)comment;) 78 | ) 79 | 80 | 81 | ;; Newline recognition 82 | 83 | (module quote 84 | "(func (export \"f1\") (result i32)" 85 | " (i32.const 1)" 86 | " ;; comment\0a" 87 | " (return (i32.const 2))" 88 | "\0a" 89 | ")" 90 | "(func (export \"f2\") (result i32)" 91 | " (i32.const 1)" 92 | " ;; comment\0d" 93 | " (return (i32.const 2))" 94 | "\0a" 95 | ")" 96 | "(func (export \"f3\") (result i32)" 97 | " (i32.const 1)" 98 | " ;; comment\0d\0a" 99 | " (return (i32.const 2))" 100 | "\0a" 101 | ")" 102 | ) 103 | 104 | (assert_return (invoke "f1") (i32.const 2)) 105 | (assert_return (invoke "f2") (i32.const 2)) 106 | (assert_return (invoke "f3") (i32.const 2)) 107 | -------------------------------------------------------------------------------- /tests/testsuite/extract-parts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | # This script extracts the modules from the testsuite test files into 7 | # individual files in the following directories: 8 | # - valid - valid wasm modules 9 | # - invalid - wasm modules that fail to validate 10 | # - malformed - wasm text tests that fail to parse 11 | 12 | wabt="../wabt" 13 | wabtbin="$wabt/bin" 14 | 15 | mkdir -p valid invalid malformed 16 | rm -f valid/*.wasm 17 | rm -f invalid/*.wasm 18 | rm -f malformed/*.wat 19 | 20 | for wast in *.wast; do 21 | base="${wast##*/}" 22 | json="invalid/${base%.wast}.json" 23 | "$wabtbin/wast2json" "$wast" -o "$json" 24 | rm "$json" 25 | done 26 | 27 | mv invalid/*.wat malformed 28 | 29 | for wasm in invalid/*.wasm; do 30 | if "$wabtbin/wasm2wat" "$wasm" -o invalid/t.wat 2>/dev/null && \ 31 | "$wabtbin/wat2wasm" invalid/t.wat -o /dev/null 2>/dev/null ; then 32 | mv "$wasm" valid 33 | fi 34 | done 35 | rm invalid/t.wat 36 | -------------------------------------------------------------------------------- /tests/testsuite/fac.wast: -------------------------------------------------------------------------------- 1 | (module 2 | ;; Recursive factorial 3 | (func (export "fac-rec") (param i64) (result i64) 4 | (if (result i64) (i64.eq (local.get 0) (i64.const 0)) 5 | (then (i64.const 1)) 6 | (else 7 | (i64.mul (local.get 0) (call 0 (i64.sub (local.get 0) (i64.const 1)))) 8 | ) 9 | ) 10 | ) 11 | 12 | ;; Recursive factorial named 13 | (func $fac-rec-named (export "fac-rec-named") (param $n i64) (result i64) 14 | (if (result i64) (i64.eq (local.get $n) (i64.const 0)) 15 | (then (i64.const 1)) 16 | (else 17 | (i64.mul 18 | (local.get $n) 19 | (call $fac-rec-named (i64.sub (local.get $n) (i64.const 1))) 20 | ) 21 | ) 22 | ) 23 | ) 24 | 25 | ;; Iterative factorial 26 | (func (export "fac-iter") (param i64) (result i64) 27 | (local i64 i64) 28 | (local.set 1 (local.get 0)) 29 | (local.set 2 (i64.const 1)) 30 | (block 31 | (loop 32 | (if 33 | (i64.eq (local.get 1) (i64.const 0)) 34 | (then (br 2)) 35 | (else 36 | (local.set 2 (i64.mul (local.get 1) (local.get 2))) 37 | (local.set 1 (i64.sub (local.get 1) (i64.const 1))) 38 | ) 39 | ) 40 | (br 0) 41 | ) 42 | ) 43 | (local.get 2) 44 | ) 45 | 46 | ;; Iterative factorial named 47 | (func (export "fac-iter-named") (param $n i64) (result i64) 48 | (local $i i64) 49 | (local $res i64) 50 | (local.set $i (local.get $n)) 51 | (local.set $res (i64.const 1)) 52 | (block $done 53 | (loop $loop 54 | (if 55 | (i64.eq (local.get $i) (i64.const 0)) 56 | (then (br $done)) 57 | (else 58 | (local.set $res (i64.mul (local.get $i) (local.get $res))) 59 | (local.set $i (i64.sub (local.get $i) (i64.const 1))) 60 | ) 61 | ) 62 | (br $loop) 63 | ) 64 | ) 65 | (local.get $res) 66 | ) 67 | 68 | ;; Optimized factorial. 69 | (func (export "fac-opt") (param i64) (result i64) 70 | (local i64) 71 | (local.set 1 (i64.const 1)) 72 | (block 73 | (br_if 0 (i64.lt_s (local.get 0) (i64.const 2))) 74 | (loop 75 | (local.set 1 (i64.mul (local.get 1) (local.get 0))) 76 | (local.set 0 (i64.add (local.get 0) (i64.const -1))) 77 | (br_if 0 (i64.gt_s (local.get 0) (i64.const 1))) 78 | ) 79 | ) 80 | (local.get 1) 81 | ) 82 | 83 | ;; Iterative factorial without locals. 84 | (func $pick0 (param i64) (result i64 i64) 85 | (local.get 0) (local.get 0) 86 | ) 87 | (func $pick1 (param i64 i64) (result i64 i64 i64) 88 | (local.get 0) (local.get 1) (local.get 0) 89 | ) 90 | (func (export "fac-ssa") (param i64) (result i64) 91 | (i64.const 1) (local.get 0) 92 | (loop $l (param i64 i64) (result i64) 93 | (call $pick1) (call $pick1) (i64.mul) 94 | (call $pick1) (i64.const 1) (i64.sub) 95 | (call $pick0) (i64.const 0) (i64.gt_u) 96 | (br_if $l) 97 | (drop) (return) 98 | ) 99 | ) 100 | ) 101 | 102 | (assert_return (invoke "fac-rec" (i64.const 25)) (i64.const 7034535277573963776)) 103 | (assert_return (invoke "fac-iter" (i64.const 25)) (i64.const 7034535277573963776)) 104 | (assert_return (invoke "fac-rec-named" (i64.const 25)) (i64.const 7034535277573963776)) 105 | (assert_return (invoke "fac-iter-named" (i64.const 25)) (i64.const 7034535277573963776)) 106 | (assert_return (invoke "fac-opt" (i64.const 25)) (i64.const 7034535277573963776)) 107 | (assert_return (invoke "fac-ssa" (i64.const 25)) (i64.const 7034535277573963776)) 108 | 109 | (assert_exhaustion (invoke "fac-rec" (i64.const 1073741824)) "call stack exhausted") 110 | -------------------------------------------------------------------------------- /tests/testsuite/forward.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func $even (export "even") (param $n i32) (result i32) 3 | (if (result i32) (i32.eq (local.get $n) (i32.const 0)) 4 | (then (i32.const 1)) 5 | (else (call $odd (i32.sub (local.get $n) (i32.const 1)))) 6 | ) 7 | ) 8 | 9 | (func $odd (export "odd") (param $n i32) (result i32) 10 | (if (result i32) (i32.eq (local.get $n) (i32.const 0)) 11 | (then (i32.const 0)) 12 | (else (call $even (i32.sub (local.get $n) (i32.const 1)))) 13 | ) 14 | ) 15 | ) 16 | 17 | (assert_return (invoke "even" (i32.const 13)) (i32.const 0)) 18 | (assert_return (invoke "even" (i32.const 20)) (i32.const 1)) 19 | (assert_return (invoke "odd" (i32.const 13)) (i32.const 1)) 20 | (assert_return (invoke "odd" (i32.const 20)) (i32.const 0)) 21 | -------------------------------------------------------------------------------- /tests/testsuite/inline-module.wast: -------------------------------------------------------------------------------- 1 | (func) (memory 0) (func (export "f")) 2 | -------------------------------------------------------------------------------- /tests/testsuite/memory_redundancy.wast: -------------------------------------------------------------------------------- 1 | ;; Test that optimizers don't do redundant-load, store-to-load, or dead-store 2 | ;; optimizations when there are interfering stores, even of different types 3 | ;; and to non-identical addresses. 4 | 5 | (module 6 | (memory 1 1) 7 | 8 | (func (export "zero_everything") 9 | (i32.store (i32.const 0) (i32.const 0)) 10 | (i32.store (i32.const 4) (i32.const 0)) 11 | (i32.store (i32.const 8) (i32.const 0)) 12 | (i32.store (i32.const 12) (i32.const 0)) 13 | ) 14 | 15 | (func (export "test_store_to_load") (result i32) 16 | (i32.store (i32.const 8) (i32.const 0)) 17 | (f32.store (i32.const 5) (f32.const -0.0)) 18 | (i32.load (i32.const 8)) 19 | ) 20 | 21 | (func (export "test_redundant_load") (result i32) 22 | (local $t i32) 23 | (local $s i32) 24 | (local.set $t (i32.load (i32.const 8))) 25 | (i32.store (i32.const 5) (i32.const 0x80000000)) 26 | (local.set $s (i32.load (i32.const 8))) 27 | (i32.add (local.get $t) (local.get $s)) 28 | ) 29 | 30 | (func (export "test_dead_store") (result f32) 31 | (local $t f32) 32 | (i32.store (i32.const 8) (i32.const 0x23232323)) 33 | (local.set $t (f32.load (i32.const 11))) 34 | (i32.store (i32.const 8) (i32.const 0)) 35 | (local.get $t) 36 | ) 37 | 38 | ;; A function named "malloc" which implementations nonetheless shouldn't 39 | ;; assume behaves like C malloc. 40 | (func $malloc (export "malloc") 41 | (param $size i32) 42 | (result i32) 43 | (i32.const 16) 44 | ) 45 | 46 | ;; Call malloc twice, but unlike C malloc, we don't get non-aliasing pointers. 47 | (func (export "malloc_aliasing") 48 | (result i32) 49 | (local $x i32) 50 | (local $y i32) 51 | (local.set $x (call $malloc (i32.const 4))) 52 | (local.set $y (call $malloc (i32.const 4))) 53 | (i32.store (local.get $x) (i32.const 42)) 54 | (i32.store (local.get $y) (i32.const 43)) 55 | (i32.load (local.get $x)) 56 | ) 57 | ) 58 | 59 | (assert_return (invoke "test_store_to_load") (i32.const 0x00000080)) 60 | (invoke "zero_everything") 61 | (assert_return (invoke "test_redundant_load") (i32.const 0x00000080)) 62 | (invoke "zero_everything") 63 | (assert_return (invoke "test_dead_store") (f32.const 0x1.18p-144)) 64 | (invoke "zero_everything") 65 | (assert_return (invoke "malloc_aliasing") (i32.const 43)) 66 | -------------------------------------------------------------------------------- /tests/testsuite/memory_size.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (func (export "size") (result i32) (memory.size)) 4 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 5 | ) 6 | 7 | (assert_return (invoke "size") (i32.const 0)) 8 | (assert_return (invoke "grow" (i32.const 1))) 9 | (assert_return (invoke "size") (i32.const 1)) 10 | (assert_return (invoke "grow" (i32.const 4))) 11 | (assert_return (invoke "size") (i32.const 5)) 12 | (assert_return (invoke "grow" (i32.const 0))) 13 | (assert_return (invoke "size") (i32.const 5)) 14 | 15 | (module 16 | (memory 1) 17 | (func (export "size") (result i32) (memory.size)) 18 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 19 | ) 20 | 21 | (assert_return (invoke "size") (i32.const 1)) 22 | (assert_return (invoke "grow" (i32.const 1))) 23 | (assert_return (invoke "size") (i32.const 2)) 24 | (assert_return (invoke "grow" (i32.const 4))) 25 | (assert_return (invoke "size") (i32.const 6)) 26 | (assert_return (invoke "grow" (i32.const 0))) 27 | (assert_return (invoke "size") (i32.const 6)) 28 | 29 | (module 30 | (memory 0 2) 31 | (func (export "size") (result i32) (memory.size)) 32 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 33 | ) 34 | 35 | (assert_return (invoke "size") (i32.const 0)) 36 | (assert_return (invoke "grow" (i32.const 3))) 37 | (assert_return (invoke "size") (i32.const 0)) 38 | (assert_return (invoke "grow" (i32.const 1))) 39 | (assert_return (invoke "size") (i32.const 1)) 40 | (assert_return (invoke "grow" (i32.const 0))) 41 | (assert_return (invoke "size") (i32.const 1)) 42 | (assert_return (invoke "grow" (i32.const 4))) 43 | (assert_return (invoke "size") (i32.const 1)) 44 | (assert_return (invoke "grow" (i32.const 1))) 45 | (assert_return (invoke "size") (i32.const 2)) 46 | 47 | (module 48 | (memory 3 8) 49 | (func (export "size") (result i32) (memory.size)) 50 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 51 | ) 52 | 53 | (assert_return (invoke "size") (i32.const 3)) 54 | (assert_return (invoke "grow" (i32.const 1))) 55 | (assert_return (invoke "size") (i32.const 4)) 56 | (assert_return (invoke "grow" (i32.const 3))) 57 | (assert_return (invoke "size") (i32.const 7)) 58 | (assert_return (invoke "grow" (i32.const 0))) 59 | (assert_return (invoke "size") (i32.const 7)) 60 | (assert_return (invoke "grow" (i32.const 2))) 61 | (assert_return (invoke "size") (i32.const 7)) 62 | (assert_return (invoke "grow" (i32.const 1))) 63 | (assert_return (invoke "size") (i32.const 8)) 64 | 65 | 66 | ;; Type errors 67 | 68 | (assert_invalid 69 | (module 70 | (memory 1) 71 | (func $type-result-i32-vs-empty 72 | (memory.size) 73 | ) 74 | ) 75 | "type mismatch" 76 | ) 77 | (assert_invalid 78 | (module 79 | (memory 1) 80 | (func $type-result-i32-vs-f32 (result f32) 81 | (memory.size) 82 | ) 83 | ) 84 | "type mismatch" 85 | ) 86 | -------------------------------------------------------------------------------- /tests/testsuite/obsolete-keywords.wast: -------------------------------------------------------------------------------- 1 | ;; Renamed in https://github.com/WebAssembly/spec/pull/720 2 | (assert_malformed 3 | (module quote 4 | "(memory 1)" 5 | "(func (drop (current_memory)))" 6 | ) 7 | "unknown operator current_memory" 8 | ) 9 | 10 | (assert_malformed 11 | (module quote 12 | "(memory 1)" 13 | "(func (drop (grow_memory (i32.const 0))))" 14 | ) 15 | "unknown operator grow_memory" 16 | ) 17 | 18 | ;; Renamed in https://github.com/WebAssembly/spec/pull/926 19 | (assert_malformed 20 | (module quote 21 | "(func (local $i i32) (drop (get_local $i)))" 22 | ) 23 | "unknown operator get_local" 24 | ) 25 | 26 | (assert_malformed 27 | (module quote 28 | "(func (local $i i32) (set_local $i (i32.const 0)))" 29 | ) 30 | "unknown operator set_local" 31 | ) 32 | 33 | (assert_malformed 34 | (module quote 35 | "(func (local $i i32) (drop (tee_local $i (i32.const 0))))" 36 | ) 37 | "unknown operator tee_local" 38 | ) 39 | 40 | (assert_malformed 41 | (module quote 42 | "(global $g anyfunc (ref.null func))" 43 | ) 44 | "unknown operator anyfunc" 45 | ) 46 | 47 | (assert_malformed 48 | (module quote 49 | "(global $g i32 (i32.const 0))" 50 | "(func (drop (get_global $g)))" 51 | ) 52 | "unknown operator get_global" 53 | ) 54 | 55 | (assert_malformed 56 | (module quote 57 | "(global $g (mut i32) (i32.const 0))" 58 | "(func (set_global $g (i32.const 0)))" 59 | ) 60 | "unknown operator set_global" 61 | ) 62 | 63 | (assert_malformed 64 | (module quote 65 | "(func (drop (i32.wrap/i64 (i64.const 0))))" 66 | ) 67 | "unknown operator i32.wrap/i64" 68 | ) 69 | 70 | (assert_malformed 71 | (module quote 72 | "(func (drop (i32.trunc_s:sat/f32 (f32.const 0))))" 73 | ) 74 | "unknown operator i32.trunc_s:sat/f32" 75 | ) 76 | 77 | (assert_malformed 78 | (module quote 79 | "(func (drop (f32x4.convert_s/i32x4 (v128.const i64x2 0 0))))" 80 | ) 81 | "unknown operator f32x4.convert_s/i32x4" 82 | ) 83 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/exception-handling/ref_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "externref") (result externref) (ref.null extern)) 3 | (func (export "exnref") (result exnref) (ref.null exn)) 4 | (func (export "funcref") (result funcref) (ref.null func)) 5 | 6 | (global externref (ref.null extern)) 7 | (global exnref (ref.null exn)) 8 | (global funcref (ref.null func)) 9 | ) 10 | 11 | (assert_return (invoke "externref") (ref.null extern)) 12 | (assert_return (invoke "exnref") (ref.null exn)) 13 | (assert_return (invoke "funcref") (ref.null func)) 14 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/exception-handling/tag.wast: -------------------------------------------------------------------------------- 1 | ;; Test tag section 2 | 3 | (module 4 | (tag) 5 | (tag (param i32)) 6 | (tag (export "t2") (param i32)) 7 | (tag $t3 (param i32 f32)) 8 | (export "t3" (tag 3)) 9 | ) 10 | 11 | (register "test") 12 | 13 | (module 14 | (tag $t0 (import "test" "t2") (param i32)) 15 | (import "test" "t3" (tag $t1 (param i32 f32))) 16 | ) 17 | 18 | (assert_invalid 19 | (module (tag (result i32))) 20 | "non-empty tag result type" 21 | ) 22 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/exception-handling/throw.wast: -------------------------------------------------------------------------------- 1 | ;; Test throw instruction. 2 | 3 | (module 4 | (tag $e0) 5 | (tag $e-i32 (param i32)) 6 | (tag $e-f32 (param f32)) 7 | (tag $e-i64 (param i64)) 8 | (tag $e-f64 (param f64)) 9 | (tag $e-i32-i32 (param i32 i32)) 10 | 11 | (func $throw-if (export "throw-if") (param i32) (result i32) 12 | (local.get 0) 13 | (i32.const 0) (if (i32.ne) (then (throw $e0))) 14 | (i32.const 0) 15 | ) 16 | 17 | (func (export "throw-param-f32") (param f32) (local.get 0) (throw $e-f32)) 18 | 19 | (func (export "throw-param-i64") (param i64) (local.get 0) (throw $e-i64)) 20 | 21 | (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) 22 | 23 | (func (export "throw-polymorphic") (throw $e0) (throw $e-i32)) 24 | 25 | (func (export "throw-polymorphic-block") (block (result i32) (throw $e0)) (throw $e-i32)) 26 | 27 | (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) 28 | (func (export "test-throw-1-2") 29 | (block $h (result i32 i32) 30 | (try_table (catch $e-i32-i32 $h) (call $throw-1-2)) 31 | (return) 32 | ) 33 | (if (i32.ne (i32.const 2)) (then (unreachable))) 34 | (if (i32.ne (i32.const 1)) (then (unreachable))) 35 | ) 36 | ) 37 | 38 | (assert_return (invoke "throw-if" (i32.const 0)) (i32.const 0)) 39 | (assert_exception (invoke "throw-if" (i32.const 10))) 40 | (assert_exception (invoke "throw-if" (i32.const -1))) 41 | 42 | (assert_exception (invoke "throw-param-f32" (f32.const 5.0))) 43 | (assert_exception (invoke "throw-param-i64" (i64.const 5))) 44 | (assert_exception (invoke "throw-param-f64" (f64.const 5.0))) 45 | 46 | (assert_exception (invoke "throw-polymorphic")) 47 | (assert_exception (invoke "throw-polymorphic-block")) 48 | 49 | (assert_return (invoke "test-throw-1-2")) 50 | 51 | (assert_invalid (module (func (throw 0))) "unknown tag 0") 52 | (assert_invalid (module (tag (param i32)) (func (throw 0))) 53 | "type mismatch: instruction requires [i32] but stack has []") 54 | (assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) 55 | "type mismatch: instruction requires [i32] but stack has [i64]") 56 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/exception-handling/throw_ref.wast: -------------------------------------------------------------------------------- 1 | ;; Test throw_ref instruction. 2 | 3 | (module 4 | (tag $e0) 5 | (tag $e1) 6 | 7 | (func (export "catch-throw_ref-0") 8 | (block $h (result exnref) 9 | (try_table (catch_ref $e0 $h) (throw $e0)) 10 | (unreachable) 11 | ) 12 | (throw_ref) 13 | ) 14 | 15 | (func (export "catch-throw_ref-1") (param i32) (result i32) 16 | (block $h (result exnref) 17 | (try_table (result i32) (catch_ref $e0 $h) (throw $e0)) 18 | (return) 19 | ) 20 | (if (param exnref) (i32.eqz (local.get 0)) 21 | (then (throw_ref)) 22 | (else (drop)) 23 | ) 24 | (i32.const 23) 25 | ) 26 | 27 | (func (export "catchall-throw_ref-0") 28 | (block $h (result exnref) 29 | (try_table (result exnref) (catch_all_ref $h) (throw $e0)) 30 | ) 31 | (throw_ref) 32 | ) 33 | 34 | (func (export "catchall-throw_ref-1") (param i32) (result i32) 35 | (block $h (result exnref) 36 | (try_table (result i32) (catch_all_ref $h) (throw $e0)) 37 | (return) 38 | ) 39 | (if (param exnref) (i32.eqz (local.get 0)) 40 | (then (throw_ref)) 41 | (else (drop)) 42 | ) 43 | (i32.const 23) 44 | ) 45 | 46 | (func (export "throw_ref-nested") (param i32) (result i32) 47 | (local $exn1 exnref) 48 | (local $exn2 exnref) 49 | (block $h1 (result exnref) 50 | (try_table (result i32) (catch_ref $e1 $h1) (throw $e1)) 51 | (return) 52 | ) 53 | (local.set $exn1) 54 | (block $h2 (result exnref) 55 | (try_table (result i32) (catch_ref $e0 $h2) (throw $e0)) 56 | (return) 57 | ) 58 | (local.set $exn2) 59 | (if (i32.eq (local.get 0) (i32.const 0)) 60 | (then (throw_ref (local.get $exn1))) 61 | ) 62 | (if (i32.eq (local.get 0) (i32.const 1)) 63 | (then (throw_ref (local.get $exn2))) 64 | ) 65 | (i32.const 23) 66 | ) 67 | 68 | (func (export "throw_ref-recatch") (param i32) (result i32) 69 | (local $e exnref) 70 | (block $h1 (result exnref) 71 | (try_table (result i32) (catch_ref $e0 $h1) (throw $e0)) 72 | (return) 73 | ) 74 | (local.set $e) 75 | (block $h2 (result exnref) 76 | (try_table (result i32) (catch_ref $e0 $h2) 77 | (if (i32.eqz (local.get 0)) 78 | (then (throw_ref (local.get $e))) 79 | ) 80 | (i32.const 42) 81 | ) 82 | (return) 83 | ) 84 | (drop) (i32.const 23) 85 | ) 86 | 87 | (func (export "throw_ref-stack-polymorphism") 88 | (local $e exnref) 89 | (block $h (result exnref) 90 | (try_table (result f64) (catch_ref $e0 $h) (throw $e0)) 91 | (unreachable) 92 | ) 93 | (local.set $e) 94 | (i32.const 1) 95 | (throw_ref (local.get $e)) 96 | ) 97 | ) 98 | 99 | (assert_exception (invoke "catch-throw_ref-0")) 100 | 101 | (assert_exception (invoke "catch-throw_ref-1" (i32.const 0))) 102 | (assert_return (invoke "catch-throw_ref-1" (i32.const 1)) (i32.const 23)) 103 | 104 | (assert_exception (invoke "catchall-throw_ref-0")) 105 | 106 | (assert_exception (invoke "catchall-throw_ref-1" (i32.const 0))) 107 | (assert_return (invoke "catchall-throw_ref-1" (i32.const 1)) (i32.const 23)) 108 | (assert_exception (invoke "throw_ref-nested" (i32.const 0))) 109 | (assert_exception (invoke "throw_ref-nested" (i32.const 1))) 110 | (assert_return (invoke "throw_ref-nested" (i32.const 2)) (i32.const 23)) 111 | 112 | (assert_return (invoke "throw_ref-recatch" (i32.const 0)) (i32.const 23)) 113 | (assert_return (invoke "throw_ref-recatch" (i32.const 1)) (i32.const 42)) 114 | 115 | (assert_exception (invoke "throw_ref-stack-polymorphism")) 116 | 117 | (assert_invalid (module (func (throw_ref))) "type mismatch") 118 | (assert_invalid (module (func (block (throw_ref)))) "type mismatch") 119 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/br_on_non_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (call_ref $t 6 | (block $l (result (ref $t)) 7 | (br_on_non_null $l (local.get $r)) 8 | (return (i32.const -1)) 9 | ) 10 | ) 11 | ) 12 | (func $n (param $r (ref null $t)) (result i32) 13 | (call_ref $t 14 | (block $l (result (ref $t)) 15 | (br_on_non_null $l (local.get $r)) 16 | (return (i32.const -1)) 17 | ) 18 | ) 19 | ) 20 | 21 | (elem func $f) 22 | (func $f (result i32) (i32.const 7)) 23 | 24 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 25 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 26 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 27 | 28 | (func (export "unreachable") (result i32) 29 | (block $l (result (ref $t)) 30 | (br_on_non_null $l (unreachable)) 31 | (return (i32.const -1)) 32 | ) 33 | (call_ref $t) 34 | ) 35 | ) 36 | 37 | (assert_trap (invoke "unreachable") "unreachable") 38 | 39 | (assert_return (invoke "nullable-null") (i32.const -1)) 40 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 41 | (assert_return (invoke "nullable-f") (i32.const 7)) 42 | 43 | (module 44 | (type $t (func)) 45 | (func (param $r (ref null $t)) (drop (block (result (ref $t)) (br_on_non_null 0 (local.get $r)) (unreachable)))) 46 | (func (param $r (ref null func)) (drop (block (result (ref func)) (br_on_non_null 0 (local.get $r)) (unreachable)))) 47 | (func (param $r (ref null extern)) (drop (block (result (ref extern)) (br_on_non_null 0 (local.get $r)) (unreachable)))) 48 | ) 49 | 50 | 51 | (module 52 | (type $t (func (param i32) (result i32))) 53 | (elem func $f) 54 | (func $f (param i32) (result i32) (i32.mul (local.get 0) (local.get 0))) 55 | 56 | (func $a (param $n i32) (param $r (ref null $t)) (result i32) 57 | (call_ref $t 58 | (block $l (result i32 (ref $t)) 59 | (return (br_on_non_null $l (local.get $n) (local.get $r))) 60 | ) 61 | ) 62 | ) 63 | 64 | (func (export "args-null") (param $n i32) (result i32) 65 | (call $a (local.get $n) (ref.null $t)) 66 | ) 67 | (func (export "args-f") (param $n i32) (result i32) 68 | (call $a (local.get $n) (ref.func $f)) 69 | ) 70 | ) 71 | 72 | (assert_return (invoke "args-null" (i32.const 3)) (i32.const 3)) 73 | (assert_return (invoke "args-f" (i32.const 3)) (i32.const 9)) 74 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/br_on_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (block $l 6 | (return (call_ref $t (br_on_null $l (local.get $r)))) 7 | ) 8 | (i32.const -1) 9 | ) 10 | (func $n (param $r (ref null $t)) (result i32) 11 | (block $l 12 | (return (call_ref $t (br_on_null $l (local.get $r)))) 13 | ) 14 | (i32.const -1) 15 | ) 16 | 17 | (elem func $f) 18 | (func $f (result i32) (i32.const 7)) 19 | 20 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 21 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 22 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 23 | 24 | (func (export "unreachable") (result i32) 25 | (block $l 26 | (return (call_ref $t (br_on_null $l (unreachable)))) 27 | ) 28 | (i32.const -1) 29 | ) 30 | ) 31 | 32 | (assert_trap (invoke "unreachable") "unreachable") 33 | 34 | (assert_return (invoke "nullable-null") (i32.const -1)) 35 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 36 | (assert_return (invoke "nullable-f") (i32.const 7)) 37 | 38 | (module 39 | (type $t (func)) 40 | (func (param $r (ref null $t)) (drop (br_on_null 0 (local.get $r)))) 41 | (func (param $r (ref null func)) (drop (br_on_null 0 (local.get $r)))) 42 | (func (param $r (ref null extern)) (drop (br_on_null 0 (local.get $r)))) 43 | ) 44 | 45 | 46 | (module 47 | (type $t (func (param i32) (result i32))) 48 | (elem func $f) 49 | (func $f (param i32) (result i32) (i32.mul (local.get 0) (local.get 0))) 50 | 51 | (func $a (param $n i32) (param $r (ref null $t)) (result i32) 52 | (block $l (result i32) 53 | (return (call_ref $t (br_on_null $l (local.get $n) (local.get $r)))) 54 | ) 55 | ) 56 | 57 | (func (export "args-null") (param $n i32) (result i32) 58 | (call $a (local.get $n) (ref.null $t)) 59 | ) 60 | (func (export "args-f") (param $n i32) (result i32) 61 | (call $a (local.get $n) (ref.func $f)) 62 | ) 63 | ) 64 | 65 | (assert_return (invoke "args-null" (i32.const 3)) (i32.const 3)) 66 | (assert_return (invoke "args-f" (i32.const 3)) (i32.const 9)) 67 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/local_init.wast: -------------------------------------------------------------------------------- 1 | ;; Uninitialized undefaulted locals 2 | 3 | (module 4 | (func (export "get-after-set") (param $p (ref extern)) (result (ref extern)) 5 | (local $x (ref extern)) 6 | (local.set $x (local.get $p)) 7 | (local.get $x) 8 | ) 9 | (func (export "get-after-tee") (param $p (ref extern)) (result (ref extern)) 10 | (local $x (ref extern)) 11 | (drop (local.tee $x (local.get $p))) 12 | (local.get $x) 13 | ) 14 | (func (export "get-in-block-after-set") (param $p (ref extern)) (result (ref extern)) 15 | (local $x (ref extern)) 16 | (local.set $x (local.get $p)) 17 | (block (result (ref extern)) (local.get $x)) 18 | ) 19 | ) 20 | 21 | (assert_return (invoke "get-after-set" (ref.extern 1)) (ref.extern 1)) 22 | (assert_return (invoke "get-after-tee" (ref.extern 2)) (ref.extern 2)) 23 | (assert_return (invoke "get-in-block-after-set" (ref.extern 3)) (ref.extern 3)) 24 | 25 | (assert_invalid 26 | (module (func $uninit (local $x (ref extern)) (drop (local.get $x)))) 27 | "uninitialized local" 28 | ) 29 | (assert_invalid 30 | (module 31 | (func $uninit-after-end (param $p (ref extern)) 32 | (local $x (ref extern)) 33 | (block (local.set $x (local.get $p)) (drop (local.tee $x (local.get $p)))) 34 | (drop (local.get $x)) 35 | ) 36 | ) 37 | "uninitialized local" 38 | ) 39 | (assert_invalid 40 | (module 41 | (func $uninit-in-else (param $p (ref extern)) 42 | (local $x (ref extern)) 43 | (if (i32.const 0) 44 | (then (local.set $x (local.get $p))) 45 | (else (local.get $x)) 46 | ) 47 | ) 48 | ) 49 | "uninitialized local" 50 | ) 51 | 52 | (assert_invalid 53 | (module 54 | (func $uninit-from-if (param $p (ref extern)) 55 | (local $x (ref extern)) 56 | (if (i32.const 0) 57 | (then (local.set $x (local.get $p))) 58 | (else (local.set $x (local.get $p))) 59 | ) 60 | (drop (local.get $x)) 61 | ) 62 | ) 63 | "uninitialized local" 64 | ) 65 | 66 | (module 67 | (func (export "tee-init") (param $p (ref extern)) (result (ref extern)) 68 | (local $x (ref extern)) 69 | (drop (local.tee $x (local.get $p))) 70 | (local.get $x) 71 | ) 72 | ) 73 | 74 | (assert_return (invoke "tee-init" (ref.extern 1)) (ref.extern 1)) 75 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/ref.wast: -------------------------------------------------------------------------------- 1 | ;; Syntax 2 | 3 | (module 4 | (type $t (func)) 5 | 6 | (func 7 | (param 8 | funcref 9 | externref 10 | (ref func) 11 | (ref extern) 12 | (ref 0) 13 | (ref $t) 14 | (ref 0) 15 | (ref $t) 16 | (ref null func) 17 | (ref null extern) 18 | (ref null 0) 19 | (ref null $t) 20 | ) 21 | ) 22 | ) 23 | 24 | 25 | ;; Undefined type index. 26 | 27 | (assert_invalid 28 | (module (type $type-func-param-invalid (func (param (ref 1))))) 29 | "unknown type" 30 | ) 31 | (assert_invalid 32 | (module (type $type-func-result-invalid (func (result (ref 1))))) 33 | "unknown type" 34 | ) 35 | 36 | (assert_invalid 37 | (module (global $global-invalid (ref null 1) (ref.null 1))) 38 | "unknown type" 39 | ) 40 | 41 | (assert_invalid 42 | (module (table $table-invalid 10 (ref null 1))) 43 | "unknown type" 44 | ) 45 | 46 | (assert_invalid 47 | (module (elem $elem-invalid (ref 1))) 48 | "unknown type" 49 | ) 50 | 51 | (assert_invalid 52 | (module (func $func-param-invalid (param (ref 1)))) 53 | "unknown type" 54 | ) 55 | (assert_invalid 56 | (module (func $func-result-invalid (result (ref 1)))) 57 | "unknown type" 58 | ) 59 | (assert_invalid 60 | (module (func $func-local-invalid (local (ref null 1)))) 61 | "unknown type" 62 | ) 63 | 64 | (assert_invalid 65 | (module (func $block-result-invalid (drop (block (result (ref 1)) (unreachable))))) 66 | "unknown type" 67 | ) 68 | (assert_invalid 69 | (module (func $loop-result-invalid (drop (loop (result (ref 1)) (unreachable))))) 70 | "unknown type" 71 | ) 72 | (assert_invalid 73 | (module (func $if-invalid (drop (if (result (ref 1)) (then) (else))))) 74 | "unknown type" 75 | ) 76 | 77 | (assert_invalid 78 | (module (func $select-result-invalid (drop (select (result (ref 1)) (unreachable))))) 79 | "unknown type" 80 | ) 81 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/ref_as_non_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (call_ref $t (ref.as_non_null (local.get $r))) 6 | ) 7 | (func $n (param $r (ref null $t)) (result i32) 8 | (call_ref $t (ref.as_non_null (local.get $r))) 9 | ) 10 | 11 | (elem func $f) 12 | (func $f (result i32) (i32.const 7)) 13 | 14 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 15 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 16 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 17 | 18 | (func (export "unreachable") (result i32) 19 | (unreachable) 20 | (ref.as_non_null) 21 | (call $nn) 22 | ) 23 | ) 24 | 25 | (assert_trap (invoke "unreachable") "unreachable") 26 | 27 | (assert_trap (invoke "nullable-null") "null reference") 28 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 29 | (assert_return (invoke "nullable-f") (i32.const 7)) 30 | 31 | (assert_invalid 32 | (module 33 | (type $t (func (result i32))) 34 | (func $g (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) 35 | (func (call $g (ref.null $t))) 36 | ) 37 | "type mismatch" 38 | ) 39 | 40 | 41 | (module 42 | (type $t (func)) 43 | (func (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) 44 | (func (param $r (ref func)) (drop (ref.as_non_null (local.get $r)))) 45 | (func (param $r (ref extern)) (drop (ref.as_non_null (local.get $r)))) 46 | ) 47 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/ref_func.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "f") (param $x i32) (result i32) (local.get $x)) 3 | ) 4 | (register "M") 5 | 6 | (module 7 | (func $f (import "M" "f") (param i32) (result i32)) 8 | (func $g (param $x i32) (result i32) 9 | (i32.add (local.get $x) (i32.const 1)) 10 | ) 11 | 12 | (global funcref (ref.func $f)) 13 | (global funcref (ref.func $g)) 14 | (global $v (mut funcref) (ref.func $f)) 15 | 16 | (global funcref (ref.func $gf1)) 17 | (global funcref (ref.func $gf2)) 18 | (func (drop (ref.func $ff1)) (drop (ref.func $ff2))) 19 | (elem declare func $gf1 $ff1) 20 | (elem declare funcref (ref.func $gf2) (ref.func $ff2)) 21 | (func $gf1) 22 | (func $gf2) 23 | (func $ff1) 24 | (func $ff2) 25 | 26 | (func (export "is_null-f") (result i32) 27 | (ref.is_null (ref.func $f)) 28 | ) 29 | (func (export "is_null-g") (result i32) 30 | (ref.is_null (ref.func $g)) 31 | ) 32 | (func (export "is_null-v") (result i32) 33 | (ref.is_null (global.get $v)) 34 | ) 35 | 36 | (func (export "set-f") (global.set $v (ref.func $f))) 37 | (func (export "set-g") (global.set $v (ref.func $g))) 38 | 39 | (table $t 1 funcref) 40 | (elem declare func $f $g) 41 | 42 | (func (export "call-f") (param $x i32) (result i32) 43 | (table.set $t (i32.const 0) (ref.func $f)) 44 | (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) 45 | ) 46 | (func (export "call-g") (param $x i32) (result i32) 47 | (table.set $t (i32.const 0) (ref.func $g)) 48 | (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) 49 | ) 50 | (func (export "call-v") (param $x i32) (result i32) 51 | (table.set $t (i32.const 0) (global.get $v)) 52 | (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) 53 | ) 54 | ) 55 | 56 | (assert_return (invoke "is_null-f") (i32.const 0)) 57 | (assert_return (invoke "is_null-g") (i32.const 0)) 58 | (assert_return (invoke "is_null-v") (i32.const 0)) 59 | 60 | (assert_return (invoke "call-f" (i32.const 4)) (i32.const 4)) 61 | (assert_return (invoke "call-g" (i32.const 4)) (i32.const 5)) 62 | (assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) 63 | (invoke "set-g") 64 | (assert_return (invoke "call-v" (i32.const 4)) (i32.const 5)) 65 | (invoke "set-f") 66 | (assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) 67 | 68 | (assert_invalid 69 | (module 70 | (func $f (import "M" "f") (param i32) (result i32)) 71 | (func $g (import "M" "g") (param i32) (result i32)) 72 | (global funcref (ref.func 7)) 73 | ) 74 | "unknown function 7" 75 | ) 76 | 77 | 78 | ;; Reference declaration 79 | 80 | (module 81 | (func $f1) 82 | (func $f2) 83 | (func $f3) 84 | (func $f4) 85 | (func $f5) 86 | (func $f6) 87 | 88 | (table $t 1 funcref) 89 | 90 | (global funcref (ref.func $f1)) 91 | (export "f" (func $f2)) 92 | (elem (table $t) (i32.const 0) func $f3) 93 | (elem (table $t) (i32.const 0) funcref (ref.func $f4)) 94 | (elem func $f5) 95 | (elem funcref (ref.func $f6)) 96 | 97 | (func 98 | (ref.func $f1) 99 | (ref.func $f2) 100 | (ref.func $f3) 101 | (ref.func $f4) 102 | (ref.func $f5) 103 | (ref.func $f6) 104 | (return) 105 | ) 106 | ) 107 | 108 | (assert_invalid 109 | (module (func $f (drop (ref.func $f)))) 110 | "undeclared function reference" 111 | ) 112 | (assert_invalid 113 | (module (start $f) (func $f (drop (ref.func $f)))) 114 | "undeclared function reference" 115 | ) 116 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/ref_is_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (func $dummy) 4 | 5 | (func $f1 (export "funcref") (param $x funcref) (result i32) 6 | (ref.is_null (local.get $x)) 7 | ) 8 | (func $f2 (export "externref") (param $x externref) (result i32) 9 | (ref.is_null (local.get $x)) 10 | ) 11 | (func $f3 (param $x (ref null $t)) (result i32) 12 | (ref.is_null (local.get $x)) 13 | ) 14 | (func $f3' (export "ref-null") (result i32) 15 | (call $f3 (ref.null $t)) 16 | ) 17 | 18 | (table $t1 2 funcref) 19 | (table $t2 2 externref) 20 | (table $t3 2 (ref null $t)) 21 | (elem (table $t1) (i32.const 1) func $dummy) 22 | (elem (table $t3) (i32.const 1) (ref $t) (ref.func $dummy)) 23 | 24 | (func (export "init") (param $r externref) 25 | (table.set $t2 (i32.const 1) (local.get $r)) 26 | ) 27 | (func (export "deinit") 28 | (table.set $t1 (i32.const 1) (ref.null func)) 29 | (table.set $t2 (i32.const 1) (ref.null extern)) 30 | (table.set $t3 (i32.const 1) (ref.null $t)) 31 | ) 32 | 33 | (func (export "funcref-elem") (param $x i32) (result i32) 34 | (call $f1 (table.get $t1 (local.get $x))) 35 | ) 36 | (func (export "externref-elem") (param $x i32) (result i32) 37 | (call $f2 (table.get $t2 (local.get $x))) 38 | ) 39 | (func (export "ref-elem") (param $x i32) (result i32) 40 | (call $f3 (table.get $t3 (local.get $x))) 41 | ) 42 | ) 43 | 44 | (assert_return (invoke "funcref" (ref.null func)) (i32.const 1)) 45 | (assert_return (invoke "externref" (ref.null extern)) (i32.const 1)) 46 | (assert_return (invoke "ref-null") (i32.const 1)) 47 | 48 | (assert_return (invoke "externref" (ref.extern 1)) (i32.const 0)) 49 | 50 | (invoke "init" (ref.extern 0)) 51 | 52 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 53 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 54 | (assert_return (invoke "ref-elem" (i32.const 0)) (i32.const 1)) 55 | 56 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) 57 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 0)) 58 | (assert_return (invoke "ref-elem" (i32.const 1)) (i32.const 0)) 59 | 60 | (invoke "deinit") 61 | 62 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 63 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 64 | (assert_return (invoke "ref-elem" (i32.const 0)) (i32.const 1)) 65 | 66 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) 67 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) 68 | (assert_return (invoke "ref-elem" (i32.const 1)) (i32.const 1)) 69 | 70 | 71 | (module 72 | (type $t (func)) 73 | (func (param $r (ref $t)) (drop (ref.is_null (local.get $r)))) 74 | (func (param $r (ref func)) (drop (ref.is_null (local.get $r)))) 75 | (func (param $r (ref extern)) (drop (ref.is_null (local.get $r)))) 76 | ) 77 | 78 | (assert_invalid 79 | (module (func $ref-vs-num (param i32) (ref.is_null (local.get 0)))) 80 | "type mismatch" 81 | ) 82 | (assert_invalid 83 | (module (func $ref-vs-empty (ref.is_null))) 84 | "type mismatch" 85 | ) 86 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/ref_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (func (export "externref") (result externref) (ref.null extern)) 4 | (func (export "funcref") (result funcref) (ref.null func)) 5 | (func (export "ref") (result (ref null $t)) (ref.null $t)) 6 | 7 | (global externref (ref.null extern)) 8 | (global funcref (ref.null func)) 9 | (global (ref null $t) (ref.null $t)) 10 | ) 11 | 12 | (assert_return (invoke "externref") (ref.null extern)) 13 | (assert_return (invoke "funcref") (ref.null func)) 14 | (assert_return (invoke "ref") (ref.null)) 15 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/table-sub.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (table $t1 10 (ref null func)) 4 | (table $t2 10 (ref null $t)) 5 | (elem $el funcref) 6 | (func $f 7 | (table.init $t1 $el (i32.const 0) (i32.const 1) (i32.const 2)) 8 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 9 | ) 10 | ) 11 | 12 | (assert_invalid 13 | (module 14 | (table $t1 10 funcref) 15 | (table $t2 10 externref) 16 | (func $f 17 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 18 | ) 19 | ) 20 | "type mismatch" 21 | ) 22 | 23 | (assert_invalid 24 | (module 25 | (table $t 10 funcref) 26 | (elem $el externref) 27 | (func $f 28 | (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) 29 | ) 30 | ) 31 | "type mismatch" 32 | ) 33 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/function-references/unreached-valid.wast: -------------------------------------------------------------------------------- 1 | (module 2 | 3 | ;; Check that both sides of the select are evaluated 4 | (func (export "select-trap-left") (param $cond i32) (result i32) 5 | (select (unreachable) (i32.const 0) (local.get $cond)) 6 | ) 7 | (func (export "select-trap-right") (param $cond i32) (result i32) 8 | (select (i32.const 0) (unreachable) (local.get $cond)) 9 | ) 10 | 11 | (func (export "select-unreached") 12 | (unreachable) (select) 13 | (unreachable) (i32.const 0) (select) 14 | (unreachable) (i32.const 0) (i32.const 0) (select) 15 | (unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select) 16 | (unreachable) (f32.const 0) (i32.const 0) (select) 17 | (unreachable) 18 | ) 19 | 20 | (func (export "select-unreached-result1") (result i32) 21 | (unreachable) (i32.add (select)) 22 | ) 23 | 24 | (func (export "select-unreached-result2") (result i64) 25 | (unreachable) (i64.add (select (i64.const 0) (i32.const 0))) 26 | ) 27 | 28 | (func (export "select-unreached-num") 29 | (unreachable) 30 | (select) 31 | (i32.eqz) 32 | (drop) 33 | ) 34 | (func (export "select-unreached-ref") 35 | (unreachable) 36 | (select) 37 | (ref.is_null) 38 | (drop) 39 | ) 40 | 41 | (type $t (func (param i32) (result i32))) 42 | (func (export "call_ref-unreached") (result i32) 43 | (unreachable) 44 | (call_ref $t) 45 | ) 46 | ) 47 | 48 | (assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") 49 | (assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") 50 | (assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") 51 | (assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable") 52 | 53 | (assert_trap (invoke "select-unreached-result1") "unreachable") 54 | (assert_trap (invoke "select-unreached-result2") "unreachable") 55 | (assert_trap (invoke "select-unreached-num") "unreachable") 56 | (assert_trap (invoke "select-unreached-ref") "unreachable") 57 | 58 | (assert_trap (invoke "call_ref-unreached") "unreachable") 59 | 60 | 61 | ;; Validation after unreachable 62 | 63 | (module 64 | (func (export "meet-bottom") 65 | (block (result f64) 66 | (block (result f32) 67 | (unreachable) 68 | (br_table 0 1 1 (i32.const 1)) 69 | ) 70 | (drop) 71 | (f64.const 0) 72 | ) 73 | (drop) 74 | ) 75 | ) 76 | 77 | (assert_trap (invoke "meet-bottom") "unreachable") 78 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/array_fill.wast: -------------------------------------------------------------------------------- 1 | ;; Bulk instructions 2 | 3 | ;; invalid uses 4 | 5 | (assert_invalid 6 | (module 7 | (type $a (array i8)) 8 | 9 | (func (export "array.fill-immutable") (param $1 (ref $a)) (param $2 i32) 10 | (array.fill $a (local.get $1) (i32.const 0) (local.get $2) (i32.const 0)) 11 | ) 12 | ) 13 | "array is immutable" 14 | ) 15 | 16 | (assert_invalid 17 | (module 18 | (type $a (array (mut i8))) 19 | 20 | (func (export "array.fill-invalid-1") (param $1 (ref $a)) (param $2 funcref) 21 | (array.fill $a (local.get $1) (i32.const 0) (local.get $2) (i32.const 0)) 22 | ) 23 | ) 24 | "type mismatch" 25 | ) 26 | 27 | (assert_invalid 28 | (module 29 | (type $b (array (mut funcref))) 30 | 31 | (func (export "array.fill-invalid-1") (param $1 (ref $b)) (param $2 i32) 32 | (array.fill $b (local.get $1) (i32.const 0) (local.get $2) (i32.const 0)) 33 | ) 34 | ) 35 | "type mismatch" 36 | ) 37 | 38 | (module 39 | (type $arr8 (array i8)) 40 | (type $arr8_mut (array (mut i8))) 41 | 42 | (global $g_arr8 (ref $arr8) (array.new $arr8 (i32.const 10) (i32.const 12))) 43 | (global $g_arr8_mut (mut (ref $arr8_mut)) (array.new_default $arr8_mut (i32.const 12))) 44 | 45 | (func (export "array_get_nth") (param $1 i32) (result i32) 46 | (array.get_u $arr8_mut (global.get $g_arr8_mut) (local.get $1)) 47 | ) 48 | 49 | (func (export "array_fill-null") 50 | (array.fill $arr8_mut (ref.null $arr8_mut) (i32.const 0) (i32.const 0) (i32.const 0)) 51 | ) 52 | 53 | (func (export "array_fill") (param $1 i32) (param $2 i32) (param $3 i32) 54 | (array.fill $arr8_mut (global.get $g_arr8_mut) (local.get $1) (local.get $2) (local.get $3)) 55 | ) 56 | ) 57 | 58 | ;; null array argument traps 59 | (assert_trap (invoke "array_fill-null") "null array reference") 60 | 61 | ;; OOB initial index traps 62 | (assert_trap (invoke "array_fill" (i32.const 13) (i32.const 0) (i32.const 0)) "out of bounds array access") 63 | 64 | ;; OOB length traps 65 | (assert_trap (invoke "array_fill" (i32.const 0) (i32.const 0) (i32.const 13)) "out of bounds array access") 66 | 67 | ;; start index = array size, len = 0 doesn't trap 68 | (assert_return (invoke "array_fill" (i32.const 12) (i32.const 0) (i32.const 0))) 69 | 70 | ;; check arrays were not modified 71 | (assert_return (invoke "array_get_nth" (i32.const 0)) (i32.const 0)) 72 | (assert_return (invoke "array_get_nth" (i32.const 5)) (i32.const 0)) 73 | (assert_return (invoke "array_get_nth" (i32.const 11)) (i32.const 0)) 74 | (assert_trap (invoke "array_get_nth" (i32.const 12)) "out of bounds array access") 75 | 76 | ;; normal case 77 | (assert_return (invoke "array_fill" (i32.const 2) (i32.const 11) (i32.const 2))) 78 | (assert_return (invoke "array_get_nth" (i32.const 1)) (i32.const 0)) 79 | (assert_return (invoke "array_get_nth" (i32.const 2)) (i32.const 11)) 80 | (assert_return (invoke "array_get_nth" (i32.const 3)) (i32.const 11)) 81 | (assert_return (invoke "array_get_nth" (i32.const 4)) (i32.const 0)) 82 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/binary-gc.wast: -------------------------------------------------------------------------------- 1 | (assert_malformed 2 | (module binary 3 | "\00asm" "\01\00\00\00" 4 | "\01" ;; Type section id 5 | "\04" ;; Type section length 6 | "\01" ;; Types vector length 7 | "\5e" ;; Array type, -0x22 8 | "\78" ;; Storage type: i8 or -0x08 9 | "\02" ;; Mutability, should be 0 or 1, but isn't 10 | ) 11 | "malformed mutability" 12 | ) 13 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/br_on_non_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (call_ref $t 6 | (block $l (result (ref $t)) 7 | (br_on_non_null $l (local.get $r)) 8 | (return (i32.const -1)) 9 | ) 10 | ) 11 | ) 12 | (func $n (param $r (ref null $t)) (result i32) 13 | (call_ref $t 14 | (block $l (result (ref $t)) 15 | (br_on_non_null $l (local.get $r)) 16 | (return (i32.const -1)) 17 | ) 18 | ) 19 | ) 20 | 21 | (elem func $f) 22 | (func $f (result i32) (i32.const 7)) 23 | 24 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 25 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 26 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 27 | 28 | (func (export "unreachable") (result i32) 29 | (block $l (result (ref $t)) 30 | (br_on_non_null $l (unreachable)) 31 | (return (i32.const -1)) 32 | ) 33 | (call_ref $t) 34 | ) 35 | ) 36 | 37 | (assert_trap (invoke "unreachable") "unreachable") 38 | 39 | (assert_return (invoke "nullable-null") (i32.const -1)) 40 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 41 | (assert_return (invoke "nullable-f") (i32.const 7)) 42 | 43 | (module 44 | (type $t (func)) 45 | (func (param $r (ref null $t)) (drop (block (result (ref $t)) (br_on_non_null 0 (local.get $r)) (unreachable)))) 46 | (func (param $r (ref null func)) (drop (block (result (ref func)) (br_on_non_null 0 (local.get $r)) (unreachable)))) 47 | (func (param $r (ref null extern)) (drop (block (result (ref extern)) (br_on_non_null 0 (local.get $r)) (unreachable)))) 48 | ) 49 | 50 | 51 | (module 52 | (type $t (func (param i32) (result i32))) 53 | (elem func $f) 54 | (func $f (param i32) (result i32) (i32.mul (local.get 0) (local.get 0))) 55 | 56 | (func $a (param $n i32) (param $r (ref null $t)) (result i32) 57 | (call_ref $t 58 | (block $l (result i32 (ref $t)) 59 | (return (br_on_non_null $l (local.get $n) (local.get $r))) 60 | ) 61 | ) 62 | ) 63 | 64 | (func (export "args-null") (param $n i32) (result i32) 65 | (call $a (local.get $n) (ref.null $t)) 66 | ) 67 | (func (export "args-f") (param $n i32) (result i32) 68 | (call $a (local.get $n) (ref.func $f)) 69 | ) 70 | ) 71 | 72 | (assert_return (invoke "args-null" (i32.const 3)) (i32.const 3)) 73 | (assert_return (invoke "args-f" (i32.const 3)) (i32.const 9)) 74 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/br_on_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (block $l 6 | (return (call_ref $t (br_on_null $l (local.get $r)))) 7 | ) 8 | (i32.const -1) 9 | ) 10 | (func $n (param $r (ref null $t)) (result i32) 11 | (block $l 12 | (return (call_ref $t (br_on_null $l (local.get $r)))) 13 | ) 14 | (i32.const -1) 15 | ) 16 | 17 | (elem func $f) 18 | (func $f (result i32) (i32.const 7)) 19 | 20 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 21 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 22 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 23 | 24 | (func (export "unreachable") (result i32) 25 | (block $l 26 | (return (call_ref $t (br_on_null $l (unreachable)))) 27 | ) 28 | (i32.const -1) 29 | ) 30 | ) 31 | 32 | (assert_trap (invoke "unreachable") "unreachable") 33 | 34 | (assert_return (invoke "nullable-null") (i32.const -1)) 35 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 36 | (assert_return (invoke "nullable-f") (i32.const 7)) 37 | 38 | (module 39 | (type $t (func)) 40 | (func (param $r (ref null $t)) (drop (br_on_null 0 (local.get $r)))) 41 | (func (param $r (ref null func)) (drop (br_on_null 0 (local.get $r)))) 42 | (func (param $r (ref null extern)) (drop (br_on_null 0 (local.get $r)))) 43 | ) 44 | 45 | 46 | (module 47 | (type $t (func (param i32) (result i32))) 48 | (elem func $f) 49 | (func $f (param i32) (result i32) (i32.mul (local.get 0) (local.get 0))) 50 | 51 | (func $a (param $n i32) (param $r (ref null $t)) (result i32) 52 | (block $l (result i32) 53 | (return (call_ref $t (br_on_null $l (local.get $n) (local.get $r)))) 54 | ) 55 | ) 56 | 57 | (func (export "args-null") (param $n i32) (result i32) 58 | (call $a (local.get $n) (ref.null $t)) 59 | ) 60 | (func (export "args-f") (param $n i32) (result i32) 61 | (call $a (local.get $n) (ref.func $f)) 62 | ) 63 | ) 64 | 65 | (assert_return (invoke "args-null" (i32.const 3)) (i32.const 3)) 66 | (assert_return (invoke "args-f" (i32.const 3)) (i32.const 9)) 67 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/extern.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $ft (func)) 3 | (type $st (struct)) 4 | (type $at (array i8)) 5 | 6 | (table 10 anyref) 7 | 8 | (elem declare func $f) 9 | (func $f) 10 | 11 | (func (export "init") (param $x externref) 12 | (table.set (i32.const 0) (ref.null any)) 13 | (table.set (i32.const 1) (ref.i31 (i32.const 7))) 14 | (table.set (i32.const 2) (struct.new_default $st)) 15 | (table.set (i32.const 3) (array.new_default $at (i32.const 0))) 16 | (table.set (i32.const 4) (any.convert_extern (local.get $x))) 17 | ) 18 | 19 | (func (export "internalize") (param externref) (result anyref) 20 | (any.convert_extern (local.get 0)) 21 | ) 22 | (func (export "externalize") (param anyref) (result externref) 23 | (extern.convert_any (local.get 0)) 24 | ) 25 | 26 | (func (export "externalize-i") (param i32) (result externref) 27 | (extern.convert_any (table.get (local.get 0))) 28 | ) 29 | (func (export "externalize-ii") (param i32) (result anyref) 30 | (any.convert_extern (extern.convert_any (table.get (local.get 0)))) 31 | ) 32 | ) 33 | 34 | (invoke "init" (ref.extern 0)) 35 | 36 | (assert_return (invoke "internalize" (ref.extern 1)) (ref.host 1)) 37 | (assert_return (invoke "internalize" (ref.null extern)) (ref.null any)) 38 | 39 | (assert_return (invoke "externalize" (ref.host 2)) (ref.extern 2)) 40 | (assert_return (invoke "externalize" (ref.null any)) (ref.null extern)) 41 | 42 | (assert_return (invoke "externalize-i" (i32.const 0)) (ref.null extern)) 43 | (assert_return (invoke "externalize-i" (i32.const 1)) (ref.extern)) 44 | (assert_return (invoke "externalize-i" (i32.const 2)) (ref.extern)) 45 | (assert_return (invoke "externalize-i" (i32.const 3)) (ref.extern)) 46 | (assert_return (invoke "externalize-i" (i32.const 4)) (ref.extern)) 47 | (assert_return (invoke "externalize-i" (i32.const 5)) (ref.null extern)) 48 | 49 | (assert_return (invoke "externalize-ii" (i32.const 0)) (ref.null any)) 50 | (assert_return (invoke "externalize-ii" (i32.const 1)) (ref.i31)) 51 | (assert_return (invoke "externalize-ii" (i32.const 2)) (ref.struct)) 52 | (assert_return (invoke "externalize-ii" (i32.const 3)) (ref.array)) 53 | (assert_return (invoke "externalize-ii" (i32.const 4)) (ref.host 0)) 54 | (assert_return (invoke "externalize-ii" (i32.const 5)) (ref.null any)) 55 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/i31.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "new") (param $i i32) (result (ref i31)) 3 | (ref.i31 (local.get $i)) 4 | ) 5 | 6 | (func (export "get_u") (param $i i32) (result i32) 7 | (i31.get_u (ref.i31 (local.get $i))) 8 | ) 9 | (func (export "get_s") (param $i i32) (result i32) 10 | (i31.get_s (ref.i31 (local.get $i))) 11 | ) 12 | 13 | (func (export "get_u-null") (result i32) 14 | (i31.get_u (ref.null i31)) 15 | ) 16 | (func (export "get_s-null") (result i32) 17 | (i31.get_u (ref.null i31)) 18 | ) 19 | 20 | (global $i (ref i31) (ref.i31 (i32.const 2))) 21 | (global $m (mut (ref i31)) (ref.i31 (i32.const 3))) 22 | (func (export "get_globals") (result i32 i32) 23 | (i31.get_u (global.get $i)) 24 | (i31.get_u (global.get $m)) 25 | ) 26 | ) 27 | 28 | (assert_return (invoke "new" (i32.const 1)) (ref.i31)) 29 | 30 | (assert_return (invoke "get_u" (i32.const 0)) (i32.const 0)) 31 | (assert_return (invoke "get_u" (i32.const 100)) (i32.const 100)) 32 | (assert_return (invoke "get_u" (i32.const -1)) (i32.const 0x7fff_ffff)) 33 | (assert_return (invoke "get_u" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff)) 34 | (assert_return (invoke "get_u" (i32.const 0x4000_0000)) (i32.const 0x4000_0000)) 35 | (assert_return (invoke "get_u" (i32.const 0x7fff_ffff)) (i32.const 0x7fff_ffff)) 36 | (assert_return (invoke "get_u" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa)) 37 | (assert_return (invoke "get_u" (i32.const 0xcaaa_aaaa)) (i32.const 0x4aaa_aaaa)) 38 | 39 | (assert_return (invoke "get_s" (i32.const 0)) (i32.const 0)) 40 | (assert_return (invoke "get_s" (i32.const 100)) (i32.const 100)) 41 | (assert_return (invoke "get_s" (i32.const -1)) (i32.const -1)) 42 | (assert_return (invoke "get_s" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff)) 43 | (assert_return (invoke "get_s" (i32.const 0x4000_0000)) (i32.const -0x4000_0000)) 44 | (assert_return (invoke "get_s" (i32.const 0x7fff_ffff)) (i32.const -1)) 45 | (assert_return (invoke "get_s" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa)) 46 | (assert_return (invoke "get_s" (i32.const 0xcaaa_aaaa)) (i32.const 0xcaaa_aaaa)) 47 | 48 | (assert_trap (invoke "get_u-null") "null i31 reference") 49 | (assert_trap (invoke "get_s-null") "null i31 reference") 50 | 51 | (assert_return (invoke "get_globals") (i32.const 2) (i32.const 3)) 52 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/local_init.wast: -------------------------------------------------------------------------------- 1 | ;; Uninitialized undefaulted locals 2 | 3 | (module 4 | (func (export "get-after-set") (param $p (ref extern)) (result (ref extern)) 5 | (local $x (ref extern)) 6 | (local.set $x (local.get $p)) 7 | (local.get $x) 8 | ) 9 | (func (export "get-after-tee") (param $p (ref extern)) (result (ref extern)) 10 | (local $x (ref extern)) 11 | (drop (local.tee $x (local.get $p))) 12 | (local.get $x) 13 | ) 14 | (func (export "get-in-block-after-set") (param $p (ref extern)) (result (ref extern)) 15 | (local $x (ref extern)) 16 | (local.set $x (local.get $p)) 17 | (block (result (ref extern)) (local.get $x)) 18 | ) 19 | ) 20 | 21 | (assert_return (invoke "get-after-set" (ref.extern 1)) (ref.extern 1)) 22 | (assert_return (invoke "get-after-tee" (ref.extern 2)) (ref.extern 2)) 23 | (assert_return (invoke "get-in-block-after-set" (ref.extern 3)) (ref.extern 3)) 24 | 25 | (assert_invalid 26 | (module (func $uninit (local $x (ref extern)) (drop (local.get $x)))) 27 | "uninitialized local" 28 | ) 29 | (assert_invalid 30 | (module 31 | (func $uninit-after-end (param $p (ref extern)) 32 | (local $x (ref extern)) 33 | (block (local.set $x (local.get $p)) (drop (local.tee $x (local.get $p)))) 34 | (drop (local.get $x)) 35 | ) 36 | ) 37 | "uninitialized local" 38 | ) 39 | (assert_invalid 40 | (module 41 | (func $uninit-in-else (param $p (ref extern)) 42 | (local $x (ref extern)) 43 | (if (i32.const 0) 44 | (then (local.set $x (local.get $p))) 45 | (else (local.get $x)) 46 | ) 47 | ) 48 | ) 49 | "uninitialized local" 50 | ) 51 | 52 | (assert_invalid 53 | (module 54 | (func $uninit-from-if (param $p (ref extern)) 55 | (local $x (ref extern)) 56 | (if (i32.const 0) 57 | (then (local.set $x (local.get $p))) 58 | (else (local.set $x (local.get $p))) 59 | ) 60 | (drop (local.get $x)) 61 | ) 62 | ) 63 | "uninitialized local" 64 | ) 65 | 66 | (module 67 | (func (export "tee-init") (param $p (ref extern)) (result (ref extern)) 68 | (local $x (ref extern)) 69 | (drop (local.tee $x (local.get $p))) 70 | (local.get $x) 71 | ) 72 | ) 73 | 74 | (assert_return (invoke "tee-init" (ref.extern 1)) (ref.extern 1)) 75 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/ref.wast: -------------------------------------------------------------------------------- 1 | ;; Syntax 2 | 3 | (module 4 | (type $t (func)) 5 | 6 | (func 7 | (param 8 | funcref 9 | externref 10 | (ref func) 11 | (ref extern) 12 | (ref 0) 13 | (ref $t) 14 | (ref 0) 15 | (ref $t) 16 | (ref null func) 17 | (ref null extern) 18 | (ref null 0) 19 | (ref null $t) 20 | ) 21 | ) 22 | ) 23 | 24 | 25 | ;; Undefined type index. 26 | 27 | (assert_invalid 28 | (module (type $type-func-param-invalid (func (param (ref 1))))) 29 | "unknown type" 30 | ) 31 | (assert_invalid 32 | (module (type $type-func-result-invalid (func (result (ref 1))))) 33 | "unknown type" 34 | ) 35 | 36 | (assert_invalid 37 | (module (global $global-invalid (ref null 1) (ref.null 1))) 38 | "unknown type" 39 | ) 40 | 41 | (assert_invalid 42 | (module (table $table-invalid 10 (ref null 1))) 43 | "unknown type" 44 | ) 45 | 46 | (assert_invalid 47 | (module (elem $elem-invalid (ref 1))) 48 | "unknown type" 49 | ) 50 | 51 | (assert_invalid 52 | (module (func $func-param-invalid (param (ref 1)))) 53 | "unknown type" 54 | ) 55 | (assert_invalid 56 | (module (func $func-result-invalid (result (ref 1)))) 57 | "unknown type" 58 | ) 59 | (assert_invalid 60 | (module (func $func-local-invalid (local (ref null 1)))) 61 | "unknown type" 62 | ) 63 | 64 | (assert_invalid 65 | (module (func $block-result-invalid (drop (block (result (ref 1)) (unreachable))))) 66 | "unknown type" 67 | ) 68 | (assert_invalid 69 | (module (func $loop-result-invalid (drop (loop (result (ref 1)) (unreachable))))) 70 | "unknown type" 71 | ) 72 | (assert_invalid 73 | (module (func $if-invalid (drop (if (result (ref 1)) (then) (else))))) 74 | "unknown type" 75 | ) 76 | 77 | (assert_invalid 78 | (module (func $select-result-invalid (drop (select (result (ref 1)) (unreachable))))) 79 | "unknown type" 80 | ) 81 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/ref_as_non_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (call_ref $t (ref.as_non_null (local.get $r))) 6 | ) 7 | (func $n (param $r (ref null $t)) (result i32) 8 | (call_ref $t (ref.as_non_null (local.get $r))) 9 | ) 10 | 11 | (elem func $f) 12 | (func $f (result i32) (i32.const 7)) 13 | 14 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 15 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 16 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 17 | 18 | (func (export "unreachable") (result i32) 19 | (unreachable) 20 | (ref.as_non_null) 21 | (call $nn) 22 | ) 23 | ) 24 | 25 | (assert_trap (invoke "unreachable") "unreachable") 26 | 27 | (assert_trap (invoke "nullable-null") "null reference") 28 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 29 | (assert_return (invoke "nullable-f") (i32.const 7)) 30 | 31 | (assert_invalid 32 | (module 33 | (type $t (func (result i32))) 34 | (func $g (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) 35 | (func (call $g (ref.null $t))) 36 | ) 37 | "type mismatch" 38 | ) 39 | 40 | 41 | (module 42 | (type $t (func)) 43 | (func (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) 44 | (func (param $r (ref func)) (drop (ref.as_non_null (local.get $r)))) 45 | (func (param $r (ref extern)) (drop (ref.as_non_null (local.get $r)))) 46 | ) 47 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/ref_is_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (func $dummy) 4 | 5 | (func $f1 (export "funcref") (param $x funcref) (result i32) 6 | (ref.is_null (local.get $x)) 7 | ) 8 | (func $f2 (export "externref") (param $x externref) (result i32) 9 | (ref.is_null (local.get $x)) 10 | ) 11 | (func $f3 (param $x (ref null $t)) (result i32) 12 | (ref.is_null (local.get $x)) 13 | ) 14 | (func $f3' (export "ref-null") (result i32) 15 | (call $f3 (ref.null $t)) 16 | ) 17 | 18 | (table $t1 2 funcref) 19 | (table $t2 2 externref) 20 | (table $t3 2 (ref null $t)) 21 | (elem (table $t1) (i32.const 1) func $dummy) 22 | (elem (table $t3) (i32.const 1) (ref $t) (ref.func $dummy)) 23 | 24 | (func (export "init") (param $r externref) 25 | (table.set $t2 (i32.const 1) (local.get $r)) 26 | ) 27 | (func (export "deinit") 28 | (table.set $t1 (i32.const 1) (ref.null func)) 29 | (table.set $t2 (i32.const 1) (ref.null extern)) 30 | (table.set $t3 (i32.const 1) (ref.null $t)) 31 | ) 32 | 33 | (func (export "funcref-elem") (param $x i32) (result i32) 34 | (call $f1 (table.get $t1 (local.get $x))) 35 | ) 36 | (func (export "externref-elem") (param $x i32) (result i32) 37 | (call $f2 (table.get $t2 (local.get $x))) 38 | ) 39 | (func (export "ref-elem") (param $x i32) (result i32) 40 | (call $f3 (table.get $t3 (local.get $x))) 41 | ) 42 | ) 43 | 44 | (assert_return (invoke "funcref" (ref.null func)) (i32.const 1)) 45 | (assert_return (invoke "externref" (ref.null extern)) (i32.const 1)) 46 | (assert_return (invoke "ref-null") (i32.const 1)) 47 | 48 | (assert_return (invoke "externref" (ref.extern 1)) (i32.const 0)) 49 | 50 | (invoke "init" (ref.extern 0)) 51 | 52 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 53 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 54 | (assert_return (invoke "ref-elem" (i32.const 0)) (i32.const 1)) 55 | 56 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) 57 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 0)) 58 | (assert_return (invoke "ref-elem" (i32.const 1)) (i32.const 0)) 59 | 60 | (invoke "deinit") 61 | 62 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 63 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 64 | (assert_return (invoke "ref-elem" (i32.const 0)) (i32.const 1)) 65 | 66 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) 67 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) 68 | (assert_return (invoke "ref-elem" (i32.const 1)) (i32.const 1)) 69 | 70 | 71 | (module 72 | (type $t (func)) 73 | (func (param $r (ref $t)) (drop (ref.is_null (local.get $r)))) 74 | (func (param $r (ref func)) (drop (ref.is_null (local.get $r)))) 75 | (func (param $r (ref extern)) (drop (ref.is_null (local.get $r)))) 76 | ) 77 | 78 | (assert_invalid 79 | (module (func $ref-vs-num (param i32) (ref.is_null (local.get 0)))) 80 | "type mismatch" 81 | ) 82 | (assert_invalid 83 | (module (func $ref-vs-empty (ref.is_null))) 84 | "type mismatch" 85 | ) 86 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/ref_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (func (export "anyref") (result anyref) (ref.null any)) 4 | (func (export "funcref") (result funcref) (ref.null func)) 5 | (func (export "ref") (result (ref null $t)) (ref.null $t)) 6 | 7 | (global anyref (ref.null any)) 8 | (global funcref (ref.null func)) 9 | (global (ref null $t) (ref.null $t)) 10 | ) 11 | 12 | (assert_return (invoke "anyref") (ref.null any)) 13 | (assert_return (invoke "funcref") (ref.null func)) 14 | (assert_return (invoke "ref") (ref.null)) 15 | 16 | 17 | (module 18 | (type $t (func)) 19 | (global $null nullref (ref.null none)) 20 | (global $nullfunc nullfuncref (ref.null nofunc)) 21 | (global $nullextern nullexternref (ref.null noextern)) 22 | (func (export "anyref") (result anyref) (global.get $null)) 23 | (func (export "nullref") (result nullref) (global.get $null)) 24 | (func (export "funcref") (result funcref) (global.get $nullfunc)) 25 | (func (export "nullfuncref") (result nullfuncref) (global.get $nullfunc)) 26 | (func (export "externref") (result externref) (global.get $nullextern)) 27 | (func (export "nullexternref") (result nullexternref) (global.get $nullextern)) 28 | (func (export "ref") (result (ref null $t)) (global.get $nullfunc)) 29 | 30 | (global anyref (ref.null any)) 31 | (global anyref (ref.null none)) 32 | (global funcref (ref.null func)) 33 | (global funcref (ref.null nofunc)) 34 | (global externref (ref.null extern)) 35 | (global externref (ref.null noextern)) 36 | (global nullref (ref.null none)) 37 | (global nullfuncref (ref.null nofunc)) 38 | (global nullexternref (ref.null noextern)) 39 | (global (ref null $t) (ref.null $t)) 40 | (global (ref null $t) (ref.null nofunc)) 41 | ) 42 | 43 | (assert_return (invoke "anyref") (ref.null any)) 44 | (assert_return (invoke "anyref") (ref.null none)) 45 | (assert_return (invoke "anyref") (ref.null)) 46 | (assert_return (invoke "nullref") (ref.null any)) 47 | (assert_return (invoke "nullref") (ref.null none)) 48 | (assert_return (invoke "nullref") (ref.null)) 49 | (assert_return (invoke "funcref") (ref.null func)) 50 | (assert_return (invoke "funcref") (ref.null nofunc)) 51 | (assert_return (invoke "funcref") (ref.null)) 52 | (assert_return (invoke "nullfuncref") (ref.null func)) 53 | (assert_return (invoke "nullfuncref") (ref.null nofunc)) 54 | (assert_return (invoke "nullfuncref") (ref.null)) 55 | (assert_return (invoke "externref") (ref.null extern)) 56 | (assert_return (invoke "externref") (ref.null noextern)) 57 | (assert_return (invoke "externref") (ref.null)) 58 | (assert_return (invoke "nullexternref") (ref.null extern)) 59 | (assert_return (invoke "nullexternref") (ref.null noextern)) 60 | (assert_return (invoke "nullexternref") (ref.null)) 61 | (assert_return (invoke "ref") (ref.null func)) 62 | (assert_return (invoke "ref") (ref.null nofunc)) 63 | (assert_return (invoke "ref") (ref.null)) 64 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/table-sub.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (table $t1 10 (ref null func)) 4 | (table $t2 10 (ref null $t)) 5 | (elem $el funcref) 6 | (func $f 7 | (table.init $t1 $el (i32.const 0) (i32.const 1) (i32.const 2)) 8 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 9 | ) 10 | ) 11 | 12 | (assert_invalid 13 | (module 14 | (table $t1 10 funcref) 15 | (table $t2 10 externref) 16 | (func $f 17 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 18 | ) 19 | ) 20 | "type mismatch" 21 | ) 22 | 23 | (assert_invalid 24 | (module 25 | (table $t 10 funcref) 26 | (elem $el externref) 27 | (func $f 28 | (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) 29 | ) 30 | ) 31 | "type mismatch" 32 | ) 33 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/type-canon.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (rec 3 | (type $t1 (func (param i32 (ref $t3)))) 4 | (type $t2 (func (param i32 (ref $t1)))) 5 | (type $t3 (func (param i32 (ref $t2)))) 6 | ) 7 | ) 8 | 9 | (module 10 | (rec 11 | (type $t0 (func (param i32 (ref $t2) (ref $t3)))) 12 | (type $t1 (func (param i32 (ref $t0) i32 (ref $t4)))) 13 | (type $t2 (func (param i32 (ref $t2) (ref $t1)))) 14 | (type $t3 (func (param i32 (ref $t2) i32 (ref $t4)))) 15 | (type $t4 (func (param (ref $t0) (ref $t2)))) 16 | ) 17 | ) 18 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/gc/unreached-valid.wast: -------------------------------------------------------------------------------- 1 | (module 2 | 3 | ;; Check that both sides of the select are evaluated 4 | (func (export "select-trap-left") (param $cond i32) (result i32) 5 | (select (unreachable) (i32.const 0) (local.get $cond)) 6 | ) 7 | (func (export "select-trap-right") (param $cond i32) (result i32) 8 | (select (i32.const 0) (unreachable) (local.get $cond)) 9 | ) 10 | 11 | (func (export "select-unreached") 12 | (unreachable) (select) 13 | (unreachable) (i32.const 0) (select) 14 | (unreachable) (i32.const 0) (i32.const 0) (select) 15 | (unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select) 16 | (unreachable) (f32.const 0) (i32.const 0) (select) 17 | (unreachable) 18 | ) 19 | 20 | (func (export "select-unreached-result1") (result i32) 21 | (unreachable) (i32.add (select)) 22 | ) 23 | 24 | (func (export "select-unreached-result2") (result i64) 25 | (unreachable) (i64.add (select (i64.const 0) (i32.const 0))) 26 | ) 27 | 28 | (func (export "select-unreached-num") 29 | (unreachable) 30 | (select) 31 | (i32.eqz) 32 | (drop) 33 | ) 34 | (func (export "select-unreached-ref") 35 | (unreachable) 36 | (select) 37 | (ref.is_null) 38 | (drop) 39 | ) 40 | 41 | (type $t (func (param i32) (result i32))) 42 | (func (export "call_ref-unreached") (result i32) 43 | (unreachable) 44 | (call_ref $t) 45 | ) 46 | ) 47 | 48 | (assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") 49 | (assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") 50 | (assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") 51 | (assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable") 52 | 53 | (assert_trap (invoke "select-unreached-result1") "unreachable") 54 | (assert_trap (invoke "select-unreached-result2") "unreachable") 55 | (assert_trap (invoke "select-unreached-num") "unreachable") 56 | (assert_trap (invoke "select-unreached-ref") "unreachable") 57 | 58 | (assert_trap (invoke "call_ref-unreached") "unreachable") 59 | 60 | 61 | ;; Validation after unreachable 62 | 63 | (module 64 | (func (export "meet-bottom") 65 | (block (result f64) 66 | (block (result f32) 67 | (unreachable) 68 | (br_table 0 1 1 (i32.const 1)) 69 | ) 70 | (drop) 71 | (f64.const 0) 72 | ) 73 | (drop) 74 | ) 75 | ) 76 | 77 | (assert_trap (invoke "meet-bottom") "unreachable") 78 | 79 | 80 | ;; Bottom heap type 81 | 82 | (module 83 | (func (result (ref func)) 84 | (unreachable) 85 | (ref.as_non_null) 86 | ) 87 | (func (result (ref extern)) 88 | (unreachable) 89 | (ref.as_non_null) 90 | ) 91 | 92 | (func (result (ref func)) 93 | (block (result funcref) 94 | (unreachable) 95 | (br_on_null 0) 96 | (return) 97 | ) 98 | (unreachable) 99 | ) 100 | (func (result (ref extern)) 101 | (block (result externref) 102 | (unreachable) 103 | (br_on_null 0) 104 | (return) 105 | ) 106 | (unreachable) 107 | ) 108 | ) 109 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/memory64/memory_redundancy64.wast: -------------------------------------------------------------------------------- 1 | ;; Test that optimizers don't do redundant-load, store-to-load, or dead-store 2 | ;; optimizations when there are interfering stores, even of different types 3 | ;; and to non-identical addresses. 4 | 5 | (module 6 | (memory i64 1 1) 7 | 8 | (func (export "zero_everything") 9 | (i32.store (i64.const 0) (i32.const 0)) 10 | (i32.store (i64.const 4) (i32.const 0)) 11 | (i32.store (i64.const 8) (i32.const 0)) 12 | (i32.store (i64.const 12) (i32.const 0)) 13 | ) 14 | 15 | (func (export "test_store_to_load") (result i32) 16 | (i32.store (i64.const 8) (i32.const 0)) 17 | (f32.store (i64.const 5) (f32.const -0.0)) 18 | (i32.load (i64.const 8)) 19 | ) 20 | 21 | (func (export "test_redundant_load") (result i32) 22 | (local $t i32) 23 | (local $s i32) 24 | (local.set $t (i32.load (i64.const 8))) 25 | (i32.store (i64.const 5) (i32.const 0x80000000)) 26 | (local.set $s (i32.load (i64.const 8))) 27 | (i32.add (local.get $t) (local.get $s)) 28 | ) 29 | 30 | (func (export "test_dead_store") (result f32) 31 | (local $t f32) 32 | (i32.store (i64.const 8) (i32.const 0x23232323)) 33 | (local.set $t (f32.load (i64.const 11))) 34 | (i32.store (i64.const 8) (i32.const 0)) 35 | (local.get $t) 36 | ) 37 | 38 | ;; A function named "malloc" which implementations nonetheless shouldn't 39 | ;; assume behaves like C malloc. 40 | (func $malloc (export "malloc") 41 | (param $size i64) 42 | (result i64) 43 | (i64.const 16) 44 | ) 45 | 46 | ;; Call malloc twice, but unlike C malloc, we don't get non-aliasing pointers. 47 | (func (export "malloc_aliasing") 48 | (result i32) 49 | (local $x i64) 50 | (local $y i64) 51 | (local.set $x (call $malloc (i64.const 4))) 52 | (local.set $y (call $malloc (i64.const 4))) 53 | (i32.store (local.get $x) (i32.const 42)) 54 | (i32.store (local.get $y) (i32.const 43)) 55 | (i32.load (local.get $x)) 56 | ) 57 | ) 58 | 59 | (assert_return (invoke "test_store_to_load") (i32.const 0x00000080)) 60 | (invoke "zero_everything") 61 | (assert_return (invoke "test_redundant_load") (i32.const 0x00000080)) 62 | (invoke "zero_everything") 63 | (assert_return (invoke "test_dead_store") (f32.const 0x1.18p-144)) 64 | (invoke "zero_everything") 65 | (assert_return (invoke "malloc_aliasing") (i32.const 43)) 66 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/align0.wast: -------------------------------------------------------------------------------- 1 | ;; Test aligned and unaligned read/write 2 | 3 | (module 4 | (memory $mem0 0) 5 | (memory $mem1 1) 6 | (memory $mem2 0) 7 | 8 | ;; $default: natural alignment, $1: align=1, $2: align=2, $4: align=4, $8: align=8 9 | 10 | (func (export "f32_align_switch") (param i32) (result f32) 11 | (local f32 f32) 12 | (local.set 1 (f32.const 10.0)) 13 | (block $4 14 | (block $2 15 | (block $1 16 | (block $default 17 | (block $0 18 | (br_table $0 $default $1 $2 $4 (local.get 0)) 19 | ) ;; 0 20 | (f32.store $mem1 (i32.const 0) (local.get 1)) 21 | (local.set 2 (f32.load $mem1 (i32.const 0))) 22 | (br $4) 23 | ) ;; default 24 | (f32.store $mem1 align=1 (i32.const 0) (local.get 1)) 25 | (local.set 2 (f32.load $mem1 align=1 (i32.const 0))) 26 | (br $4) 27 | ) ;; 1 28 | (f32.store $mem1 align=2 (i32.const 0) (local.get 1)) 29 | (local.set 2 (f32.load $mem1 align=2 (i32.const 0))) 30 | (br $4) 31 | ) ;; 2 32 | (f32.store $mem1 align=4 (i32.const 0) (local.get 1)) 33 | (local.set 2 (f32.load $mem1 align=4 (i32.const 0))) 34 | ) ;; 4 35 | (local.get 2) 36 | ) 37 | ) 38 | 39 | (assert_return (invoke "f32_align_switch" (i32.const 0)) (f32.const 10.0)) 40 | (assert_return (invoke "f32_align_switch" (i32.const 1)) (f32.const 10.0)) 41 | (assert_return (invoke "f32_align_switch" (i32.const 2)) (f32.const 10.0)) 42 | (assert_return (invoke "f32_align_switch" (i32.const 3)) (f32.const 10.0)) 43 | 44 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/binary0.wast: -------------------------------------------------------------------------------- 1 | ;; Unsigned LEB128 can have non-minimal length 2 | (module binary 3 | "\00asm" "\01\00\00\00" 4 | "\05\07\02" ;; Memory section with 2 entries 5 | "\00\82\00" ;; no max, minimum 2 6 | "\00\82\00" ;; no max, minimum 2 7 | ) 8 | (module binary 9 | "\00asm" "\01\00\00\00" 10 | "\05\13\03" ;; Memory section with 3 entries 11 | "\00\83\80\80\80\00" ;; no max, minimum 3 12 | "\00\84\80\80\80\00" ;; no max, minimum 4 13 | "\00\85\80\80\80\00" ;; no max, minimum 5 14 | ) 15 | 16 | (module binary 17 | "\00asm" "\01\00\00\00" 18 | "\05\05\02" ;; Memory section with 2 entries 19 | "\00\00" ;; no max, minimum 0 20 | "\00\00" ;; no max, minimum 0 21 | "\0b\06\01" ;; Data section with 1 entry 22 | "\00" ;; Memory index 0 23 | "\41\00\0b\00" ;; (i32.const 0) with contents "" 24 | ) 25 | 26 | (module binary 27 | "\00asm" "\01\00\00\00" 28 | "\05\05\02" ;; Memory section with 2 entries 29 | "\00\00" ;; no max, minimum 0 30 | "\00\01" ;; no max, minimum 1 31 | "\0b\07\01" ;; Data section with 1 entry 32 | "\02\01" ;; Memory index 1 33 | "\41\00\0b\00" ;; (i32.const 0) with contents "" 34 | ) 35 | 36 | (module binary 37 | "\00asm" "\01\00\00\00" 38 | "\05\05\02" ;; Memory section with 2 entries 39 | "\00\00" ;; no max, minimum 0 40 | "\00\01" ;; no max, minimum 1 41 | "\0b\0a\01" ;; Data section with 1 entry 42 | "\02\81\80\80\00" ;; Memory index 1 43 | "\41\00\0b\00" ;; (i32.const 0) with contents "" 44 | ) 45 | 46 | ;; Unsigned LEB128 must not be overlong 47 | (assert_malformed 48 | (module binary 49 | "\00asm" "\01\00\00\00" 50 | "\05\0a\02" ;; Memory section with 2 entries 51 | "\00\01" ;; no max, minimum 1 52 | "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many 53 | ) 54 | "integer representation too long" 55 | ) 56 | 57 | ;; 2 memories declared, 1 given 58 | (assert_malformed 59 | (module binary 60 | "\00asm" "\01\00\00\00" 61 | "\05\03\02" ;; memory section with inconsistent count (1 declared, 0 given) 62 | "\00\00" ;; memory 0 (missed) 63 | ;; "\00\00" ;; memory 1 (missing) 64 | ) 65 | "unexpected end of section or function" 66 | ) 67 | 68 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/data0.wast: -------------------------------------------------------------------------------- 1 | ;; Test the data section 2 | 3 | ;; Syntax 4 | 5 | (module 6 | (memory $mem0 1) 7 | (memory $mem1 1) 8 | (memory $mem2 1) 9 | 10 | (data (i32.const 0)) 11 | (data (i32.const 1) "a" "" "bcd") 12 | (data (offset (i32.const 0))) 13 | (data (offset (i32.const 0)) "" "a" "bc" "") 14 | (data (memory 0) (i32.const 0)) 15 | (data (memory 0x0) (i32.const 1) "a" "" "bcd") 16 | (data (memory 0x000) (offset (i32.const 0))) 17 | (data (memory 0) (offset (i32.const 0)) "" "a" "bc" "") 18 | (data (memory $mem0) (i32.const 0)) 19 | (data (memory $mem1) (i32.const 1) "a" "" "bcd") 20 | (data (memory $mem2) (offset (i32.const 0))) 21 | (data (memory $mem0) (offset (i32.const 0)) "" "a" "bc" "") 22 | 23 | (data $d1 (i32.const 0)) 24 | (data $d2 (i32.const 1) "a" "" "bcd") 25 | (data $d3 (offset (i32.const 0))) 26 | (data $d4 (offset (i32.const 0)) "" "a" "bc" "") 27 | (data $d5 (memory 0) (i32.const 0)) 28 | (data $d6 (memory 0x0) (i32.const 1) "a" "" "bcd") 29 | (data $d7 (memory 0x000) (offset (i32.const 0))) 30 | (data $d8 (memory 0) (offset (i32.const 0)) "" "a" "bc" "") 31 | (data $d9 (memory $mem0) (i32.const 0)) 32 | (data $d10 (memory $mem1) (i32.const 1) "a" "" "bcd") 33 | (data $d11 (memory $mem2) (offset (i32.const 0))) 34 | (data $d12 (memory $mem0) (offset (i32.const 0)) "" "a" "bc" "") 35 | ) 36 | 37 | ;; Basic use 38 | 39 | (module 40 | (memory 1) 41 | (data (i32.const 0) "a") 42 | ) 43 | (module 44 | (import "spectest" "memory" (memory 1)) 45 | (import "spectest" "memory" (memory 1)) 46 | (import "spectest" "memory" (memory 1)) 47 | (data (memory 0) (i32.const 0) "a") 48 | (data (memory 1) (i32.const 0) "a") 49 | (data (memory 2) (i32.const 0) "a") 50 | ) 51 | 52 | (module 53 | (global (import "spectest" "global_i32") i32) 54 | (memory 1) 55 | (data (global.get 0) "a") 56 | ) 57 | (module 58 | (global (import "spectest" "global_i32") i32) 59 | (import "spectest" "memory" (memory 1)) 60 | (data (global.get 0) "a") 61 | ) 62 | 63 | (module 64 | (global $g (import "spectest" "global_i32") i32) 65 | (memory 1) 66 | (data (global.get $g) "a") 67 | ) 68 | (module 69 | (global $g (import "spectest" "global_i32") i32) 70 | (import "spectest" "memory" (memory 1)) 71 | (data (global.get $g) "a") 72 | ) 73 | 74 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/data1.wast: -------------------------------------------------------------------------------- 1 | ;; Invalid bounds for data 2 | 3 | (assert_trap 4 | (module 5 | (memory 1) 6 | (memory 0) 7 | (memory 2) 8 | (data (memory 1) (i32.const 0) "a") 9 | ) 10 | "out of bounds memory access" 11 | ) 12 | 13 | (assert_trap 14 | (module 15 | (memory 1 1) 16 | (memory 1 1) 17 | (memory 0 0) 18 | (data (memory 2) (i32.const 0) "a") 19 | ) 20 | "out of bounds memory access" 21 | ) 22 | 23 | (assert_trap 24 | (module 25 | (memory 1 1) 26 | (memory 0 1) 27 | (memory 1 1) 28 | (data (memory 1) (i32.const 0) "a") 29 | ) 30 | "out of bounds memory access" 31 | ) 32 | (assert_trap 33 | (module 34 | (memory 1) 35 | (memory 1) 36 | (memory 0) 37 | (data (memory 2) (i32.const 1)) 38 | ) 39 | "out of bounds memory access" 40 | ) 41 | (assert_trap 42 | (module 43 | (memory 1 1) 44 | (memory 1 1) 45 | (memory 0 1) 46 | (data (memory 2) (i32.const 1)) 47 | ) 48 | "out of bounds memory access" 49 | ) 50 | 51 | ;; This seems to cause a time-out on Travis. 52 | (;assert_unlinkable 53 | (module 54 | (memory 0x10000) 55 | (data (i32.const 0xffffffff) "ab") 56 | ) 57 | "" ;; either out of memory or out of bounds 58 | ;) 59 | 60 | (assert_trap 61 | (module 62 | (global (import "spectest" "global_i32") i32) 63 | (memory 3) 64 | (memory 0) 65 | (memory 3) 66 | (data (memory 1) (global.get 0) "a") 67 | ) 68 | "out of bounds memory access" 69 | ) 70 | 71 | (assert_trap 72 | (module 73 | (memory 2 2) 74 | (memory 1 2) 75 | (memory 2 2) 76 | (data (memory 1) (i32.const 0x1_0000) "a") 77 | ) 78 | "out of bounds memory access" 79 | ) 80 | (assert_trap 81 | (module 82 | (import "spectest" "memory" (memory 1)) 83 | (data (i32.const 0x1_0000) "a") 84 | ) 85 | "out of bounds memory access" 86 | ) 87 | 88 | (assert_trap 89 | (module 90 | (memory 3) 91 | (memory 3) 92 | (memory 2) 93 | (data (memory 2) (i32.const 0x2_0000) "a") 94 | ) 95 | "out of bounds memory access" 96 | ) 97 | 98 | (assert_trap 99 | (module 100 | (memory 3 3) 101 | (memory 2 3) 102 | (memory 3 3) 103 | (data (memory 1) (i32.const 0x2_0000) "a") 104 | ) 105 | "out of bounds memory access" 106 | ) 107 | 108 | (assert_trap 109 | (module 110 | (memory 0) 111 | (memory 0) 112 | (memory 1) 113 | (data (memory 2) (i32.const -1) "a") 114 | ) 115 | "out of bounds memory access" 116 | ) 117 | (assert_trap 118 | (module 119 | (import "spectest" "memory" (memory 1)) 120 | (import "spectest" "memory" (memory 1)) 121 | (import "spectest" "memory" (memory 1)) 122 | (data (memory 2) (i32.const -1) "a") 123 | ) 124 | "out of bounds memory access" 125 | ) 126 | 127 | (assert_trap 128 | (module 129 | (memory 2) 130 | (memory 2) 131 | (memory 2) 132 | (data (memory 2) (i32.const -100) "a") 133 | ) 134 | "out of bounds memory access" 135 | ) 136 | (assert_trap 137 | (module 138 | (import "spectest" "memory" (memory 1)) 139 | (import "spectest" "memory" (memory 1)) 140 | (import "spectest" "memory" (memory 1)) 141 | (import "spectest" "memory" (memory 1)) 142 | (data (memory 3) (i32.const -100) "a") 143 | ) 144 | "out of bounds memory access" 145 | ) 146 | 147 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/data_drop0.wast: -------------------------------------------------------------------------------- 1 | ;; data.drop 2 | (module 3 | (memory $mem0 0) 4 | (memory $mem1 1) 5 | (memory $mem2 0) 6 | (data $p "x") 7 | (data $a (memory 1) (i32.const 0) "x") 8 | 9 | (func (export "drop_passive") (data.drop $p)) 10 | (func (export "init_passive") (param $len i32) 11 | (memory.init $mem1 $p (i32.const 0) (i32.const 0) (local.get $len))) 12 | 13 | (func (export "drop_active") (data.drop $a)) 14 | (func (export "init_active") (param $len i32) 15 | (memory.init $mem1 $a (i32.const 0) (i32.const 0) (local.get $len))) 16 | ) 17 | 18 | (invoke "init_passive" (i32.const 1)) 19 | (invoke "drop_passive") 20 | (invoke "drop_passive") 21 | (assert_return (invoke "init_passive" (i32.const 0))) 22 | (assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds memory access") 23 | (invoke "init_passive" (i32.const 0)) 24 | (invoke "drop_active") 25 | (assert_return (invoke "init_active" (i32.const 0))) 26 | (assert_trap (invoke "init_active" (i32.const 1)) "out of bounds memory access") 27 | (invoke "init_active" (i32.const 0)) 28 | 29 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/exports0.wast: -------------------------------------------------------------------------------- 1 | ;; Memories 2 | 3 | (module (memory 0) (export "a" (memory 0))) 4 | (module (memory 0) (export "a" (memory 0)) (export "b" (memory 0))) 5 | (module (memory 0) (memory 0) (export "a" (memory 0)) (export "b" (memory 1))) 6 | (module 7 | (memory $mem0 0) 8 | (memory $mem1 0) 9 | (memory $mem2 0) 10 | (memory $mem3 0) 11 | (memory $mem4 0) 12 | (memory $mem5 0) 13 | (memory $mem6 0) 14 | 15 | (export "a" (memory $mem0)) 16 | (export "b" (memory $mem1)) 17 | (export "ac" (memory $mem2)) 18 | (export "bc" (memory $mem3)) 19 | (export "ad" (memory $mem4)) 20 | (export "bd" (memory $mem5)) 21 | (export "be" (memory $mem6)) 22 | 23 | (export "za" (memory $mem0)) 24 | (export "zb" (memory $mem1)) 25 | (export "zac" (memory $mem2)) 26 | (export "zbc" (memory $mem3)) 27 | (export "zad" (memory $mem4)) 28 | (export "zbd" (memory $mem5)) 29 | (export "zbe" (memory $mem6)) 30 | ) 31 | 32 | (module 33 | (export "a" (memory 0)) 34 | (memory 6) 35 | 36 | (export "b" (memory 1)) 37 | (memory 3) 38 | ) 39 | 40 | (module 41 | (export "a" (memory 0)) 42 | (memory 0 1) 43 | (memory 0 1) 44 | (memory 0 1) 45 | (memory 0 1) 46 | 47 | (export "b" (memory 3)) 48 | ) 49 | (module (export "a" (memory $a)) (memory $a 0)) 50 | (module (export "a" (memory $a)) (memory $a 0 1)) 51 | 52 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/float_exprs0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0 0) 3 | (memory $m 1 1) 4 | (memory 0 0) 5 | (func (export "init") (param $i i32) (param $x f64) 6 | (f64.store $m (local.get $i) (local.get $x))) 7 | 8 | (func (export "run") (param $n i32) (param $z f64) 9 | (local $i i32) 10 | (block $exit 11 | (loop $cont 12 | (f64.store $m 13 | (local.get $i) 14 | (f64.div (f64.load $m (local.get $i)) (local.get $z)) 15 | ) 16 | (local.set $i (i32.add (local.get $i) (i32.const 8))) 17 | (br_if $cont (i32.lt_u (local.get $i) (local.get $n))) 18 | ) 19 | ) 20 | ) 21 | 22 | (func (export "check") (param $i i32) (result f64) (f64.load $m (local.get $i))) 23 | ) 24 | 25 | (invoke "init" (i32.const 0) (f64.const 15.1)) 26 | (invoke "init" (i32.const 8) (f64.const 15.2)) 27 | (invoke "init" (i32.const 16) (f64.const 15.3)) 28 | (invoke "init" (i32.const 24) (f64.const 15.4)) 29 | (assert_return (invoke "check" (i32.const 0)) (f64.const 15.1)) 30 | (assert_return (invoke "check" (i32.const 8)) (f64.const 15.2)) 31 | (assert_return (invoke "check" (i32.const 16)) (f64.const 15.3)) 32 | (assert_return (invoke "check" (i32.const 24)) (f64.const 15.4)) 33 | (invoke "run" (i32.const 32) (f64.const 3.0)) 34 | (assert_return (invoke "check" (i32.const 0)) (f64.const 0x1.4222222222222p+2)) 35 | (assert_return (invoke "check" (i32.const 8)) (f64.const 0x1.4444444444444p+2)) 36 | (assert_return (invoke "check" (i32.const 16)) (f64.const 0x1.4666666666667p+2)) 37 | (assert_return (invoke "check" (i32.const 24)) (f64.const 0x1.4888888888889p+2)) 38 | 39 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/float_memory0.wast: -------------------------------------------------------------------------------- 1 | ;; Test that floating-point load and store are bit-preserving. 2 | 3 | ;; Test that load and store do not canonicalize NaNs as x87 does. 4 | 5 | (module 6 | (memory 0 0) 7 | (memory 0 0) 8 | (memory 0 0) 9 | (memory $m (data "\00\00\a0\7f")) 10 | (memory 0 0) 11 | (memory 0 0) 12 | 13 | (func (export "f32.load") (result f32) (f32.load $m (i32.const 0))) 14 | (func (export "i32.load") (result i32) (i32.load $m (i32.const 0))) 15 | (func (export "f32.store") (f32.store $m (i32.const 0) (f32.const nan:0x200000))) 16 | (func (export "i32.store") (i32.store $m (i32.const 0) (i32.const 0x7fa00000))) 17 | (func (export "reset") (i32.store $m (i32.const 0) (i32.const 0))) 18 | ) 19 | 20 | (assert_return (invoke "i32.load") (i32.const 0x7fa00000)) 21 | (assert_return (invoke "f32.load") (f32.const nan:0x200000)) 22 | (invoke "reset") 23 | (assert_return (invoke "i32.load") (i32.const 0x0)) 24 | (assert_return (invoke "f32.load") (f32.const 0.0)) 25 | (invoke "f32.store") 26 | (assert_return (invoke "i32.load") (i32.const 0x7fa00000)) 27 | (assert_return (invoke "f32.load") (f32.const nan:0x200000)) 28 | (invoke "reset") 29 | (assert_return (invoke "i32.load") (i32.const 0x0)) 30 | (assert_return (invoke "f32.load") (f32.const 0.0)) 31 | (invoke "i32.store") 32 | (assert_return (invoke "i32.load") (i32.const 0x7fa00000)) 33 | (assert_return (invoke "f32.load") (f32.const nan:0x200000)) 34 | 35 | (module 36 | (memory 0 0) 37 | (memory $m (data "\00\00\00\00\00\00\f4\7f")) 38 | 39 | (func (export "f64.load") (result f64) (f64.load $m (i32.const 0))) 40 | (func (export "i64.load") (result i64) (i64.load $m (i32.const 0))) 41 | (func (export "f64.store") (f64.store $m (i32.const 0) (f64.const nan:0x4000000000000))) 42 | (func (export "i64.store") (i64.store $m (i32.const 0) (i64.const 0x7ff4000000000000))) 43 | (func (export "reset") (i64.store $m (i32.const 0) (i64.const 0))) 44 | ) 45 | 46 | (assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000)) 47 | (assert_return (invoke "f64.load") (f64.const nan:0x4000000000000)) 48 | (invoke "reset") 49 | (assert_return (invoke "i64.load") (i64.const 0x0)) 50 | (assert_return (invoke "f64.load") (f64.const 0.0)) 51 | (invoke "f64.store") 52 | (assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000)) 53 | (assert_return (invoke "f64.load") (f64.const nan:0x4000000000000)) 54 | (invoke "reset") 55 | (assert_return (invoke "i64.load") (i64.const 0x0)) 56 | (assert_return (invoke "f64.load") (f64.const 0.0)) 57 | (invoke "i64.store") 58 | (assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000)) 59 | (assert_return (invoke "f64.load") (f64.const nan:0x4000000000000)) 60 | 61 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/imports0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "func")) 3 | (func (export "func-i32") (param i32)) 4 | (func (export "func-f32") (param f32)) 5 | (func (export "func->i32") (result i32) (i32.const 22)) 6 | (func (export "func->f32") (result f32) (f32.const 11)) 7 | (func (export "func-i32->i32") (param i32) (result i32) (local.get 0)) 8 | (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) 9 | (global (export "global-i32") i32 (i32.const 55)) 10 | (global (export "global-f32") f32 (f32.const 44)) 11 | (global (export "global-mut-i64") (mut i64) (i64.const 66)) 12 | (table (export "table-10-inf") 10 funcref) 13 | (table (export "table-10-20") 10 20 funcref) 14 | (memory (export "memory-2-inf") 2) 15 | (memory (export "memory-2-4") 2 4) 16 | ) 17 | 18 | (register "test") 19 | 20 | (assert_unlinkable 21 | (module (import "test" "memory-2-inf" (func))) 22 | "incompatible import type" 23 | ) 24 | (assert_unlinkable 25 | (module (import "test" "memory-2-4" (func))) 26 | "incompatible import type" 27 | ) 28 | 29 | (assert_unlinkable 30 | (module (import "test" "memory-2-inf" (global i32))) 31 | "incompatible import type" 32 | ) 33 | (assert_unlinkable 34 | (module (import "test" "memory-2-4" (global i32))) 35 | "incompatible import type" 36 | ) 37 | 38 | (assert_unlinkable 39 | (module (import "test" "memory-2-inf" (table 10 funcref))) 40 | "incompatible import type" 41 | ) 42 | (assert_unlinkable 43 | (module (import "test" "memory-2-4" (table 10 funcref))) 44 | "incompatible import type" 45 | ) 46 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/imports1.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (import "spectest" "memory" (memory 1 2)) 3 | (import "spectest" "memory" (memory 1 2)) 4 | (memory $m (import "spectest" "memory") 1 2) 5 | (import "spectest" "memory" (memory 1 2)) 6 | 7 | (data (memory 2) (i32.const 10) "\10") 8 | 9 | (func (export "load") (param i32) (result i32) (i32.load $m (local.get 0))) 10 | ) 11 | 12 | (assert_return (invoke "load" (i32.const 0)) (i32.const 0)) 13 | (assert_return (invoke "load" (i32.const 10)) (i32.const 16)) 14 | (assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000)) 15 | (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access") 16 | 17 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/imports2.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory (export "z") 0 0) 3 | (memory (export "memory-2-inf") 2) 4 | (memory (export "memory-2-4") 2 4) 5 | ) 6 | 7 | (register "test") 8 | 9 | (module 10 | (import "test" "z" (memory 0)) 11 | (memory $m (import "spectest" "memory") 1 2) 12 | (data (memory 1) (i32.const 10) "\10") 13 | 14 | (func (export "load") (param i32) (result i32) (i32.load $m (local.get 0))) 15 | ) 16 | 17 | (assert_return (invoke "load" (i32.const 0)) (i32.const 0)) 18 | (assert_return (invoke "load" (i32.const 10)) (i32.const 16)) 19 | (assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000)) 20 | (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access") 21 | 22 | (module 23 | (memory (import "spectest" "memory") 1 2) 24 | (data (memory 0) (i32.const 10) "\10") 25 | 26 | (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) 27 | ) 28 | (assert_return (invoke "load" (i32.const 0)) (i32.const 0)) 29 | (assert_return (invoke "load" (i32.const 10)) (i32.const 16)) 30 | (assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000)) 31 | (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access") 32 | 33 | (module 34 | (import "test" "memory-2-inf" (memory 2)) 35 | (import "test" "memory-2-inf" (memory 1)) 36 | (import "test" "memory-2-inf" (memory 0)) 37 | ) 38 | 39 | (module 40 | (import "spectest" "memory" (memory 1)) 41 | (import "spectest" "memory" (memory 0)) 42 | (import "spectest" "memory" (memory 1 2)) 43 | (import "spectest" "memory" (memory 0 2)) 44 | (import "spectest" "memory" (memory 1 3)) 45 | (import "spectest" "memory" (memory 0 3)) 46 | ) 47 | 48 | (assert_unlinkable 49 | (module (import "test" "unknown" (memory 1))) 50 | "unknown import" 51 | ) 52 | (assert_unlinkable 53 | (module (import "spectest" "unknown" (memory 1))) 54 | "unknown import" 55 | ) 56 | 57 | (assert_unlinkable 58 | (module (import "test" "memory-2-inf" (memory 3))) 59 | "incompatible import type" 60 | ) 61 | (assert_unlinkable 62 | (module (import "test" "memory-2-inf" (memory 2 3))) 63 | "incompatible import type" 64 | ) 65 | (assert_unlinkable 66 | (module (import "spectest" "memory" (memory 2))) 67 | "incompatible import type" 68 | ) 69 | (assert_unlinkable 70 | (module (import "spectest" "memory" (memory 1 1))) 71 | "incompatible import type" 72 | ) 73 | 74 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/imports3.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "func")) 3 | (func (export "func-i32") (param i32)) 4 | (func (export "func-f32") (param f32)) 5 | (func (export "func->i32") (result i32) (i32.const 22)) 6 | (func (export "func->f32") (result f32) (f32.const 11)) 7 | (func (export "func-i32->i32") (param i32) (result i32) (local.get 0)) 8 | (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) 9 | (global (export "global-i32") i32 (i32.const 55)) 10 | (global (export "global-f32") f32 (f32.const 44)) 11 | (global (export "global-mut-i64") (mut i64) (i64.const 66)) 12 | (table (export "table-10-inf") 10 funcref) 13 | (table (export "table-10-20") 10 20 funcref) 14 | (memory (export "memory-2-inf") 2) 15 | (memory (export "memory-2-4") 2 4) 16 | ) 17 | 18 | (register "test") 19 | (assert_unlinkable 20 | (module 21 | (import "test" "memory-2-4" (memory 1)) 22 | (import "test" "func-i32" (memory 1)) 23 | ) 24 | "incompatible import type" 25 | ) 26 | (assert_unlinkable 27 | (module 28 | (import "test" "memory-2-4" (memory 1)) 29 | (import "test" "global-i32" (memory 1)) 30 | ) 31 | "incompatible import type" 32 | ) 33 | (assert_unlinkable 34 | (module 35 | (import "test" "memory-2-4" (memory 1)) 36 | (import "test" "table-10-inf" (memory 1)) 37 | ) 38 | "incompatible import type" 39 | ) 40 | (assert_unlinkable 41 | (module 42 | (import "test" "memory-2-4" (memory 1)) 43 | (import "spectest" "print_i32" (memory 1)) 44 | ) 45 | "incompatible import type" 46 | ) 47 | (assert_unlinkable 48 | (module 49 | (import "test" "memory-2-4" (memory 1)) 50 | (import "spectest" "global_i32" (memory 1)) 51 | ) 52 | "incompatible import type" 53 | ) 54 | (assert_unlinkable 55 | (module 56 | (import "test" "memory-2-4" (memory 1)) 57 | (import "spectest" "table" (memory 1)) 58 | ) 59 | "incompatible import type" 60 | ) 61 | 62 | (assert_unlinkable 63 | (module 64 | (import "test" "memory-2-4" (memory 1)) 65 | (import "spectest" "memory" (memory 2)) 66 | ) 67 | "incompatible import type" 68 | ) 69 | (assert_unlinkable 70 | (module 71 | (import "test" "memory-2-4" (memory 1)) 72 | (import "spectest" "memory" (memory 1 1)) 73 | ) 74 | "incompatible import type" 75 | ) 76 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/imports4.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory (export "memory-2-inf") 2) 3 | (memory (export "memory-2-4") 2 4) 4 | ) 5 | 6 | (register "test") 7 | 8 | (module 9 | (import "test" "memory-2-4" (memory 1)) 10 | (memory $m (import "spectest" "memory") 0 3) ;; actual has max size 2 11 | (func (export "grow") (param i32) (result i32) (memory.grow $m (local.get 0))) 12 | ) 13 | (assert_return (invoke "grow" (i32.const 0)) (i32.const 1)) 14 | (assert_return (invoke "grow" (i32.const 1)) (i32.const 1)) 15 | (assert_return (invoke "grow" (i32.const 0)) (i32.const 2)) 16 | (assert_return (invoke "grow" (i32.const 1)) (i32.const -1)) 17 | (assert_return (invoke "grow" (i32.const 0)) (i32.const 2)) 18 | 19 | (module $Mgm 20 | (memory 0) 21 | (memory 0) 22 | (memory $m (export "memory") 1) ;; initial size is 1 23 | (func (export "grow") (result i32) (memory.grow $m (i32.const 1))) 24 | ) 25 | (register "grown-memory" $Mgm) 26 | (assert_return (invoke $Mgm "grow") (i32.const 1)) ;; now size is 2 27 | 28 | (module $Mgim1 29 | ;; imported memory limits should match, because external memory size is 2 now 30 | (import "test" "memory-2-4" (memory 1)) 31 | (memory $m (export "memory") (import "grown-memory" "memory") 2) 32 | (memory 0) 33 | (memory 0) 34 | (func (export "grow") (result i32) (memory.grow $m (i32.const 1))) 35 | ) 36 | (register "grown-imported-memory" $Mgim1) 37 | (assert_return (invoke $Mgim1 "grow") (i32.const 2)) ;; now size is 3 38 | 39 | (module $Mgim2 40 | ;; imported memory limits should match, because external memory size is 3 now 41 | (import "test" "memory-2-4" (memory 1)) 42 | (memory $m (import "grown-imported-memory" "memory") 3) 43 | (memory 0) 44 | (memory 0) 45 | (func (export "size") (result i32) (memory.size $m)) 46 | ) 47 | (assert_return (invoke $Mgim2 "size") (i32.const 3)) 48 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/linking0.wast: -------------------------------------------------------------------------------- 1 | (module $Mt 2 | (type (func (result i32))) 3 | (type (func)) 4 | 5 | (table (export "tab") 10 funcref) 6 | (elem (i32.const 2) $g $g $g $g) 7 | (func $g (result i32) (i32.const 4)) 8 | (func (export "h") (result i32) (i32.const -4)) 9 | 10 | (func (export "call") (param i32) (result i32) 11 | (call_indirect (type 0) (local.get 0)) 12 | ) 13 | ) 14 | (register "Mt" $Mt) 15 | 16 | (assert_unlinkable 17 | (module 18 | (table (import "Mt" "tab") 10 funcref) 19 | (memory (import "spectest" "memory") 1) 20 | (memory (import "Mt" "mem") 1) ;; does not exist 21 | (func $f (result i32) (i32.const 0)) 22 | (elem (i32.const 7) $f) 23 | (elem (i32.const 9) $f) 24 | ) 25 | "unknown import" 26 | ) 27 | (assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized element") 28 | 29 | 30 | (assert_trap 31 | (module 32 | (table (import "Mt" "tab") 10 funcref) 33 | (func $f (result i32) (i32.const 0)) 34 | (elem (i32.const 7) $f) 35 | (memory 0) 36 | (memory $m 1) 37 | (memory 0) 38 | (data $m (i32.const 0x10000) "d") ;; out of bounds 39 | ) 40 | "out of bounds memory access" 41 | ) 42 | (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) 43 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/linking1.wast: -------------------------------------------------------------------------------- 1 | (module $Mm 2 | (memory $mem0 (export "mem0") 0 0) 3 | (memory $mem1 (export "mem1") 1 5) 4 | (memory $mem2 (export "mem2") 0 0) 5 | 6 | (data (memory 1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") 7 | 8 | (func (export "load") (param $a i32) (result i32) 9 | (i32.load8_u $mem1 (local.get 0)) 10 | ) 11 | ) 12 | (register "Mm" $Mm) 13 | 14 | (module $Nm 15 | (func $loadM (import "Mm" "load") (param i32) (result i32)) 16 | (memory (import "Mm" "mem0") 0) 17 | 18 | (memory $m 1) 19 | (data (memory 1) (i32.const 10) "\f0\f1\f2\f3\f4\f5") 20 | 21 | (export "Mm.load" (func $loadM)) 22 | (func (export "load") (param $a i32) (result i32) 23 | (i32.load8_u $m (local.get 0)) 24 | ) 25 | ) 26 | 27 | (assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 2)) 28 | (assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 2)) 29 | (assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2)) 30 | 31 | (module $Om 32 | (memory (import "Mm" "mem1") 1) 33 | (data (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7") 34 | 35 | (func (export "load") (param $a i32) (result i32) 36 | (i32.load8_u (local.get 0)) 37 | ) 38 | ) 39 | 40 | (assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 0xa7)) 41 | (assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 0xa7)) 42 | (assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2)) 43 | (assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7)) 44 | 45 | (module 46 | (memory (import "Mm" "mem1") 0) 47 | (data (i32.const 0xffff) "a") 48 | ) 49 | 50 | (assert_trap 51 | (module 52 | (memory (import "Mm" "mem0") 0) 53 | (data (i32.const 0xffff) "a") 54 | ) 55 | "out of bounds memory access" 56 | ) 57 | 58 | (assert_trap 59 | (module 60 | (memory (import "Mm" "mem1") 0) 61 | (data (i32.const 0x10000) "a") 62 | ) 63 | "out of bounds memory access" 64 | ) 65 | 66 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/linking2.wast: -------------------------------------------------------------------------------- 1 | (module $Mm 2 | (memory $mem0 (export "mem0") 0 0) 3 | (memory $mem1 (export "mem1") 1 5) 4 | (memory $mem2 (export "mem2") 0 0) 5 | 6 | (data (memory 1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") 7 | 8 | (func (export "load") (param $a i32) (result i32) 9 | (i32.load8_u $mem1 (local.get 0)) 10 | ) 11 | ) 12 | (register "Mm" $Mm) 13 | 14 | (module $Pm 15 | (memory (import "Mm" "mem1") 1 8) 16 | 17 | (func (export "grow") (param $a i32) (result i32) 18 | (memory.grow (local.get 0)) 19 | ) 20 | ) 21 | 22 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 1)) 23 | (assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1)) 24 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3)) 25 | (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3)) 26 | (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4)) 27 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5)) 28 | (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1)) 29 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5)) 30 | 31 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/linking3.wast: -------------------------------------------------------------------------------- 1 | (module $Mm 2 | (memory $mem0 (export "mem0") 0 0) 3 | (memory $mem1 (export "mem1") 5 5) 4 | (memory $mem2 (export "mem2") 0 0) 5 | 6 | (data (memory 1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") 7 | 8 | (func (export "load") (param $a i32) (result i32) 9 | (i32.load8_u $mem1 (local.get 0)) 10 | ) 11 | ) 12 | (register "Mm" $Mm) 13 | 14 | (assert_unlinkable 15 | (module 16 | (func $host (import "spectest" "print")) 17 | (memory (import "Mm" "mem1") 1) 18 | (table (import "Mm" "tab") 0 funcref) ;; does not exist 19 | (data (i32.const 0) "abc") 20 | ) 21 | "unknown import" 22 | ) 23 | (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) 24 | 25 | ;; Unlike in v1 spec, active data segments written before an 26 | ;; out-of-bounds access persist after the instantiation failure. 27 | (assert_trap 28 | (module 29 | ;; Note: the memory is 5 pages large by the time we get here. 30 | (memory (import "Mm" "mem1") 1) 31 | (data (i32.const 0) "abc") 32 | (data (i32.const 327670) "zzzzzzzzzzzzzzzzzz") ;; (partially) out of bounds 33 | ) 34 | "out of bounds memory access" 35 | ) 36 | (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) 37 | (assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0)) 38 | 39 | (assert_trap 40 | (module 41 | (memory (import "Mm" "mem1") 1) 42 | (data (i32.const 0) "abc") 43 | (table 0 funcref) 44 | (func) 45 | (elem (i32.const 0) 0) ;; out of bounds 46 | ) 47 | "out of bounds table access" 48 | ) 49 | (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) 50 | 51 | ;; Store is modified if the start function traps. 52 | (module $Ms 53 | (type $t (func (result i32))) 54 | (memory (export "memory") 1) 55 | (table (export "table") 1 funcref) 56 | (func (export "get memory[0]") (type $t) 57 | (i32.load8_u (i32.const 0)) 58 | ) 59 | (func (export "get table[0]") (type $t) 60 | (call_indirect (type $t) (i32.const 0)) 61 | ) 62 | ) 63 | (register "Ms" $Ms) 64 | 65 | (assert_trap 66 | (module 67 | (import "Ms" "memory" (memory 1)) 68 | (import "Ms" "table" (table 1 funcref)) 69 | (data (i32.const 0) "hello") 70 | (elem (i32.const 0) $f) 71 | (func $f (result i32) 72 | (i32.const 0xdead) 73 | ) 74 | (func $main 75 | (unreachable) 76 | ) 77 | (start $main) 78 | ) 79 | "unreachable" 80 | ) 81 | 82 | (assert_return (invoke $Ms "get memory[0]") (i32.const 104)) ;; 'h' 83 | (assert_return (invoke $Ms "get table[0]") (i32.const 0xdead)) 84 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/load0.wast: -------------------------------------------------------------------------------- 1 | ;; Multiple memories 2 | 3 | (module 4 | (memory $mem1 1) 5 | (memory $mem2 1) 6 | 7 | (func (export "load1") (param i32) (result i64) 8 | (i64.load $mem1 (local.get 0)) 9 | ) 10 | (func (export "load2") (param i32) (result i64) 11 | (i64.load $mem2 (local.get 0)) 12 | ) 13 | 14 | (data (memory $mem1) (i32.const 0) "\01") 15 | (data (memory $mem2) (i32.const 0) "\02") 16 | ) 17 | 18 | (assert_return (invoke "load1" (i32.const 0)) (i64.const 1)) 19 | (assert_return (invoke "load2" (i32.const 0)) (i64.const 2)) 20 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/load1.wast: -------------------------------------------------------------------------------- 1 | (module $M 2 | (memory (export "mem") 2) 3 | 4 | (func (export "read") (param i32) (result i32) 5 | (i32.load8_u (local.get 0)) 6 | ) 7 | ) 8 | (register "M") 9 | 10 | (module 11 | (memory $mem1 (import "M" "mem") 2) 12 | (memory $mem2 3) 13 | 14 | (data (memory $mem1) (i32.const 20) "\01\02\03\04\05") 15 | (data (memory $mem2) (i32.const 50) "\0A\0B\0C\0D\0E") 16 | 17 | (func (export "read1") (param i32) (result i32) 18 | (i32.load8_u $mem1 (local.get 0)) 19 | ) 20 | (func (export "read2") (param i32) (result i32) 21 | (i32.load8_u $mem2 (local.get 0)) 22 | ) 23 | ) 24 | 25 | (assert_return (invoke $M "read" (i32.const 20)) (i32.const 1)) 26 | (assert_return (invoke $M "read" (i32.const 21)) (i32.const 2)) 27 | (assert_return (invoke $M "read" (i32.const 22)) (i32.const 3)) 28 | (assert_return (invoke $M "read" (i32.const 23)) (i32.const 4)) 29 | (assert_return (invoke $M "read" (i32.const 24)) (i32.const 5)) 30 | 31 | (assert_return (invoke "read1" (i32.const 20)) (i32.const 1)) 32 | (assert_return (invoke "read1" (i32.const 21)) (i32.const 2)) 33 | (assert_return (invoke "read1" (i32.const 22)) (i32.const 3)) 34 | (assert_return (invoke "read1" (i32.const 23)) (i32.const 4)) 35 | (assert_return (invoke "read1" (i32.const 24)) (i32.const 5)) 36 | 37 | (assert_return (invoke "read2" (i32.const 50)) (i32.const 10)) 38 | (assert_return (invoke "read2" (i32.const 51)) (i32.const 11)) 39 | (assert_return (invoke "read2" (i32.const 52)) (i32.const 12)) 40 | (assert_return (invoke "read2" (i32.const 53)) (i32.const 13)) 41 | (assert_return (invoke "read2" (i32.const 54)) (i32.const 14)) 42 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory-multi.wast: -------------------------------------------------------------------------------- 1 | ;; From wasmtime misc_testsuite/multi-memory/simple.wast 2 | 3 | ;; Should be replaced with suitable extensions to ../meta/generate_memory_*.js 4 | 5 | (module 6 | (memory $mem1 1) 7 | (memory $mem2 1) 8 | 9 | (func (export "init1") (result i32) 10 | (memory.init $mem1 $d (i32.const 1) (i32.const 0) (i32.const 4)) 11 | (i32.load $mem1 (i32.const 1)) 12 | ) 13 | 14 | (func (export "init2") (result i32) 15 | (memory.init $mem2 $d (i32.const 1) (i32.const 4) (i32.const 4)) 16 | (i32.load $mem2 (i32.const 1)) 17 | ) 18 | 19 | (data $d "\01\00\00\00" "\02\00\00\00") 20 | ) 21 | 22 | (assert_return (invoke "init1") (i32.const 1)) 23 | (assert_return (invoke "init2") (i32.const 2)) 24 | 25 | 26 | (module 27 | (memory $mem1 1) 28 | (memory $mem2 1) 29 | 30 | (func (export "fill1") (result i32) 31 | (memory.fill $mem1 (i32.const 1) (i32.const 0x01) (i32.const 4)) 32 | (i32.load $mem1 (i32.const 1)) 33 | ) 34 | 35 | (func (export "fill2") (result i32) 36 | (memory.fill $mem2 (i32.const 1) (i32.const 0x02) (i32.const 2)) 37 | (i32.load $mem2 (i32.const 1)) 38 | ) 39 | ) 40 | 41 | (assert_return (invoke "fill1") (i32.const 0x01010101)) 42 | (assert_return (invoke "fill2") (i32.const 0x0202)) 43 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_copy0.wast: -------------------------------------------------------------------------------- 1 | ;; memory.copy 2 | (module 3 | (memory $mem0 (data "\ff\11\44\ee")) 4 | (memory $mem1 (data "\ee\22\55\ff")) 5 | (memory $mem2 (data "\dd\33\66\00")) 6 | (memory $mem3 (data "\aa\bb\cc\dd")) 7 | 8 | (func (export "copy") (param i32 i32 i32) 9 | (memory.copy $mem3 $mem3 10 | (local.get 0) 11 | (local.get 1) 12 | (local.get 2))) 13 | 14 | (func (export "load8_u") (param i32) (result i32) 15 | (i32.load8_u $mem3 (local.get 0))) 16 | ) 17 | 18 | ;; Non-overlapping copy. 19 | (invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4)) 20 | 21 | (assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) 22 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa)) 23 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb)) 24 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) 25 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) 26 | (assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) 27 | 28 | ;; Overlap, source > dest 29 | (invoke "copy" (i32.const 8) (i32.const 10) (i32.const 4)) 30 | (assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0xaa)) 31 | (assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0xbb)) 32 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xcc)) 33 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xdd)) 34 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) 35 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) 36 | 37 | ;; Overlap, source < dest 38 | (invoke "copy" (i32.const 10) (i32.const 7) (i32.const 6)) 39 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) 40 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa)) 41 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb)) 42 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc)) 43 | (assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd)) 44 | (assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc)) 45 | (assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0)) 46 | 47 | ;; Copy ending at memory limit is ok. 48 | (invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) 49 | (invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) 50 | 51 | ;; Succeed when copying 0 bytes at the end of the region. 52 | (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 53 | (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) 54 | 55 | ;; Copying 0 bytes outside the memory traps. 56 | (assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 57 | "out of bounds memory access") 58 | (assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) 59 | "out of bounds memory access") 60 | 61 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_copy1.wast: -------------------------------------------------------------------------------- 1 | ;; test memory.copy across different memories. 2 | (module 3 | (memory $mem0 (data "\ff\11\44\ee")) 4 | (memory $mem1 (data "\ee\22\55\ff")) 5 | (memory $mem2 (data "\dd\33\66\00")) 6 | (memory $mem3 (data "\aa\bb\cc\dd")) 7 | 8 | (func (export "copy") (param i32 i32 i32) 9 | (memory.copy $mem0 $mem3 10 | (local.get 0) 11 | (local.get 1) 12 | (local.get 2))) 13 | 14 | (func (export "load8_u") (param i32) (result i32) 15 | (i32.load8_u $mem0 (local.get 0))) 16 | ) 17 | 18 | ;; Non-overlapping copy. 19 | (invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4)) 20 | 21 | (assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) 22 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa)) 23 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb)) 24 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) 25 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) 26 | (assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) 27 | 28 | ;; Copy ending at memory limit is ok. 29 | (invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) 30 | (invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) 31 | 32 | ;; Succeed when copying 0 bytes at the end of the region. 33 | (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 34 | (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) 35 | 36 | ;; Copying 0 bytes outside the memory traps. 37 | (assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 38 | "out of bounds memory access") 39 | (assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) 40 | "out of bounds memory access") 41 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_fill0.wast: -------------------------------------------------------------------------------- 1 | ;; memory.fill 2 | (module 3 | (memory $mem0 0) 4 | (memory $mem1 0) 5 | (memory $mem2 1) 6 | 7 | (func (export "fill") (param i32 i32 i32) 8 | (memory.fill $mem2 9 | (local.get 0) 10 | (local.get 1) 11 | (local.get 2))) 12 | 13 | (func (export "load8_u") (param i32) (result i32) 14 | (i32.load8_u $mem2 (local.get 0))) 15 | ) 16 | 17 | ;; Basic fill test. 18 | (invoke "fill" (i32.const 1) (i32.const 0xff) (i32.const 3)) 19 | (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) 20 | (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xff)) 21 | (assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0xff)) 22 | (assert_return (invoke "load8_u" (i32.const 3)) (i32.const 0xff)) 23 | (assert_return (invoke "load8_u" (i32.const 4)) (i32.const 0)) 24 | 25 | ;; Fill value is stored as a byte. 26 | (invoke "fill" (i32.const 0) (i32.const 0xbbaa) (i32.const 2)) 27 | (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xaa)) 28 | (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xaa)) 29 | 30 | ;; Fill all of memory 31 | (invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000)) 32 | 33 | ;; Out-of-bounds writes trap, and nothing is written 34 | (assert_trap (invoke "fill" (i32.const 0xff00) (i32.const 1) (i32.const 0x101)) 35 | "out of bounds memory access") 36 | (assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 0)) 37 | (assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0)) 38 | 39 | ;; Succeed when writing 0 bytes at the end of the region. 40 | (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 41 | 42 | ;; Writing 0 bytes outside the memory traps. 43 | (assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 44 | "out of bounds memory access") 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_init0.wast: -------------------------------------------------------------------------------- 1 | ;; memory.init 2 | (module 3 | (memory $mem0 0) 4 | (memory $mem1 0) 5 | (memory $mem2 1) 6 | (memory $mem3 0) 7 | (data $mem2 "\aa\bb\cc\dd") 8 | 9 | (func (export "init") (param i32 i32 i32) 10 | (memory.init $mem2 0 11 | (local.get 0) 12 | (local.get 1) 13 | (local.get 2))) 14 | 15 | (func (export "load8_u") (param i32) (result i32) 16 | (i32.load8_u $mem2 (local.get 0))) 17 | ) 18 | 19 | (invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) 20 | (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xbb)) 21 | (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xcc)) 22 | (assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0)) 23 | 24 | ;; Init ending at memory limit and segment limit is ok. 25 | (invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4)) 26 | 27 | ;; Out-of-bounds writes trap, and nothing is written. 28 | (assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3)) 29 | "out of bounds memory access") 30 | (assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xcc)) 31 | (assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xdd)) 32 | 33 | ;; Succeed when writing 0 bytes at the end of either region. 34 | (invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 35 | (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) 36 | 37 | ;; Writing 0 bytes outside the memory traps. 38 | (assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 39 | "out of bounds memory access") 40 | (assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) 41 | "out of bounds memory access") 42 | 43 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_size.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (func (export "size") (result i32) (memory.size)) 4 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 5 | ) 6 | 7 | (assert_return (invoke "size") (i32.const 0)) 8 | (assert_return (invoke "grow" (i32.const 1))) 9 | (assert_return (invoke "size") (i32.const 1)) 10 | (assert_return (invoke "grow" (i32.const 4))) 11 | (assert_return (invoke "size") (i32.const 5)) 12 | (assert_return (invoke "grow" (i32.const 0))) 13 | (assert_return (invoke "size") (i32.const 5)) 14 | 15 | (module 16 | (memory 1) 17 | (func (export "size") (result i32) (memory.size)) 18 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 19 | ) 20 | 21 | (assert_return (invoke "size") (i32.const 1)) 22 | (assert_return (invoke "grow" (i32.const 1))) 23 | (assert_return (invoke "size") (i32.const 2)) 24 | (assert_return (invoke "grow" (i32.const 4))) 25 | (assert_return (invoke "size") (i32.const 6)) 26 | (assert_return (invoke "grow" (i32.const 0))) 27 | (assert_return (invoke "size") (i32.const 6)) 28 | 29 | (module 30 | (memory 0 2) 31 | (func (export "size") (result i32) (memory.size)) 32 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 33 | ) 34 | 35 | (assert_return (invoke "size") (i32.const 0)) 36 | (assert_return (invoke "grow" (i32.const 3))) 37 | (assert_return (invoke "size") (i32.const 0)) 38 | (assert_return (invoke "grow" (i32.const 1))) 39 | (assert_return (invoke "size") (i32.const 1)) 40 | (assert_return (invoke "grow" (i32.const 0))) 41 | (assert_return (invoke "size") (i32.const 1)) 42 | (assert_return (invoke "grow" (i32.const 4))) 43 | (assert_return (invoke "size") (i32.const 1)) 44 | (assert_return (invoke "grow" (i32.const 1))) 45 | (assert_return (invoke "size") (i32.const 2)) 46 | 47 | (module 48 | (memory 3 8) 49 | (func (export "size") (result i32) (memory.size)) 50 | (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz)))) 51 | ) 52 | 53 | (assert_return (invoke "size") (i32.const 3)) 54 | (assert_return (invoke "grow" (i32.const 1))) 55 | (assert_return (invoke "size") (i32.const 4)) 56 | (assert_return (invoke "grow" (i32.const 3))) 57 | (assert_return (invoke "size") (i32.const 7)) 58 | (assert_return (invoke "grow" (i32.const 0))) 59 | (assert_return (invoke "size") (i32.const 7)) 60 | (assert_return (invoke "grow" (i32.const 2))) 61 | (assert_return (invoke "size") (i32.const 7)) 62 | (assert_return (invoke "grow" (i32.const 1))) 63 | (assert_return (invoke "size") (i32.const 8)) 64 | 65 | 66 | ;; Multiple memories 67 | 68 | (module 69 | (memory (export "mem1") 2 4) 70 | (memory (export "mem2") 0) 71 | ) 72 | (register "M") 73 | 74 | (module 75 | (memory $mem1 (import "M" "mem1") 1 5) 76 | (memory $mem2 (import "M" "mem2") 0) 77 | (memory $mem3 3) 78 | (memory $mem4 4 5) 79 | 80 | (func (export "size1") (result i32) (memory.size $mem1)) 81 | (func (export "size2") (result i32) (memory.size $mem2)) 82 | (func (export "size3") (result i32) (memory.size $mem3)) 83 | (func (export "size4") (result i32) (memory.size $mem4)) 84 | ) 85 | 86 | (assert_return (invoke "size1") (i32.const 2)) 87 | (assert_return (invoke "size2") (i32.const 0)) 88 | (assert_return (invoke "size3") (i32.const 3)) 89 | (assert_return (invoke "size4") (i32.const 4)) 90 | 91 | 92 | ;; Type errors 93 | 94 | (assert_invalid 95 | (module 96 | (memory 1) 97 | (func $type-result-i32-vs-empty 98 | (memory.size) 99 | ) 100 | ) 101 | "type mismatch" 102 | ) 103 | (assert_invalid 104 | (module 105 | (memory 1) 106 | (func $type-result-i32-vs-f32 (result f32) 107 | (memory.size) 108 | ) 109 | ) 110 | "type mismatch" 111 | ) 112 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_size0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory 0) 4 | (memory 0) 5 | (memory 0) 6 | (memory $m 0) 7 | 8 | (func (export "size") (result i32) (memory.size $m)) 9 | (func (export "grow") (param $sz i32) (drop (memory.grow $m (local.get $sz)))) 10 | ) 11 | 12 | (assert_return (invoke "size") (i32.const 0)) 13 | (assert_return (invoke "grow" (i32.const 1))) 14 | (assert_return (invoke "size") (i32.const 1)) 15 | (assert_return (invoke "grow" (i32.const 4))) 16 | (assert_return (invoke "size") (i32.const 5)) 17 | (assert_return (invoke "grow" (i32.const 0))) 18 | (assert_return (invoke "size") (i32.const 5)) 19 | 20 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_size1.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory 0) 4 | (memory $n 0) 5 | (memory 0) 6 | (memory $m 0) 7 | 8 | (func (export "size") (result i32) (memory.size $m)) 9 | (func (export "grow") (param $sz i32) (drop (memory.grow $m (local.get $sz)))) 10 | 11 | (func (export "sizen") (result i32) (memory.size $n)) 12 | (func (export "grown") (param $sz i32) (drop (memory.grow $n (local.get $sz)))) 13 | ) 14 | 15 | (assert_return (invoke "size") (i32.const 0)) 16 | (assert_return (invoke "sizen") (i32.const 0)) 17 | (assert_return (invoke "grow" (i32.const 1))) 18 | (assert_return (invoke "size") (i32.const 1)) 19 | (assert_return (invoke "sizen") (i32.const 0)) 20 | (assert_return (invoke "grow" (i32.const 4))) 21 | (assert_return (invoke "size") (i32.const 5)) 22 | (assert_return (invoke "sizen") (i32.const 0)) 23 | (assert_return (invoke "grow" (i32.const 0))) 24 | (assert_return (invoke "size") (i32.const 5)) 25 | (assert_return (invoke "sizen") (i32.const 0)) 26 | 27 | (assert_return (invoke "grown" (i32.const 1))) 28 | (assert_return (invoke "size") (i32.const 5)) 29 | (assert_return (invoke "sizen") (i32.const 1)) 30 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_size2.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0 0) 3 | (memory 0 0) 4 | (memory $n 0 0) 5 | (memory $m 0 2) 6 | 7 | (func (export "size") (result i32) (memory.size $m)) 8 | (func (export "grow") (param $sz i32) (drop (memory.grow $m (local.get $sz)))) 9 | 10 | (func (export "sizen") (result i32) (memory.size $n)) 11 | (func (export "grown") (param $sz i32) (drop (memory.grow $n (local.get $sz)))) 12 | ) 13 | 14 | (assert_return (invoke "size") (i32.const 0)) 15 | (assert_return (invoke "sizen") (i32.const 0)) 16 | (assert_return (invoke "grow" (i32.const 3))) 17 | (assert_return (invoke "sizen") (i32.const 0)) 18 | (assert_return (invoke "size") (i32.const 0)) 19 | (assert_return (invoke "grow" (i32.const 1))) 20 | (assert_return (invoke "sizen") (i32.const 0)) 21 | (assert_return (invoke "size") (i32.const 1)) 22 | (assert_return (invoke "grow" (i32.const 0))) 23 | (assert_return (invoke "sizen") (i32.const 0)) 24 | (assert_return (invoke "size") (i32.const 1)) 25 | (assert_return (invoke "grow" (i32.const 4))) 26 | (assert_return (invoke "sizen") (i32.const 0)) 27 | (assert_return (invoke "size") (i32.const 1)) 28 | (assert_return (invoke "grow" (i32.const 1))) 29 | (assert_return (invoke "sizen") (i32.const 0)) 30 | (assert_return (invoke "size") (i32.const 2)) 31 | 32 | (assert_return (invoke "grown" (i32.const 1))) 33 | (assert_return (invoke "sizen") (i32.const 0)) 34 | (assert_return (invoke "size") (i32.const 2)) 35 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_size3.wast: -------------------------------------------------------------------------------- 1 | ;; Type errors 2 | 3 | (assert_invalid 4 | (module 5 | (memory 0) 6 | (memory $m 1) 7 | (memory 0) 8 | (func $type-result-i32-vs-empty 9 | (memory.size $m) 10 | ) 11 | ) 12 | "type mismatch" 13 | ) 14 | (assert_invalid 15 | (module 16 | (memory 0) 17 | (memory 0) 18 | (memory 0) 19 | (memory $m 1) 20 | (func $type-result-i32-vs-f32 (result f32) 21 | (memory.size $m) 22 | ) 23 | ) 24 | "type mismatch" 25 | ) 26 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/memory_trap0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory 0) 4 | (memory $m 1) 5 | 6 | (func $addr_limit (result i32) 7 | (i32.mul (memory.size $m) (i32.const 0x10000)) 8 | ) 9 | 10 | (func (export "store") (param $i i32) (param $v i32) 11 | (i32.store $m (i32.add (call $addr_limit) (local.get $i)) (local.get $v)) 12 | ) 13 | 14 | (func (export "load") (param $i i32) (result i32) 15 | (i32.load $m (i32.add (call $addr_limit) (local.get $i))) 16 | ) 17 | 18 | (func (export "memory.grow") (param i32) (result i32) 19 | (memory.grow $m (local.get 0)) 20 | ) 21 | ) 22 | 23 | (assert_return (invoke "store" (i32.const -4) (i32.const 42))) 24 | (assert_return (invoke "load" (i32.const -4)) (i32.const 42)) 25 | (assert_trap (invoke "store" (i32.const -3) (i32.const 0x12345678)) "out of bounds memory access") 26 | (assert_trap (invoke "load" (i32.const -3)) "out of bounds memory access") 27 | (assert_trap (invoke "store" (i32.const -2) (i32.const 13)) "out of bounds memory access") 28 | (assert_trap (invoke "load" (i32.const -2)) "out of bounds memory access") 29 | (assert_trap (invoke "store" (i32.const -1) (i32.const 13)) "out of bounds memory access") 30 | (assert_trap (invoke "load" (i32.const -1)) "out of bounds memory access") 31 | (assert_trap (invoke "store" (i32.const 0) (i32.const 13)) "out of bounds memory access") 32 | (assert_trap (invoke "load" (i32.const 0)) "out of bounds memory access") 33 | (assert_trap (invoke "store" (i32.const 0x80000000) (i32.const 13)) "out of bounds memory access") 34 | (assert_trap (invoke "load" (i32.const 0x80000000)) "out of bounds memory access") 35 | (assert_return (invoke "memory.grow" (i32.const 0x10001)) (i32.const -1)) 36 | 37 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/simd_memory-multi.wast: -------------------------------------------------------------------------------- 1 | ;; From wasmtime misc_testsuite/multi-memory/simple.wast 2 | 3 | ;; Test syntax for load/store_lane immediates 4 | 5 | (module 6 | (memory 1) 7 | (memory $m 1) 8 | 9 | (func 10 | (local $v v128) 11 | 12 | (drop (v128.load8_lane 1 (i32.const 0) (local.get $v))) 13 | (drop (v128.load8_lane 1 offset=0 1 (i32.const 0) (local.get $v))) 14 | (drop (v128.load8_lane 1 offset=0 align=1 1 (i32.const 0) (local.get $v))) 15 | (drop (v128.load8_lane 1 align=1 1 (i32.const 0) (local.get $v))) 16 | 17 | (drop (v128.load8_lane $m 1 (i32.const 0) (local.get $v))) 18 | (drop (v128.load8_lane $m offset=0 1 (i32.const 0) (local.get $v))) 19 | (drop (v128.load8_lane $m offset=0 align=1 1 (i32.const 0) (local.get $v))) 20 | (drop (v128.load8_lane $m align=1 1 (i32.const 0) (local.get $v))) 21 | 22 | (drop (v128.load8_lane 1 1 (i32.const 0) (local.get $v))) 23 | (drop (v128.load8_lane 1 offset=0 1 (i32.const 0) (local.get $v))) 24 | (drop (v128.load8_lane 1 offset=0 align=1 1 (i32.const 0) (local.get $v))) 25 | (drop (v128.load8_lane 1 align=1 1 (i32.const 0) (local.get $v))) 26 | 27 | (v128.store8_lane 1 (i32.const 0) (local.get $v)) 28 | (v128.store8_lane offset=0 1 (i32.const 0) (local.get $v)) 29 | (v128.store8_lane offset=0 align=1 1 (i32.const 0) (local.get $v)) 30 | (v128.store8_lane align=1 1 (i32.const 0) (local.get $v)) 31 | 32 | (v128.store8_lane $m 1 (i32.const 0) (local.get $v)) 33 | (v128.store8_lane $m offset=0 1 (i32.const 0) (local.get $v)) 34 | (v128.store8_lane $m offset=0 align=1 1 (i32.const 0) (local.get $v)) 35 | (v128.store8_lane $m align=1 1 (i32.const 0) (local.get $v)) 36 | 37 | (v128.store8_lane 1 1 (i32.const 0) (local.get $v)) 38 | (v128.store8_lane 1 offset=0 1 (i32.const 0) (local.get $v)) 39 | (v128.store8_lane 1 offset=0 align=1 1 (i32.const 0) (local.get $v)) 40 | (v128.store8_lane 1 align=1 1 (i32.const 0) (local.get $v)) 41 | ) 42 | ) 43 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/start0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory $m (data "A")) 4 | (memory $n 1) 5 | 6 | (func $inc 7 | (i32.store8 $m 8 | (i32.const 0) 9 | (i32.add 10 | (i32.load8_u $m (i32.const 0)) 11 | (i32.const 1) 12 | ) 13 | ) 14 | ) 15 | (func $get (result i32) 16 | (return (i32.load8_u $m (i32.const 0))) 17 | ) 18 | (func $getn (result i32) 19 | (return (i32.load8_u $n (i32.const 0))) 20 | ) 21 | (func $main 22 | (call $inc) 23 | (call $inc) 24 | (call $inc) 25 | ) 26 | 27 | (start $main) 28 | (export "inc" (func $inc)) 29 | (export "get" (func $get)) 30 | (export "getn" (func $getn)) 31 | ) 32 | (assert_return (invoke "get") (i32.const 68)) 33 | (assert_return (invoke "getn") (i32.const 0)) 34 | 35 | (invoke "inc") 36 | (assert_return (invoke "get") (i32.const 69)) 37 | (assert_return (invoke "getn") (i32.const 0)) 38 | 39 | (invoke "inc") 40 | (assert_return (invoke "get") (i32.const 70)) 41 | (assert_return (invoke "getn") (i32.const 0)) 42 | 43 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/store0.wast: -------------------------------------------------------------------------------- 1 | ;; Multiple memories 2 | 3 | (module 4 | (memory $mem1 1) 5 | (memory $mem2 1) 6 | 7 | (func (export "load1") (param i32) (result i64) 8 | (i64.load $mem1 (local.get 0)) 9 | ) 10 | (func (export "load2") (param i32) (result i64) 11 | (i64.load $mem2 (local.get 0)) 12 | ) 13 | 14 | (func (export "store1") (param i32 i64) 15 | (i64.store $mem1 (local.get 0) (local.get 1)) 16 | ) 17 | (func (export "store2") (param i32 i64) 18 | (i64.store $mem2 (local.get 0) (local.get 1)) 19 | ) 20 | ) 21 | 22 | (invoke "store1" (i32.const 0) (i64.const 1)) 23 | (invoke "store2" (i32.const 0) (i64.const 2)) 24 | (assert_return (invoke "load1" (i32.const 0)) (i64.const 1)) 25 | (assert_return (invoke "load2" (i32.const 0)) (i64.const 2)) 26 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/store1.wast: -------------------------------------------------------------------------------- 1 | (module $M1 2 | (memory (export "mem") 1) 3 | 4 | (func (export "load") (param i32) (result i64) 5 | (i64.load (local.get 0)) 6 | ) 7 | (func (export "store") (param i32 i64) 8 | (i64.store (local.get 0) (local.get 1)) 9 | ) 10 | ) 11 | (register "M1") 12 | 13 | (module $M2 14 | (memory (export "mem") 1) 15 | 16 | (func (export "load") (param i32) (result i64) 17 | (i64.load (local.get 0)) 18 | ) 19 | (func (export "store") (param i32 i64) 20 | (i64.store (local.get 0) (local.get 1)) 21 | ) 22 | ) 23 | (register "M2") 24 | 25 | (invoke $M1 "store" (i32.const 0) (i64.const 1)) 26 | (invoke $M2 "store" (i32.const 0) (i64.const 2)) 27 | (assert_return (invoke $M1 "load" (i32.const 0)) (i64.const 1)) 28 | (assert_return (invoke $M2 "load" (i32.const 0)) (i64.const 2)) 29 | 30 | (module 31 | (memory $mem1 (import "M1" "mem") 1) 32 | (memory $mem2 (import "M2" "mem") 1) 33 | 34 | (func (export "load1") (param i32) (result i64) 35 | (i64.load $mem1 (local.get 0)) 36 | ) 37 | (func (export "load2") (param i32) (result i64) 38 | (i64.load $mem2 (local.get 0)) 39 | ) 40 | 41 | (func (export "store1") (param i32 i64) 42 | (i64.store $mem1 (local.get 0) (local.get 1)) 43 | ) 44 | (func (export "store2") (param i32 i64) 45 | (i64.store $mem2 (local.get 0) (local.get 1)) 46 | ) 47 | ) 48 | 49 | (invoke "store1" (i32.const 0) (i64.const 1)) 50 | (invoke "store2" (i32.const 0) (i64.const 2)) 51 | (assert_return (invoke "load1" (i32.const 0)) (i64.const 1)) 52 | (assert_return (invoke "load2" (i32.const 0)) (i64.const 2)) 53 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/multi-memory/traps0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory $mem0 1) 3 | (memory $mem1 1) 4 | (memory $mem2 1) 5 | 6 | (func (export "no_dce.i32.load") (param $i i32) (drop (i32.load $mem1 (local.get $i)))) 7 | (func (export "no_dce.i32.load16_s") (param $i i32) (drop (i32.load16_s $mem1 (local.get $i)))) 8 | (func (export "no_dce.i32.load16_u") (param $i i32) (drop (i32.load16_u $mem1 (local.get $i)))) 9 | (func (export "no_dce.i32.load8_s") (param $i i32) (drop (i32.load8_s $mem1 (local.get $i)))) 10 | (func (export "no_dce.i32.load8_u") (param $i i32) (drop (i32.load8_u $mem1 (local.get $i)))) 11 | (func (export "no_dce.i64.load") (param $i i32) (drop (i64.load $mem1 (local.get $i)))) 12 | (func (export "no_dce.i64.load32_s") (param $i i32) (drop (i64.load32_s $mem1 (local.get $i)))) 13 | (func (export "no_dce.i64.load32_u") (param $i i32) (drop (i64.load32_u $mem2 (local.get $i)))) 14 | (func (export "no_dce.i64.load16_s") (param $i i32) (drop (i64.load16_s $mem2 (local.get $i)))) 15 | (func (export "no_dce.i64.load16_u") (param $i i32) (drop (i64.load16_u $mem2 (local.get $i)))) 16 | (func (export "no_dce.i64.load8_s") (param $i i32) (drop (i64.load8_s $mem2 (local.get $i)))) 17 | (func (export "no_dce.i64.load8_u") (param $i i32) (drop (i64.load8_u $mem2 (local.get $i)))) 18 | (func (export "no_dce.f32.load") (param $i i32) (drop (f32.load $mem2 (local.get $i)))) 19 | (func (export "no_dce.f64.load") (param $i i32) (drop (f64.load $mem2 (local.get $i)))) 20 | ) 21 | 22 | (assert_trap (invoke "no_dce.i32.load" (i32.const 65536)) "out of bounds memory access") 23 | (assert_trap (invoke "no_dce.i32.load16_s" (i32.const 65536)) "out of bounds memory access") 24 | (assert_trap (invoke "no_dce.i32.load16_u" (i32.const 65536)) "out of bounds memory access") 25 | (assert_trap (invoke "no_dce.i32.load8_s" (i32.const 65536)) "out of bounds memory access") 26 | (assert_trap (invoke "no_dce.i32.load8_u" (i32.const 65536)) "out of bounds memory access") 27 | (assert_trap (invoke "no_dce.i64.load" (i32.const 65536)) "out of bounds memory access") 28 | (assert_trap (invoke "no_dce.i64.load32_s" (i32.const 65536)) "out of bounds memory access") 29 | (assert_trap (invoke "no_dce.i64.load32_u" (i32.const 65536)) "out of bounds memory access") 30 | (assert_trap (invoke "no_dce.i64.load16_s" (i32.const 65536)) "out of bounds memory access") 31 | (assert_trap (invoke "no_dce.i64.load16_u" (i32.const 65536)) "out of bounds memory access") 32 | (assert_trap (invoke "no_dce.i64.load8_s" (i32.const 65536)) "out of bounds memory access") 33 | (assert_trap (invoke "no_dce.i64.load8_u" (i32.const 65536)) "out of bounds memory access") 34 | (assert_trap (invoke "no_dce.f32.load" (i32.const 65536)) "out of bounds memory access") 35 | (assert_trap (invoke "no_dce.f64.load" (i32.const 65536)) "out of bounds memory access") 36 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/relaxed-simd/i16x8_relaxed_q15mulr_s.wast: -------------------------------------------------------------------------------- 1 | ;; Tests for i16x8.relaxed_q15mulr_s. 2 | ;; `either` comes from https://github.com/WebAssembly/threads. 3 | 4 | (module 5 | (func (export "i16x8.relaxed_q15mulr_s") (param v128 v128) (result v128) (i16x8.relaxed_q15mulr_s (local.get 0) (local.get 1))) 6 | 7 | (func (export "i16x8.relaxed_q15mulr_s_cmp") (param v128 v128) (result v128) 8 | (i16x8.eq 9 | (i16x8.relaxed_q15mulr_s (local.get 0) (local.get 1)) 10 | (i16x8.relaxed_q15mulr_s (local.get 0) (local.get 1)))) 11 | ) 12 | 13 | ;; INT16_MIN = -32768 14 | (assert_return (invoke "i16x8.relaxed_q15mulr_s" 15 | (v128.const i16x8 -32768 -32767 32767 0 0 0 0 0) 16 | (v128.const i16x8 -32768 -32768 32767 0 0 0 0 0)) 17 | ;; overflows, return either INT16_MIN or INT16_MAX 18 | (either (v128.const i16x8 -32768 32767 32766 0 0 0 0 0) 19 | (v128.const i16x8 32767 32767 32766 0 0 0 0 0))) 20 | 21 | ;; Check that multiple calls to the relaxed instruction with same inputs returns same results. 22 | 23 | (assert_return (invoke "i16x8.relaxed_q15mulr_s_cmp" 24 | (v128.const i16x8 -32768 -32767 32767 0 0 0 0 0) 25 | (v128.const i16x8 -32768 -32768 32767 0 0 0 0 0)) 26 | ;; overflows, return either INT16_MIN or INT16_MAX 27 | (v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1)) 28 | 29 | -------------------------------------------------------------------------------- /tests/testsuite/proposals/relaxed-simd/i8x16_relaxed_swizzle.wast: -------------------------------------------------------------------------------- 1 | ;; Tests for relaxed i8x16 swizzle. 2 | ;; `either` comes from https://github.com/WebAssembly/threads. 3 | 4 | (module 5 | (func (export "i8x16.relaxed_swizzle") (param v128 v128) (result v128) (i8x16.relaxed_swizzle (local.get 0) (local.get 1))) 6 | 7 | (func (export "i8x16.relaxed_swizzle_cmp") (param v128 v128) (result v128) 8 | (i8x16.eq 9 | (i8x16.relaxed_swizzle (local.get 0) (local.get 1)) 10 | (i8x16.relaxed_swizzle (local.get 0) (local.get 1)))) 11 | ) 12 | 13 | (assert_return (invoke "i8x16.relaxed_swizzle" 14 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 15 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)) 16 | (either (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 17 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))) 18 | 19 | ;; out of range, returns 0 or modulo 15 if < 128 20 | (assert_return (invoke "i8x16.relaxed_swizzle" 21 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 22 | (v128.const i8x16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)) 23 | (either (v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 24 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))) 25 | 26 | ;; out of range, returns 0 if >= 128 27 | (assert_return (invoke "i8x16.relaxed_swizzle" 28 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 29 | (v128.const i8x16 128 129 130 131 132 133 134 135 248 249 250 251 252 253 254 255)) 30 | (either (v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 31 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))) 32 | 33 | ;; Check that multiple calls to the relaxed instruction with same inputs returns same results. 34 | 35 | ;; out of range, returns 0 or modulo 15 if < 128 36 | (assert_return (invoke "i8x16.relaxed_swizzle_cmp" 37 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 38 | (v128.const i8x16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)) 39 | (v128.const i8x16 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1)) 40 | 41 | ;; out of range, returns 0 if >= 128 42 | (assert_return (invoke "i8x16.relaxed_swizzle_cmp" 43 | (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 44 | (v128.const i8x16 128 129 130 131 132 133 134 135 248 249 250 251 252 253 254 255)) 45 | (v128.const i8x16 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1)) 46 | -------------------------------------------------------------------------------- /tests/testsuite/ref_func.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "f") (param $x i32) (result i32) (local.get $x)) 3 | ) 4 | (register "M") 5 | 6 | (module 7 | (func $f (import "M" "f") (param i32) (result i32)) 8 | (func $g (param $x i32) (result i32) 9 | (i32.add (local.get $x) (i32.const 1)) 10 | ) 11 | 12 | (global funcref (ref.func $f)) 13 | (global funcref (ref.func $g)) 14 | (global $v (mut funcref) (ref.func $f)) 15 | 16 | (global funcref (ref.func $gf1)) 17 | (global funcref (ref.func $gf2)) 18 | (func (drop (ref.func $ff1)) (drop (ref.func $ff2))) 19 | (elem declare func $gf1 $ff1) 20 | (elem declare funcref (ref.func $gf2) (ref.func $ff2)) 21 | (func $gf1) 22 | (func $gf2) 23 | (func $ff1) 24 | (func $ff2) 25 | 26 | (func (export "is_null-f") (result i32) 27 | (ref.is_null (ref.func $f)) 28 | ) 29 | (func (export "is_null-g") (result i32) 30 | (ref.is_null (ref.func $g)) 31 | ) 32 | (func (export "is_null-v") (result i32) 33 | (ref.is_null (global.get $v)) 34 | ) 35 | 36 | (func (export "set-f") (global.set $v (ref.func $f))) 37 | (func (export "set-g") (global.set $v (ref.func $g))) 38 | 39 | (table $t 1 funcref) 40 | (elem declare func $f $g) 41 | 42 | (func (export "call-f") (param $x i32) (result i32) 43 | (table.set $t (i32.const 0) (ref.func $f)) 44 | (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) 45 | ) 46 | (func (export "call-g") (param $x i32) (result i32) 47 | (table.set $t (i32.const 0) (ref.func $g)) 48 | (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) 49 | ) 50 | (func (export "call-v") (param $x i32) (result i32) 51 | (table.set $t (i32.const 0) (global.get $v)) 52 | (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0)) 53 | ) 54 | ) 55 | 56 | (assert_return (invoke "is_null-f") (i32.const 0)) 57 | (assert_return (invoke "is_null-g") (i32.const 0)) 58 | (assert_return (invoke "is_null-v") (i32.const 0)) 59 | 60 | (assert_return (invoke "call-f" (i32.const 4)) (i32.const 4)) 61 | (assert_return (invoke "call-g" (i32.const 4)) (i32.const 5)) 62 | (assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) 63 | (invoke "set-g") 64 | (assert_return (invoke "call-v" (i32.const 4)) (i32.const 5)) 65 | (invoke "set-f") 66 | (assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) 67 | 68 | (assert_invalid 69 | (module 70 | (func $f (import "M" "f") (param i32) (result i32)) 71 | (func $g (import "M" "g") (param i32) (result i32)) 72 | (global funcref (ref.func 7)) 73 | ) 74 | "unknown function 7" 75 | ) 76 | 77 | 78 | ;; Reference declaration 79 | 80 | (module 81 | (func $f1) 82 | (func $f2) 83 | (func $f3) 84 | (func $f4) 85 | (func $f5) 86 | (func $f6) 87 | 88 | (table $t 1 funcref) 89 | 90 | (global funcref (ref.func $f1)) 91 | (export "f" (func $f2)) 92 | (elem (table $t) (i32.const 0) func $f3) 93 | (elem (table $t) (i32.const 0) funcref (ref.func $f4)) 94 | (elem func $f5) 95 | (elem funcref (ref.func $f6)) 96 | 97 | (func 98 | (ref.func $f1) 99 | (ref.func $f2) 100 | (ref.func $f3) 101 | (ref.func $f4) 102 | (ref.func $f5) 103 | (ref.func $f6) 104 | (return) 105 | ) 106 | ) 107 | 108 | (assert_invalid 109 | (module (func $f (drop (ref.func $f)))) 110 | "undeclared function reference" 111 | ) 112 | (assert_invalid 113 | (module (start $f) (func $f (drop (ref.func $f)))) 114 | "undeclared function reference" 115 | ) 116 | -------------------------------------------------------------------------------- /tests/testsuite/ref_is_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func $f1 (export "funcref") (param $x funcref) (result i32) 3 | (ref.is_null (local.get $x)) 4 | ) 5 | (func $f2 (export "externref") (param $x externref) (result i32) 6 | (ref.is_null (local.get $x)) 7 | ) 8 | 9 | (table $t1 2 funcref) 10 | (table $t2 2 externref) 11 | (elem (table $t1) (i32.const 1) func $dummy) 12 | (func $dummy) 13 | 14 | (func (export "init") (param $r externref) 15 | (table.set $t2 (i32.const 1) (local.get $r)) 16 | ) 17 | (func (export "deinit") 18 | (table.set $t1 (i32.const 1) (ref.null func)) 19 | (table.set $t2 (i32.const 1) (ref.null extern)) 20 | ) 21 | 22 | (func (export "funcref-elem") (param $x i32) (result i32) 23 | (call $f1 (table.get $t1 (local.get $x))) 24 | ) 25 | (func (export "externref-elem") (param $x i32) (result i32) 26 | (call $f2 (table.get $t2 (local.get $x))) 27 | ) 28 | ) 29 | 30 | (assert_return (invoke "funcref" (ref.null func)) (i32.const 1)) 31 | (assert_return (invoke "externref" (ref.null extern)) (i32.const 1)) 32 | 33 | (assert_return (invoke "externref" (ref.extern 1)) (i32.const 0)) 34 | 35 | (invoke "init" (ref.extern 0)) 36 | 37 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 38 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 39 | 40 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) 41 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 0)) 42 | 43 | (invoke "deinit") 44 | 45 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 46 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 47 | 48 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) 49 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) 50 | 51 | (assert_invalid 52 | (module (func $ref-vs-num (param i32) (ref.is_null (local.get 0)))) 53 | "type mismatch" 54 | ) 55 | (assert_invalid 56 | (module (func $ref-vs-empty (ref.is_null))) 57 | "type mismatch" 58 | ) 59 | -------------------------------------------------------------------------------- /tests/testsuite/ref_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "externref") (result externref) (ref.null extern)) 3 | (func (export "funcref") (result funcref) (ref.null func)) 4 | 5 | (global externref (ref.null extern)) 6 | (global funcref (ref.null func)) 7 | ) 8 | 9 | (assert_return (invoke "externref") (ref.null extern)) 10 | (assert_return (invoke "funcref") (ref.null func)) 11 | -------------------------------------------------------------------------------- /tests/testsuite/repos/README.md: -------------------------------------------------------------------------------- 1 | The spec and proposal repositories will be cloned in this directory by the 2 | `update-testsuite.sh` script. Don't apply local changes to these repositories, 3 | as the script may destroy them. 4 | -------------------------------------------------------------------------------- /tests/testsuite/simd_i64x2_arith2.wast: -------------------------------------------------------------------------------- 1 | ;; Tests for i64x2 [abs] operations. 2 | 3 | (module 4 | (func (export "i64x2.abs") (param v128) (result v128) (i64x2.abs (local.get 0))) 5 | (func (export "i64x2.abs_with_const_0") (result v128) (i64x2.abs (v128.const i64x2 -9223372036854775808 9223372036854775807))) 6 | ) 7 | 8 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 1 1)) 9 | (v128.const i64x2 1 1)) 10 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -1 -1)) 11 | (v128.const i64x2 1 1)) 12 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 18446744073709551615 18446744073709551615)) 13 | (v128.const i64x2 1 1)) 14 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 0xffffffffffffffff 0xffffffffffffffff)) 15 | (v128.const i64x2 0x1 0x1)) 16 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 9223372036854775808 9223372036854775808)) 17 | (v128.const i64x2 9223372036854775808 9223372036854775808)) 18 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -9223372036854775808 -9223372036854775808)) 19 | (v128.const i64x2 9223372036854775808 9223372036854775808)) 20 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -0x8000000000000000 -0x8000000000000000)) 21 | (v128.const i64x2 0x8000000000000000 0x8000000000000000)) 22 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 0x8000000000000000 0x8000000000000000)) 23 | (v128.const i64x2 0x8000000000000000 0x8000000000000000)) 24 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 01_2_3 01_2_3)) 25 | (v128.const i64x2 01_2_3 01_2_3)) 26 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -01_2_3 -01_2_3)) 27 | (v128.const i64x2 123 123)) 28 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 0x80 0x80)) 29 | (v128.const i64x2 0x80 0x80)) 30 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -0x80 -0x80)) 31 | (v128.const i64x2 0x80 0x80)) 32 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 0x0_8_0 0x0_8_0)) 33 | (v128.const i64x2 0x0_8_0 0x0_8_0)) 34 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -0x0_8_0 -0x0_8_0)) 35 | (v128.const i64x2 0x80 0x80)) 36 | 37 | ;; Const vs const 38 | (assert_return (invoke "i64x2.abs_with_const_0") (v128.const i64x2 9223372036854775808 9223372036854775807)) 39 | 40 | ;; Param vs const 41 | 42 | ;; Test different lanes go through different if-then clauses 43 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -9223372036854775808 9223372036854775807)) 44 | (v128.const i64x2 9223372036854775808 9223372036854775807)) 45 | 46 | ;; Test opposite signs of zero 47 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -0 -0)) 48 | (v128.const i64x2 -0 -0)) 49 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 +0 0)) 50 | (v128.const i64x2 +0 0)) 51 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 -0 -0)) 52 | (v128.const i64x2 -0 -0)) 53 | (assert_return (invoke "i64x2.abs" (v128.const i64x2 +0 +0)) 54 | (v128.const i64x2 +0 +0)) 55 | 56 | ;; Unknown operators 57 | 58 | ;; Type check 59 | (assert_invalid (module (func (result v128) (i64x2.abs (f32.const 0.0)))) "type mismatch") 60 | 61 | ;; Test operation with empty argument 62 | 63 | (assert_invalid 64 | (module 65 | (func $i64x2.abs-arg-empty (result v128) 66 | (i64x2.abs) 67 | ) 68 | ) 69 | "type mismatch" 70 | ) 71 | 72 | ;; Combination 73 | (module 74 | (func (export "i64x2.abs-i64x2.abs") (param v128) (result v128) (i64x2.abs (i64x2.abs (local.get 0)))) 75 | ) 76 | 77 | (assert_return (invoke "i64x2.abs-i64x2.abs" (v128.const i64x2 -1 -1)) 78 | (v128.const i64x2 1 1)) 79 | -------------------------------------------------------------------------------- /tests/testsuite/simd_linking.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (global (export "g-v128") v128 (v128.const i64x2 0 0)) 3 | (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0)) 4 | ) 5 | (register "Mv128") 6 | 7 | (module 8 | ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732 9 | ;; has made it to the downstream node.js that we use on CI. 10 | ;; (import "Mv128" "g-v128" (global v128)) 11 | (import "Mv128" "mg-v128" (global (mut v128))) 12 | ) 13 | -------------------------------------------------------------------------------- /tests/testsuite/start.wast: -------------------------------------------------------------------------------- 1 | (assert_invalid 2 | (module (func) (start 1)) 3 | "unknown function" 4 | ) 5 | 6 | (assert_invalid 7 | (module 8 | (func $main (result i32) (return (i32.const 0))) 9 | (start $main) 10 | ) 11 | "start function" 12 | ) 13 | (assert_invalid 14 | (module 15 | (func $main (param $a i32)) 16 | (start $main) 17 | ) 18 | "start function" 19 | ) 20 | 21 | (module 22 | (memory (data "A")) 23 | (func $inc 24 | (i32.store8 25 | (i32.const 0) 26 | (i32.add 27 | (i32.load8_u (i32.const 0)) 28 | (i32.const 1) 29 | ) 30 | ) 31 | ) 32 | (func $get (result i32) 33 | (return (i32.load8_u (i32.const 0))) 34 | ) 35 | (func $main 36 | (call $inc) 37 | (call $inc) 38 | (call $inc) 39 | ) 40 | 41 | (start $main) 42 | (export "inc" (func $inc)) 43 | (export "get" (func $get)) 44 | ) 45 | (assert_return (invoke "get") (i32.const 68)) 46 | (invoke "inc") 47 | (assert_return (invoke "get") (i32.const 69)) 48 | (invoke "inc") 49 | (assert_return (invoke "get") (i32.const 70)) 50 | 51 | (module 52 | (memory (data "A")) 53 | (func $inc 54 | (i32.store8 55 | (i32.const 0) 56 | (i32.add 57 | (i32.load8_u (i32.const 0)) 58 | (i32.const 1) 59 | ) 60 | ) 61 | ) 62 | (func $get (result i32) 63 | (return (i32.load8_u (i32.const 0))) 64 | ) 65 | (func $main 66 | (call $inc) 67 | (call $inc) 68 | (call $inc) 69 | ) 70 | (start 2) 71 | (export "inc" (func $inc)) 72 | (export "get" (func $get)) 73 | ) 74 | (assert_return (invoke "get") (i32.const 68)) 75 | (invoke "inc") 76 | (assert_return (invoke "get") (i32.const 69)) 77 | (invoke "inc") 78 | (assert_return (invoke "get") (i32.const 70)) 79 | 80 | (module 81 | (func $print_i32 (import "spectest" "print_i32") (param i32)) 82 | (func $main (call $print_i32 (i32.const 1))) 83 | (start 1) 84 | ) 85 | 86 | (module 87 | (func $print_i32 (import "spectest" "print_i32") (param i32)) 88 | (func $main (call $print_i32 (i32.const 2))) 89 | (start $main) 90 | ) 91 | 92 | (module 93 | (func $print (import "spectest" "print")) 94 | (start $print) 95 | ) 96 | 97 | (assert_trap 98 | (module (func $main (unreachable)) (start $main)) 99 | "unreachable" 100 | ) 101 | 102 | (assert_malformed 103 | (module quote "(module (func $a (unreachable)) (func $b (unreachable)) (start $a) (start $b))") 104 | "multiple start sections" 105 | ) 106 | -------------------------------------------------------------------------------- /tests/testsuite/table-sub.wast: -------------------------------------------------------------------------------- 1 | (assert_invalid 2 | (module 3 | (table $t1 10 funcref) 4 | (table $t2 10 externref) 5 | (func $f 6 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 7 | ) 8 | ) 9 | "type mismatch" 10 | ) 11 | 12 | (assert_invalid 13 | (module 14 | (table $t 10 funcref) 15 | (elem $el externref) 16 | (func $f 17 | (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) 18 | ) 19 | ) 20 | "type mismatch" 21 | ) 22 | -------------------------------------------------------------------------------- /tests/testsuite/table.wast: -------------------------------------------------------------------------------- 1 | ;; Test table section structure 2 | 3 | (module (table 0 funcref)) 4 | (module (table 1 funcref)) 5 | (module (table 0 0 funcref)) 6 | (module (table 0 1 funcref)) 7 | (module (table 1 256 funcref)) 8 | (module (table 0 65536 funcref)) 9 | (module (table 0 0xffff_ffff funcref)) 10 | 11 | (module (table 0 funcref) (table 0 funcref)) 12 | (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) 13 | 14 | (assert_invalid (module (elem (i32.const 0))) "unknown table") 15 | (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") 16 | 17 | 18 | (assert_invalid 19 | (module (table 1 0 funcref)) 20 | "size minimum must not be greater than maximum" 21 | ) 22 | (assert_invalid 23 | (module (table 0xffff_ffff 0 funcref)) 24 | "size minimum must not be greater than maximum" 25 | ) 26 | 27 | (assert_malformed 28 | (module quote "(table 0x1_0000_0000 funcref)") 29 | "i32 constant out of range" 30 | ) 31 | (assert_malformed 32 | (module quote "(table 0x1_0000_0000 0x1_0000_0000 funcref)") 33 | "i32 constant out of range" 34 | ) 35 | (assert_malformed 36 | (module quote "(table 0 0x1_0000_0000 funcref)") 37 | "i32 constant out of range" 38 | ) 39 | 40 | 41 | ;; Duplicate table identifiers 42 | 43 | (assert_malformed (module quote 44 | "(table $foo 1 funcref)" 45 | "(table $foo 1 funcref)") 46 | "duplicate table") 47 | (assert_malformed (module quote 48 | "(import \"\" \"\" (table $foo 1 funcref))" 49 | "(table $foo 1 funcref)") 50 | "duplicate table") 51 | (assert_malformed (module quote 52 | "(import \"\" \"\" (table $foo 1 funcref))" 53 | "(import \"\" \"\" (table $foo 1 funcref))") 54 | "duplicate table") 55 | -------------------------------------------------------------------------------- /tests/testsuite/table_get.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (table $t2 2 externref) 3 | (table $t3 3 funcref) 4 | (elem (table $t3) (i32.const 1) func $dummy) 5 | (func $dummy) 6 | 7 | (func (export "init") (param $r externref) 8 | (table.set $t2 (i32.const 1) (local.get $r)) 9 | (table.set $t3 (i32.const 2) (table.get $t3 (i32.const 1))) 10 | ) 11 | 12 | (func (export "get-externref") (param $i i32) (result externref) 13 | (table.get (local.get $i)) 14 | ) 15 | (func $f3 (export "get-funcref") (param $i i32) (result funcref) 16 | (table.get $t3 (local.get $i)) 17 | ) 18 | 19 | (func (export "is_null-funcref") (param $i i32) (result i32) 20 | (ref.is_null (call $f3 (local.get $i))) 21 | ) 22 | ) 23 | 24 | (invoke "init" (ref.extern 1)) 25 | 26 | (assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) 27 | (assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1)) 28 | 29 | (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) 30 | (assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0)) 31 | (assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0)) 32 | 33 | (assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds table access") 34 | (assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds table access") 35 | (assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds table access") 36 | (assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds table access") 37 | 38 | 39 | ;; Type errors 40 | 41 | (assert_invalid 42 | (module 43 | (table $t 10 externref) 44 | (func $type-index-empty-vs-i32 (result externref) 45 | (table.get $t) 46 | ) 47 | ) 48 | "type mismatch" 49 | ) 50 | (assert_invalid 51 | (module 52 | (table $t 10 externref) 53 | (func $type-index-f32-vs-i32 (result externref) 54 | (table.get $t (f32.const 1)) 55 | ) 56 | ) 57 | "type mismatch" 58 | ) 59 | 60 | (assert_invalid 61 | (module 62 | (table $t 10 externref) 63 | (func $type-result-externref-vs-empty 64 | (table.get $t (i32.const 0)) 65 | ) 66 | ) 67 | "type mismatch" 68 | ) 69 | (assert_invalid 70 | (module 71 | (table $t 10 externref) 72 | (func $type-result-externref-vs-funcref (result funcref) 73 | (table.get $t (i32.const 1)) 74 | ) 75 | ) 76 | "type mismatch" 77 | ) 78 | 79 | (assert_invalid 80 | (module 81 | (table $t1 1 funcref) 82 | (table $t2 1 externref) 83 | (func $type-result-externref-vs-funcref-multi (result funcref) 84 | (table.get $t2 (i32.const 0)) 85 | ) 86 | ) 87 | "type mismatch" 88 | ) 89 | -------------------------------------------------------------------------------- /tests/testsuite/table_size.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (table $t0 0 externref) 3 | (table $t1 1 externref) 4 | (table $t2 0 2 externref) 5 | (table $t3 3 8 externref) 6 | 7 | (func (export "size-t0") (result i32) table.size) 8 | (func (export "size-t1") (result i32) (table.size $t1)) 9 | (func (export "size-t2") (result i32) (table.size $t2)) 10 | (func (export "size-t3") (result i32) (table.size $t3)) 11 | 12 | (func (export "grow-t0") (param $sz i32) 13 | (drop (table.grow $t0 (ref.null extern) (local.get $sz))) 14 | ) 15 | (func (export "grow-t1") (param $sz i32) 16 | (drop (table.grow $t1 (ref.null extern) (local.get $sz))) 17 | ) 18 | (func (export "grow-t2") (param $sz i32) 19 | (drop (table.grow $t2 (ref.null extern) (local.get $sz))) 20 | ) 21 | (func (export "grow-t3") (param $sz i32) 22 | (drop (table.grow $t3 (ref.null extern) (local.get $sz))) 23 | ) 24 | ) 25 | 26 | (assert_return (invoke "size-t0") (i32.const 0)) 27 | (assert_return (invoke "grow-t0" (i32.const 1))) 28 | (assert_return (invoke "size-t0") (i32.const 1)) 29 | (assert_return (invoke "grow-t0" (i32.const 4))) 30 | (assert_return (invoke "size-t0") (i32.const 5)) 31 | (assert_return (invoke "grow-t0" (i32.const 0))) 32 | (assert_return (invoke "size-t0") (i32.const 5)) 33 | 34 | (assert_return (invoke "size-t1") (i32.const 1)) 35 | (assert_return (invoke "grow-t1" (i32.const 1))) 36 | (assert_return (invoke "size-t1") (i32.const 2)) 37 | (assert_return (invoke "grow-t1" (i32.const 4))) 38 | (assert_return (invoke "size-t1") (i32.const 6)) 39 | (assert_return (invoke "grow-t1" (i32.const 0))) 40 | (assert_return (invoke "size-t1") (i32.const 6)) 41 | 42 | (assert_return (invoke "size-t2") (i32.const 0)) 43 | (assert_return (invoke "grow-t2" (i32.const 3))) 44 | (assert_return (invoke "size-t2") (i32.const 0)) 45 | (assert_return (invoke "grow-t2" (i32.const 1))) 46 | (assert_return (invoke "size-t2") (i32.const 1)) 47 | (assert_return (invoke "grow-t2" (i32.const 0))) 48 | (assert_return (invoke "size-t2") (i32.const 1)) 49 | (assert_return (invoke "grow-t2" (i32.const 4))) 50 | (assert_return (invoke "size-t2") (i32.const 1)) 51 | (assert_return (invoke "grow-t2" (i32.const 1))) 52 | (assert_return (invoke "size-t2") (i32.const 2)) 53 | 54 | (assert_return (invoke "size-t3") (i32.const 3)) 55 | (assert_return (invoke "grow-t3" (i32.const 1))) 56 | (assert_return (invoke "size-t3") (i32.const 4)) 57 | (assert_return (invoke "grow-t3" (i32.const 3))) 58 | (assert_return (invoke "size-t3") (i32.const 7)) 59 | (assert_return (invoke "grow-t3" (i32.const 0))) 60 | (assert_return (invoke "size-t3") (i32.const 7)) 61 | (assert_return (invoke "grow-t3" (i32.const 2))) 62 | (assert_return (invoke "size-t3") (i32.const 7)) 63 | (assert_return (invoke "grow-t3" (i32.const 1))) 64 | (assert_return (invoke "size-t3") (i32.const 8)) 65 | 66 | 67 | ;; Type errors 68 | 69 | (assert_invalid 70 | (module 71 | (table $t 1 externref) 72 | (func $type-result-i32-vs-empty 73 | (table.size $t) 74 | ) 75 | ) 76 | "type mismatch" 77 | ) 78 | (assert_invalid 79 | (module 80 | (table $t 1 externref) 81 | (func $type-result-i32-vs-f32 (result f32) 82 | (table.size $t) 83 | ) 84 | ) 85 | "type mismatch" 86 | ) 87 | -------------------------------------------------------------------------------- /tests/testsuite/type.wast: -------------------------------------------------------------------------------- 1 | ;; Test type definitions 2 | 3 | (module 4 | (type (func)) 5 | (type $t (func)) 6 | 7 | (type (func (param i32))) 8 | (type (func (param $x i32))) 9 | (type (func (result i32))) 10 | (type (func (param i32) (result i32))) 11 | (type (func (param $x i32) (result i32))) 12 | 13 | (type (func (param f32 f64))) 14 | (type (func (result i64 f32))) 15 | (type (func (param i32 i64) (result f32 f64))) 16 | 17 | (type (func (param f32) (param f64))) 18 | (type (func (param $x f32) (param f64))) 19 | (type (func (param f32) (param $y f64))) 20 | (type (func (param $x f32) (param $y f64))) 21 | (type (func (result i64) (result f32))) 22 | (type (func (param i32) (param i64) (result f32) (result f64))) 23 | (type (func (param $x i32) (param $y i64) (result f32) (result f64))) 24 | 25 | (type (func (param f32 f64) (param $x i32) (param f64 i32 i32))) 26 | (type (func (result i64 i64 f32) (result f32 i32))) 27 | (type 28 | (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32)) 29 | ) 30 | 31 | (type (func (param) (param $x f32) (param) (param) (param f64 i32) (param))) 32 | (type 33 | (func (result) (result) (result i64 i64) (result) (result f32) (result)) 34 | ) 35 | (type 36 | (func 37 | (param i32 i32) (param i64 i32) (param) (param $x i32) (param) 38 | (result) (result f32 f64) (result f64 i32) (result) 39 | ) 40 | ) 41 | ) 42 | 43 | (assert_malformed 44 | (module quote "(type (func (result i32) (param i32)))") 45 | "unexpected token" 46 | ) 47 | (assert_malformed 48 | (module quote "(type (func (result $x i32)))") 49 | "unexpected token" 50 | ) 51 | -------------------------------------------------------------------------------- /tests/testsuite/unreached-valid.wast: -------------------------------------------------------------------------------- 1 | (module 2 | 3 | ;; Check that both sides of the select are evaluated 4 | (func (export "select-trap-left") (param $cond i32) (result i32) 5 | (select (unreachable) (i32.const 0) (local.get $cond)) 6 | ) 7 | (func (export "select-trap-right") (param $cond i32) (result i32) 8 | (select (i32.const 0) (unreachable) (local.get $cond)) 9 | ) 10 | 11 | (func (export "select-unreached") 12 | (unreachable) (select) 13 | (unreachable) (i32.const 0) (select) 14 | (unreachable) (i32.const 0) (i32.const 0) (select) 15 | (unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select) 16 | (unreachable) (f32.const 0) (i32.const 0) (select) 17 | (unreachable) 18 | ) 19 | 20 | (func (export "select_unreached_result_1") (result i32) 21 | (unreachable) (i32.add (select)) 22 | ) 23 | 24 | (func (export "select_unreached_result_2") (result i64) 25 | (unreachable) (i64.add (select (i64.const 0) (i32.const 0))) 26 | ) 27 | 28 | (func (export "unreachable-num") 29 | (unreachable) 30 | (select) 31 | (i32.eqz) 32 | (drop) 33 | ) 34 | (func (export "unreachable-ref") 35 | (unreachable) 36 | (select) 37 | (ref.is_null) 38 | (drop) 39 | ) 40 | ) 41 | 42 | (assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") 43 | (assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") 44 | (assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") 45 | (assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable") 46 | 47 | ;; Validation after unreachable 48 | 49 | (module 50 | (func (export "meet-bottom") 51 | (block (result f64) 52 | (block (result f32) 53 | (unreachable) 54 | (br_table 0 1 1 (i32.const 1)) 55 | ) 56 | (drop) 57 | (f64.const 0) 58 | ) 59 | (drop) 60 | ) 61 | ) 62 | 63 | (assert_trap (invoke "meet-bottom") "unreachable") 64 | --------------------------------------------------------------------------------