diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml
index 261ac5e..e8e1b07 100644
--- a/.github/workflows/scala.yml
+++ b/.github/workflows/scala.yml
@@ -31,8 +31,8 @@ jobs:
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y perl minisat curl gnupg2 locales clang-11 wget
- name: Install wasmfx-tools
run: |
- #cd third-party/wasmfx-tools
- #cargo build --release
+ cd third-party/wasmfx-tools
+ cargo build --release
- name: Run tests
run: |
sbt 'test'
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..74800c2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "third-party/wasmfx-tools"]
+ path = third-party/wasmfx-tools
+ url = https://github.com/wasmfx/wasmfx-tools.git
diff --git a/benchmarks/wasm/.gitignore b/benchmarks/wasm/.gitignore
new file mode 100644
index 0000000..01bed35
--- /dev/null
+++ b/benchmarks/wasm/.gitignore
@@ -0,0 +1,3 @@
+*.wasm
+!2o1u.wat
+!2o1u-no-label.wat
diff --git a/benchmarks/wasm/ack.rs b/benchmarks/wasm/ack.rs
new file mode 100644
index 0000000..f6e385f
--- /dev/null
+++ b/benchmarks/wasm/ack.rs
@@ -0,0 +1,16 @@
+#[no_mangle]
+#[inline(never)]
+fn ack(m: i32, n: i32) -> i32 {
+ if m == 0 {
+ n + 1
+ } else if n == 0 {
+ ack(m - 1, 1)
+ } else {
+ ack(m - 1, ack(m, n - 1))
+ }
+}
+
+#[no_mangle]
+fn real_main() -> i32 {
+ ack(2, 2)
+}
diff --git a/benchmarks/wasm/ack.wat b/benchmarks/wasm/ack.wat
new file mode 100644
index 0000000..e28608e
--- /dev/null
+++ b/benchmarks/wasm/ack.wat
@@ -0,0 +1,57 @@
+(module $ack.wat.temp
+ (type (;0;) (func (param i32 i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (func $ack (type 0) (param i32 i32) (result i32)
+ local.get 0
+ local.set 0
+ local.get 1
+ local.set 1
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 1
+ local.set 1
+ local.get 0
+ local.tee 0
+ i32.eqz
+ br_if 1 (;@1;)
+ block ;; label = @3
+ block ;; label = @4
+ local.get 1
+ br_if 0 (;@4;)
+ i32.const 1
+ local.set 1
+ br 1 (;@3;)
+ end
+ local.get 0
+ local.get 1
+ i32.const -1
+ i32.add
+ call $ack
+ local.set 1
+ end
+ local.get 0
+ i32.const -1
+ i32.add
+ local.set 0
+ local.get 1
+ local.set 1
+ br 0 (;@2;)
+ end
+ end
+ local.get 1
+ i32.const 1
+ i32.add)
+ (func $real_main (type 1) (result i32)
+ i32.const 2
+ i32.const 2
+ call $ack)
+ (table (;0;) 1 1 funcref)
+ (memory (;0;) 16)
+ (global $__stack_pointer (mut i32) (i32.const 1048576))
+ (global (;1;) i32 (i32.const 1048576))
+ (global (;2;) i32 (i32.const 1048576))
+ (export "memory" (memory 0))
+ (export "ack" (func 0))
+ (export "real_main" (func 1))
+ (export "__data_end" (global 1))
+ (export "__heap_base" (global 2)))
diff --git a/benchmarks/wasm/block.wat b/benchmarks/wasm/block.wat
new file mode 100644
index 0000000..d445695
--- /dev/null
+++ b/benchmarks/wasm/block.wat
@@ -0,0 +1,70 @@
+(module
+ (func $test_block (param i32 i32 i32) (result i32)
+ local.get 0
+ local.get 1
+ local.get 2
+ block (param i32 i32 i32) (result i32 i32)
+ i32.add
+ end
+ i32.add
+ )
+ (func $real_main (result i32)
+ i32.const 1
+ i32.const 3
+ i32.const 5
+ call $test_block
+ )
+ ;; Sum from [0, 10]
+ (func $test_loop_input (result i32)
+ (local i32)
+ i32.const 10
+ local.set 0
+ i32.const 0
+ loop (param i32) (result i32)
+ local.get 0
+ i32.add
+ local.get 0
+ i32.const 1
+ i32.sub
+ local.set 0
+ i32.const 0
+ local.get 0
+ i32.ne
+ br_if 0
+ end
+ )
+ (func $test_if_input (result i32)
+ i32.const 10
+ i32.const 5
+ i32.const 1
+ if (param i32 i32) (result i32 i32)
+ i32.const 10
+ i32.add
+ else
+ end
+ i32.add
+ )
+ (func $test_poly_br (result i32)
+ i32.const -30
+ i32.const 0 ;; unused
+ i32.const 0 ;; unused
+ i32.const 0 ;; unused
+ block (param i32 i32 i32) (result i32 i32)
+ i32.const 0 ;; truncated
+ i32.const 10000 ;; truncated
+ i32.const 10
+ i32.const 20
+ br 0
+ i32.add
+ end
+ i32.add
+ i32.add ;; add value -30 and 30
+ ;; i32.add
+ ;; We can't use i32.add instruction here, because the overflowed value has been truncted
+ ;; when block exited.
+ )
+ (export "real_main" (func 1))
+ (export "test_loop_input" (func 2))
+ (export "test_if_input" (func 3))
+ (export "test_poly_br" (func 4))
+)
diff --git a/benchmarks/wasm/bst.c b/benchmarks/wasm/bst.c
new file mode 100644
index 0000000..e69de29
diff --git a/benchmarks/wasm/btree/2o1u-unlabeled.wat b/benchmarks/wasm/btree/2o1u-unlabeled.wat
new file mode 100644
index 0000000..096f100
--- /dev/null
+++ b/benchmarks/wasm/btree/2o1u-unlabeled.wat
@@ -0,0 +1,2635 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func (param i32 i32) (result i32)))
+ (type (;2;) (func (param i32 i32)))
+ (type (;3;) (func (param i32 i32 i32)))
+ (type (;4;) (func))
+ (func (;0;) (type 0) (param i32) (result i32)
+ i32.const 0
+ local.get 0
+ i32.store
+ i32.const 0
+ i32.const 1
+ i32.store offset=4
+ i32.const 0
+ i32.const 65536
+ i32.store offset=8
+ i32.const 1
+ memory.grow
+ i32.const -1
+ i32.ne
+ if ;; label = @1
+ i32.const 65536
+ i32.const 1
+ i32.store
+ i32.const 65536
+ i32.const 0
+ i32.store offset=4
+ end
+ i32.const 65536)
+ (func (;1;) (type 1) (param i32 i32) (result i32)
+ (local i32)
+ i32.const 0
+ local.set 2
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 2
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.le_s
+ if ;; label = @3
+ local.get 1
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.gt_s
+ if ;; label = @4
+ i32.const 1
+ local.get 2
+ i32.add
+ local.set 2
+ br 2 (;@2;)
+ else
+ br 3 (;@1;)
+ end
+ else
+ br 2 (;@1;)
+ end
+ end
+ end
+ local.get 2
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.le_s
+ if (result i32) ;; label = @1
+ local.get 1
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.eq
+ if (result i32) ;; label = @2
+ local.get 0
+ i32.const 8
+ i32.add
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ else
+ local.get 0
+ i32.load
+ i32.const 1
+ i32.eq
+ if (result i32) ;; label = @3
+ i32.const -1
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.get 1
+ call 1
+ end
+ end
+ else
+ local.get 0
+ i32.load
+ i32.const 1
+ i32.eq
+ if (result i32) ;; label = @2
+ i32.const -1
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.get 1
+ call 1
+ end
+ end)
+ (func (;2;) (type 2) (param i32 i32)
+ (local i32 i32)
+ i32.const 1
+ memory.grow
+ i32.const -1
+ i32.ne
+ if ;; label = @1
+ i32.const 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.const 65536
+ i32.mul
+ local.set 2
+ i32.const 0
+ i32.const 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load
+ i32.const 1
+ i32.eq
+ if ;; label = @2
+ local.get 2
+ i32.const 1
+ i32.store
+ else
+ local.get 2
+ i32.const 0
+ i32.store
+ end
+ local.get 2
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ i32.const 0
+ local.set 3
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @4
+ br 2 (;@2;)
+ else
+ local.get 2
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.add
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@3;)
+ end
+ end
+ end
+ i32.const 0
+ local.set 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @2
+ block ;; label = @3
+ loop ;; label = @4
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.eq
+ if ;; label = @5
+ br 2 (;@3;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 2
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@4;)
+ end
+ end
+ end
+ end
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ local.get 0
+ i32.load offset=4
+ local.set 3
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 1
+ local.get 3
+ i32.eq
+ if ;; label = @4
+ br 2 (;@2;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.sub
+ local.set 3
+ br 1 (;@3;)
+ end
+ end
+ end
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ local.get 2
+ i32.store offset=8
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ local.set 3
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 1
+ i32.const 1
+ i32.sub
+ local.get 3
+ i32.eq
+ if ;; label = @4
+ br 2 (;@2;)
+ else
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ local.get 0
+ i32.add
+ local.get 3
+ i32.const 4
+ i32.mul
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.sub
+ local.set 3
+ br 1 (;@3;)
+ end
+ end
+ end
+ local.get 1
+ i32.const 4
+ i32.mul
+ local.get 0
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 1
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 0
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ end)
+ (func (;3;) (type 2) (param i32 i32)
+ (local i32 i32)
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ local.set 2
+ local.get 0
+ i32.load
+ i32.const 1
+ i32.eq
+ if ;; label = @1
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 2
+ i32.const 0
+ i32.ge_s
+ if (result i32) ;; label = @4
+ local.get 1
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.lt_s
+ else
+ i32.const 0
+ end
+ local.get 2
+ i32.const 0
+ i32.ge_s
+ i32.and
+ if ;; label = @4
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 2
+ i32.const 1
+ i32.sub
+ local.set 2
+ br 1 (;@3;)
+ else
+ br 2 (;@2;)
+ end
+ end
+ end
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ local.get 1
+ i32.store offset=8
+ local.get 0
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ else
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 2
+ i32.const 0
+ i32.ge_s
+ if ;; label = @4
+ local.get 1
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.lt_s
+ if ;; label = @5
+ local.get 2
+ i32.const 1
+ i32.sub
+ local.set 2
+ br 2 (;@3;)
+ else
+ br 3 (;@2;)
+ end
+ else
+ br 2 (;@2;)
+ end
+ end
+ end
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 2
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @2
+ local.get 0
+ local.get 2
+ call 2
+ local.get 1
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.gt_s
+ if ;; label = @3
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 2
+ end
+ end
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.get 1
+ call 3
+ end)
+ (func (;4;) (type 0) (param i32) (result i32)
+ (local i32 i32)
+ i32.const 0
+ i32.load offset=8
+ local.tee 2
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.eq
+ if (result i32) ;; label = @1
+ i32.const 1
+ memory.grow
+ i32.const -1
+ i32.ne
+ if (result i32) ;; label = @2
+ i32.const 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.const 65536
+ i32.mul
+ local.set 1
+ i32.const 0
+ i32.const 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ i32.const 0
+ local.get 1
+ i32.store offset=8
+ local.get 1
+ i32.const 0
+ i32.store
+ local.get 1
+ i32.const 0
+ i32.store offset=4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 1
+ i32.add
+ local.get 2
+ i32.store offset=8
+ local.get 1
+ i32.const 0
+ call 2
+ local.get 1
+ local.get 0
+ call 3
+ local.get 1
+ else
+ i32.const -1
+ end
+ else
+ local.get 2
+ local.get 0
+ call 3
+ local.get 2
+ end)
+ (func (;5;) (type 1) (param i32 i32) (result i32)
+ (local i32 i32 i32 i32)
+ local.get 0
+ i32.load
+ i32.const 1
+ i32.eq
+ if ;; label = @1
+ i32.const 0
+ local.set 2
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 0
+ i32.load offset=4
+ local.get 2
+ i32.eq
+ if ;; label = @4
+ br 2 (;@2;)
+ else
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ local.get 1
+ i32.eq
+ if ;; label = @5
+ local.get 2
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 0
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ br 3 (;@2;)
+ end
+ end
+ i32.const 1
+ local.get 2
+ i32.add
+ local.set 2
+ br 0 (;@3;)
+ end
+ end
+ else
+ i32.const 0
+ local.set 2
+ block ;; label = @2
+ loop ;; label = @3
+ local.get 2
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.le_s
+ if (result i32) ;; label = @4
+ local.get 1
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.gt_s
+ else
+ i32.const 0
+ end
+ local.get 2
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.le_s
+ i32.and
+ if ;; label = @4
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 2
+ br 1 (;@3;)
+ else
+ br 2 (;@2;)
+ end
+ end
+ end
+ local.get 2
+ local.get 0
+ i32.load offset=4
+ i32.lt_s
+ if (result i32) ;; label = @2
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ local.get 1
+ i32.eq
+ else
+ i32.const 0
+ end
+ if ;; label = @2
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.tee 5
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.ge_s
+ if ;; label = @3
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ local.get 5
+ i32.const 4
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ i32.load offset=8
+ local.get 5
+ local.get 5
+ i32.const 4
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ i32.load offset=8
+ call 5
+ drop
+ i32.store offset=8
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.tee 5
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.ge_s
+ if ;; label = @4
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ local.get 5
+ i32.const 4
+ i32.const 0
+ i32.mul
+ i32.add
+ i32.load offset=8
+ local.get 5
+ local.get 5
+ i32.const 4
+ i32.const 0
+ i32.mul
+ i32.add
+ i32.load offset=8
+ call 5
+ drop
+ i32.store offset=8
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.set 5
+ local.get 5
+ i32.const 4
+ local.get 5
+ i32.load offset=4
+ i32.mul
+ i32.add
+ local.get 1
+ i32.store offset=8
+ i32.const 0
+ local.set 3
+ block ;; label = @5
+ loop ;; label = @6
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.eq
+ if ;; label = @7
+ br 2 (;@5;)
+ else
+ local.get 5
+ i32.const 4
+ local.get 5
+ i32.load offset=4
+ local.get 3
+ i32.add
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@6;)
+ end
+ end
+ end
+ local.get 5
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.add
+ i32.store offset=4
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @5
+ i32.const 0
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 5
+ i32.load offset=4
+ local.get 3
+ i32.add
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ end
+ local.get 2
+ local.set 3
+ block ;; label = @5
+ loop ;; label = @6
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ local.get 3
+ i32.eq
+ if ;; label = @7
+ br 2 (;@5;)
+ else
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@6;)
+ end
+ end
+ end
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 3
+ block ;; label = @5
+ loop ;; label = @6
+ local.get 0
+ i32.load offset=4
+ local.get 3
+ i32.eq
+ if ;; label = @7
+ br 2 (;@5;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@6;)
+ end
+ end
+ end
+ local.get 0
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ local.get 5
+ local.get 1
+ call 5
+ drop
+ end
+ end
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.set 5
+ local.get 5
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @3
+ i32.const -1
+ local.set 4
+ local.get 2
+ i32.const 1
+ i32.add
+ local.get 0
+ i32.load offset=4
+ i32.le_s
+ if ;; label = @4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.ge_s
+ if ;; label = @5
+ local.get 5
+ i32.const 4
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 5
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ i32.const 0
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @6
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ end
+ local.get 5
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.store offset=4
+ i32.const 0
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @6
+ i32.const 0
+ local.set 3
+ block ;; label = @7
+ loop ;; label = @8
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.eq
+ if ;; label = @9
+ br 2 (;@7;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@8;)
+ end
+ end
+ end
+ end
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ i32.const 0
+ local.set 4
+ end
+ end
+ local.get 4
+ i32.const -1
+ i32.eq
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 0
+ i32.ge_s
+ i32.and
+ if ;; label = @4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 2
+ i32.div_s
+ i32.ge_s
+ if ;; label = @5
+ local.get 5
+ i32.load offset=4
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ i32.const 0
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ local.get 5
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ local.get 5
+ i32.const 4
+ local.get 3
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.sub
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @6
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ local.set 3
+ block ;; label = @7
+ loop ;; label = @8
+ local.get 3
+ i32.const 0
+ i32.eq
+ if ;; label = @9
+ br 2 (;@7;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.sub
+ local.set 3
+ br 1 (;@8;)
+ end
+ end
+ end
+ end
+ local.get 5
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ local.get 5
+ i32.const 4
+ i32.const 0
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @6
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ end
+ i32.const 0
+ local.set 4
+ end
+ end
+ local.get 4
+ i32.const -1
+ i32.eq
+ if ;; label = @4
+ local.get 2
+ i32.const 1
+ i32.add
+ local.get 0
+ i32.load offset=4
+ i32.le_s
+ if ;; label = @5
+ local.get 5
+ i32.const 4
+ local.get 5
+ i32.load offset=4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ i32.const 0
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ local.get 5
+ i32.const 4
+ local.get 5
+ i32.load offset=4
+ local.get 3
+ i32.add
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @6
+ i32.const 0
+ local.set 3
+ block ;; label = @7
+ loop ;; label = @8
+ local.get 3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.eq
+ if ;; label = @9
+ br 2 (;@7;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 5
+ i32.load offset=4
+ local.get 3
+ i32.add
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@8;)
+ end
+ end
+ end
+ end
+ local.get 5
+ local.get 5
+ i32.load offset=4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.add
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ local.get 0
+ i32.load offset=4
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 2
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 0
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ i32.const 0
+ local.set 4
+ end
+ local.get 4
+ i32.const -1
+ i32.eq
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 0
+ i32.ge_s
+ i32.and
+ if ;; label = @5
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ i32.const 0
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ local.get 5
+ i32.load offset=4
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 4
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ local.get 3
+ i32.add
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ local.get 5
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 5
+ i32.load
+ i32.const 1
+ i32.ne
+ if ;; label = @6
+ i32.const 0
+ local.set 3
+ block ;; label = @7
+ loop ;; label = @8
+ local.get 3
+ local.get 5
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ i32.eq
+ if ;; label = @9
+ br 2 (;@7;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ local.get 3
+ i32.add
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 5
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@8;)
+ end
+ end
+ end
+ end
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.load offset=4
+ local.get 5
+ i32.load offset=4
+ i32.add
+ i32.const 1
+ i32.add
+ i32.store offset=4
+ local.get 2
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ local.get 0
+ i32.load offset=4
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 2
+ i32.const 1
+ i32.sub
+ local.set 3
+ block ;; label = @6
+ loop ;; label = @7
+ local.get 3
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.eq
+ if ;; label = @8
+ br 2 (;@6;)
+ else
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.mul
+ i32.add
+ local.get 0
+ i32.const 4
+ local.get 3
+ i32.const 1
+ i32.add
+ i32.mul
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ local.get 3
+ i32.const 1
+ i32.add
+ local.set 3
+ br 1 (;@7;)
+ end
+ end
+ end
+ local.get 0
+ local.get 0
+ i32.load offset=4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ end
+ end
+ end
+ local.get 4
+ i32.const -1
+ i32.eq
+ if ;; label = @3
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ local.get 2
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.add
+ local.get 0
+ i32.add
+ i32.load offset=8
+ local.get 1
+ call 5
+ drop
+ else
+ local.get 5
+ local.get 1
+ call 5
+ drop
+ end
+ end
+ end
+ i32.const 0
+ i32.load offset=8
+ i32.load offset=4
+ i32.const 0
+ i32.eq
+ if ;; label = @1
+ i32.const 0
+ i32.const 0
+ i32.load
+ i32.const 1
+ i32.sub
+ i32.const 4
+ i32.mul
+ i32.const 0
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.const 0
+ i32.load offset=8
+ i32.add
+ i32.load offset=8
+ i32.store offset=8
+ end
+ i32.const 0
+ i32.load offset=8)
+ (func (;6;) (type 3) (param i32 i32 i32)
+ (local i32)
+ local.get 0
+ local.get 1
+ i32.gt_s
+ local.get 0
+ local.get 2
+ i32.ne
+ local.get 1
+ local.get 2
+ i32.ne
+ i32.and
+ i32.and
+ i32.eqz
+ if ;; label = @1
+ unreachable
+ end
+ i32.const 4
+ call 0
+ local.set 3
+ local.get 0
+ call 4
+ local.set 3
+ local.get 1
+ call 4
+ local.set 3
+ local.get 2
+ call 4
+ local.set 3
+ local.get 3
+ local.get 0
+ call 1
+ i32.const -1
+ i32.ne
+ local.get 3
+ local.get 1
+ call 1
+ i32.const -1
+ i32.ne
+ local.get 3
+ local.get 2
+ call 1
+ i32.const -1
+ i32.ne
+ i32.and
+ i32.and
+ local.get 3
+ local.get 0
+ call 5
+ local.tee 3
+ local.get 0
+ call 1
+ i32.const -1
+ i32.eq
+ local.get 3
+ local.get 1
+ call 5
+ local.tee 3
+ local.get 1
+ call 1
+ i32.const -1
+ i32.eq
+ i32.and
+ i32.and
+ drop)
+ (func (;7;) (type 4)
+ i32.const 3
+ i32.const 2
+ i32.const 1
+ call 6)
+ (memory (;0;) 2)
+ (export "main" (func 7))
+ (start 7))
diff --git a/benchmarks/wasm/btree/2o1u.wat b/benchmarks/wasm/btree/2o1u.wat
new file mode 100644
index 0000000..880e175
--- /dev/null
+++ b/benchmarks/wasm/btree/2o1u.wat
@@ -0,0 +1,2821 @@
+(module
+ ;; (import "env" "log" (func $log (param i32)))
+ (memory $0 2)
+ (func $createBtree (param i32) (result i32) ;; createBtree(t), where t: degree of the btree
+ (i32.const 0)
+ (local.get 0)
+ (i32.store) ;; store t at address 0
+ (i32.const 0)
+ (i32.const 1)
+ (i32.store offset=4) ;; store the number of nodes in the btree = 1
+ (i32.const 0)
+ (i32.const 65536)
+ (i32.store offset=8) ;; store the root addr
+ (i32.const 1) ;; Now create root
+ (memory.grow) ;; create new page
+ (i32.const -1)
+ (i32.ne)
+ (if ;; if we can grow memory
+ (then
+ (i32.const 65536) ;; 64KiB = 65536 bytes
+ (i32.const 1)
+ (i32.store) ;; store 1(TRUE) regarding if node is leaf
+ (i32.const 65536) ;; now store number of keys
+ (i32.const 0)
+ (i32.store offset=4) ;; store number of keys = 0
+ )
+ )
+ (i32.const 65536) ;; returns the address of the root
+ )
+ ;; btreeSearch(x, k), where x: node address; k: key to search. Returns address of the key or -1 if key is not in tree.
+ (func $btreeSearch (param i32) (param i32) (result i32) (local i32)
+ (i32.const 0)
+ (local.set 2) ;; i = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 2) ;; i
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.children
+ (i32.const 1)
+ (i32.sub) ;; x.n -1
+ (i32.le_s) ;; i <= x.children-1
+ (if
+ (then
+ (local.get 1) ;; k
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.gt_s) ;; k > x.keys[i]
+ (if
+ (then
+ (i32.const 1)
+ (local.get 2)
+ (i32.add)
+ (local.set 2) ;; i = i+1
+ (br $loop)
+ )
+ (else
+ (br $loop_break)
+ )
+ )
+ )
+ (else
+ (br $loop_break)
+ )
+ )
+ )
+ )
+ (local.get 2) ;; i
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.children
+ (i32.const 1)
+ (i32.sub) ;; x.n - 1
+ (i32.le_s) ;; i <= x.children - 1
+ (if (result i32)
+ (then
+ (local.get 1) ;; k
+ (local.get 0) ;; x
+ ;; x+4*i
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.eq)
+ ;; k == x.keys[i]
+ (if (result i32)
+ (then
+ (local.get 0) ;; save the address, which is x+8+i*4
+ (i32.const 8)
+ (i32.add) ;; x+8
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x+8+i*4
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.load) ;; x is leaf?
+ (i32.const 1) ;; if == 1, then yes
+ (i32.eq)
+ (if (result i32)
+ (then
+ (i32.const -1)
+ )
+ (else
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + i*4
+ (i32.load offset=8) ;; load the address of the child in index i
+ (local.get 1) ;; k
+ (call $btreeSearch) ;; btreeSearch(x.children[i], k)
+ )
+ )
+ )
+ )
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.load) ;; x is leaf?
+ (i32.const 1) ;; if == 1, then yes
+ (i32.eq)
+ (if (result i32)
+ (then
+ (i32.const -1)
+ )
+ (else
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + i*4
+ (i32.load offset=8) ;; load the address of the child in index i
+ (local.get 1) ;; k
+ (call $btreeSearch) ;; btreeSearch(x.children[i], k)
+ )
+ )
+ )
+ )
+ )
+ ;; btreeSplitChild(x, i), where x: addr of a non full internal node; i: index such that x.children[i] is a full child of x
+ (func $btreeSplitChild (param i32) (param i32) (local i32) (local i32)
+ (i32.const 1) ;; create a new node
+ (memory.grow) ;; create new page
+ (i32.const -1)
+ (i32.ne)
+ (if ;; if we can grow memory
+ (then ;; get the number of nodes in the tree
+ (i32.const 0)
+ (i32.load offset=4) ;; number of nodes in the tree
+ (i32.const 1)
+ (i32.add) ;; number of nodes + 1
+ (i32.const 65536)
+ (i32.mul) ;; address is 64KiB*(number of nodes+1)
+ (local.set 2)
+ (i32.const 0) ;; change number of nodes
+ (i32.const 0)
+ (i32.load offset=4)
+ (i32.const 1)
+ (i32.add)
+ (i32.store offset=4) ;; set number of nodes to + 1
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + i*4
+ (i32.load offset=8) ;; load the addr of the child in index i : y
+ (i32.load) ;; check if x.children[i] is leaf ;; load the first i32 in the child
+ (i32.const 1)
+ (i32.eq) ;; is y leaf?
+ (if
+ (then ;; yes
+ (local.get 2) ;; addr of new node z
+ (i32.const 1)
+ (i32.store) ;; store 1(TRUE) regarding if node is leaf
+ )
+ (else ;; no
+ (local.get 2) ;; addr of new node z
+ (i32.const 0)
+ (i32.store) ;; store 0(FALSE) regarding if node is leaf
+ )
+ )
+ (local.get 2) ;; now store number of children, which will be t/2 -1 ;; addr of z
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.const 1)
+ (i32.sub) ;; (t/2)-1
+ (i32.store offset=4) ;; store number of children = (t/2)-1
+ (i32.const 0) ;; now to store the keys
+ (local.set 3) ;; counter = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; counter
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.const 1)
+ (i32.sub) ;; (t/2)-1
+ (i32.eq) ;; counter == (t/2)-1
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 2) ;; addr of z ;; we will store in the new node's address. z.keys[counter]
+ (i32.const 4)
+ (local.get 3) ;; counter
+ (i32.mul) ;; counter * 4
+ (i32.add) ;; addr + counter * 4 -> where the key is goint to be located
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + i*4
+ (i32.load offset=8) ;; load the address of the child in index i = y
+ (i32.const 4) ;; now get x.children[i].keys[counter+(t/2)]
+ (local.get 3) ;; counter
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.add) ;; counter + (t/2)
+ (i32.mul) ;; counter + (t/2) *4
+ (i32.add) ;; y + counter + (t/2) *4
+ (i32.load offset=8) ;; y.keys[counter + (t/2)]
+ (i32.store offset=8) ;; z.keys[counter] = y.keys[counter + (t/2)]
+ (local.get 3) ;; increment counter
+ (i32.const 1)
+ (i32.add)
+ (local.set 3)
+ (br $loop)
+ )
+ )
+ )
+ )
+ (i32.const 0)
+ (local.set 3) ;; set counter back to 0
+ (i32.const 0) ;; check if x.children[i] is leaf
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + i*4
+ (i32.load offset=8) ;; load the address of the child in index i = y
+ (i32.load) ;; get first i32 in child --> isLeaf
+ (i32.const 1)
+ (i32.ne) ;; is leaf?
+ (if
+ (then ;; not leaf so we have to update the children
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; counter
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.eq) ;; counter == (t/2)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;; now get z.children[counter]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; counter
+ (i32.const 4)
+ (i32.mul) ;; counter*4
+ (i32.add) ;; (t-1)*4 + counter*4
+ (local.get 2) ;; z
+ (i32.add) ;; z + (t-1)*4 + counter*4 --> address where addr of child is stored
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; load the address of the child in index i = y
+ (i32.const 0) ;; get x.children[i].children[counter+(t/2)]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; counter
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.add) ;; counter + t/2
+ (i32.const 4)
+ (i32.mul) ;; counter+t/2 * 4
+ (i32.add) ;; (t-1)*4 + (counter+(t/2))*4
+ (i32.add) ;; x.children[i] + (t-1)*4 + (counter + (t/2))*4
+ (i32.load offset=8) ;; load the address of the child in index counter + t/2
+ (i32.store offset=8) ;; z.children[counter] = x.children[i].children[counter]
+ (local.get 3) ;; increment counter
+ (i32.const 1)
+ (i32.add)
+ (local.set 3)
+ (br $loop)
+ )
+ )
+ )
+ )
+ )
+ )
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; load the address of the child in index i = y
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.const 1)
+ (i32.sub) ;; t/2 -1
+ (i32.store offset=4) ;; number of keys of x.children[i] is now t/2 -1
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; get x.n
+ (local.set 3) ;; counter = x.n
+ (block $loop_break
+ (loop $loop
+ (local.get 1) ;; i
+ (local.get 3) ;; counter
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;; get x.children[counter + 1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; counter
+ (i32.const 1)
+ (i32.add) ;; counter + 1
+ (i32.const 4)
+ (i32.mul) ;; (counter + 1)*4
+ (i32.add) ;; (t-1)*4 + (counter + 1)*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + (counter + 1)*4 -->address where addr of child is stored
+ (i32.const 0) ;; get x.children[counter]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; counter
+ (i32.const 4)
+ (i32.mul) ;; (counter)*4
+ (i32.add) ;; (t-1)*4 + (counter)*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + (counter)*4
+ (i32.load offset=8) ;; load the addr of the child in index (counter)
+ (i32.store offset=8) ;; x.children[counter+1] = x.children[counter]
+ (local.get 3) ;; decrement counter
+ (i32.const 1)
+ (i32.sub)
+ (local.set 3)
+ (br $loop)
+ )
+ )
+ )
+ )
+ (i32.const 0) ;; get x.children[i + 1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 1)
+ (i32.add) ;; i + 1
+ (i32.const 4)
+ (i32.mul) ;; (i + 1)*4
+ (i32.add) ;; (t-1)*4 + (i + 1)*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + (i + 1)*4 --> addr where we will store the new addr of the child
+ (local.get 2) ;; addr of z
+ (i32.store offset=8) ;; x.children[i+1] = z
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; get x.n
+ (i32.const 1)
+ (i32.sub)
+ (local.set 3) ;; counter = x.n -1
+ (block $loop_break
+ (loop $loop
+ (local.get 1) ;; i
+ (i32.const 1)
+ (i32.sub) ;; i-1
+ (local.get 3) ;; counter
+ (i32.eq) ;; counter == i-1
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 3) ;; get x.keys[counter + 1] ;; counter
+ (i32.const 1)
+ (i32.add) ;; counter + 1
+ (i32.const 4)
+ (i32.mul) ;; (counter + 1)*4
+ (local.get 0) ;; x
+ (i32.add) ;; x +(counter + 1)*4 --> addr where we will store the new key
+ (local.get 3) ;; counter
+ (i32.const 4)
+ (i32.mul) ;; (counter)*4
+ (local.get 0) ;; x
+ (i32.add) ;; x +(counter)*4
+ (i32.load offset=8) ;; load the key in index (counter)
+ (i32.store offset=8) ;; x.keys[counter+1] = x.keys[counter]
+ (local.get 3) ;; decrement counter
+ (i32.const 1)
+ (i32.sub)
+ (local.set 3)
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 1) ;; get x.keys[i]
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x +i*4 --> addr of the key
+ (i32.const 0) ;; get x.children[i].keys[t/2]
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.const 1)
+ (i32.sub) ;; t/2 -1
+ (i32.const 4)
+ (i32.mul) ;; (t/2)-1 *4
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 1) ;; i
+ (i32.const 4)
+ (i32.mul) ;; (i)*4
+ (i32.add) ;; (t-1)*4 + (i)*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 + (i)*4
+ (i32.load offset=8) ;; load the address of the child in index (i)
+ (i32.add) ;; y + (t/2)-1 *4
+ (i32.load offset=8) ;; load the key in index (t/2)-1 from node x.children[i]
+ (i32.store offset=8) ;; store the new key in the addr
+ (local.get 0)
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.add) ;; x.n + 1
+ (i32.store offset=4) ;; x.n = x.n + 1
+ )
+ )
+ )
+ ;; btreeInsertNonFull(x, k), where x: addr of a non full internal node; k: the key to insert
+ (func $btreeInsertNonFull (param i32) (param i32) (local i32) (local $tmp i32)
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub) ;; x.n -1
+ (local.set 2) ;; i = x.n -1
+ (local.get 0) ;; x
+ (i32.load) ;; get first i32 --> isLeaf
+ (i32.const 1)
+ (i32.eq) ;; is leaf?
+ (if
+ (then ;; x is leaf
+ (block $loop_break
+ (loop $loop
+ (local.get 2) ;; i
+ (i32.const 0)
+ (i32.ge_s) ;; i <= 0?
+ (if (result i32)
+ (then
+ (local.get 1) ;; k
+ (local.get 0) ;; x
+ ;; x+4*i
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.lt_s) ;; k < x.keys[i]
+ )
+ (else
+ (i32.const 0)
+ )
+ )
+ (local.get 2) ;; i
+ (i32.const 0)
+ (i32.ge_s) ;; i <= 0?
+ (i32.and)
+ (if
+ (then
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; x + i+1 *4 --> addr of x.keys[i+1]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i *4
+ (i32.add) ;; x + i *4 --> addr of x.keys[i]
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.store offset=8) ;; x.keys[i+1] = x.keys[i]
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (local.set 2) ;; i = i-1
+ (br $loop)
+ )
+ (else
+ (br $loop_break)
+ )
+ )
+ )
+ )
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; x + i+1 *4 --> addr of x.keys[i+1]
+ (local.get 1) ;; k
+ (i32.store offset=8) ;; x.keys[i+1] = k
+ (local.get 0)
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.add)
+ (i32.store offset=4) ;; x.n = x.n +1
+ )
+ (else ;; x is not leaf
+ (block $loop_break
+ (loop $loop
+ (local.get 2) ;; i
+ (i32.const 0)
+ (i32.ge_s) ;; i >= 0
+ (if
+ (then
+ (local.get 1) ;; k
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.lt_s) ;; k < x.keys[i]
+ (if
+ (then
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub) ;; i -1
+ (local.set 2) ;; i = i-1
+ (br $loop)
+ )
+ (else
+ (br $loop_break)
+ )
+ )
+ )
+ (else
+ (br $loop_break)
+ )
+ )
+ )
+ )
+ (local.get 2)
+ (i32.const 1)
+ (i32.add)
+ (local.set 2) ;;i = i+1
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> address of the child in index i = y
+ (i32.load offset=8) ;; load the address of the child in index i = y
+ (i32.load offset=4) ;; get y.n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.eq) ;; y.n == t-1 --> node is full
+ (if
+ (then
+ (local.get 0) ;; x
+ (local.get 2) ;; i
+ (call $btreeSplitChild)
+ (local.get 1) ;; k
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.gt_s) ;; k>x.keys[i]
+ (if
+ (then
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (local.set 2) ;; i = i+1
+ )
+ )
+ )
+ )
+ (i32.const 0) ;; get x.children[i]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; load the address of the child in index i = y
+ (local.get 1) ;; k
+ (call $btreeInsertNonFull)
+ )
+ )
+ )
+ (func $btreeInsert (param i32) (result i32) (local i32) (local i32)
+ (i32.const 0)
+ (i32.load offset=8) ;; root addr
+ (local.tee 2) ;; set r
+ (i32.load offset=4) ;; r.n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.eq) ;; r.n == t-1 --> root is full
+ (if (result i32)
+ (then
+ (i32.const 1) ;; create a new node
+ (memory.grow) ;; create new page
+ (i32.const -1)
+ (i32.ne)
+ (if (result i32) ;; if we can grow memory
+ (then
+ (i32.const 0) ;; get the number of nodes in the tree
+ (i32.load offset=4) ;; number of nodes in the tree
+ (i32.const 1)
+ (i32.add) ;; number of nodes + 1
+ (i32.const 65536)
+ (i32.mul) ;; address of s is 64KiB*(number of nodes+1)
+ (local.set 1)
+ (i32.const 0) ;; change number of nodes
+ (i32.const 0)
+ (i32.load offset=4)
+ (i32.const 1)
+ (i32.add)
+ (i32.store offset=4) ;; set number of nodes to + 1
+ (i32.const 0)
+ (local.get 1) ;; s
+ (i32.store offset=8) ;; root addr is now s
+ (local.get 1) ;; s
+ (i32.const 0)
+ (i32.store) ;; store 0(FALSE) regarding if node is leaf
+ (local.get 1) ;; now store number of keys
+ (i32.const 0)
+ (i32.store offset=4) ;; store number of keys = 0
+ (i32.const 0) ;; store children addresses
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0) ;; index = 0
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 1) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addre where addr of child number 0 is located
+ (local.get 2)
+ (i32.store offset=8) ;; s.children[0] = r
+ (local.get 1) ;; s
+ (i32.const 0)
+ (call $btreeSplitChild)
+ (local.get 1) ;; s
+ (local.get 0) ;; k
+ (call $btreeInsertNonFull)
+ (local.get 1) ;; return the address of the new root
+ )
+ (else
+ (i32.const -1) ;; return -1 because we could not create a new node
+ )
+ )
+ )
+ (else
+ (local.get 2) ;; r
+ (local.get 0) ;; k
+ (call $btreeInsertNonFull)
+ (local.get 2) ;; return the address of the root, which is the same
+ )
+ )
+ )
+ ;; Returns the address of the new root (if applicable, otherwise returns the addres of the root)
+ (func $btreeDelete (param i32) (param i32) (result i32) (local i32) (local i32) (local i32) (local i32)
+ (local.get 0) ;; x
+ (i32.load) ;; get first i32 --> isLeaf
+ (i32.const 1)
+ (i32.eq) ;; is leaf?
+ (if
+ (then ;; x is leaf
+ (i32.const 0)
+ (local.set 2) ;; i = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (local.get 2) ;; i
+ (i32.eq) ;; i == x.n
+ (if
+ (then
+ (br $loop_break) ;; break from loop
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (local.get 1) ;; k
+ (i32.eq) ;; k == x.keys[i]
+ (if
+ (then
+ (local.get 2) ;; i
+ (local.set 3) ;; j = i
+ (block $while_break
+ (loop $while
+ (local.get 3) ;; j
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub) ;; x.n-1
+ (i32.eq) ;; j == x.n-1
+ (if
+ (then
+ (br $while_break)
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3) ;; j
+ (i32.mul) ;; j*4
+ (i32.add) ;; x + j*4 --> addr where x.keys[j] is stored
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3) ;; j
+ (i32.const 1)
+ (i32.add) ;; j+1
+ (i32.mul) ;; j+1 *4
+ (i32.add) ;; x + j+1 *4 --> addr where x.keys[j+1] is stored
+ (i32.load offset=8) ;; x.keys[j+1]
+ (i32.store offset=8) ;; x.keys[j] = x.keys[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $while)
+ )
+ )
+ )
+ )
+ (local.get 0) ;; x
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub)
+ (i32.store offset=4) ;; x.n = x.n -1
+ (br $loop_break)
+ )
+ )
+ )
+ )
+ (i32.const 1)
+ (local.get 2)
+ (i32.add)
+ (local.set 2) ;; i = i+1
+ (br $loop) ;; continue
+ )
+ )
+ )
+ (else ;; x is not leaf
+ (i32.const 0) ;;get the index of the appropriate child/key
+ (local.set 2) ;; i = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 2) ;; i
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub)
+ (i32.le_s) ;; i <= x.n - 1
+ (if (result i32)
+ (then
+ (local.get 1) ;; k
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.gt_s) ;; k > x.keys[i]
+ )
+ (else
+ (i32.const 0)
+ )
+ )
+ (local.get 2) ;; i
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub)
+ (i32.le_s) ;; i <= x.n - 1
+ (i32.and) ;; i <= x.n - 1 && k > x.keys[i]
+ (if
+ (then
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (local.set 2) ;; i = i + 1
+ (br $loop)
+ )
+ (else
+ (br $loop_break)
+ )
+ )
+ )
+ )
+ (local.get 2)
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.lt_s) ;; i < x.n
+ (if (result i32)
+ (then
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[i]
+ (local.get 1) ;; k
+ (i32.eq) ;; k == x.keys[i]
+ )
+ (else
+ (i32.const 0)
+ )
+ )
+ (if
+ (then ;; key is present in node x
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> address where addr of child in index i is located
+ (i32.load offset=8) ;; x.c[i]
+ (local.tee 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.ge_s) ;; x.c[i].n >= t/2
+ (if
+ (then
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i]
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.sub) ;; index = x.c[i].n - 1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i].keys[x.c[i].n - 1]
+ (local.get 5) ;; x.c[i]
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.sub) ;; index = x.c[i].n - 1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i].keys[x.c[i].n - 1]
+ (call $btreeDelete) ;; (x.c[i], x.c[i].keys[x.c[i].n - 1])
+ (drop)
+ (i32.store offset=8) ;; x.keys[i] = x.c[i].keys[x.c[i].n - 1]
+ )
+ (else
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> address where addr of child in index i is located
+ (i32.load offset=8) ;; x.c[i+1]
+ (local.tee 5)
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.ge_s) ;; x.c[i+1].n >= t/2
+ (if
+ (then
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i]
+ (local.get 5) ;; x.c[i+1]
+ (i32.const 4)
+ (i32.const 0) ;; index = 0
+ (i32.mul) ;; i *4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i+1].keys[0]
+ (local.get 5) ;; x.c[i+1]
+ (local.get 5) ;; x.c[i+1]
+ (i32.const 4)
+ (i32.const 0) ;; index = 0
+ (i32.mul) ;; i *4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i+1].keys[0]
+ (call $btreeDelete)
+ (drop)
+ (i32.store offset=8) ;; x.keys[i] = x.c[i+1].keys[0]
+ )
+ (else
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> address where addr of child in index i is located
+ (i32.load offset=8) ;; x.c[i]
+ (local.set 5)
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 5)
+ (i32.load offset=4) ;; index = x.c[i].n
+ (i32.mul) ;; i *4
+ (i32.add) ;; x + i*4 --> addr where x.c[i].keys[x.c[i].n] will be stored
+ (local.get 1) ;; k
+ (i32.store offset=8) ;; x.c[i].keys[x.c[i].n] = k
+ (i32.const 0) ;; now merge x.c[i] with x.c[i+1]
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.eq)
+ (if ;; j == x.c[i+1].n
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 5)
+ (i32.load offset=4)
+ (local.get 3)
+ (i32.add)
+ (i32.const 1)
+ (i32.add) ;; index = x.c[i].n + j + 1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[index]
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.const 4)
+ (local.get 3) ;; index = j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x.c[i+1] + i*4 ;; addr of x.c[i+1].keys[j]
+ (i32.load offset=8) ;; x.c[i+1].keys[j]
+ (i32.store offset=8) ;; x.c[i].keys[index] = x.c[i+1].keys[j]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 5)
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.add) ;; x.c[i].n +1
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.add)
+ (i32.store offset=4) ;; x.c[i].n = x.c[i].n + 1 + x.c[i+1].n
+ (local.get 5)
+ (i32.load)
+ (i32.const 1)
+ (i32.ne)
+ (if
+ (then
+ (i32.const 0) ;; now adjust the children
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.const 1)
+ (i32.add)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[i].c[x.c[i].n+j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (local.get 3) ;; j
+ (i32.add) ;; index = x.c[i].n+j
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 5) ;; x.c[i]
+ (i32.add) ;; x.c[i] + (t-1)*4 --> address where x.c[i].c[x.c[i].n+j] is stored
+ (i32.const 0) ;;get x.c[i+1].c[j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; j
+ (i32.const 4)
+ (i32.mul) ;; j *4
+ (i32.add) ;; (t-1)*4 + j *4
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.add) ;; x.c[i+1] + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1].c[j]
+ (i32.store offset=8) ;; x.c[i].c[x.c[i].n+j] = x.c[i+1].c[j]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $loop)
+ )
+ )
+ )
+ )
+ )
+ )
+ (local.get 2) ;; i
+ (local.set 3) ;; j = i
+ (block $loop_break
+ (loop $loop
+ (local.get 0)
+ (i32.load offset=4)
+ (i32.const 1)
+ (i32.sub)
+ (local.get 3)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3) ;; j
+ (i32.mul) ;; j*4
+ (i32.add) ;; x + j*4 ;; addr of x.keys[j]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3) ;; j
+ (i32.const 1)
+ (i32.add)
+ (i32.mul) ;; j+1*4
+ (i32.add) ;; x + j+1*4 ;; addr of x.keys[j+1]
+ (i32.load offset=8)
+ (i32.store offset=8) ;; x.keys[j] = x.keys[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 2)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = i+1
+ (block $loop_break
+ (loop $loop
+ (local.get 0)
+ (i32.load offset=4)
+ (local.get 3)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; j
+ (i32.const 4)
+ (i32.mul) ;; j *4
+ (i32.add) ;; (t-1)*4 + j+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[j]
+ (i32.const 0) ;;get x.c[j+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; j
+ (i32.const 1)
+ (i32.add) ;; j+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[j+1]
+ (i32.load offset=8)
+ (i32.store offset=8) ;; x.c[j] = x.c[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 0)
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub)
+ (i32.store offset=4) ;; x.n = x.n-1
+ (local.get 5) ;; x.c[i]
+ (local.get 1) ;; k
+ (call $btreeDelete)
+ (drop)
+ )
+ )
+ )
+ )
+ )
+ (else ;; key not present in node x
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 4)
+ (i32.mul) ;; i*4
+ (i32.add) ;; (t-1)*4 + i*4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> address where addr of child in index i is located
+ (i32.load offset=8) ;; x.c[i]
+ (local.set 5)
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s)
+ (i32.const 1)
+ (i32.sub) ;; t/2 - 1
+ (i32.eq)
+ (if
+ (then
+ (i32.const -1)
+ (local.set 4) ;; changed = -1
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.le_s) ;; i+1 <= x.n
+ (if
+ (then
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8)
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.ge_s) ;; x.c[i+1].n >= t/2
+ (if
+ (then
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.const 1)
+ (i32.sub) ;; index = t/2 -1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[t/2-1]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i]
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.store offset=8) ;; x.c[i].keys[t/2-1] = x.keys[i]
+ (local.get 5)
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.add)
+ (i32.store offset=4) ;;x.c[i].n = x.c[i].n +1
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i]
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.const 4)
+ (i32.const 0) ;; index = 0
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i+1].keys[0]
+ (i32.load offset=8) ;; x.c[i+1].keys[0]
+ (i32.store offset=8) ;; x.keys[i] = x.c[i+1].keys[0]
+ (local.get 5)
+ (i32.load) ;; x.c[i] is leaf?
+ (i32.const 1)
+ (i32.ne)
+ (if ;; if x.c[i] is not leaf, we have to adjust children
+ (then
+ (i32.const 0) ;;get x.c[i].c[t/2]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; index = t/2
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 5) ;; x.c[i]
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[i].c[t/2]
+ (i32.const 0) ;;get x.c[i+1].c[0]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0) ;; index = 0
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1].c[0]
+ (i32.store offset=8) ;; x.c[i].c[t/2] = x.c[i+1].c[0]
+ )
+ )
+ (local.get 5) ;; x.c[i]
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.store offset=4) ;; x.c[i].n = t/2
+ (i32.const 0)
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.const 1)
+ (i32.sub)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.const 4)
+ (local.get 3) ;; index = j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 --> address where x.c[i+1].keys[j] is located
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.const 4)
+ (local.get 3)
+ (i32.const 1)
+ (i32.add) ;; index = j+1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i+1].keys[j+1]
+ (i32.store offset=8) ;; x.c[i+1].keys[j] = x.c[i+1].keys[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 5)
+ (i32.load)
+ (i32.const 1)
+ (i32.ne)
+ (if ;; if x.c[i] is not leaf, we have to adjust children
+ (then
+ (i32.const 0)
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; index = j
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.add) ;; x + (t-1)*4 --> address where x.c[i+1].c[j] is located
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3)
+ (i32.const 1)
+ (i32.add) ;; index = j+1
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1].c[j+1]
+ (i32.store offset=8) ;; x.c[i+1].c[j] = x.c[i+1].c[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j+1
+ (br $loop)
+ )
+ )
+ )
+ )
+ )
+ )
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr where x.c[i+1] is located
+ (i32.load offset=8)
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.const 1)
+ (i32.sub)
+ (i32.store offset=4) ;; x.c[i+1].n = x.c[i+1].n - 1
+ (i32.const 0)
+ (local.set 4) ;; changed = 0
+ )
+ )
+ )
+ )
+ (local.get 4) ;; changed
+ (i32.const -1)
+ (i32.eq)
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub) ;; i - 1
+ (i32.const 0)
+ (i32.ge_s) ;; i -1 >= 0
+ (i32.and) ;; changed == -1 && i -1 >= 0
+ (if
+ (then
+ (i32.const 0) ;;get x.c[i-1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8)
+ (i32.load offset=4) ;; x.c[i-1].n
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 2)
+ (i32.div_s) ;; t/2
+ (i32.ge_s) ;; x.c[i-1].n >= t/2
+ (if
+ (then
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (local.set 3) ;; j = x.c[i].n
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 3) ;; j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[j]
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 3) ;; j
+ (i32.const 1)
+ (i32.sub) ;; j-1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[j-1]
+ (i32.load offset=8) ;; x.c[i].keys[j-1]
+ (i32.store offset=8) ;; x.c[i].keys[j] = x.c[i].keys[j-1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.sub)
+ (local.set 3) ;; j = j-1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 5)
+ (i32.load)
+ (i32.const 1)
+ (i32.ne)
+ (if
+ (then
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = x.c[i].n + 1
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[i].c[j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; j
+ (i32.const 4)
+ (i32.mul) ;; j *4
+ (i32.add) ;; (t-1)*4 + j *4
+ (local.get 5) ;; x.c[i]
+ (i32.add) ;; x + (t-1)*4 --> address where x.c[i].c[j] is located
+ (i32.const 0) ;;get x.c[i].c[j-1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; j
+ (i32.const 1)
+ (i32.sub) ;; j-1
+ (i32.const 4)
+ (i32.mul) ;; j *4
+ (i32.add) ;; (t-1)*4 + j *4
+ (local.get 5) ;; x.c[i]
+ (i32.add)
+ (i32.load offset=8) ;; x.c[i].c[j-1]
+ (i32.store offset=8) ;; x.c[i].c[j] = x.c[i].c[j-1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.sub)
+ (local.set 3) ;; j = j-1
+ (br $loop)
+ )
+ )
+ )
+ )
+ )
+ )
+ (local.get 5)
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.add)
+ (i32.store offset=4) ;; ;; x.c[i].n = x.c[i].n + 1
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (i32.const 0) ;; index = 0
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[0]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub) ;; index = i-1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i-1]
+ (i32.load offset=8) ;; x.keys[i-1]
+ (i32.store offset=8) ;; x.c[i].keys[0] = x.keys[i-1]
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8)
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8)
+ (i32.load offset=4) ;; x.c[i-1].n
+ (i32.const 1)
+ (i32.sub)
+ (i32.store offset=4) ;; x.c[i-1].n = x.c[i-1].n - 1
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub) ;; index = i-1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i-1]
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.const 4)
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.load offset=4) ;; index = x.c[i-1].n
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i-1].keys[x.c[i-1].n]
+ (i32.load offset=8)
+ (i32.store offset=8) ;; x.keys[i-1] = x.c[i-1].keys[x.c[i-1].n]
+ (local.get 5)
+ (i32.load)
+ (i32.const 1)
+ (i32.ne)
+ (if
+ (then
+ (i32.const 0) ;; get x.c[i].c[0]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0) ;; index = 0
+ (i32.const 4)
+ (i32.mul) ;; i *4
+ (i32.add) ;; (t-1)*4 + i *4
+ (local.get 5) ;; x.c[i]
+ (i32.add) ;; x + (t-1)*4 ;; addr where x.c[i].c[0] is located
+ (i32.const 0) ;; get x.c[i-1].c[x.c[i-1].n + 1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.load offset=4) ;; x.c[i-1].n
+ (i32.const 1)
+ (i32.add) ;; index = x.c[i-1.n + 1]
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (i32.const 0) ;;get x.c[i-1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1].c[x.c[i-1].n + 1]
+ (i32.store offset=8) ;; x.c[i].c[0] = x.c[i-1].c[x.c[i-1].n + 1]
+ )
+ )
+ (i32.const 0)
+ (local.set 4) ;; changed = 0
+ )
+ )
+ )
+ )
+ (local.get 4) ;; changed
+ (i32.const -1)
+ (i32.eq)
+ (if ;; changed == -1?
+ (then
+ (local.get 2) ;; we have to merge x.c[i] with one sibling;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.le_s)
+ (if ;; i+1 <= x.n
+ (then
+ (local.get 5) ;; merge with right sibling;; x.c[i]
+ (i32.const 4)
+ (local.get 5)
+ (i32.load offset=4) ;; index = x.c[i].n
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[x.c[i].n]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; index = i
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i]
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.store offset=8) ;; x.c[i].keys[x.c[i].n] = x.keys[i]
+ (i32.const 0)
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 5)
+ (i32.load offset=4)
+ (local.get 3)
+ (i32.add)
+ (i32.const 1)
+ (i32.add) ;; index = x.c[i].n+j+1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i].keys[x.c[i].n+j]
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.const 4)
+ (local.get 3) ;; index = j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i+1].keys[j]
+ (i32.store offset=8) ;; x.c[i].keys[x.c[i].n+j] = x.c[i+1].keys[j]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 5)
+ (i32.load)
+ (i32.const 1)
+ (i32.ne)
+ (if
+ (then
+ (i32.const 0)
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.const 1)
+ (i32.add) ;; x.c[i+1].n + 1
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[i].c[x.c[i].n+j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 5)
+ (i32.load offset=4)
+ (local.get 3)
+ (i32.add)
+ (i32.const 1)
+ (i32.add) ;; index = x.c[i].n+j+1
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 5) ;; x.c[i]
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[i].c[x.c[i].n+j]
+ (i32.const 0) ;;get x.c[i].c[x.c[i].n+j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; index = j
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1].c[j]
+ (i32.store offset=8) ;; x.c[i].c[x.c[i].n+j] = x.c[i+1].c[j]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ )
+ )
+ (local.get 5) ;; x.c[i]
+ (local.get 5) ;; x.c[i]
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 0) ;;get x.c[i+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i+1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i+1]
+ (i32.load offset=4) ;; x.c[i+1].n
+ (i32.add) ;; x.c[i].n + x.c[i+1].n
+ (i32.const 1)
+ (i32.add) ;; x.c[i].n + x.c[i+1].n + 1
+ (i32.store offset=4) ;; x.c[i].n = x.c[i].n + x.c[i+1].n + 1
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.add) ;; i+1
+ (local.set 3) ;; j = i+1
+ (block $loop_break ;; re-organize x
+ (loop $loop
+ (local.get 3)
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; index = j
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[j]
+ (i32.const 0) ;;get x.c[j+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3)
+ (i32.const 1)
+ (i32.add) ;; index = j + 1
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[j+1]
+ (i32.load offset=8) ;; x.c[j+1]
+ (i32.store offset=8) ;; x.c[j] = x.c[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 2) ;; i
+ (local.set 3) ;; j = i
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3) ;; index = j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[j]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3)
+ (i32.const 1)
+ (i32.add) ;; index = j + 1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[j+1]
+ (i32.store offset=8) ;; x.keys[j] = x.keys[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 0) ;; x
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub) ;; x.n - 1
+ (i32.store offset=4) ;; x.n = x.n - 1
+ (i32.const 0)
+ (local.set 4) ;; changed = 0
+ )
+ )
+ (local.get 4) ;; changed
+ (i32.const -1)
+ (i32.eq) ;; changed == -1 ?
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub) ;; i - 1
+ (i32.const 0)
+ (i32.ge_s) ;; i - 1 >= 0?
+ (i32.and) ;; changed == -1 && i - 1 >= 0
+ (if
+ (then
+ (i32.const 0) ;; merge with left sibling ;;get x.c[i-1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.const 4)
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.load offset=4) ;; index = x.c[i-1].n
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i-1].keys[x.c[i-1].n]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 2) ;; index = i
+ (i32.const 1)
+ (i32.sub) ;; index = i-1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[i-1]
+ (i32.load offset=8) ;; x.keys[i]
+ (i32.store offset=8) ;; x.c[i-1].keys[x.c[i-1].n] = x.keys[i-1]
+ (i32.const 0)
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (local.get 5) ;; x.c[i]
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;; x.c[i-1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.const 4)
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.load offset=4) ;; x.c[i-1].n
+ (local.get 3)
+ (i32.add)
+ (i32.const 1)
+ (i32.add) ;; index = x.c[i-1].n+j+1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.c[i-1].keys[x.c[i-1].n+j]
+ (local.get 5) ;; x.c[i]
+ (i32.const 4)
+ (local.get 3) ;; index = j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.c[i].keys[j]
+ (i32.store offset=8) ;; x.c[i-1].keys[x.c[i-1].n+j] = x.c[i].keys[j]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 5)
+ (i32.load)
+ (i32.const 1)
+ (i32.ne)
+ (if
+ (then
+ (i32.const 0)
+ (local.set 3) ;; j = 0
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (local.get 5) ;; x.c[i]
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.const 1)
+ (i32.add) ;; x.c[i].n + 1
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[i-1].c[x.c[i-1].n+j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.load offset=4)
+ (local.get 3)
+ (i32.add)
+ (i32.const 1)
+ (i32.add) ;; index = x.c[i-1].n+j+1
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[i-1].c[x.c[i-1].n+j]
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; index = j
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 5) ;; x.c[i]
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i].c[j]
+ (i32.store offset=8) ;; x.c[i-1].c[x.c[i-1].n+j] = x.c[i].c[j]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ )
+ )
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (i32.load offset=4) ;; x.c[i-1].n
+ (local.get 5)
+ (i32.load offset=4) ;; x.c[i].n
+ (i32.add) ;; x.c[i-1].n + x.c[i].n
+ (i32.const 1)
+ (i32.add) ;; x.c[i].n + x.c[i+1].n + 1
+ (i32.store offset=4) ;; x.c[i-1].n = x.c[i-1].n + x.c[i].n + 1
+ (local.get 2) ;; i
+ (local.set 3) ;; j = i
+ (block $loop_break ;; re-organize x
+ (loop $loop
+ (local.get 3)
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (i32.const 0) ;;get x.c[j]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3) ;; index = j
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[j]
+ (i32.const 0) ;;get x.c[j+1]
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 3)
+ (i32.const 1)
+ (i32.add) ;; index = j + 1
+ (i32.const 4)
+ (i32.mul) ;; i-1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4 --> addr of x.c[j]
+ (i32.load offset=8) ;; x.c[j+1]
+ (i32.store offset=8) ;; x.c[j] = x.c[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (local.set 3) ;; j = i - 1
+ (block $loop_break
+ (loop $loop
+ (local.get 3) ;; j
+ (local.get 0)
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub)
+ (i32.eq)
+ (if
+ (then
+ (br $loop_break)
+ )
+ (else
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3) ;; index = j
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4 ;; addr of x.keys[j]
+ (local.get 0) ;; x
+ (i32.const 4)
+ (local.get 3)
+ (i32.const 1)
+ (i32.add) ;; index = j + 1
+ (i32.mul) ;; i*4
+ (i32.add) ;; x + i*4
+ (i32.load offset=8) ;; x.keys[j+1]
+ (i32.store offset=8) ;; x.keys[j] = x.keys[j+1]
+ (local.get 3)
+ (i32.const 1)
+ (i32.add)
+ (local.set 3) ;; j = j + 1
+ (br $loop)
+ )
+ )
+ )
+ )
+ (local.get 0) ;; x
+ (local.get 0) ;; x
+ (i32.load offset=4) ;; x.n
+ (i32.const 1)
+ (i32.sub) ;; x.n - 1
+ (i32.store offset=4) ;; x.n = x.n - 1
+ )
+ )
+ )
+ )
+ )
+ )
+ (local.get 4)
+ (i32.const -1)
+ (i32.eq)
+ (if ;; changed == -1? if yes, we merged with left sibling
+ (then
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (local.get 2) ;; i
+ (i32.const 1)
+ (i32.sub)
+ (i32.const 4)
+ (i32.mul) ;; i+1 *4
+ (i32.add) ;; (t-1)*4 + i-1 *4
+ (local.get 0) ;; x
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; x.c[i-1]
+ (local.get 1)
+ (call $btreeDelete)
+ (drop)
+ )
+ (else
+ (local.get 5) ;; x.c[i]
+ (local.get 1)
+ (call $btreeDelete)
+ (drop)
+ )
+ )
+ )
+ )
+ ) ;; end of if x is not leaf
+ )
+ (i32.const 0)
+ (i32.load offset=8) ;; root addr
+ (i32.load offset=4)
+ (i32.const 0)
+ (i32.eq)
+ (if ;; if root is empty
+ (then
+ (i32.const 0)
+ (i32.const 0)
+ (i32.load) ;; t
+ (i32.const 1)
+ (i32.sub) ;; t-1
+ (i32.const 4)
+ (i32.mul) ;; (t-1)*4
+ (i32.const 0) ;; index = 0
+ (i32.const 4)
+ (i32.mul) ;; i *4
+ (i32.add) ;; (t-1)*4 + i *4
+ (i32.const 0)
+ (i32.load offset=8) ;; root addr
+ (i32.add) ;; x + (t-1)*4
+ (i32.load offset=8) ;; root.c[0]
+ (i32.store offset=8) ;; root = root.c[0]
+ )
+ )
+ (i32.const 0)
+ (i32.load offset=8) ;; root addr
+ )
+ (func $main (param $a i32) (param $b i32) (param $h i32)
+ (local $btree i32)
+ (local.get $a)
+ (local.get $b)
+ (i32.gt_s) ;; a > b
+ (local.get $a)
+ (local.get $h)
+ (i32.ne) ;; a != h
+ (local.get $b)
+ (local.get $h)
+ (i32.ne) ;; b != h
+ (i32.and)
+ (i32.and)
+ (i32.eqz)
+ (if (then (unreachable)))
+ (i32.const 4) ;;create a tree with degree 4
+ (call $createBtree)
+ (local.set $btree)
+ ;; insert variables
+ (local.get $a)
+ (call $btreeInsert)
+ (local.set $btree)
+ (local.get $b)
+ (call $btreeInsert)
+ (local.set $btree)
+ (local.get $h)
+ (call $btreeInsert)
+ (local.set $btree)
+ ;; search for variables & check that they were inserted
+ (local.get $btree)
+ (local.get $a)
+ (call $btreeSearch)
+ (i32.const -1)
+ (i32.ne)
+ (local.get $btree)
+ (local.get $b)
+ (call $btreeSearch)
+ (i32.const -1)
+ (i32.ne)
+ (local.get $btree)
+ (local.get $h)
+ (call $btreeSearch)
+ (i32.const -1)
+ (i32.ne)
+ (i32.and)
+ (i32.and)
+ ;; delete & check that it was deleted
+ ;; a
+ (local.get $btree)
+ (local.get $a)
+ (call $btreeDelete)
+ (local.tee $btree)
+ (local.get $a)
+ (call $btreeSearch)
+ (i32.const -1)
+ (i32.eq)
+ ;; b
+ (local.get $btree)
+ (local.get $b)
+ (call $btreeDelete)
+ (local.tee $btree)
+ (local.get $b)
+ (call $btreeSearch)
+ (i32.const -1)
+ (i32.eq)
+ (i32.and)
+ (i32.and)
+ (drop)
+ )
+ (export "main" (func $real_main))
+ (func $real_main
+ i32.const 3
+ i32.const 2
+ i32.const 1
+ call $main
+ )
+ (start $real_main)
+)
diff --git a/benchmarks/wasm/btree/start.js b/benchmarks/wasm/btree/start.js
new file mode 100644
index 0000000..8104d9d
--- /dev/null
+++ b/benchmarks/wasm/btree/start.js
@@ -0,0 +1,19 @@
+const fs = require("fs");
+
+async function main() {
+ const bytes = fs.readFileSync("2o1u.wasm");
+ const env = { log: val => console.log(`logged ${val}`), };
+ const { instance } = await WebAssembly.instantiate(
+ bytes,
+ {
+ env: {
+ log(val) {
+ console.log(`log saw ${val}`);
+ }
+ }
+ }
+ );
+ instance.exports.real_main();
+ console.log(`finished`);
+}
+main();
\ No newline at end of file
diff --git a/benchmarks/wasm/build_wat_c.sh b/benchmarks/wasm/build_wat_c.sh
new file mode 100755
index 0000000..e56d784
--- /dev/null
+++ b/benchmarks/wasm/build_wat_c.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# TODO: use clang? zig compiles stdlib to wasm
+# also figure out how to compile to freestanding?
+
+# zig cc -target wasm32-wasi -O3 -o "$2.temp" $1
+# zig cc -target wasm32-freestanding -O3 -o "$2.temp" $1
+
+sudo docker run --rm \
+ --volume "$(pwd):/home/wasp/tmp" \
+ -w "/home/wasp/tmp" \
+ ghcr.io/wasp-platform/wasp:latest \
+ clang --target=wasm32 -O0 --no-standard-libraries -Wl,--export-all -Wl,--no-entry -o "$2.temp" $1
+
+# clang-15 --target=wasm32 --no-standard-libraries -Wl,--export-all -Wl,--no-entry -o $2.temp $1
+
+wasm2wat "$2.temp" > "$2"
+rm "$2.temp"
+./Collections-C/scripts/patch_wat.py "$2"
+# wasp "$2" -e '(invoke "__original_main")' -o "$2.wasp.wat"
+# ./Collections-C/scripts/patch_wat.py "$2.wasp.wat"
+# mv "$2.wasp.wat" "$2"
diff --git a/benchmarks/wasm/build_wat_rs.sh b/benchmarks/wasm/build_wat_rs.sh
new file mode 100755
index 0000000..c3b4466
--- /dev/null
+++ b/benchmarks/wasm/build_wat_rs.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# c has a lot of extra stuff for WASI I think
+# also ran into a case where the wasm2wat output was incorrect
+# clang -O1 -target wasm32 -nostdlib -Wl,--no-entry -Wl,--export-all -Wl,--allow-undefined -o "$2.temp" "$1"
+
+# zig isn't making wasm files with build-lib
+# zig build-exe -target wasm32-freestanding --name "$2" "$1" -lc
+# zig build-exe -target wasm32-wasi --name "$2" "$1" -lc
+
+# rust makes a clean wat file
+rustc -C opt-level=1 --crate-type cdylib "$1" -o "$2.temp" --target wasm32-unknown-unknown
+
+# wasm-tools print will print all the dwarf info
+wasm2wat "$2.temp" > "$2"
+rm "$2.temp"
diff --git a/benchmarks/wasm/count.wat b/benchmarks/wasm/count.wat
new file mode 100644
index 0000000..1bb0ee6
--- /dev/null
+++ b/benchmarks/wasm/count.wat
@@ -0,0 +1,24 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func))
+ (func (;0;) (type 0) (param i32) (result i32)
+ local.get 0
+ i32.eqz
+ if (result i32) ;; label = @1
+ local.get 0
+ else
+ local.get 0
+ i32.const 1
+ i32.sub
+ return_call 0
+ end
+ )
+ (func (;1;) (type 1)
+ ;; TODO: now setting it to 100K will result in stack overflow
+ i32.const 1000 ;; it will not terminate when it's 1mil
+ ;; TODO: this doesn't seem like an error in our semantics
+ ;; but something about sbt. But why?
+ call 0
+ )
+ (start 1)
+)
diff --git a/benchmarks/wasm/even_odd.rs b/benchmarks/wasm/even_odd.rs
new file mode 100644
index 0000000..91ff319
--- /dev/null
+++ b/benchmarks/wasm/even_odd.rs
@@ -0,0 +1,18 @@
+#[no_mangle]
+#[inline(never)]
+fn is_even(n: u32) -> bool {
+ if n == 0 { true }
+ else { is_odd(n - 1) }
+}
+
+#[no_mangle]
+#[inline(never)]
+fn is_odd(n: u32) -> bool {
+ if n == 0 { false }
+ else { is_even(n - 1) }
+}
+
+#[no_mangle]
+fn real_main() -> bool {
+ is_even(12)
+}
diff --git a/benchmarks/wasm/even_odd.wat b/benchmarks/wasm/even_odd.wat
new file mode 100644
index 0000000..27e1036
--- /dev/null
+++ b/benchmarks/wasm/even_odd.wat
@@ -0,0 +1,31 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (func (;0;) (type 0) (param i32) (result i32)
+ block ;; label = @1
+ local.get 0
+ br_if 0 (;@1;)
+ i32.const 1
+ return
+ end
+ local.get 0
+ i32.const -1
+ i32.add
+ call 1)
+ (func (;1;) (type 0) (param i32) (result i32)
+ block ;; label = @1
+ local.get 0
+ br_if 0 (;@1;)
+ i32.const 0
+ return
+ end
+ local.get 0
+ i32.const -1
+ i32.add
+ call 0)
+ (func (;2;) (type 1) (result i32)
+ i32.const 13
+ call 1)
+ (start 2)
+ (memory (;0;) 16)
+)
diff --git a/benchmarks/wasm/fact.wat b/benchmarks/wasm/fact.wat
new file mode 100644
index 0000000..2eb2f73
--- /dev/null
+++ b/benchmarks/wasm/fact.wat
@@ -0,0 +1,40 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func (param i32) (result i32)))
+ (type (;2;) (func (result i32)))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1) (param i32) (result i32)
+ (local i32 i32)
+ local.get 0
+ local.set 1
+ i32.const 1
+ local.set 2
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 2
+ call 0
+ local.get 1
+ i32.const 0
+ i32.eq
+ if ;; label = @3
+ br 2 (;@1;)
+ else
+ local.get 1
+ local.get 2
+ i32.mul
+ local.set 2
+ local.get 1
+ i32.const 1
+ i32.sub
+ local.set 1
+ end
+ br 0 (;@2;)
+ end
+ end
+ local.get 2)
+ (func $main (type 2) (result i32)
+ i32.const 5
+ call 1
+ )
+ (start 2)
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/fib.rs b/benchmarks/wasm/fib.rs
new file mode 100644
index 0000000..a9fb792
--- /dev/null
+++ b/benchmarks/wasm/fib.rs
@@ -0,0 +1,12 @@
+#[no_mangle]
+#[inline(never)]
+fn fibonacci(n: i32) -> i32 {
+ if n == 0 { 0 }
+ else if n == 1 { 1 }
+ else { fibonacci(n - 1) + fibonacci(n - 2) }
+}
+
+#[no_mangle]
+fn real_main() -> i32 {
+ fibonacci(12)
+}
diff --git a/benchmarks/wasm/fib.wat b/benchmarks/wasm/fib.wat
new file mode 100644
index 0000000..86bd955
--- /dev/null
+++ b/benchmarks/wasm/fib.wat
@@ -0,0 +1,59 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (func (;0;) (type 0) (param i32) (result i32)
+ (local i32)
+ i32.const 0
+ local.set 1
+ local.get 0
+ local.set 0
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 1
+ local.set 1
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ local.get 0
+ local.tee 0
+ br_table 0 (;@5;) 1 (;@4;) 2 (;@3;)
+ end
+ local.get 0
+ local.set 0
+ br 3 (;@1;)
+ end
+ i32.const 1
+ local.set 0
+ br 2 (;@1;)
+ end
+ local.get 1
+ local.get 0
+ i32.const -1
+ i32.add
+ call 0
+ i32.add
+ local.set 1
+ local.get 0
+ i32.const -2
+ i32.add
+ local.set 0
+ br 0 (;@2;)
+ end
+ end
+ local.get 1
+ local.get 0
+ i32.add)
+ (func (;1;) (type 1) (result i32)
+ i32.const 12
+ call 0)
+ (start 1)
+ (table (;0;) 1 1 funcref)
+ (memory (;0;) 16)
+ (global (;0;) (mut i32) (i32.const 1048576))
+ (global (;1;) i32 (i32.const 1048576))
+ (global (;2;) i32 (i32.const 1048576))
+ (export "memory" (memory 0))
+ (export "fibonacci" (func 0))
+ (export "real_main" (func 1))
+ (export "__data_end" (global 1))
+ (export "__heap_base" (global 2)))
diff --git a/benchmarks/wasm/for_loop.wat b/benchmarks/wasm/for_loop.wat
new file mode 100644
index 0000000..404a01b
--- /dev/null
+++ b/benchmarks/wasm/for_loop.wat
@@ -0,0 +1,40 @@
+(module
+ (func $for_loop (result i32)
+ (local i32)
+ (local i32)
+
+ for
+ (
+ ;; init
+ i32.const 0
+ local.set 0
+ i32.const 0
+ local.set 1
+ |
+ ;; cond
+ local.get 1
+ i32.const 10
+ i32.gt_s
+ i32.eqz
+ |
+ ;; post
+ local.get 1
+ i32.const 1
+ i32.add
+ local.set 1
+ )
+
+ ;; es
+ local.get 0
+ local.get 1
+ i32.add
+ local.set 0
+
+ local.get 0
+
+
+ )
+
+ (export "for_loop" (func 0))
+
+ )
\ No newline at end of file
diff --git a/benchmarks/wasm/linsearch.rs b/benchmarks/wasm/linsearch.rs
new file mode 100644
index 0000000..312e679
--- /dev/null
+++ b/benchmarks/wasm/linsearch.rs
@@ -0,0 +1 @@
+fn
diff --git a/benchmarks/wasm/load.wat b/benchmarks/wasm/load.wat
new file mode 100644
index 0000000..916328a
--- /dev/null
+++ b/benchmarks/wasm/load.wat
@@ -0,0 +1,19 @@
+(module
+ (type (;0;) (func (result i32)))
+ (type (;1;) (func))
+ (func (;0;) (type 0) (result i32)
+ i32.const 0
+ i32.const 1
+ i32.store
+ i32.const 0
+ i32.load
+ )
+ (func (;1;) (type 1)
+ call 0
+ ;; should be 65536
+ ;; drop
+ )
+ (start 1)
+ (memory (;0;) 2)
+ (export "main" (func 1))
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/loop.wat b/benchmarks/wasm/loop.wat
new file mode 100644
index 0000000..b51e251
--- /dev/null
+++ b/benchmarks/wasm/loop.wat
@@ -0,0 +1,21 @@
+;; https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Control_flow/loop
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ loop ;; label = @1
+ local.get 0
+ i32.const 1
+ i32.add
+ local.set 0
+ local.get 0
+ call 0
+ local.get 0
+ i32.const 10
+ i32.lt_s
+ br_if 0 (;@1;)
+ end
+ local.get 0)
+ (start 1))
diff --git a/benchmarks/wasm/loop_poly.wat b/benchmarks/wasm/loop_poly.wat
new file mode 100644
index 0000000..7cbb2e2
--- /dev/null
+++ b/benchmarks/wasm/loop_poly.wat
@@ -0,0 +1,20 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (func (param i32) (result i32)))
+ (func $test_poly_loop (;0;) (type 0)
+ i32.const 42
+ i32.const 0
+ block (param i32 i32) (result i32 i32)
+ loop (type 1) (param i32) (result i32) ;; label = @1
+ i32.const 1
+ i32.const 2
+ br 1 (;@1;)
+ end
+ end
+ ;; this is not a valid wasm program due to the mismatch of stack shape,
+ ;; we only do this for testing purposes.
+ ;; i32.add
+ ;; drop
+ )
+ (start 0)
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/pow.rs b/benchmarks/wasm/pow.rs
new file mode 100644
index 0000000..3ce1cda
--- /dev/null
+++ b/benchmarks/wasm/pow.rs
@@ -0,0 +1,14 @@
+#[no_mangle]
+#[inline(never)]
+fn power(a: i32, b: i32) -> i32 {
+ if b == 0 {
+ 1
+ } else {
+ a * power(a, b - 1)
+ }
+}
+
+#[no_mangle]
+fn real_main() -> i32 {
+ power(2, 10)
+}
diff --git a/benchmarks/wasm/pow.wat b/benchmarks/wasm/pow.wat
new file mode 100644
index 0000000..cd537b7
--- /dev/null
+++ b/benchmarks/wasm/pow.wat
@@ -0,0 +1,43 @@
+(module $pow.temp
+ (type (;0;) (func (param i32 i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (func $power (type 0) (param i32 i32) (result i32)
+ (local i32)
+ i32.const 1
+ local.set 2
+ local.get 1
+ local.set 1
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 2
+ local.set 2
+ local.get 1
+ local.tee 1
+ i32.eqz
+ br_if 1 (;@1;)
+ local.get 2
+ local.get 0
+ i32.mul
+ local.set 2
+ local.get 1
+ i32.const -1
+ i32.add
+ local.set 1
+ br 0 (;@2;)
+ end
+ end
+ local.get 2)
+ (func $real_main (type 1) (result i32)
+ i32.const 2
+ i32.const 10
+ call $power)
+ (table (;0;) 1 1 funcref)
+ (memory (;0;) 16)
+ (global $__stack_pointer (mut i32) (i32.const 1048576))
+ (global (;1;) i32 (i32.const 1048576))
+ (global (;2;) i32 (i32.const 1048576))
+ (export "memory" (memory 0))
+ (export "power" (func 0))
+ (export "real_main" (func 1))
+ (export "__data_end" (global 1))
+ (export "__heap_base" (global 2)))
diff --git a/benchmarks/wasm/return.wat b/benchmarks/wasm/return.wat
new file mode 100644
index 0000000..f62890a
--- /dev/null
+++ b/benchmarks/wasm/return.wat
@@ -0,0 +1,16 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (func (result i32)))
+ (func (type 1)
+ block
+ i32.const 42
+ return
+ end
+ i32.const 100
+ )
+ (func (type 0)
+ call 0
+ unreachable
+ )
+ (export "$real_main" (func 1))
+)
diff --git a/benchmarks/wasm/return_call.wat b/benchmarks/wasm/return_call.wat
new file mode 100644
index 0000000..8e30615
--- /dev/null
+++ b/benchmarks/wasm/return_call.wat
@@ -0,0 +1,33 @@
+(module
+ (type (;0;) (func (param i64) (result i32)))
+ (type (;1;) (func))
+ (func (;0;) (type 0) (param i64) (result i32)
+ local.get 0
+ i64.eqz
+ if (result i32) ;; label = @1
+ i32.const 44
+ else
+ local.get 0
+ i64.const 1
+ i64.sub
+ return_call 1
+ end
+ )
+ (func (;1;) (type 0) (param i64) (result i32)
+ local.get 0
+ i64.eqz
+ if (result i32) ;; label = @1
+ i32.const 99
+ else
+ local.get 0
+ i64.const 1
+ i64.sub
+ return_call 0
+ end
+ )
+ (func (;2;) (type 1)
+ i64.const 10000 ;; 100000 seems causing Github CI failed
+ call 0
+ )
+ (start 2)
+)
diff --git a/benchmarks/wasm/script/script_basic.bin.wast b/benchmarks/wasm/script/script_basic.bin.wast
new file mode 100644
index 0000000..e0ae65f
--- /dev/null
+++ b/benchmarks/wasm/script/script_basic.bin.wast
@@ -0,0 +1,7 @@
+(module binary
+ "\00\61\73\6d\01\00\00\00\01\85\80\80\80\00\01\60"
+ "\00\01\7f\03\82\80\80\80\00\01\00\07\87\80\80\80"
+ "\00\01\03\6f\6e\65\00\00\0a\8a\80\80\80\00\01\84"
+ "\80\80\80\00\00\41\01\0b"
+)
+(assert_return (invoke "one") (i32.const 0x1))
diff --git a/benchmarks/wasm/script/script_basic.wast b/benchmarks/wasm/script/script_basic.wast
new file mode 100644
index 0000000..4d1d1cb
--- /dev/null
+++ b/benchmarks/wasm/script/script_basic.wast
@@ -0,0 +1,8 @@
+(module
+ (func $one (result i32)
+ i32.const 1)
+ (export "one" (func 0))
+)
+
+(assert_return (invoke "one") (i32.const 1))
+
diff --git a/benchmarks/wasm/spectest/return_call.bin.wast b/benchmarks/wasm/spectest/return_call.bin.wast
new file mode 100644
index 0000000..a3ad319
--- /dev/null
+++ b/benchmarks/wasm/spectest/return_call.bin.wast
@@ -0,0 +1,194 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\c8\80\80\80\00\0e\60"
+ "\00\01\7f\60\00\01\7e\60\00\01\7d\60\00\01\7c\60"
+ "\01\7f\01\7f\60\01\7e\01\7e\60\01\7d\01\7d\60\01"
+ "\7c\01\7c\60\02\7d\7f\01\7f\60\02\7f\7e\01\7e\60"
+ "\02\7c\7d\01\7d\60\02\7e\7c\01\7c\60\02\7e\7e\01"
+ "\7e\60\01\7e\01\7f\03\9d\80\80\80\00\1c\00\01\02"
+ "\03\04\05\06\07\08\09\0a\0b\00\01\02\03\00\01\02"
+ "\03\00\01\02\03\0c\05\0d\0d\07\d8\81\80\80\00\10"
+ "\08\74\79\70\65\2d\69\33\32\00\0c\08\74\79\70\65"
+ "\2d\69\36\34\00\0d\08\74\79\70\65\2d\66\33\32\00"
+ "\0e\08\74\79\70\65\2d\66\36\34\00\0f\0e\74\79\70"
+ "\65\2d\66\69\72\73\74\2d\69\33\32\00\10\0e\74\79"
+ "\70\65\2d\66\69\72\73\74\2d\69\36\34\00\11\0e\74"
+ "\79\70\65\2d\66\69\72\73\74\2d\66\33\32\00\12\0e"
+ "\74\79\70\65\2d\66\69\72\73\74\2d\66\36\34\00\13"
+ "\0f\74\79\70\65\2d\73\65\63\6f\6e\64\2d\69\33\32"
+ "\00\14\0f\74\79\70\65\2d\73\65\63\6f\6e\64\2d\69"
+ "\36\34\00\15\0f\74\79\70\65\2d\73\65\63\6f\6e\64"
+ "\2d\66\33\32\00\16\0f\74\79\70\65\2d\73\65\63\6f"
+ "\6e\64\2d\66\36\34\00\17\07\66\61\63\2d\61\63\63"
+ "\00\18\05\63\6f\75\6e\74\00\19\04\65\76\65\6e\00"
+ "\1a\03\6f\64\64\00\1b\0a\80\83\80\80\00\1c\85\80"
+ "\80\80\00\00\41\b2\02\0b\85\80\80\80\00\00\42\e4"
+ "\02\0b\87\80\80\80\00\00\43\00\20\73\45\0b\8b\80"
+ "\80\80\00\00\44\00\00\00\00\00\c8\ae\40\0b\84\80"
+ "\80\80\00\00\20\00\0b\84\80\80\80\00\00\20\00\0b"
+ "\84\80\80\80\00\00\20\00\0b\84\80\80\80\00\00\20"
+ "\00\0b\84\80\80\80\00\00\20\01\0b\84\80\80\80\00"
+ "\00\20\01\0b\84\80\80\80\00\00\20\01\0b\84\80\80"
+ "\80\00\00\20\01\0b\84\80\80\80\00\00\12\00\0b\84"
+ "\80\80\80\00\00\12\01\0b\84\80\80\80\00\00\12\02"
+ "\0b\84\80\80\80\00\00\12\03\0b\86\80\80\80\00\00"
+ "\41\20\12\04\0b\87\80\80\80\00\00\42\c0\00\12\05"
+ "\0b\89\80\80\80\00\00\43\c3\f5\a8\3f\12\06\0b\8d"
+ "\80\80\80\00\00\44\3d\0a\d7\a3\70\3d\fa\3f\12\07"
+ "\0b\8b\80\80\80\00\00\43\66\66\00\42\41\20\12\08"
+ "\0b\89\80\80\80\00\00\41\20\42\c0\00\12\09\0b\92"
+ "\80\80\80\00\00\44\00\00\00\00\00\00\50\40\43\00"
+ "\00\00\42\12\0a\0b\90\80\80\80\00\00\42\c0\00\44"
+ "\66\66\66\66\66\06\50\40\12\0b\0b\97\80\80\80\00"
+ "\00\20\00\50\04\7e\20\01\05\20\00\42\01\7d\20\00"
+ "\20\01\7e\12\18\0b\0b\92\80\80\80\00\00\20\00\50"
+ "\04\7e\20\00\05\20\00\42\01\7d\12\19\0b\0b\92\80"
+ "\80\80\00\00\20\00\50\04\7f\41\2c\05\20\00\42\01"
+ "\7d\12\1b\0b\0b\93\80\80\80\00\00\20\00\50\04\7f"
+ "\41\e3\00\05\20\00\42\01\7d\12\1a\0b\0b"
+)
+(module instance)
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+;; (assert_return (invoke "type-f32") (f32.const 0x1.e64p+11))
+;; (assert_return (invoke "type-f64") (f64.const 0x1.ec8p+11))
+(assert_return (invoke "type-first-i32") (i32.const 0x20))
+(assert_return (invoke "type-first-i64") (i64.const 0x40))
+;; (assert_return (invoke "type-first-f32") (f32.const 0x1.51eb_86p+0))
+;; (assert_return (invoke "type-first-f64") (f64.const 0x1.a3d7_0a3d_70a3_dp+0))
+(assert_return (invoke "type-second-i32") (i32.const 0x20))
+(assert_return (invoke "type-second-i64") (i64.const 0x40))
+(assert_return (invoke "type-second-f32") (f32.const 0x1p+5))
+;; (assert_return (invoke "type-second-f64") (f64.const 0x1.0066_6666_6666_6p+6))
+(assert_return
+ (invoke "fac-acc" (i64.const 0x0) (i64.const 0x1))
+ (i64.const 0x1)
+)
+(assert_return
+ (invoke "fac-acc" (i64.const 0x1) (i64.const 0x1))
+ (i64.const 0x1)
+)
+(assert_return
+ (invoke "fac-acc" (i64.const 0x5) (i64.const 0x1))
+ (i64.const 0x78)
+)
+(assert_return (invoke "count" (i64.const 0x0)) (i64.const 0x0))
+(assert_return (invoke "count" (i64.const 0x3e8)) (i64.const 0x0))
+;; See `count.wat` for why this is commented out
+;; (assert_return (invoke "count" (i64.const 0xf_4240)) (i64.const 0x0))
+(assert_return (invoke "even" (i64.const 0x0)) (i32.const 0x2c))
+(assert_return (invoke "even" (i64.const 0x1)) (i32.const 0x63))
+(assert_return (invoke "even" (i64.const 0x64)) (i32.const 0x2c))
+(assert_return (invoke "even" (i64.const 0x4d)) (i32.const 0x63))
+;; See `return_call.wat` for why these are commented out
+;; (assert_return (invoke "even" (i64.const 0xf_4240)) (i32.const 0x2c))
+;; (assert_return (invoke "even" (i64.const 0xf_4241)) (i32.const 0x63))
+(assert_return (invoke "odd" (i64.const 0x0)) (i32.const 0x63))
+(assert_return (invoke "odd" (i64.const 0x1)) (i32.const 0x2c))
+(assert_return (invoke "odd" (i64.const 0xc8)) (i32.const 0x63))
+(assert_return (invoke "odd" (i64.const 0x4d)) (i32.const 0x2c))
+;; (assert_return (invoke "odd" (i64.const 0xf_4240)) (i32.const 0x63))
+;; (assert_return (invoke "odd" (i64.const 0xf_423f)) (i32.const 0x2c))
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\00\01\7f\60\00\00\03\83\80\80\80\00\02\00\01\0a"
+ "\93\80\80\80\00\02\86\80\80\80\00\00\12\01\41\00"
+ "\0b\82\80\80\80\00\00\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\00\01\7f\60\00\01\7e\03\83\80\80\80\00\02\00\01"
+ "\0a\95\80\80\80\00\02\86\80\80\80\00\00\12\01\41"
+ "\00\0b\84\80\80\80\00\00\42\01\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\00\00\60\01\7f\00\03\83\80\80\80\00\02\00\01\0a"
+ "\91\80\80\80\00\02\84\80\80\80\00\00\12\01\0b\82"
+ "\80\80\80\00\00\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\00\00\60\02\7c\7f\00\03\83\80\80\80\00\02\00\01"
+ "\0a\91\80\80\80\00\02\84\80\80\80\00\00\12\01\0b"
+ "\82\80\80\80\00\00\0b"
+ )
+ "type mismatch"
+)
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\84\80\80\80\00\01\60"
+ "\00\00\03\83\80\80\80\00\02\00\00\0a\93\80\80\80"
+ "\00\02\86\80\80\80\00\00\41\01\12\01\0b\82\80\80"
+ "\80\00\00\0b"
+)
+(module instance)
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\84\80\80\80\00\01\60"
+ "\00\00\03\83\80\80\80\00\02\00\00\0a\9c\80\80\80"
+ "\00\02\8f\80\80\80\00\00\44\00\00\00\00\00\00\00"
+ "\40\41\01\12\01\0b\82\80\80\80\00\00\0b"
+)
+(module instance)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\00\00\60\02\7f\7f\00\03\83\80\80\80\00\02\00\01"
+ "\0a\94\80\80\80\00\02\87\80\80\80\00\00\01\41\01"
+ "\12\01\0b\82\80\80\80\00\00\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\00\00\60\02\7f\7f\00\03\83\80\80\80\00\02\00\01"
+ "\0a\94\80\80\80\00\02\87\80\80\80\00\00\41\01\01"
+ "\12\01\0b\82\80\80\80\00\00\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\00\00\60\02\7f\7c\00\03\83\80\80\80\00\02\00\01"
+ "\0a\9c\80\80\80\00\02\8f\80\80\80\00\00\44\00\00"
+ "\00\00\00\00\f0\3f\41\01\12\01\0b\82\80\80\80\00"
+ "\00\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\00\00\60\02\7c\7f\00\03\83\80\80\80\00\02\00\01"
+ "\0a\9c\80\80\80\00\02\8f\80\80\80\00\00\41\01\44"
+ "\00\00\00\00\00\00\f0\3f\12\01\0b\82\80\80\80\00"
+ "\00\0b"
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\84\80\80\80\00\01\60"
+ "\00\00\03\82\80\80\80\00\01\00\0a\8a\80\80\80\00"
+ "\01\84\80\80\80\00\00\12\01\0b"
+ )
+ "unknown function"
+)
+(assert_invalid
+ (module binary
+ "\00\61\73\6d\01\00\00\00\01\84\80\80\80\00\01\60"
+ "\00\00\03\82\80\80\80\00\01\00\0a\8e\80\80\80\00"
+ "\01\88\80\80\80\00\00\12\94\98\db\e2\03\0b"
+ )
+ "unknown function"
+)
diff --git a/benchmarks/wasm/spectest/return_call.wast b/benchmarks/wasm/spectest/return_call.wast
new file mode 100644
index 0000000..e1b0aa6
--- /dev/null
+++ b/benchmarks/wasm/spectest/return_call.wast
@@ -0,0 +1,199 @@
+;; Test `return_call` operator
+
+(module
+ ;; Auxiliary definitions
+ (func $const-i32 (result i32) (i32.const 0x132))
+ (func $const-i64 (result i64) (i64.const 0x164))
+ (func $const-f32 (result f32) (f32.const 0xf32))
+ (func $const-f64 (result f64) (f64.const 0xf64))
+
+ (func $id-i32 (param i32) (result i32) (local.get 0))
+ (func $id-i64 (param i64) (result i64) (local.get 0))
+ (func $id-f32 (param f32) (result f32) (local.get 0))
+ (func $id-f64 (param f64) (result f64) (local.get 0))
+
+ (func $f32-i32 (param f32 i32) (result i32) (local.get 1))
+ (func $i32-i64 (param i32 i64) (result i64) (local.get 1))
+ (func $f64-f32 (param f64 f32) (result f32) (local.get 1))
+ (func $i64-f64 (param i64 f64) (result f64) (local.get 1))
+
+ ;; Typing
+
+ (func (export "type-i32") (result i32) (return_call $const-i32))
+ (func (export "type-i64") (result i64) (return_call $const-i64))
+ (func (export "type-f32") (result f32) (return_call $const-f32))
+ (func (export "type-f64") (result f64) (return_call $const-f64))
+
+ (func (export "type-first-i32") (result i32) (return_call $id-i32 (i32.const 32)))
+ (func (export "type-first-i64") (result i64) (return_call $id-i64 (i64.const 64)))
+ (func (export "type-first-f32") (result f32) (return_call $id-f32 (f32.const 1.32)))
+ (func (export "type-first-f64") (result f64) (return_call $id-f64 (f64.const 1.64)))
+
+ (func (export "type-second-i32") (result i32)
+ (return_call $f32-i32 (f32.const 32.1) (i32.const 32))
+ )
+ (func (export "type-second-i64") (result i64)
+ (return_call $i32-i64 (i32.const 32) (i64.const 64))
+ )
+ (func (export "type-second-f32") (result f32)
+ (return_call $f64-f32 (f64.const 64) (f32.const 32))
+ )
+ (func (export "type-second-f64") (result f64)
+ (return_call $i64-f64 (i64.const 64) (f64.const 64.1))
+ )
+
+ ;; Recursion
+
+ (func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 1))
+ (else
+ (return_call $fac-acc
+ (i64.sub (local.get 0) (i64.const 1))
+ (i64.mul (local.get 0) (local.get 1))
+ )
+ )
+ )
+ )
+
+ (func $count (export "count") (param i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 0))
+ (else (return_call $count (i64.sub (local.get 0) (i64.const 1))))
+ )
+ )
+
+ (func $even (export "even") (param i64) (result i32)
+ (if (result i32) (i64.eqz (local.get 0))
+ (then (i32.const 44))
+ (else (return_call $odd (i64.sub (local.get 0) (i64.const 1))))
+ )
+ )
+ (func $odd (export "odd") (param i64) (result i32)
+ (if (result i32) (i64.eqz (local.get 0))
+ (then (i32.const 99))
+ (else (return_call $even (i64.sub (local.get 0) (i64.const 1))))
+ )
+ )
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "fac-acc" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 5) (i64.const 1)) (i64.const 120))
+
+(assert_return (invoke "count" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "count" (i64.const 1000)) (i64.const 0))
+;; (assert_return (invoke "count" (i64.const 1_000_000)) (i64.const 0))
+
+(assert_return (invoke "even" (i64.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i64.const 100)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 77)) (i32.const 99))
+;; (assert_return (invoke "even" (i64.const 1_000_000)) (i32.const 44))
+;; (assert_return (invoke "even" (i64.const 1_000_001)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i64.const 200)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 77)) (i32.const 44))
+;; TODO: also look at the follwoing test
+;; (assert_return (invoke "odd" (i64.const 1_000_000)) (i32.const 99))
+;; (assert_return (invoke "odd" (i64.const 999_999)) (i32.const 44))
+
+
+;; Invalid typing
+
+(assert_invalid
+ (module
+ (func $type-void-vs-num (result i32) (return_call 1) (i32.const 0))
+ (func)
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-num-vs-num (result i32) (return_call 1) (i32.const 0))
+ (func (result i64) (i64.const 1))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (func $arity-0-vs-1 (return_call 1))
+ (func (param i32))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $arity-0-vs-2 (return_call 1))
+ (func (param f64 i32))
+ )
+ "type mismatch"
+)
+
+(module
+ (func $arity-1-vs-0 (i32.const 1) (return_call 1))
+ (func)
+)
+
+(module
+ (func $arity-2-vs-0 (f64.const 2) (i32.const 1) (return_call 1))
+ (func)
+)
+
+(assert_invalid
+ (module
+ (func $type-first-void-vs-num (return_call 1 (nop) (i32.const 1)))
+ (func (param i32 i32))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-second-void-vs-num (return_call 1 (i32.const 1) (nop)))
+ (func (param i32 i32))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-first-num-vs-num (return_call 1 (f64.const 1) (i32.const 1)))
+ (func (param i32 f64))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-second-num-vs-num (return_call 1 (i32.const 1) (f64.const 1)))
+ (func (param f64 i32))
+ )
+ "type mismatch"
+)
+
+
+;; Unbound function
+
+(assert_invalid
+ (module (func $unbound-func (return_call 1)))
+ "unknown function"
+)
+(assert_invalid
+ (module (func $large-func (return_call 1012321300)))
+ "unknown function"
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/start.wat b/benchmarks/wasm/start.wat
new file mode 100644
index 0000000..4d4dca3
--- /dev/null
+++ b/benchmarks/wasm/start.wat
@@ -0,0 +1,14 @@
+(module
+ (type (;0;) (func))
+ (func (;0;) (type 0)
+ i32.const 1
+ i32.const 3
+ i32.add
+ drop)
+ (func (;1;) (type 1)
+ i32.const 4
+ i32.const 3
+ i32.add
+ drop)
+ (start 0)
+)
diff --git a/benchmarks/wasm/sum.wat b/benchmarks/wasm/sum.wat
new file mode 100644
index 0000000..8841f58
--- /dev/null
+++ b/benchmarks/wasm/sum.wat
@@ -0,0 +1,24 @@
+(module
+ (type (;0;) (func (param i32)))
+ (import "console" "log" (func (type 0)))
+ (func (param i32 i32) (result i32)
+ local.get 0
+ i32.eqz
+ if (result i32)
+ local.get 1
+ else
+ local.get 0
+ i32.const 1
+ i32.sub
+ local.get 1
+ local.get 0
+ i32.add
+ (return_call 1)
+ end
+ )
+ (func (result i32)
+ i32.const 10
+ i32.const 0
+ (return_call 1))
+ (export "sum10" (func 2))
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/test.c b/benchmarks/wasm/test.c
new file mode 100644
index 0000000..f229930
--- /dev/null
+++ b/benchmarks/wasm/test.c
@@ -0,0 +1,15 @@
+static int cnt = 0;
+
+int sym_int(char* name) { return cnt++; }
+void assert(int expr) {}
+
+int main() {
+ int a = sym_int("a");
+ int b = sym_int("b");
+
+ if (a == b) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/benchmarks/wasm/test.rs b/benchmarks/wasm/test.rs
new file mode 100644
index 0000000..b96e8d0
--- /dev/null
+++ b/benchmarks/wasm/test.rs
@@ -0,0 +1,103 @@
+// #[no_mangle]
+// #[inline(never)]
+// fn test(a: i32, b: i32) -> i32 {
+// a + b
+// }
+
+// #[no_mangle]
+// #[inline(never)]
+// fn factorial(n: i32) -> i32 {
+// if n == 0 {
+// 1
+// } else {
+// n * factorial(n - 1)
+// }
+// }
+
+/*
+#[no_mangle]
+#[inline(never)]
+fn test_ret(a: i32) -> i32 {
+ let mut n = 1;
+
+ // Loop while `n` is less than 101
+ while n < 101 {
+ if n % 15 == 0 {
+ //println!("fizzbuzz");
+ return 1;
+ } else if n % 3 == 0 {
+ return 2;
+ //println!("fizz");
+ } else if n % 5 == 0 {
+ return 3;
+ //println!("buzz");
+ } else {
+ n += 1;
+ return 4;
+ //println!("{}", n);
+ }
+ // Increment counter
+ }
+
+ return -1;
+}
+*/
+
+#[no_mangle]
+#[inline(never)]
+fn power(a: i32, b: i32) -> i32 {
+ if b == 0 {
+ 1
+ } else {
+ a * power(a, b - 1)
+ }
+}
+
+#[no_mangle]
+#[inline(never)]
+fn ack(m: i32, n: i32) -> i32 {
+ if m == 0 {
+ n + 1
+ } else if n == 0 {
+ ack(m - 1, 1)
+ } else {
+ ack(m - 1, ack(m, n - 1))
+ }
+}
+
+#[no_mangle]
+#[inline(never)]
+fn opaque(x: i32) -> i32 {
+ x + 1
+}
+
+#[no_mangle]
+#[inline(never)]
+fn opaque1(x: i32) -> i32 {
+ x + 5
+}
+
+#[no_mangle]
+#[inline(never)]
+fn opaque2(x: i32) -> i32 {
+ x + 100
+}
+
+#[no_mangle]
+#[inline(never)]
+fn conditional(x: i32) -> i32 {
+ if x == 0 {
+ x + 10
+ } else {
+ opaque(x)
+ }
+}
+
+#[no_mangle]
+fn real_main() -> i32 {
+ // conditional(5)
+ // factorial(5)
+ // power(3, 3)
+ ack(2, 2)
+ //test_ret(11)
+}
diff --git a/benchmarks/wasm/test.wat b/benchmarks/wasm/test.wat
new file mode 100644
index 0000000..2ad9ed8
--- /dev/null
+++ b/benchmarks/wasm/test.wat
@@ -0,0 +1,164 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (func (param i32) (result i32)))
+ (type (;2;) (func (param i32)))
+ (type (;3;) (func (result i32)))
+ (type (;4;) (func (param i32 i32) (result i32)))
+ (func $__wasm_call_ctors (type 0))
+ (func $sym_int (type 1) (param i32) (result i32)
+ (local i32 i32 i32 i32 i32 i32 i32 i32)
+ global.get 0
+ local.set 1
+ i32.const 16
+ local.set 2
+ local.get 1
+ local.get 2
+ i32.sub
+ local.set 3
+ local.get 3
+ local.get 0
+ i32.store offset=12
+ i32.const 0
+ local.set 4
+ local.get 4
+ i32.load offset=1028
+ local.set 5
+ i32.const 1
+ local.set 6
+ local.get 5
+ local.get 6
+ i32.add
+ local.set 7
+ i32.const 0
+ local.set 8
+ local.get 8
+ local.get 7
+ i32.store offset=1028
+ local.get 5
+ return)
+ (func $assert (type 2) (param i32)
+ (local i32 i32 i32)
+ global.get 0
+ local.set 1
+ i32.const 16
+ local.set 2
+ local.get 1
+ local.get 2
+ i32.sub
+ local.set 3
+ local.get 3
+ local.get 0
+ i32.store offset=12
+ return)
+ (func $__original_main (type 3) (result i32)
+ (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
+ global.get 0
+ local.set 0
+ i32.const 16
+ local.set 1
+ local.get 0
+ local.get 1
+ i32.sub
+ local.set 2
+ local.get 2
+ global.set 0
+ i32.const 1026
+ local.set 3
+ i32.const 1024
+ local.set 4
+ i32.const 0
+ local.set 5
+ local.get 2
+ local.get 5
+ i32.store offset=12
+ local.get 4
+ i32.symbolic
+ local.set 6
+ local.get 2
+ local.get 6
+ i32.store offset=8
+ local.get 3
+ i32.symbolic
+ local.set 7
+ local.get 2
+ local.get 7
+ i32.store offset=4
+ local.get 2
+ i32.load offset=8
+ local.set 8
+ local.get 2
+ i32.load offset=4
+ local.set 9
+ local.get 8
+ local.set 10
+ local.get 9
+ local.set 11
+ local.get 10
+ local.get 11
+ i32.eq
+ local.set 12
+ i32.const 1
+ local.set 13
+ local.get 12
+ local.get 13
+ i32.and
+ local.set 14
+ block ;; label = @1
+ block ;; label = @2
+ local.get 14
+ i32.eqz
+ br_if 0 (;@2;)
+ i32.const 1
+ local.set 15
+ local.get 2
+ local.get 15
+ i32.store offset=12
+ br 1 (;@1;)
+ end
+ i32.const 0
+ local.set 16
+ local.get 2
+ local.get 16
+ i32.store offset=12
+ end
+ local.get 2
+ i32.load offset=12
+ local.set 17
+ i32.const 16
+ local.set 18
+ local.get 2
+ local.get 18
+ i32.add
+ local.set 19
+ local.get 19
+ global.set 0
+ local.get 17
+ return)
+ (func $main (type 4) (param i32 i32) (result i32)
+ (local i32)
+ call $__original_main
+ local.set 2
+ local.get 2
+ return)
+ (table (;0;) 1 1 funcref)
+ (memory (;0;) 2)
+ (global (;0;) (mut i32) (i32.const 66576))
+ (global (;1;) i32 (i32.const 1024))
+ (global (;2;) i32 (i32.const 1032))
+ (global (;3;) i32 (i32.const 1024))
+ (global (;4;) i32 (i32.const 66576))
+ (global (;5;) i32 (i32.const 0))
+ (global (;6;) i32 (i32.const 1))
+ (export "memory" (memory 0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "sym_int" (func $sym_int))
+ (export "assert" (func $assert))
+ (export "__original_main" (func $__original_main))
+ (export "main" (func $main))
+ (export "__dso_handle" (global 1))
+ (export "__data_end" (global 2))
+ (export "__global_base" (global 3))
+ (export "__heap_base" (global 4))
+ (export "__memory_base" (global 5))
+ (export "__table_base" (global 6))
+ (data (;0;) (i32.const 1024) "a\00b\00"))
diff --git a/benchmarks/wasm/test_loop.c b/benchmarks/wasm/test_loop.c
new file mode 100644
index 0000000..f236f0a
--- /dev/null
+++ b/benchmarks/wasm/test_loop.c
@@ -0,0 +1,15 @@
+int sym_int(char* name) { return (int) name; }
+void assert(int expr) {}
+
+int main() {
+ int a = sym_int("a");
+ int b = sym_int("b");
+ int n = 0;
+
+ while (a < b) {
+ a++;
+ n++;
+ }
+
+ return n;
+}
diff --git a/benchmarks/wasm/tribonacci.c b/benchmarks/wasm/tribonacci.c
new file mode 100644
index 0000000..9556656
--- /dev/null
+++ b/benchmarks/wasm/tribonacci.c
@@ -0,0 +1,10 @@
+int tribonacci(int n) {
+ if (n == 0) { return 0; }
+ else if (n == 1) { return 1; }
+ else if (n == 2) { return 1; }
+ else { return tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3); }
+}
+
+int real_main() {
+ return tribonacci(12);
+}
diff --git a/benchmarks/wasm/tribonacci.wat b/benchmarks/wasm/tribonacci.wat
new file mode 100644
index 0000000..01a5084
--- /dev/null
+++ b/benchmarks/wasm/tribonacci.wat
@@ -0,0 +1,43 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (func (;0;) (type 0) (param i32) (result i32)
+ local.get 0
+ if (result i32) ;; label = @1
+ local.get 0
+ i32.const 1
+ i32.eq
+ if (result i32) ;; label = @2
+ i32.const 1
+ else
+ local.get 0
+ i32.const 2
+ i32.eq
+ if (result i32) ;; label = @3
+ i32.const 1
+ else
+ local.get 0
+ i32.const 1
+ i32.sub
+ call 0
+ local.get 0
+ i32.const 2
+ i32.sub
+ call 0
+ i32.add
+ local.get 0
+ i32.const 3
+ i32.sub
+ call 0
+ i32.add
+ end
+ end
+ else
+ i32.const 0
+ end)
+ (func (;1;) (type 1) (result i32)
+ i32.const 12
+ call 0)
+ (start 1)
+ (memory (;0;) 0)
+ (export "memory" (memory 0)))
diff --git a/benchmarks/wasm/tribonacci_ret.rs b/benchmarks/wasm/tribonacci_ret.rs
new file mode 100644
index 0000000..ae57605
--- /dev/null
+++ b/benchmarks/wasm/tribonacci_ret.rs
@@ -0,0 +1,13 @@
+#[no_mangle]
+#[inline(never)]
+fn tribonacci(n: i32) -> i32 {
+ if n == 0 { 0 }
+ else if n == 1 { 1 }
+ else if n == 2 { 1 }
+ else { tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3) }
+}
+
+#[no_mangle]
+fn real_main() -> i32 {
+ tribonacci(12)
+}
diff --git a/benchmarks/wasm/tribonacci_ret.wat b/benchmarks/wasm/tribonacci_ret.wat
new file mode 100644
index 0000000..88e70e2
--- /dev/null
+++ b/benchmarks/wasm/tribonacci_ret.wat
@@ -0,0 +1,68 @@
+(module $tribonacci.wat.temp
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (func $tribonacci (type 0) (param i32) (result i32)
+ (local i32 i32)
+ local.get 0
+ i32.const 2
+ i32.shl
+ i32.const 1048576
+ i32.add
+ local.set 1
+ i32.const 0
+ local.set 2
+ local.get 0
+ local.set 0
+ loop (result i32) ;; label = @1
+ local.get 2
+ local.set 2
+ local.get 1
+ local.set 1
+ block ;; label = @2
+ local.get 0
+ local.tee 0
+ i32.const 2
+ i32.gt_u
+ br_if 0 (;@2;)
+ local.get 1
+ i32.load
+ local.get 2
+ i32.add
+ return
+ end
+ local.get 1
+ i32.const -12
+ i32.add
+ local.set 1
+ local.get 0
+ i32.const -1
+ i32.add
+ call $tribonacci
+ local.get 0
+ i32.const -2
+ i32.add
+ call $tribonacci
+ i32.add
+ local.get 2
+ i32.add
+ local.set 2
+ local.get 0
+ i32.const -3
+ i32.add
+ local.set 0
+ br 0 (;@1;)
+ end)
+ (func $real_main (type 1) (result i32)
+ i32.const 12
+ call $tribonacci)
+ (table (;0;) 1 1 funcref)
+ (memory (;0;) 17)
+ (global $__stack_pointer (mut i32) (i32.const 1048576))
+ (global (;1;) i32 (i32.const 1048588))
+ (global (;2;) i32 (i32.const 1048592))
+ (export "memory" (memory 0))
+ (export "tribonacci" (func $tribonacci))
+ (export "real_main" (func $real_main))
+ (export "__data_end" (global 1))
+ (export "__heap_base" (global 2))
+ (data $.rodata (i32.const 1048576) "\00\00\00\00\01\00\00\00\01\00\00\00"))
diff --git a/benchmarks/wasm/trycatch/deep.wat b/benchmarks/wasm/trycatch/deep.wat
new file mode 100644
index 0000000..fe05f99
--- /dev/null
+++ b/benchmarks/wasm/trycatch/deep.wat
@@ -0,0 +1,30 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try ;; 1 2 3 2 4 4 5
+ i32.const 1
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 3
+ call 0
+ i32.const -1
+ ;; [-1]
+ throw
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/multishot.wat b/benchmarks/wasm/trycatch/multishot.wat
new file mode 100644
index 0000000..bd5846f
--- /dev/null
+++ b/benchmarks/wasm/trycatch/multishot.wat
@@ -0,0 +1,31 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ local.set 0 ;; now we are really abusing the type system ...
+ local.get 0
+ resume0
+ i32.const 4
+ call 0
+ local.get 0
+ resume0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/nested_try_catch.wat b/benchmarks/wasm/trycatch/nested_try_catch.wat
new file mode 100644
index 0000000..c18429f
--- /dev/null
+++ b/benchmarks/wasm/trycatch/nested_try_catch.wat
@@ -0,0 +1,43 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ try
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop ;; [resume]
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ i32.const -1
+ throw
+ i32.const 7
+ call 0
+ catch
+ ;; [-1, resume]
+ drop
+ i32.const 6
+ call 0
+ resume0
+ i32.const 8
+ call 0
+ end
+ i32.const 9
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/throw_twice.wat b/benchmarks/wasm/trycatch/throw_twice.wat
new file mode 100644
index 0000000..dc960f4
--- /dev/null
+++ b/benchmarks/wasm/trycatch/throw_twice.wat
@@ -0,0 +1,38 @@
+;; kept in delimited continuation example
+(module
+ ;; output: 1, 2, 6, 2, 3, 4, 4, 5
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ block
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 6
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ end
+ end
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/throw_twice2.wat b/benchmarks/wasm/trycatch/throw_twice2.wat
new file mode 100644
index 0000000..2fe3297
--- /dev/null
+++ b/benchmarks/wasm/trycatch/throw_twice2.wat
@@ -0,0 +1,38 @@
+;; pushed to meta continuation example
+(module
+ ;; output: 1, 2, 6, 2, 3, 4, 5
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ block
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ end
+ i32.const 6
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ end
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4 ;; |---> adk
+ call 0 ;; |
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch.wat b/benchmarks/wasm/trycatch/try_catch.wat
new file mode 100644
index 0000000..2577fd8
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch.wat
@@ -0,0 +1,27 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_block.wat b/benchmarks/wasm/trycatch/try_catch_block.wat
new file mode 100644
index 0000000..b4ba3c6
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_block.wat
@@ -0,0 +1,31 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ block
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ end
+ end
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_br.wat b/benchmarks/wasm/trycatch/try_catch_br.wat
new file mode 100644
index 0000000..aaefdf2
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_br.wat
@@ -0,0 +1,32 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ block (result i32)
+ try
+ i32.const 1
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ ;;drop
+ br 0
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ end
+ i32.const 6
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_br2.wat b/benchmarks/wasm/trycatch/try_catch_br2.wat
new file mode 100644
index 0000000..19e19ed
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_br2.wat
@@ -0,0 +1,32 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ br 0
+ i32.const 3
+ call 0
+ end
+ i32.const 6
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_br3.wat b/benchmarks/wasm/trycatch/try_catch_br3.wat
new file mode 100644
index 0000000..3e6a41d
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_br3.wat
@@ -0,0 +1,36 @@
+;; ignored example
+(module
+ ;; output: 1, 2, 3, 4, 5
+ ;; 4 is printed, because the delimited continuation is kept when breaking out of the block,
+ ;; it's inside the trail1
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ block
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ br 0
+ end
+ end
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_br4.wat b/benchmarks/wasm/trycatch/try_catch_br4.wat
new file mode 100644
index 0000000..9b10ef3
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_br4.wat
@@ -0,0 +1,52 @@
+;; pushed to meta continuation example
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32 i32)
+ i32.const 0
+ local.set 1
+ try
+ i32.const 1
+ call 0
+ block
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ end
+ i32.const 6
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ end
+ i32.const 3
+ call 0
+ catch
+ ;; increment local 1
+ i32.const 1
+ local.get 1
+ i32.add
+ local.set 1
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ local.get 1
+ i32.const 1
+ i32.eq
+ if (param i32 (; input cont actually ;))
+ resume0
+ else
+ i32.const 7
+ call 0
+ end
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_catch_br.wat b/benchmarks/wasm/trycatch/try_catch_catch_br.wat
new file mode 100644
index 0000000..d515df3
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_catch_br.wat
@@ -0,0 +1,39 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ block
+ i32.const 42
+ ;; [42]
+ throw
+ br 0
+ i32.const 3
+ call 0
+ end
+ i32.const 6
+ call 0
+ catch
+ ;; [42, resume]
+ drop
+ local.set 0 ;; abusing the type system
+ local.get 0 ;;
+ block (param i32) ;;
+ i32.const 2
+ call 0
+ resume0
+ br 0
+ end
+ i32.const 4
+ call 0
+ local.get 0
+ resume0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_discard.wat b/benchmarks/wasm/trycatch/try_catch_discard.wat
new file mode 100644
index 0000000..c44341a
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_discard.wat
@@ -0,0 +1,25 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ i32.const 42
+ ;; [42]
+ throw
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ call 0
+ drop
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/trycatch/try_catch_succ.wat b/benchmarks/wasm/trycatch/try_catch_succ.wat
new file mode 100644
index 0000000..78e9809
--- /dev/null
+++ b/benchmarks/wasm/trycatch/try_catch_succ.wat
@@ -0,0 +1,24 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func))
+ (import "console" "log" (func (;0;) (type 0)))
+ (func (;1;) (type 1)
+ (local i32)
+ try
+ i32.const 1
+ call 0
+ i32.const 3
+ call 0
+ catch
+ ;; [42, resume]
+ i32.const 2
+ call 0
+ drop
+ resume0
+ i32.const 4
+ call 0
+ end
+ i32.const 5
+ call 0
+ )
+ (start 1))
diff --git a/benchmarks/wasm/wasmfx/README.md b/benchmarks/wasm/wasmfx/README.md
new file mode 100644
index 0000000..b2125c6
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/README.md
@@ -0,0 +1,9 @@
+# Tests for wasmfx
+
+Shorter tests: https://github.com/titzer/wizard-engine/tree/master/test/regress/ext:stack-switching
+
+Wasm reference interpreter tests: https://github.com/WebAssembly/stack-switching/blob/wasmfx/test/core/stack-switching/cont.wast
+
+Stack Switching proposal examples: https://github.com/WebAssembly/stack-switching/tree/main/proposals/stack-switching/examples
+
+
diff --git a/benchmarks/wasm/wasmfx/callcont.bin.wast b/benchmarks/wasm/wasmfx/callcont.bin.wast
new file mode 100644
index 0000000..bc0a467
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/callcont.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\01\7f\01\7f\5d\00\60\01\7f\00\60\00\01\7f\02\96"
+ "\80\80\80\00\01\08\73\70\65\63\74\65\73\74\09\70"
+ "\72\69\6e\74\5f\69\33\32\00\02\03\83\80\80\80\00"
+ "\02\00\03\07\88\80\80\80\00\01\04\6d\61\69\6e\00"
+ "\02\09\85\80\80\80\00\01\03\00\01\01\0a\9d\80\80"
+ "\80\00\02\87\80\80\80\00\00\20\00\41\01\6a\0b\8b"
+ "\80\80\80\00\00\41\0a\d2\01\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0xb))
diff --git a/benchmarks/wasm/wasmfx/callcont.wast b/benchmarks/wasm/wasmfx/callcont.wast
new file mode 100644
index 0000000..63d0b44
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/callcont.wast
@@ -0,0 +1,26 @@
+
+(module
+ ;; Import only required for printing
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+
+ (func (param i32) (result i32)
+ local.get 0
+ i32.const 1
+ i32.add
+ )
+
+ (elem declare func 1)
+
+ (func (export "main") (result i32)
+ i32.const 10
+ ref.func 1
+ cont.new 1
+ (resume 1)
+ )
+
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (cont 0))
+
+)
+
+(assert_return (invoke "main") (i32.const 11))
diff --git a/benchmarks/wasm/wasmfx/callref-strip.wast b/benchmarks/wasm/wasmfx/callref-strip.wast
new file mode 100644
index 0000000..6666fd3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/callref-strip.wast
@@ -0,0 +1,58 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func (param i32 i32)))
+ (type (;2;) (func (param (ref 0) (ref 0))))
+ (type (;3;) (func))
+ (import "spectest" "print_i32" (func (;0;) (type 0)))
+ (export "_start" (func 6))
+ (start 6)
+ (elem (;0;) declare func 4)
+ (elem (;1;) declare func 5)
+ (func (;1;) (type 0) (param i32)
+ local.get 0
+ call 0
+ )
+ (func (;2;) (type 1) (param i32 i32)
+ (local i32)
+ local.get 0
+ local.set 2
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 2
+ local.get 1
+ i32.gt_u
+ br_if 1 (;@1;)
+ local.get 2
+ call 1
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 2
+ br 0 (;@2;)
+ end
+ end
+ )
+ (func (;3;) (type 2) (param (ref 0) (ref 0))
+ i32.const 10
+ local.get 0
+ call_ref 0
+ i32.const 20
+ local.get 1
+ call_ref 0
+ )
+ (func (;4;) (type 0) (param i32)
+ local.get 0
+ i32.const 13
+ call 2
+ )
+ (func (;5;) (type 0) (param i32)
+ local.get 0
+ i32.const 23
+ call 2
+ )
+ (func (;6;) (type 3)
+ ref.func 4
+ ref.func 5
+ call 3
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/callref.wast b/benchmarks/wasm/wasmfx/callref.wast
new file mode 100644
index 0000000..76bb589
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/callref.wast
@@ -0,0 +1,33 @@
+(module
+
+ ;; Import only required for printing
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+
+ (func $process (param $x i32)
+ (call $print_i32 (local.get $x))
+ )
+
+ (func $range (param $from i32) (param $to i32)
+ (local $i i32)
+ (local.set $i (local.get $from))
+ (block $b
+ (loop $l
+ (br_if $b (i32.gt_u (local.get $i) (local.get $to)))
+ (call $process (local.get $i))
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
+ (br $l))))
+
+ (type $task (func (param i32)))
+ (func $run (param $task1 (ref $task)) (param $task2 (ref $task))
+ (call_ref $task (i32.const 10) (local.get $task1))
+ (call_ref $task (i32.const 20) (local.get $task2)))
+
+ (elem declare func $task1)
+ (elem declare func $task2)
+
+ (func $task1 (param $x i32) (call $range (local.get $x) (i32.const 13)))
+ (func $task2 (param $x i32) (call $range (local.get $x) (i32.const 23)))
+ (func $main (export "_start")
+ (call $run (ref.func $task1) (ref.func $task2)))
+ (start $main)
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/cont1-stripped.wat b/benchmarks/wasm/wasmfx/cont1-stripped.wat
new file mode 100644
index 0000000..1480bb5
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont1-stripped.wat
@@ -0,0 +1,11 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (func (param i64)))
+ (type (;2;) (func (param f32)))
+ (type (;3;) (func (param f64)))
+ (type (;4;) (cont 0))
+ (type (;5;) (cont 1))
+ (type (;6;) (cont 2))
+ (type (;7;) (cont 3))
+ (tag (;0;) (type 0) (param i32))
+)
diff --git a/benchmarks/wasm/wasmfx/cont1.wat b/benchmarks/wasm/wasmfx/cont1.wat
new file mode 100644
index 0000000..592fe64
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont1.wat
@@ -0,0 +1,12 @@
+;; Check that continuations can be made from all basic primitives types
+(module
+ (type $func1 (func (param i32)))
+ (type $func2 (func (param i64)))
+ (type $func3 (func (param f32)))
+ (type $func4 (func (param f64)))
+ (type $cont1 (cont $func1))
+ (type $cont2 (cont $func2))
+ (type $cont3 (cont $func3))
+ (type $cont4 (cont $func4))
+ (tag $tag1 (param i32))
+)
diff --git a/benchmarks/wasm/wasmfx/cont_bind3.bin.wast b/benchmarks/wasm/wasmfx/cont_bind3.bin.wast
new file mode 100644
index 0000000..518c6c0
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont_bind3.bin.wast
@@ -0,0 +1,13 @@
+(module binary
+ "\00\61\73\6d\01\00\00\00\01\91\80\80\80\00\05\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7f\01\7f\03"
+ "\83\80\80\80\00\02\02\04\06\86\80\80\80\00\01\7f"
+ "\01\41\0b\0b\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\a1\80"
+ "\80\80\00\02\86\80\80\80\00\00\20\00\24\00\0b\90"
+ "\80\80\80\00\00\20\00\d2\00\e0\03\e1\03\01\e3\01"
+ "\00\23\00\0b"
+)
+;; (module instance)
+(assert_return (invoke "main" (i32.const 0x16)) (i32.const 0x16))
+(assert_return (invoke "main" (i32.const 0xffff_fe44)) (i32.const 0xffff_fe44))
diff --git a/benchmarks/wasm/wasmfx/cont_bind4.bin.wast b/benchmarks/wasm/wasmfx/cont_bind4.bin.wast
new file mode 100644
index 0000000..3c93687
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont_bind4.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\03\83\80\80"
+ "\80\00\02\02\02\07\88\80\80\80\00\01\04\6d\61\69"
+ "\6e\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\a0"
+ "\80\80\80\00\02\87\80\80\80\00\00\20\00\41\2c\6a"
+ "\0b\8e\80\80\80\00\00\20\00\d2\00\e0\03\e1\03\01"
+ "\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x16)) (i32.const 0x42))
+(assert_return (invoke "main" (i32.const 0xffff_fe44)) (i32.const 0xffff_fe70))
diff --git a/benchmarks/wasm/wasmfx/cont_bind4.wast b/benchmarks/wasm/wasmfx/cont_bind4.wast
new file mode 100644
index 0000000..214a287
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont_bind4.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (func $add44 (param i32) (result i32) (i32.add (local.get 0) (i32.const 44)))
+ (elem declare func $add44)
+
+ (func (export "main") (param i32) (result i32)
+ (resume $c1
+ (cont.bind $c2 $c1
+ (local.get 0)
+ (cont.new $c2 (ref.func $add44))))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22)) (i32.const 66))
+(assert_return (invoke "main" (i32.const -444)) (i32.const -400))
+
diff --git a/benchmarks/wasm/wasmfx/cont_bind5-strip.wast b/benchmarks/wasm/wasmfx/cont_bind5-strip.wast
new file mode 100644
index 0000000..4e56e37
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont_bind5-strip.wast
@@ -0,0 +1,31 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (param i32 i32) (result i32)))
+ (type (;3;) (cont 2))
+ (type (;4;) (func (param i32)))
+ (type (;5;) (func))
+ (import "spectest" "print_i32" (func (;0;) (type 4)))
+ (export "main" (func 3))
+ (start 3)
+ (elem (;0;) declare func 1)
+ (func (;1;) (type 2) (param i32 i32) (result i32)
+ local.get 0
+ local.get 1
+ i32.sub
+ )
+ (func (;2;) (type 2) (param i32 i32) (result i32)
+ local.get 1
+ local.get 0
+ ref.func 1
+ cont.new 3
+ cont.bind 3 1
+ resume 1
+ )
+ (func (;3;) (type 5)
+ i32.const 22
+ i32.const 44
+ call 2
+ call 0
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/cont_bind5.bin.wast b/benchmarks/wasm/wasmfx/cont_bind5.bin.wast
new file mode 100644
index 0000000..3f710ca
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont_bind5.bin.wast
@@ -0,0 +1,18 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\01\7f\01\7f\5d\00\60\02\7f\7f\01\7f\5d\02\03\83"
+ "\80\80\80\00\02\02\02\07\88\80\80\80\00\01\04\6d"
+ "\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00"
+ "\0a\a2\80\80\80\00\02\87\80\80\80\00\00\20\00\20"
+ "\01\6b\0b\90\80\80\80\00\00\20\01\20\00\d2\00\e0"
+ "\03\e1\03\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i32.const 0x16) (i32.const 0x2c))
+ (i32.const 0xffff_ffea)
+)
+(assert_return
+ (invoke "main" (i32.const 0xffff_fe44) (i32.const 0x6f))
+ (i32.const 0xffff_fdd5)
+)
diff --git a/benchmarks/wasm/wasmfx/cont_bind5.wast b/benchmarks/wasm/wasmfx/cont_bind5.wast
new file mode 100644
index 0000000..c003420
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/cont_bind5.wast
@@ -0,0 +1,25 @@
+(module
+;; (type $f1 (func (result i32)))
+;; (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i32 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i32 i32) (result i32) (i32.sub (local.get 0) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i32 i32) (result i32)
+ (resume $c2
+ (local.get 1)
+ (cont.bind $c3 $c2
+ (local.get 0)
+ (cont.new $c3 (ref.func $sub))))
+ )
+)
+
+;; (assert_return (invoke "main" (i32.const 22) (i32.const 44)) (i32.const -22))
+;; (assert_return (invoke "main" (i32.const -444) (i32.const 111)) (i32.const -555))
+
diff --git a/benchmarks/wasm/wasmfx/diff_handler.wast b/benchmarks/wasm/wasmfx/diff_handler.wast
new file mode 100644
index 0000000..1bc735b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/diff_handler.wast
@@ -0,0 +1,42 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (param i32)))
+ (import "spectest" "print_i32" (func (;0;) (type 2)))
+ (tag (;0;) (type 0))
+ (tag (;1;) (type 0))
+ (export "_start" (func 3))
+ (start 3)
+ (elem (;0;) declare func 1 2)
+ (func (;1;) (type 0)
+ suspend 0
+ suspend 1
+ )
+ (func (;2;) (type 0)
+ block ;; label = @1
+ block (result (ref 1)) ;; label = @2
+ ref.func 1
+ cont.new 1
+ resume 1 (on 0 0 (;@2;))
+ call 0
+ br 1 (;@1;)
+ end
+ i32.const 0
+ call 0
+ resume 1
+ end
+ )
+ (func (;3;) (type 0)
+ block ;; label = @1
+ block (result (ref 1)) ;; label = @2
+ ref.func 2
+ cont.new 1
+ resume 1 (on 1 0 (;@2;))
+ br 1 (;@1;)
+ end
+ drop
+ i32.const 1
+ call 0
+ end
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/diff_resume-strip.wat b/benchmarks/wasm/wasmfx/diff_resume-strip.wat
new file mode 100644
index 0000000..964aca3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/diff_resume-strip.wat
@@ -0,0 +1,53 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (result i32)))
+ (type (;3;) (func))
+ (import "spectest" "print_i32" (func (;0;) (type 0)))
+ (tag (;0;) (type 2) (result i32))
+ (export "_start" (func 2))
+ (start 2)
+ (elem (;0;) declare func 1)
+ (func (;1;) (type 0) (param i32)
+ local.get 0
+ call 0
+ suspend 0
+ call 0
+ )
+ (func (;2;) (type 3)
+ (local i32 (ref 1))
+ ref.func 1
+ cont.new 1
+ local.set 1
+ i32.const 10
+ local.set 0
+ block ;; label = @1
+ block (result (ref 1)) ;; label = @2
+ local.get 0
+ local.get 1
+ resume 1 (on 0 0 (;@2;))
+ i32.const -2
+ call 0
+ br 1 (;@1;)
+ end
+ local.set 1
+ local.get 0
+ i32.const 1
+ i32.add
+ local.set 0
+ block ;; label = @2
+ block (result (ref 1)) ;; label = @3
+ local.get 0
+ local.get 1
+ resume 1 (on 0 0 (;@3;))
+ i32.const 42
+ call 0
+ br 1 (;@2;)
+ end
+ i32.const 111
+ call 0
+ drop
+ end
+ end
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/diff_resume.wast b/benchmarks/wasm/wasmfx/diff_resume.wast
new file mode 100644
index 0000000..80b20ef
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/diff_resume.wast
@@ -0,0 +1,52 @@
+(module
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+ (type $task (func (param i32)))
+ (type $cont (cont $task))
+
+ (tag $yield (result i32))
+
+ (func $task1 (param $x i32)
+ (call $print_i32 (local.get $x))
+ (suspend $yield) ;; DH: levaes a continuation on the stack, jump to the tag $yield
+ ;; when come back, the stack should contains a i32 value, since the return type of $yield is i32
+ (call $print_i32)
+ )
+
+ (func $main (export "_start")
+ (local $i i32)
+ (local $k (ref $cont))
+ (local.set $k (cont.new $cont (ref.func $task1)))
+ (local.set $i (i32.const 10))
+ (block $h
+ (block $on_yield (result (ref $cont))
+ (resume $cont
+ (on $yield $on_yield)
+ (local.get $i)
+ (local.get $k)
+ )
+ (call $print_i32 (i32.const -2))
+ (br $h))
+ ;; $on_yield lands here, with the continuation on the stack
+ (local.set $k)
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
+ (block $h
+ (block $on_yield2 (result (ref $cont))
+ (resume $cont
+ (on $yield $on_yield2)
+ (local.get $i)
+ (local.get $k)
+ )
+ (call $print_i32 (i32.const 42))
+ (br $h)
+ )
+ ;; $on_yield2 lands here, with the continuation on the stack
+ (call $print_i32 (i32.const 111))
+ drop
+ )
+ )
+ )
+
+ (elem declare func $task1)
+
+ (start $main)
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/fun-pipes-strip.wast b/benchmarks/wasm/wasmfx/fun-pipes-strip.wast
new file mode 100644
index 0000000..621d789
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-pipes-strip.wast
@@ -0,0 +1,116 @@
+(module
+ (type (;0;) (func (result i32)))
+ (type (;1;) (func (param i32) (result i32)))
+ (type (;2;) (cont 0))
+ (type (;3;) (cont 1))
+ (type (;4;) (func (param i32)))
+ (type (;5;) (func (param i32 (ref 2) (ref 3))))
+ (type (;6;) (func (param (ref 3) (ref 2))))
+ (type (;7;) (func (result i32 (ref 2))))
+ (type (;8;) (func (param (ref 2) (ref 3))))
+ (type (;9;) (func))
+ ;; (import "spectest" "print_i32" (func (;0;) (type 4)))
+
+ (tag (;0;) (type 4) (param i32))
+ (tag (;1;) (type 0) (result i32))
+ (export "pipe" (func 3))
+ (export "run" (func 6))
+ (start 7)
+ (export "main" (func 7))
+ (elem (;0;) declare func 4 5)
+ (func (type 4) (param i32)
+ )
+
+ (func (;1;) (type 5) (param i32 (ref 2) (ref 3))
+ block (result (ref 3)) ;; label = @1
+ local.get 0
+ local.get 2
+ resume 3 (on 1 0 (;@1;))
+ return
+ end
+ local.set 2
+ local.get 2
+ local.get 1
+ return_call 2
+ )
+ (func (;2;) (type 6) (param (ref 3) (ref 2))
+ (local i32)
+ block (type 7) (result i32 (ref 2)) ;; label = @1
+ local.get 1
+ resume 2 (on 0 0 (;@1;))
+ return
+ end
+ local.set 1
+ local.set 2
+ local.get 2
+ local.get 1
+ local.get 0
+ return_call 1
+ )
+ (func (;3;) (type 8) (param (ref 2) (ref 3))
+ i32.const -1
+ local.get 0
+ local.get 1
+ call 1
+ )
+ (func (;4;) (type 1) (param i32) (result i32)
+ loop ;; label = @1
+ i32.const -1
+ call 0
+ local.get 0
+ call 0
+ local.get 0
+ suspend 0
+ i32.const 44444
+ call 0
+ local.get 0
+ i32.const 1
+ i32.add
+ local.set 0
+ br 0 (;@1;)
+ end
+ unreachable
+ )
+ (func (;5;) (type 1) (param i32) (result i32)
+ (local i32 i32)
+ i32.const 3
+ local.set 1
+ i32.const 0
+ local.set 2
+ loop ;; label = @1
+ local.get 2
+ suspend 1
+ i32.const 55555
+ call 0
+ i32.add
+ local.set 2
+ i32.const -2
+ call 0
+ local.get 2
+ call 0
+ local.get 1
+ i32.const 1
+ i32.sub
+ local.set 1
+ local.get 1
+ i32.const 0
+ i32.ne
+ br_if 0 (;@1;)
+ end
+ local.get 2
+ return
+ )
+ (func (;6;) (type 4) (param i32)
+ local.get 0
+ ref.func 4
+ cont.new 3
+ cont.bind 3 2
+ ref.func 5
+ cont.new 3
+ call 3
+ )
+ (func (;7;) (type 9)
+ i32.const 1
+ call 6
+ )
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/fun-pipes.bin.wast b/benchmarks/wasm/wasmfx/fun-pipes.bin.wast
new file mode 100644
index 0000000..0c91234
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-pipes.bin.wast
@@ -0,0 +1,27 @@
+(module definition $pipes binary
+ "\00\61\73\6d\01\00\00\00\01\b1\80\80\80\00\0a\60"
+ "\00\01\7f\60\01\7f\01\7f\5d\00\5d\01\60\01\7f\00"
+ "\60\03\7f\64\02\64\03\00\60\02\64\03\64\02\00\60"
+ "\00\02\7f\64\02\60\02\64\02\64\03\00\60\00\00\02"
+ "\96\80\80\80\00\01\08\73\70\65\63\74\65\73\74\09"
+ "\70\72\69\6e\74\5f\69\33\32\00\04\03\88\80\80\80"
+ "\00\07\05\06\08\01\01\04\09\0d\85\80\80\80\00\02"
+ "\00\04\00\00\07\8e\80\80\80\00\02\04\70\69\70\65"
+ "\00\03\03\72\75\6e\00\06\08\81\80\80\80\00\07\09"
+ "\86\80\80\80\00\01\03\00\02\04\05\0a\c4\81\80\80"
+ "\00\07\99\80\80\80\00\00\02\64\03\20\00\20\02\e3"
+ "\03\01\00\01\00\0f\0b\21\02\20\02\20\01\12\02\0b"
+ "\9c\80\80\80\00\01\01\7f\02\07\20\01\e3\02\01\00"
+ "\00\00\0f\0b\21\01\21\02\20\02\20\01\20\00\12\01"
+ "\0b\8a\80\80\80\00\00\41\7f\20\00\20\01\10\01\0b"
+ "\9b\80\80\80\00\00\03\40\41\7f\10\00\20\00\10\00"
+ "\20\00\e2\00\20\00\41\01\6a\21\00\0c\00\0b\00\0b"
+ "\af\80\80\80\00\01\02\7f\41\0a\21\01\41\00\21\02"
+ "\03\40\20\02\e2\01\6a\21\02\41\7e\10\00\20\02\10"
+ "\00\20\01\41\01\6b\21\01\20\01\41\00\47\0d\00\0b"
+ "\20\02\0f\0b\91\80\80\80\00\00\20\00\d2\04\e0\03"
+ "\e1\03\02\d2\05\e0\03\10\03\0b\86\80\80\80\00\00"
+ "\41\00\10\06\0b"
+)
+(module instance $pipes $pipes)
+(invoke "run" (i32.const 0x0))
diff --git a/benchmarks/wasm/wasmfx/fun-pipes.wast b/benchmarks/wasm/wasmfx/fun-pipes.wast
new file mode 100644
index 0000000..6759b7e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-pipes.wast
@@ -0,0 +1,82 @@
+
+;; Simple pipes example (functional version)
+;; modified for just a single module
+(module $pipes
+ (type $pfun (func (result i32)))
+ (type $cfun (func (param i32) (result i32)))
+ (type $producer (cont $pfun))
+ (type $consumer (cont $cfun))
+
+ (start $main)
+
+ (func $log (import "spectest" "print_i32") (param i32))
+ (tag $send (param i32))
+ (tag $receive (result i32))
+
+
+ (func $piper (param $n i32) (param $p (ref $producer)) (param $c (ref $consumer))
+ (block $on-receive (result (ref $consumer))
+ (resume $consumer (on $receive $on-receive) (local.get $n) (local.get $c))
+ (return)
+ ) ;; receive
+ (local.set $c)
+ (return_call $copiper (local.get $c) (local.get $p))
+ )
+
+ (func $copiper (param $c (ref $consumer)) (param $p (ref $producer))
+ (local $n i32)
+ (block $on-send (result i32 (ref $producer))
+ (resume $producer (on $send $on-send) (local.get $p))
+ (return)
+ ) ;; send
+ (local.set $p)
+ (local.set $n)
+ (return_call $piper (local.get $n) (local.get $p) (local.get $c))
+ )
+
+ (func $pipe (export "pipe") (param $p (ref $producer)) (param $c (ref $consumer))
+ (call $piper (i32.const -1) (local.get $p) (local.get $c))
+ )
+
+ (elem declare func $nats $sum)
+
+ ;; send n, n+1, ...
+ (func $nats (param $n i32) (result i32)
+ (loop $l
+ (call $log (i32.const -1))
+ (call $log (local.get $n))
+ (suspend $send (local.get $n))
+ (local.set $n (i32.add (local.get $n) (i32.const 1)))
+ (br $l)
+ )
+ (unreachable)
+ )
+
+ ;; receive 10 nats and return their sum
+ (func $sum (param $dummy i32) (result i32)
+ (local $i i32)
+ (local $a i32)
+ (local.set $i (i32.const 10))
+ (local.set $a (i32.const 0))
+ (loop $l
+ (local.set $a (i32.add (local.get $a) (suspend $receive)))
+ (call $log (i32.const -2))
+ (call $log (local.get $a))
+ (local.set $i (i32.sub (local.get $i) (i32.const 1)))
+ (br_if $l (i32.ne (local.get $i) (i32.const 0)))
+ )
+ (return (local.get $a))
+ )
+
+ (func $run (export "run") (param $n i32)
+ (call $pipe (cont.bind $consumer $producer (local.get $n) (cont.new $consumer (ref.func $nats)))
+ (cont.new $consumer (ref.func $sum))
+ )
+ )
+ (func $main
+ (call $run (i32.const 0))
+ )
+
+)
+
+(invoke "run" (i32.const 0))
diff --git a/benchmarks/wasm/wasmfx/fun-state-strip.wat b/benchmarks/wasm/wasmfx/fun-state-strip.wat
new file mode 100644
index 0000000..3a05afa
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-state-strip.wat
@@ -0,0 +1,59 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (func (result i32)))
+ (type (;2;) (cont 0))
+ (type (;3;) (cont 1))
+ (type (;4;) (func (param i32)))
+ (type (;5;) (func (param (ref 2) i32) (result i32)))
+ (type (;6;) (func (result i32 (ref 3))))
+ (type (;7;) (func (param i32 (ref 3)) (result i32)))
+ (tag (;0;) (type 1) (result i32))
+ (tag (;1;) (type 4) (param i32))
+ (export "main" (func 3))
+ (start 3)
+ (elem (;0;) declare func 2)
+ (func (;0;) (type 5) (param (ref 2) i32) (result i32)
+ block (result (ref 2)) ;; label = @1
+ block (type 6) (result i32 (ref 3)) ;; label = @2
+ local.get 1
+ local.get 0
+ resume 2 (on 0 1 (;@1;)) (on 1 0 (;@2;))
+ return
+ end
+ return_call 1
+ end
+ local.get 1
+ return_call 0
+ )
+ (func (;1;) (type 7) (param i32 (ref 3)) (result i32)
+ block (result (ref 2)) ;; label = @1
+ block (type 6) (result i32 (ref 3)) ;; label = @2
+ local.get 1
+ resume 3 (on 0 1 (;@1;)) (on 1 0 (;@2;))
+ return
+ end
+ return_call 1
+ end
+ local.get 0
+ return_call 0
+ )
+ (func (;2;) (type 1) (result i32)
+ i32.const 7
+ suspend 1
+ suspend 0
+ i32.const 2
+ i32.const 3
+ suspend 1
+ i32.const 3
+ suspend 0
+ i32.add
+ i32.mul
+ i32.add
+ )
+ (func (;3;) (type 1) (result i32)
+ i32.const 0
+ ref.func 2
+ cont.new 3
+ call 1
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/fun-state.bin.wast b/benchmarks/wasm/wasmfx/fun-state.bin.wast
new file mode 100644
index 0000000..fe7d9b3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-state.bin.wast
@@ -0,0 +1,18 @@
+(module definition $state binary
+ "\00\61\73\6d\01\00\00\00\01\a6\80\80\80\00\08\60"
+ "\01\7f\01\7f\60\00\01\7f\5d\00\5d\01\60\01\7f\00"
+ "\60\02\64\02\7f\01\7f\60\00\02\7f\64\03\60\02\7f"
+ "\64\03\01\7f\03\85\80\80\80\00\04\05\07\01\01\0d"
+ "\85\80\80\80\00\02\00\01\00\04\07\87\80\80\80\00"
+ "\01\03\72\75\6e\00\03\09\85\80\80\80\00\01\03\00"
+ "\01\02\0a\ec\80\80\80\00\04\9d\80\80\80\00\00\02"
+ "\64\02\02\06\20\01\20\00\e3\02\02\00\00\01\00\01"
+ "\00\0f\0b\12\01\0b\20\01\12\00\0b\9b\80\80\80\00"
+ "\00\02\64\02\02\06\20\01\e3\03\02\00\00\01\00\01"
+ "\00\0f\0b\12\01\0b\20\00\12\00\0b\95\80\80\80\00"
+ "\00\41\07\e2\01\e2\00\41\02\41\03\e2\01\41\03\e2"
+ "\00\6a\6c\6a\0b\8a\80\80\80\00\00\41\00\d2\02\e0"
+ "\03\10\01\0b"
+)
+(module instance $state $state)
+(assert_return (invoke "run") (i32.const 0x13))
diff --git a/benchmarks/wasm/wasmfx/fun-state.strip.wat b/benchmarks/wasm/wasmfx/fun-state.strip.wat
new file mode 100644
index 0000000..3996404
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-state.strip.wat
@@ -0,0 +1,59 @@
+(module $state
+ (type $gf (;0;) (func (param i32) (result i32)))
+ (type $sf (;1;) (func (result i32)))
+ (type $gk (;2;) (cont $gf))
+ (type $sk (;3;) (cont $sf))
+ (type (;4;) (func (param i32)))
+ (type (;5;) (func (param (ref $gk) i32) (result i32)))
+ (type (;6;) (func (result i32 (ref $sk))))
+ (type (;7;) (func (param i32 (ref $sk)) (result i32)))
+ (tag $get (;0;) (type $sf) (result i32))
+ (tag $set (;1;) (type 4) (param i32))
+ ;; (export "run" (func $run))
+ (export "main" (func $run))
+ (elem (;0;) declare func $f)
+ (func $getting (;0;) (type 5) (param $k (ref $gk)) (param $s i32) (result i32)
+ block $on_get (result (ref $gk))
+ block $on_set (type 6) (result i32 (ref $sk))
+ local.get $s
+ local.get $k
+ resume $gk (on $get $on_get) (on $set $on_set)
+ return
+ end
+ return_call $setting
+ end
+ local.get $s
+ return_call $getting
+ )
+ (func $setting (;1;) (type 7) (param $s i32) (param $k (ref $sk)) (result i32)
+ block $on_get (result (ref $gk))
+ block $on_set (type 6) (result i32 (ref $sk))
+ local.get $k
+ resume $sk (on $get $on_get) (on $set $on_set)
+ return
+ end
+ return_call $setting
+ end
+ local.get $s
+ return_call $getting
+ )
+ (func $f (;2;) (type $sf) (result i32)
+ i32.const 7
+ suspend $set
+ suspend $get
+ i32.const 2
+ i32.const 3
+ suspend $set
+ i32.const 3
+ suspend $get
+ i32.add
+ i32.mul
+ i32.add
+ )
+ (func $run (;3;) (type $sf) (result i32)
+ i32.const 0
+ ref.func $f
+ cont.new $sk
+ call $setting
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/fun-state.wast b/benchmarks/wasm/wasmfx/fun-state.wast
new file mode 100644
index 0000000..c5d8712
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/fun-state.wast
@@ -0,0 +1,61 @@
+;; Simple state example - functional with heterogeneous continuations
+(module $state
+ (tag $get (result i32))
+ (tag $set (param i32))
+
+ (type $gf (func (param i32) (result i32)))
+ (type $sf (func (result i32)))
+
+ (type $gk (cont $gf))
+ (type $sk (cont $sf))
+
+ (func $getting (param $k (ref $gk)) (param $s i32) (result i32)
+ (block $on_get (result (ref $gk))
+ (block $on_set (result i32 (ref $sk))
+ (resume $gk (on $get $on_get) (on $set $on_set)
+ (local.get $s) (local.get $k)
+ )
+ (return)
+ ) ;; $on_set (result i32 (ref $sk))
+ (return_call $setting)
+ ) ;; $on_get (result (ref $gk))
+ (local.get $s)
+ (return_call $getting)
+ )
+
+ (func $setting (param $s i32) (param $k (ref $sk)) (result i32)
+ (block $on_get (result (ref $gk))
+ (block $on_set (result i32 (ref $sk))
+ (resume $sk (on $get $on_get) (on $set $on_set)
+ (local.get $k)
+ )
+ (return)
+ ) ;; $on_set (result i32 (ref $sk))
+ (return_call $setting)
+ ) ;; $on_get (result (ref $gk))
+ (local.get $s)
+ (return_call $getting)
+ )
+
+ (func $f (result i32)
+ (suspend $set (i32.const 7))
+ (i32.add
+ (suspend $get)
+ (i32.mul
+ (i32.const 2)
+ (suspend $set (i32.const 3))
+ (i32.add
+ (i32.const 3)
+ (suspend $get)
+ )
+ )
+ )
+ )
+
+ (elem declare func $f)
+ (func $run (export "run") (result i32)
+ (call $setting (i32.const 0) (cont.new $sk (ref.func $f)))
+ )
+)
+
+(assert_return (invoke "run") (i32.const 19))
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/gen-stripped.wast b/benchmarks/wasm/wasmfx/gen-stripped.wast
new file mode 100644
index 0000000..83c9fed
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/gen-stripped.wast
@@ -0,0 +1,42 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (param i32)))
+ (type (;3;) (func (result i32 (ref 1))))
+ (import "spectest" "print_i32" (func (;0;) (type 2)))
+ (tag (;0;) (type 2) (param i32))
+ (start 2)
+ (elem (;0;) declare func 1)
+ (func (;1;) (type 0)
+ (local i32)
+ i32.const 100
+ local.set 0
+ loop ;; label = @1
+ local.get 0
+ suspend 0
+ local.get 0
+ i32.const 1
+ i32.sub
+ local.tee 0
+ br_if 0 (;@1;)
+ end
+ )
+ (func (;2;) (type 0)
+ (local (ref 1))
+ ref.func 1
+ cont.new 1
+ local.set 0
+ loop ;; label = @1
+ block (result i32 (ref 1)) ;; label = @2
+ local.get 0
+ resume 1 (on 0 0 (;@2;)) ;; wasmfx ref interpreter has a bug on this, you can add a bracket around `resume ..` to get around
+ i32.const 42
+ call 0
+ br 2 (;@2;)
+ end
+ local.set 0
+ call 0
+ br 0 (;@1;)
+ end
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/gen-stripped.wat b/benchmarks/wasm/wasmfx/gen-stripped.wat
new file mode 100644
index 0000000..0579335
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/gen-stripped.wat
@@ -0,0 +1,40 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (param i32)))
+ (type (;3;) (func (result i32 (ref 1))))
+ (import "spectest" "print_i32" (func (;0;) (type 2)))
+ (tag (;0;) (type 2) (param i32))
+ (start 2)
+ (elem (;0;) declare func 1)
+ (func (;1;) (type 0)
+ (local i32)
+ i32.const 100
+ local.set 0
+ loop ;; label = @1
+ local.get 0
+ suspend 0
+ local.get 0
+ i32.const 1
+ i32.sub
+ local.tee 0
+ br_if 0 (;@1;)
+ end
+ )
+ (func (;2;) (type 0)
+ (local (ref 1))
+ ref.func 1
+ cont.new 1
+ local.set 0
+ loop ;; label = @1
+ block (type 3) (result i32 (ref 1)) ;; label = @2
+ local.get 0
+ resume 1 (on 0 0 (;@2;))
+ return
+ end
+ local.set 0
+ call 0
+ br 0 (;@1;)
+ end
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/gen.wat b/benchmarks/wasm/wasmfx/gen.wat
new file mode 100644
index 0000000..29367f3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/gen.wat
@@ -0,0 +1,52 @@
+(module $generator
+ (type $ft (func))
+ ;; Types of continuations used by the generator:
+ ;; No need for param or result types: No data passed back to the
+ ;; generator when resuming it, and $generator function has no return
+ ;; values.
+ (type $ct (cont $ft))
+ (func $print (import "spectest" "print_i32") (param i32))
+
+ ;; Tag used to coordinate between generator and consumer: The i32 param
+ ;; corresponds to the generated values passed; no values passed back from
+ ;; generator to consumer.
+ (tag $gen (param i32))
+
+ ;; Simple generator yielding values from 100 down to 1
+ (func $generator
+ (local $i i32)
+ (local.set $i (i32.const 100))
+ (loop $l
+ ;; Suspend execution, pass current value of $i to consumer
+ (suspend $gen (local.get $i))
+ ;; Decrement $i and exit loop once $i reaches 0
+ (local.tee $i (i32.sub (local.get $i) (i32.const 1)))
+ (br_if $l)
+ )
+ )
+ (elem declare func $generator)
+
+ (func $consumer
+ (local $c (ref $ct))
+ ;; Create continuation executing function $generator.
+ ;; Execution only starts when resumed for the first time.
+ (local.set $c (cont.new $ct (ref.func $generator)))
+
+ (loop $loop
+ (block $on_gen (result i32 (ref $ct))
+ ;; Resume continuation $c
+ (resume $ct (on $gen $on_gen) (local.get $c))
+ ;; $generator returned: no more data
+ (return)
+ )
+ ;; Generator suspended, stack now contains [i32 (ref $ct)]
+ ;; Save continuation to resume it in the next iteration
+ (local.set $c)
+ ;; Stack now contains the i32 value produced by $generator
+ (call $print)
+
+ (br $loop)
+ )
+ )
+ (start $consumer)
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/nested-strip.wat b/benchmarks/wasm/wasmfx/nested-strip.wat
new file mode 100644
index 0000000..c7c58c5
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/nested-strip.wat
@@ -0,0 +1,54 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func))
+ (type (;3;) (cont 2))
+ (type (;4;) (func (param i32)))
+ (import "spectest" "print_i32" (func (;0;) (type 4)))
+ (tag (;0;) (type 0))
+ (export "main" (func 4))
+ (start 4)
+ (elem (;0;) declare func 1)
+ (elem (;1;) declare func 2)
+ (func (;1;) (type 0)
+ i32.const 111
+ call 0
+ suspend 0
+ i32.const 333
+ call 0
+ )
+ (func (;2;) (type 0)
+ i32.const 0
+ call 0
+ ref.func 1
+ cont.new 1
+ resume 1
+ i32.const 444
+ call 0
+ return
+ )
+ (func (;3;) (type 0)
+ block (result (ref null 3)) ;; label = @1
+ ref.func 2
+ cont.new 1
+ resume 1 (on 0 0 (;@1;))
+ i32.const 404
+ call 0
+ return
+ end
+ i32.const 222
+ call 0
+ resume 3
+ i32.const 555
+ call 0
+ )
+ (func (;4;) (type 0)
+ i32.const 0
+ call 0
+ ref.func 3
+ cont.new 1
+ resume 1
+ i32.const 666
+ call 0
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/nested.wast b/benchmarks/wasm/wasmfx/nested.wast
new file mode 100644
index 0000000..4591d0b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/nested.wast
@@ -0,0 +1,41 @@
+(module
+ (type $f (func))
+ (type $c (cont $f))
+ (type $fb (func))
+ (type $cb (cont $fb))
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+ (tag $fetch)
+ (start $main)
+
+ (func $func_b
+ (call $print_i32 (i32.const 111))
+ (suspend $fetch)
+ (call $print_i32 (i32.const 333))
+ )
+ (elem declare func $func_b)
+
+ (func $func_a
+ (call $print_i32 (i32.const 000))
+ (resume $c (cont.new $c (ref.func $func_b)))
+ (call $print_i32 (i32.const 444))
+ (return)
+ )
+ (elem declare func $func_a)
+
+ (func $func_c
+ (block (result (ref null $cb))
+ (resume $c (on $fetch 0) (cont.new $c (ref.func $func_a)))
+ (call $print_i32 (i32.const 404))
+ (return)
+ )
+ (call $print_i32 (i32.const 222))
+ (resume $cb)
+ (call $print_i32 (i32.const 555))
+ )
+
+ (func $main (export "main")
+ (call $print_i32 (i32.const 0))
+ (resume $c (cont.new $c (ref.func $func_c)))
+ (call $print_i32 (i32.const 666))
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/nested_resume-strip.wast b/benchmarks/wasm/wasmfx/nested_resume-strip.wast
new file mode 100644
index 0000000..b1356dd
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/nested_resume-strip.wast
@@ -0,0 +1,45 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func))
+ (type (;3;) (cont 2))
+ (type (;4;) (func (param i32)))
+ (import "spectest" "print_i32" (func (;0;) (type 4)))
+ (tag (;0;) (type 0))
+ (export "main" (func 3))
+ (start 3)
+ (elem (;0;) declare func 1)
+ (elem (;1;) declare func 2)
+ (func (;1;) (type 0)
+ i32.const 111
+ call 0
+ suspend 0
+ i32.const 333
+ call 0
+ )
+ (func (;2;) (type 0)
+ i32.const 0
+ call 0
+ ref.func 1
+ cont.new 1
+ resume 1
+ i32.const 444
+ call 0
+ return
+ )
+ (func (;3;) (type 0)
+ block (result (ref null 3)) ;; label = @1
+ ref.func 2
+ cont.new 1
+ resume 1 (on 0 0 (;@1;))
+ i32.const 404
+ call 0
+ return
+ end
+ i32.const 222
+ call 0
+ resume 3
+ i32.const 555
+ call 0
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/nested_resume-strip.wat b/benchmarks/wasm/wasmfx/nested_resume-strip.wat
new file mode 100644
index 0000000..86b35b9
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/nested_resume-strip.wat
@@ -0,0 +1,46 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func))
+ (type (;3;) (cont 2))
+ (type (;4;) (func (param i32)))
+ (import "spectest" "print_i32" (func (;0;) (type 4)))
+ (tag (;0;) (type 0))
+ (export "main" (func 3))
+ (start 3)
+ (elem (;0;) declare func 1)
+ (elem (;1;) declare func 2)
+
+ (func (;1;) (type 0)
+ i32.const 111
+ call 0 ;; output buffer [0, 111]
+ suspend 0
+ i32.const 333 ;; output buffer [0, 111, 222, 333]
+ call 0
+ )
+
+ (func (;2;) (type 0)
+ i32.const 0
+ call 0 ;; output buffer: [0]
+ ref.func 1
+ cont.new 1
+ resume 1
+ i32.const 444 ;; output buffer [0, 111, 222, 333, 444]
+ call 0
+ return
+ )
+
+ (func (;3;) (type 0)
+ block (result (ref null 3)) ;; label = @1
+ ref.func 2
+ cont.new 1
+ resume 1 (on 0 0 (;@1;))
+ unreachable
+ end
+ i32.const 222
+ call 0 ;; output buffer [0, 111, 222]
+ resume 3
+ i32.const 555 ;; output buffer [0, 111, 222, 333, 444, 555]
+ call 0
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/nested_resume.wast b/benchmarks/wasm/wasmfx/nested_resume.wast
new file mode 100644
index 0000000..2136b0d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/nested_resume.wast
@@ -0,0 +1,35 @@
+(module
+ (type $f (func))
+ (type $c (cont $f))
+ (type $fb (func))
+ (type $cb (cont $fb))
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+ (tag $fetch)
+ (start $main)
+
+ (func $func_b
+ (call $print_i32 (i32.const 111))
+ (suspend $fetch)
+ (call $print_i32 (i32.const 333))
+ )
+ (elem declare func $func_b)
+
+ (func $func_a
+ (call $print_i32 (i32.const 000))
+ (resume $c (cont.new $c (ref.func $func_b)))
+ (call $print_i32 (i32.const 444))
+ (return)
+ )
+ (elem declare func $func_a)
+
+ (func $main (export "main")
+ (block (result (ref null $cb))
+ (resume $c (on $fetch 0) (cont.new $c (ref.func $func_a)))
+ (call $print_i32 (i32.const 404))
+ (return)
+ )
+ (call $print_i32 (i32.const 222))
+ (resume $cb)
+ (call $print_i32 (i32.const 555))
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/nested_suspend-strip.wat b/benchmarks/wasm/wasmfx/nested_suspend-strip.wat
new file mode 100644
index 0000000..ab5e2bd
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/nested_suspend-strip.wat
@@ -0,0 +1,39 @@
+(module
+ (type (;0;) (func))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (param i32)))
+ (import "spectest" "print_i32" (func (;0;) (type 2)))
+ (tag (;0;) (type 0))
+ (export "_start" (func 3))
+ (start 3)
+ ;; (elem (;0;) declare func 1 2)
+ (func (;1;) (type 0)
+ suspend 0
+ )
+ (func (;2;) (type 0)
+ block ;; label = @1
+ block (result (ref 1)) ;; label = @2
+ ref.func 1
+ cont.new 1
+ resume 1 (on 0 0 (;@2;))
+ br 1 (;@1;)
+ end
+ drop
+ i32.const 0
+ call 0
+ end
+ )
+ (func (;3;) (type 0)
+ block ;; label = @1
+ block (result (ref 1)) ;; label = @2
+ ref.func 2
+ cont.new 1
+ resume 1 (on 0 0 (;@2;))
+ br 1 (;@1;)
+ end
+ drop
+ i32.const 1
+ call 0
+ end
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/resume1.bin.wast b/benchmarks/wasm/wasmfx/resume1.bin.wast
new file mode 100644
index 0000000..da7fa5d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/resume1.bin.wast
@@ -0,0 +1,12 @@
+(module binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\00\60\00\01\7f\02\96\80\80"
+ "\80\00\01\08\73\70\65\63\74\65\73\74\09\70\72\69"
+ "\6e\74\5f\69\33\32\00\02\03\83\80\80\80\00\02\00"
+ "\03\07\88\80\80\80\00\01\04\6d\61\69\6e\00\02\09"
+ "\85\80\80\80\00\01\03\00\01\01\0a\9e\80\80\80\00"
+ "\02\88\80\80\80\00\00\41\b2\f2\19\10\00\0b\8b\80"
+ "\80\80\00\00\d2\01\e0\01\e3\01\00\41\2a\0b"
+)
+;; (module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/resume1.wast b/benchmarks/wasm/wasmfx/resume1.wast
new file mode 100644
index 0000000..e285990
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/resume1.wast
@@ -0,0 +1,16 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+ (func $empty
+ i32.const 424242
+ call $print_i32
+ )
+ (elem declare func $empty)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $empty)))
+ i32.const 42
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/resume2.wat b/benchmarks/wasm/wasmfx/resume2.wat
new file mode 100644
index 0000000..86de1fa
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/resume2.wat
@@ -0,0 +1,9 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+ (func $f42 (result i32) (i32.const 42))
+ (elem declare func $f42)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ )
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/resume_chain1-strip.wast b/benchmarks/wasm/wasmfx/resume_chain1-strip.wast
new file mode 100644
index 0000000..047bf76
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/resume_chain1-strip.wast
@@ -0,0 +1,31 @@
+(module
+ (type (;0;) (func (param i32) (result i32)))
+ (type (;1;) (cont 0))
+ (export "main" (func 2))
+ ;; (elem (;0;) declare func 0 1)
+ (func (;0;) (type 0) (param i32) (result i32)
+ local.get 0
+ i32.const 10
+ i32.add
+ )
+ (func (;1;) (type 0) (param i32) (result i32)
+ local.get 0
+ i32.const 100
+ i32.add
+ ref.func 0
+ cont.new 1
+ resume 1
+ i32.const 1000
+ i32.add
+ )
+ (func (;2;) (type 0) (param i32) (result i32)
+ local.get 0
+ ref.func 1
+ cont.new 1
+ resume 1
+ )
+)
+
+(assert_return (invoke "main" (i32.const 4)) (i32.const 1114))
+(assert_return (invoke "main" (i32.const 5)) (i32.const 1115))
+(assert_return (invoke "main" (i32.const 9)) (i32.const 1119))
diff --git a/benchmarks/wasm/wasmfx/suspend16-strip.wast b/benchmarks/wasm/wasmfx/suspend16-strip.wast
new file mode 100644
index 0000000..6a85ad3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/suspend16-strip.wast
@@ -0,0 +1,45 @@
+(module
+ (type (;0;) (func (result i32)))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (param i32) (result i32)))
+ (type (;3;) (cont 2))
+ (type (;4;) (func))
+ (type (;5;) (func (param i32)))
+ (import "spectest" "print_i32" (func (;0;) (type 5)))
+ (tag (;0;) (type 4))
+ (tag (;1;) (type 0) (result i32))
+ (start 4)
+ (elem (;0;) declare func 1)
+ (elem (;1;) declare func 2)
+ (func (;1;) (type 0) (result i32)
+ suspend 1
+ i32.const 111
+ call 0
+ i32.const 78
+ )
+ (func (;2;) (type 0) (result i32)
+ ref.func 1
+ cont.new 1
+ resume 1
+ i32.const 100
+ call 0
+ i32.const 10
+ i32.add
+ return
+ )
+ (func (;3;) (type 0) (result i32)
+ i32.const 78
+ block (result (ref null 3)) ;; label = @1
+ ref.func 2
+ cont.new 1
+ resume 1 (on 1 0 (;@1;))
+ i32.const 404
+ return
+ end
+ resume 3
+ )
+ (func
+ call 3
+ call 0
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/suspend16.bin.wast b/benchmarks/wasm/wasmfx/suspend16.bin.wast
new file mode 100644
index 0000000..aeb8d7a
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/suspend16.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\91\80\80\80\00\05\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\60\00\00\03"
+ "\84\80\80\80\00\03\00\00\00\0d\85\80\80\80\00\02"
+ "\00\04\00\00\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\02\09\89\80\80\80\00\02\03\00\01\00\03\00\01"
+ "\01\0a\bb\80\80\80\00\03\84\80\80\80\00\00\e2\01"
+ "\0b\8d\80\80\80\00\00\d2\00\e0\01\e3\01\00\41\0a"
+ "\6a\0f\0b\9a\80\80\80\00\00\41\ce\00\02\63\03\d2"
+ "\01\e0\01\e3\01\01\00\01\00\41\94\03\0f\0b\e3\03"
+ "\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x58))
diff --git a/benchmarks/wasm/wasmfx/suspend16.wast b/benchmarks/wasm/wasmfx/suspend16.wast
new file mode 100644
index 0000000..da968d8
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/suspend16.wast
@@ -0,0 +1,31 @@
+(module
+ (type $f (func (result i32)))
+ (type $c (cont $f))
+ (type $fb (func (param i32) (result i32)))
+ (type $cb (cont $fb))
+ (tag $dummy)
+ (tag $fetch (result i32))
+ ;; (import "spectest" "print_i32" (func $print (param i32)))
+
+ (func $func_b (result i32)
+ (suspend $fetch)
+ )
+ (elem declare func $func_b)
+
+ (func $func_a (result i32)
+ (resume $c (cont.new $c (ref.func $func_b)))
+ (i32.add (i32.const 10))
+ (return)
+ )
+ (elem declare func $func_a)
+ (func (export "main") (result i32)
+ (i32.const 78)
+ (block (result (ref null $cb))
+ (resume $c (on $fetch 0) (cont.new $c (ref.func $func_a)))
+ (return (i32.const 404))
+ )
+ (resume $cb)
+ )
+)
+
+;; (assert_return (invoke "main") (i32.const 88))
diff --git a/benchmarks/wasm/wasmfx/test_cont-strip.wast b/benchmarks/wasm/wasmfx/test_cont-strip.wast
new file mode 100644
index 0000000..6e7eadb
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/test_cont-strip.wast
@@ -0,0 +1,71 @@
+(module
+ (type (;0;) (func (param i32)))
+ (type (;1;) (cont 0))
+ (type (;2;) (func (result i32)))
+ (type (;3;) (func (param i32 i32)))
+ (type (;4;) (func))
+ (import "spectest" "print_i32" (func (;0;) (type 0)))
+ (tag (;0;) (type 2) (result i32))
+ (export "_start" (func 4))
+ (start 4)
+ (elem (;0;) declare func 3)
+ (func (;1;) (type 0) (param i32)
+ local.get 0
+ call 0
+ suspend 0
+ call 0
+ )
+ (func (;2;) (type 3) (param i32 i32)
+ (local i32)
+ local.get 0
+ local.set 2
+ block ;; label = @1
+ loop ;; label = @2
+ local.get 2
+ local.get 1
+ i32.gt_u
+ br_if 1 (;@1;)
+ local.get 2
+ call 1
+ local.get 2
+ i32.const 1
+ i32.add
+ local.set 2
+ br 0 (;@2;)
+ end
+ end
+ )
+ (func (;3;) (type 0) (param i32)
+ local.get 0
+ i32.const 13
+ call 2
+ )
+ (func (;4;) (type 4)
+ (local (ref 1) i32)
+ ref.func 3
+ cont.new 1
+ local.set 0
+ i32.const 10
+ local.set 1
+ block ;; label = @1
+ loop ;; label = @2
+ block (result (ref 1)) ;; label = @3
+ local.get 1
+ local.get 0
+ resume 1 (on 0 0 (;@3;))
+ i32.const -2
+ call 0
+ br 2 (;@1;)
+ end
+ local.set 0
+ local.get 1
+ i32.const 1
+ i32.add
+ local.set 1
+ i32.const -1
+ call 0
+ br 0 (;@2;)
+ end
+ end
+ )
+)
diff --git a/benchmarks/wasm/wasmfx/test_cont.wast b/benchmarks/wasm/wasmfx/test_cont.wast
new file mode 100644
index 0000000..8f54088
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/test_cont.wast
@@ -0,0 +1,55 @@
+(module
+ (import "spectest" "print_i32" (func $print_i32 (param i32)))
+ (type $task (func (param i32)))
+ (type $cont (cont $task))
+
+ (tag $yield (result i32))
+ ;; DH: tag's input + continuation
+ ;; == block's output ((ref $cont))
+ ;; == the values on the stack after suspend
+ ;; tag's output
+ ;; == continuation's input
+ ;; == the values on the stack when suspended computation is resumed
+
+ (func $process (param $x i32)
+ (call $print_i32 (local.get $x))
+ (suspend $yield) ;; DH: levaes a continuation on the stack, jump to the tag $yield
+ ;; when come back, the stack should contains a i32 value, since the return type of $yield is i32
+ (call $print_i32))
+
+ (func $range (param $from i32) (param $to i32)
+ (local $i i32)
+ (local.set $i (local.get $from))
+ (block $b
+ (loop $l
+ (br_if $b (i32.gt_u (local.get $i) (local.get $to)))
+ (call $process (local.get $i))
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
+ (br $l))))
+
+ (func $task1 (param $x i32) (call $range (local.get $x) (i32.const 13)))
+
+ (func $main (export "_start")
+ (local $k (ref $cont))
+ (local $i i32)
+ (local.set $k (cont.new $cont (ref.func $task1)))
+ (local.set $i (i32.const 10))
+ (block $h
+ (loop $l
+ (block $on_yield (result (ref $cont))
+ (resume $cont
+ (on $yield $on_yield)
+ (local.get $i)
+ (local.get $k))
+ (call $print_i32 (i32.const -2)) ;; this code is executed only when no suspend is called in $k
+ (br $h))
+ ;; $on_yield lands here, with the continuation on the stack
+ (local.set $k) ;; grab the continuation and save it
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
+ (call $print_i32 (i32.const -1))
+ (br $l))))
+
+ (elem declare func $task1)
+
+ (start $main)
+)
\ No newline at end of file
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/TODO b/benchmarks/wasm/wasmfx/wizard-stack-switching/TODO
new file mode 100644
index 0000000..def2352
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/TODO
@@ -0,0 +1,15 @@
+- typechecking tests
+ - cont.new
+ - resume
+ - resume_throw
+ - suspend
+ - handlers
+ - cont.bind
+- passing parameters of GC types
+- order of arguments to resumes
+- more chains of resumes
+- more matching of tags for a suspend
+- suspends
+- nested suspends
+- throwing + catching on another stack
+- repeat all exception handling tests and systematically split the stacks?
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/build.sh b/benchmarks/wasm/wasmfx/wizard-stack-switching/build.sh
new file mode 100755
index 0000000..4fefbc7
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/build.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+SOURCE="${BASH_SOURCE[0]}"
+while [ -h "$SOURCE" ]; do
+ HERE="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
+ SOURCE="$(readlink "$SOURCE")"
+ [[ $SOURCE != /* ]] && SOURCE="$HERE/$SOURCE"
+done
+HERE="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
+
+cd $HERE
+
+export WIZENG_LOC=$(cd $HERE/../../../ && pwd)
+export SPEC_LOC=${SPEC_LOC:=$(cd $WIZENG_LOC/wasm-spec/repos/stack-switching && pwd)}
+
+if [ ! -d $SPEC_LOC ]; then
+ echo "WebAssembly specification repo not found: $SPEC_LOC"
+ exit 1
+fi
+
+../build.sh "$@"
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont0.bin.wast
new file mode 100644
index 0000000..4439c09
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont0.bin.wast
@@ -0,0 +1,6 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\99\80\80\80\00\08\60"
+ "\00\00\60\01\7f\00\60\00\01\7f\60\01\7f\01\7f\5d"
+ "\00\5d\01\5d\02\5d\03"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont0.wast
new file mode 100644
index 0000000..47d7f9e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont0.wast
@@ -0,0 +1,10 @@
+(module
+ (type $f1 (func))
+ (type $f2 (func (param i32)))
+ (type $f3 (func (result i32)))
+ (type $f4 (func (param i32) (result i32)))
+ (type $c1 (cont $f1))
+ (type $c2 (cont $f2))
+ (type $c3 (cont $f3))
+ (type $c4 (cont $f4))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont1.bin.wast
new file mode 100644
index 0000000..4a3f5ef
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont1.bin.wast
@@ -0,0 +1,6 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9f\80\80\80\00\0a\60"
+ "\01\7f\00\60\01\7e\00\60\01\7d\00\60\01\7c\00\60"
+ "\01\7b\00\5d\00\5d\01\5d\02\5d\03\5d\04"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont1.wast
new file mode 100644
index 0000000..35dbdcc
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont1.wast
@@ -0,0 +1,13 @@
+;; Check that continuations can be made from all basic primitives types
+(module
+ (type $func1 (func (param i32)))
+ (type $func2 (func (param i64)))
+ (type $func3 (func (param f32)))
+ (type $func4 (func (param f64)))
+ (type $func5 (func (param v128)))
+ (type $cont1 (cont $func1))
+ (type $cont2 (cont $func2))
+ (type $cont3 (cont $func3))
+ (type $cont4 (cont $func4))
+ (type $cont5 (cont $func5))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont2.bin.wast
new file mode 100644
index 0000000..797cee0
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont2.bin.wast
@@ -0,0 +1,7 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\a5\80\80\80\00\0c\60"
+ "\01\6e\00\60\01\6f\00\60\01\70\00\60\01\6b\00\60"
+ "\01\6a\00\60\01\6c\00\5d\00\5d\01\5d\02\5d\03\5d"
+ "\04\5d\05"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont2.wast
new file mode 100644
index 0000000..48736d0
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont2.wast
@@ -0,0 +1,15 @@
+;; Check that continuations can be made from all reference and simple GC types
+(module
+ (type $func1 (func (param anyref)))
+ (type $func2 (func (param externref)))
+ (type $func3 (func (param funcref)))
+ (type $func4 (func (param structref)))
+ (type $func5 (func (param arrayref)))
+ (type $func6 (func (param i31ref)))
+ (type $cont1 (cont $func1))
+ (type $cont2 (cont $func2))
+ (type $cont3 (cont $func3))
+ (type $cont4 (cont $func4))
+ (type $cont5 (cont $func5))
+ (type $cont6 (cont $func6))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind0.bin.wast
new file mode 100644
index 0000000..d6aa6e7
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind0.bin.wast
@@ -0,0 +1,9 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\82\80\80\80\00\01\00\07\88\80\80"
+ "\80\00\01\04\6d\61\69\6e\00\00\0a\91\80\80\80\00"
+ "\01\8b\80\80\80\00\01\01\63\01\20\00\e1\01\01\1a"
+ "\0b"
+)
+(module instance)
+(assert_trap (invoke "main") "null continuation")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind0.wast
new file mode 100644
index 0000000..e3127f4
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind0.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func (export "main")
+ (local $x (ref null $c1))
+ (cont.bind $c1 $c1 (local.get $x))
+ drop
+ )
+)
+
+(assert_trap (invoke "main") "null continuation")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind1.bin.wast
new file mode 100644
index 0000000..0a84c61
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind1.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\83\80\80\80\00\02\00\00\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\97\80\80\80\00\02\82\80\80"
+ "\80\00\00\0b\8a\80\80\80\00\00\d2\00\e0\01\e1\01"
+ "\01\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind1.wast
new file mode 100644
index 0000000..254ca02
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind1.wast
@@ -0,0 +1,13 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $nop)
+ (elem declare func $nop)
+
+ (func (export "main")
+ (cont.bind $c1 $c1 (cont.new $c1 (ref.func $nop)))
+ drop
+ )
+)
+
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind10.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind10.bin.wast
new file mode 100644
index 0000000..b8d3b30
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind10.bin.wast
@@ -0,0 +1,21 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\96\80\80\80\00\06\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\60\02\7e\7f"
+ "\01\7f\5d\04\03\83\80\80\80\00\02\04\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\c5\80\80\80\00\02\88\80\80"
+ "\80\00\00\20\00\a7\20\01\6b\0b\b2\80\80\80\00\03"
+ "\01\64\05\01\64\03\01\64\01\d2\00\e0\05\21\02\20"
+ "\00\20\02\e1\05\03\21\03\20\01\20\03\e1\03\01\21"
+ "\04\20\04\e3\01\00\41\f1\b1\7f\20\03\e3\03\00\1a"
+ "\0b"
+)
+(module instance)
+(assert_trap
+ (invoke "main" (i64.const 0x16) (i32.const 0x2c))
+ "continuation already consumed"
+)
+(assert_trap
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fe44) (i32.const 0x6f))
+ "continuation already consumed"
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind10.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind10.wast
new file mode 100644
index 0000000..cfa936e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind10.wast
@@ -0,0 +1,29 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i64 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i64 i32) (result i32) (i32.sub (i32.wrap_i64 (local.get 0)) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i64 i32) (result i32)
+ (local $x3 (ref $c3))
+ (local $x2 (ref $c2))
+ (local $x1 (ref $c1))
+ (local.set $x3 (cont.new $c3 (ref.func $sub)))
+ (local.set $x2 (cont.bind $c3 $c2 (local.get 0) (local.get $x3)))
+ (local.set $x1 (cont.bind $c2 $c1 (local.get 1) (local.get $x2)))
+
+ (resume $c1 (local.get $x1))
+ (drop (resume $c2 (i32.const -9999) (local.get $x2)))
+ )
+)
+
+(assert_trap (invoke "main" (i64.const 22) (i32.const 44)) "continuation already consumed")
+(assert_trap (invoke "main" (i64.const -444) (i32.const 111)) "continuation already consumed")
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind11.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind11.bin.wast
new file mode 100644
index 0000000..1e9b975
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind11.bin.wast
@@ -0,0 +1,21 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\96\80\80\80\00\06\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\60\02\7e\7f"
+ "\01\7f\5d\04\03\83\80\80\80\00\02\04\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\c9\80\80\80\00\02\88\80\80"
+ "\80\00\00\20\00\a7\20\01\6b\0b\b6\80\80\80\00\03"
+ "\01\64\05\01\64\03\01\64\01\d2\00\e0\05\21\02\20"
+ "\00\20\02\e1\05\03\21\03\20\01\20\03\e1\03\01\21"
+ "\04\20\04\e3\01\00\42\f1\b1\7f\41\c8\ba\7f\20\02"
+ "\e3\05\00\1a\0b"
+)
+(module instance)
+(assert_trap
+ (invoke "main" (i64.const 0x16) (i32.const 0x2c))
+ "continuation already consumed"
+)
+(assert_trap
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fe44) (i32.const 0x6f))
+ "continuation already consumed"
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind11.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind11.wast
new file mode 100644
index 0000000..2e31646
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind11.wast
@@ -0,0 +1,29 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i64 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i64 i32) (result i32) (i32.sub (i32.wrap_i64 (local.get 0)) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i64 i32) (result i32)
+ (local $x3 (ref $c3))
+ (local $x2 (ref $c2))
+ (local $x1 (ref $c1))
+ (local.set $x3 (cont.new $c3 (ref.func $sub)))
+ (local.set $x2 (cont.bind $c3 $c2 (local.get 0) (local.get $x3)))
+ (local.set $x1 (cont.bind $c2 $c1 (local.get 1) (local.get $x2)))
+
+ (resume $c1 (local.get $x1))
+ (drop (resume $c3 (i64.const -9999) (i32.const -8888) (local.get $x3)))
+ )
+)
+
+(assert_trap (invoke "main" (i64.const 22) (i32.const 44)) "continuation already consumed")
+(assert_trap (invoke "main" (i64.const -444) (i32.const 111)) "continuation already consumed")
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind2.bin.wast
new file mode 100644
index 0000000..a1e1f33
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind2.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\83\80\80\80\00\02\00\00\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\99\80\80\80\00\02\82\80\80"
+ "\80\00\00\0b\8c\80\80\80\00\00\d2\00\e0\01\e1\01"
+ "\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind2.wast
new file mode 100644
index 0000000..72a98b8
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind2.wast
@@ -0,0 +1,12 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $nop)
+ (elem declare func $nop)
+
+ (func (export "main")
+ (resume $c1 (cont.bind $c1 $c1 (cont.new $c1 (ref.func $nop))))
+ )
+)
+
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind3.bin.wast
new file mode 100644
index 0000000..5e76cc3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind3.bin.wast
@@ -0,0 +1,13 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\91\80\80\80\00\05\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7f\01\7f\03"
+ "\83\80\80\80\00\02\02\04\06\86\80\80\80\00\01\7f"
+ "\01\41\0b\0b\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\a1\80"
+ "\80\80\00\02\86\80\80\80\00\00\20\00\24\00\0b\90"
+ "\80\80\80\00\00\20\00\d2\00\e0\03\e1\03\01\e3\01"
+ "\00\23\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x16)) (i32.const 0x16))
+(assert_return (invoke "main" (i32.const 0xffff_fe44)) (i32.const 0xffff_fe44))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind3.wast
new file mode 100644
index 0000000..dd7b16e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind3.wast
@@ -0,0 +1,24 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32)))
+ (type $c2 (cont $f2))
+
+ (global $g1 (mut i32) (i32.const 11))
+
+ (func $set (param i32) (global.set $g1 (local.get 0)))
+ (elem declare func $set)
+
+ (func (export "main") (param i32) (result i32)
+ (resume $c1
+ (cont.bind $c2 $c1
+ (local.get 0)
+ (cont.new $c2 (ref.func $set))))
+ (global.get $g1)
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22)) (i32.const 22))
+(assert_return (invoke "main" (i32.const -444)) (i32.const -444))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind4.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind4.bin.wast
new file mode 100644
index 0000000..3c93687
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind4.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\03\83\80\80"
+ "\80\00\02\02\02\07\88\80\80\80\00\01\04\6d\61\69"
+ "\6e\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\a0"
+ "\80\80\80\00\02\87\80\80\80\00\00\20\00\41\2c\6a"
+ "\0b\8e\80\80\80\00\00\20\00\d2\00\e0\03\e1\03\01"
+ "\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x16)) (i32.const 0x42))
+(assert_return (invoke "main" (i32.const 0xffff_fe44)) (i32.const 0xffff_fe70))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind4.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind4.wast
new file mode 100644
index 0000000..214a287
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind4.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (func $add44 (param i32) (result i32) (i32.add (local.get 0) (i32.const 44)))
+ (elem declare func $add44)
+
+ (func (export "main") (param i32) (result i32)
+ (resume $c1
+ (cont.bind $c2 $c1
+ (local.get 0)
+ (cont.new $c2 (ref.func $add44))))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22)) (i32.const 66))
+(assert_return (invoke "main" (i32.const -444)) (i32.const -400))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind5.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind5.bin.wast
new file mode 100644
index 0000000..3f710ca
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind5.bin.wast
@@ -0,0 +1,18 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\01\7f\01\7f\5d\00\60\02\7f\7f\01\7f\5d\02\03\83"
+ "\80\80\80\00\02\02\02\07\88\80\80\80\00\01\04\6d"
+ "\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00"
+ "\0a\a2\80\80\80\00\02\87\80\80\80\00\00\20\00\20"
+ "\01\6b\0b\90\80\80\80\00\00\20\01\20\00\d2\00\e0"
+ "\03\e1\03\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i32.const 0x16) (i32.const 0x2c))
+ (i32.const 0xffff_ffea)
+)
+(assert_return
+ (invoke "main" (i32.const 0xffff_fe44) (i32.const 0x6f))
+ (i32.const 0xffff_fdd5)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind5.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind5.wast
new file mode 100644
index 0000000..d40aedf
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind5.wast
@@ -0,0 +1,25 @@
+(module
+;; (type $f1 (func (result i32)))
+;; (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i32 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i32 i32) (result i32) (i32.sub (local.get 0) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i32 i32) (result i32)
+ (resume $c2
+ (local.get 1)
+ (cont.bind $c3 $c2
+ (local.get 0)
+ (cont.new $c3 (ref.func $sub))))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22) (i32.const 44)) (i32.const -22))
+(assert_return (invoke "main" (i32.const -444) (i32.const 111)) (i32.const -555))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind6.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind6.bin.wast
new file mode 100644
index 0000000..2e63dac
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind6.bin.wast
@@ -0,0 +1,18 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\01\7e\01\7f\5d\00\60\02\7f\7e\01\7f\5d\02\03\83"
+ "\80\80\80\00\02\02\02\07\88\80\80\80\00\01\04\6d"
+ "\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00"
+ "\0a\a3\80\80\80\00\02\88\80\80\80\00\00\20\00\20"
+ "\01\a7\6b\0b\90\80\80\80\00\00\20\01\20\00\d2\00"
+ "\e0\03\e1\03\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i32.const 0x16) (i64.const 0x2c))
+ (i32.const 0xffff_ffea)
+)
+(assert_return
+ (invoke "main" (i32.const 0xffff_fe44) (i64.const 0x6f))
+ (i32.const 0xffff_fdd5)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind6.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind6.wast
new file mode 100644
index 0000000..7e619dd
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind6.wast
@@ -0,0 +1,25 @@
+(module
+;; (type $f1 (func (result i32)))
+;; (type $c1 (cont $f1))
+
+ (type $f2 (func (param i64) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i32 i64) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i32 i64) (result i32) (i32.sub (local.get 0) (i32.wrap_i64 (local.get 1))))
+ (elem declare func $sub)
+
+ (func (export "main") (param i32 i64) (result i32)
+ (resume $c2
+ (local.get 1)
+ (cont.bind $c3 $c2
+ (local.get 0)
+ (cont.new $c3 (ref.func $sub))))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22) (i64.const 44)) (i32.const -22))
+(assert_return (invoke "main" (i32.const -444) (i64.const 111)) (i32.const -555))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind7.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind7.bin.wast
new file mode 100644
index 0000000..9d0939c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind7.bin.wast
@@ -0,0 +1,18 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\01\7f\01\7f\5d\00\60\02\7e\7f\01\7f\5d\02\03\83"
+ "\80\80\80\00\02\02\02\07\88\80\80\80\00\01\04\6d"
+ "\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00"
+ "\0a\a3\80\80\80\00\02\88\80\80\80\00\00\20\00\a7"
+ "\20\01\6b\0b\90\80\80\80\00\00\20\01\20\00\d2\00"
+ "\e0\03\e1\03\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i64.const 0x16) (i32.const 0x2c))
+ (i32.const 0xffff_ffea)
+)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fe44) (i32.const 0x6f))
+ (i32.const 0xffff_fdd5)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind7.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind7.wast
new file mode 100644
index 0000000..bb8be34
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind7.wast
@@ -0,0 +1,25 @@
+(module
+;; (type $f1 (func (result i32)))
+;; (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i64 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i64 i32) (result i32) (i32.sub (i32.wrap_i64 (local.get 0)) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i64 i32) (result i32)
+ (resume $c2
+ (local.get 1)
+ (cont.bind $c3 $c2
+ (local.get 0)
+ (cont.new $c3 (ref.func $sub))))
+ )
+)
+
+(assert_return (invoke "main" (i64.const 22) (i32.const 44)) (i32.const -22))
+(assert_return (invoke "main" (i64.const -444) (i32.const 111)) (i32.const -555))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind8.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind8.bin.wast
new file mode 100644
index 0000000..860ea90
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind8.bin.wast
@@ -0,0 +1,19 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\96\80\80\80\00\06\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\60\02\7e\7f"
+ "\01\7f\5d\04\03\83\80\80\80\00\02\04\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\a6\80\80\80\00\02\88\80\80"
+ "\80\00\00\20\00\a7\20\01\6b\0b\93\80\80\80\00\00"
+ "\20\01\20\00\d2\00\e0\05\e1\05\03\e1\03\01\e3\01"
+ "\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i64.const 0x16) (i32.const 0x2c))
+ (i32.const 0xffff_ffea)
+)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fe44) (i32.const 0x6f))
+ (i32.const 0xffff_fdd5)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind8.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind8.wast
new file mode 100644
index 0000000..b648092
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind8.wast
@@ -0,0 +1,26 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i64 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i64 i32) (result i32) (i32.sub (i32.wrap_i64 (local.get 0)) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i64 i32) (result i32)
+ (resume $c1
+ (cont.bind $c2 $c1
+ (local.get 1)
+ (cont.bind $c3 $c2
+ (local.get 0)
+ (cont.new $c3 (ref.func $sub)))))
+ )
+)
+
+(assert_return (invoke "main" (i64.const 22) (i32.const 44)) (i32.const -22))
+(assert_return (invoke "main" (i64.const -444) (i32.const 111)) (i32.const -555))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind9.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind9.bin.wast
new file mode 100644
index 0000000..11b3cdb
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind9.bin.wast
@@ -0,0 +1,20 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\96\80\80\80\00\06\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\60\02\7e\7f"
+ "\01\7f\5d\04\03\83\80\80\80\00\02\04\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\bb\80\80\80\00\02\88\80\80"
+ "\80\00\00\20\00\a7\20\01\6b\0b\a8\80\80\80\00\03"
+ "\01\64\05\01\64\03\01\64\01\d2\00\e0\05\21\02\20"
+ "\00\20\02\e1\05\03\21\03\20\01\20\03\e1\03\01\21"
+ "\04\20\04\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i64.const 0x16) (i32.const 0x2c))
+ (i32.const 0xffff_ffea)
+)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fe44) (i32.const 0x6f))
+ (i32.const 0xffff_fdd5)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind9.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind9.wast
new file mode 100644
index 0000000..9183b85
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_bind9.wast
@@ -0,0 +1,28 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (type $f2 (func (param i32) (result i32)))
+ (type $c2 (cont $f2))
+
+ (type $f3 (func (param i64 i32) (result i32)))
+ (type $c3 (cont $f3))
+
+ (func $sub (param i64 i32) (result i32) (i32.sub (i32.wrap_i64 (local.get 0)) (local.get 1)))
+ (elem declare func $sub)
+
+ (func (export "main") (param i64 i32) (result i32)
+ (local $x3 (ref $c3))
+ (local $x2 (ref $c2))
+ (local $x1 (ref $c1))
+ (local.set $x3 (cont.new $c3 (ref.func $sub)))
+ (local.set $x2 (cont.bind $c3 $c2 (local.get 0) (local.get $x3)))
+ (local.set $x1 (cont.bind $c2 $c1 (local.get 1) (local.get $x2)))
+
+ (resume $c1 (local.get $x1))
+ )
+)
+
+(assert_return (invoke "main" (i64.const 22) (i32.const 44)) (i32.const -22))
+(assert_return (invoke "main" (i64.const -444) (i32.const 111)) (i32.const -555))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new0.bin.wast
new file mode 100644
index 0000000..c502a6f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new0.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09"
+ "\85\80\80\80\00\01\03\00\01\00\0a\96\80\80\80\00"
+ "\02\82\80\80\80\00\00\0b\89\80\80\80\00\00\d2\00"
+ "\e0\01\1a\41\2a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new0.wast
new file mode 100644
index 0000000..ecc2e8d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new0.wast
@@ -0,0 +1,12 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i32)
+ (cont.new $c1 (ref.func $empty))
+ drop
+ i32.const 42
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new1.bin.wast
new file mode 100644
index 0000000..c5046f0
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new1.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8b\80\80\80\00\03\60"
+ "\00\00\5d\00\60\01\7f\01\7f\03\83\80\80\80\00\02"
+ "\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01"
+ "\09\85\80\80\80\00\01\03\00\01\00\0a\9d\80\80\80"
+ "\00\02\82\80\80\80\00\00\0b\90\80\80\80\00\00\20"
+ "\00\04\63\01\d2\00\e0\01\05\d0\01\0b\d1\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x1))
+(assert_return (invoke "main" (i32.const 0x457)) (i32.const 0x0))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new1.wast
new file mode 100644
index 0000000..4e65c95
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new1.wast
@@ -0,0 +1,17 @@
+;; Check if cont.new produces a non-null reference value
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (param i32) (result i32)
+ (ref.is_null
+ (if (result (ref null $c1)) (local.get 0)
+ (then (cont.new $c1 (ref.func $empty)))
+ (else ref.null $c1)
+ )
+ )
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "main" (i32.const 1111)) (i32.const 0))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new2.bin.wast
new file mode 100644
index 0000000..752f327
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new2.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\01\7f\60\01\7f\01\68\03\84"
+ "\80\80\80\00\03\00\02\03\07\88\80\80\80\00\01\04"
+ "\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01"
+ "\00\0a\a8\80\80\80\00\03\82\80\80\80\00\00\0b\87"
+ "\80\80\80\00\00\20\00\10\02\d1\0b\8f\80\80\80\00"
+ "\00\20\00\04\63\01\d2\00\e0\01\05\d0\01\0b\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x1))
+(assert_return (invoke "main" (i32.const 0x457)) (i32.const 0x0))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new2.wast
new file mode 100644
index 0000000..c001f84
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new2.wast
@@ -0,0 +1,18 @@
+;; Check if cont.new produces a non-null reference value
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (param i32) (result i32)
+ (ref.is_null (call $alloc (local.get 0)))
+ )
+ (func $alloc (param i32) (result (ref null cont))
+ (if (result (ref null $c1)) (local.get 0)
+ (then (cont.new $c1 (ref.func $empty)))
+ (else ref.null $c1)
+ )
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "main" (i32.const 1111)) (i32.const 0))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new_null.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new_null.bin.wast
new file mode 100644
index 0000000..8a11963
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new_null.bin.wast
@@ -0,0 +1,9 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\82\80\80\80\00\01\02"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\00\0a\8f"
+ "\80\80\80\00\01\89\80\80\80\00\00\d0\00\e0\01\1a"
+ "\41\2a\0b"
+)
+(module instance)
+(assert_trap (invoke "main") "null function reference")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new_null.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new_null.wast
new file mode 100644
index 0000000..1a6b413
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_new_null.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func (export "main") (result i32)
+ (cont.new $c1 (ref.null $f1))
+ drop
+ i32.const 42
+ )
+)
+
+(assert_trap (invoke "main") "null function reference")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table0.bin.wast
new file mode 100644
index 0000000..9c622a3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table0.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\87\80\80\80\00\02\60"
+ "\00\01\7f\5d\00\03\83\80\80\80\00\02\00\00\04\85"
+ "\80\80\80\00\01\63\01\00\05\07\88\80\80\80\00\01"
+ "\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03\00"
+ "\01\00\0a\a1\80\80\80\00\02\85\80\80\80\00\00\41"
+ "\2a\0f\0b\91\80\80\80\00\00\41\00\d2\00\e0\01\26"
+ "\00\41\00\25\00\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table0.wast
new file mode 100644
index 0000000..3d9a99b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table0.wast
@@ -0,0 +1,15 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (table $t1 5 (ref null $c1))
+
+ (func $f42 (result i32) (return (i32.const 42))) (elem declare func $f42)
+
+ (func (export "main") (result i32)
+ (table.set $t1 (i32.const 0) (cont.new $c1 (ref.func $f42)))
+ (resume $c1 (table.get $t1 (i32.const 0)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table1.bin.wast
new file mode 100644
index 0000000..85be4a7
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table1.bin.wast
@@ -0,0 +1,16 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8c\80\80\80\00\03\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\03\83\80\80\80\00"
+ "\02\00\02\04\85\80\80\80\00\01\63\01\00\05\07\88"
+ "\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80"
+ "\80\00\01\03\00\01\00\0a\a1\80\80\80\00\02\85\80"
+ "\80\80\00\00\41\2a\0f\0b\91\80\80\80\00\00\20\00"
+ "\d2\00\e0\01\26\00\20\00\25\00\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x2a))
+(assert_return (invoke "main" (i32.const 0x1)) (i32.const 0x2a))
+(assert_return (invoke "main" (i32.const 0x2)) (i32.const 0x2a))
+(assert_return (invoke "main" (i32.const 0x3)) (i32.const 0x2a))
+(assert_return (invoke "main" (i32.const 0x4)) (i32.const 0x2a))
+(assert_trap (invoke "main" (i32.const 0x5)) "out of bounds table access")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table1.wast
new file mode 100644
index 0000000..330523e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/cont_table1.wast
@@ -0,0 +1,20 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+
+ (table $t1 5 (ref null $c1))
+
+ (func $f42 (result i32) (return (i32.const 42))) (elem declare func $f42)
+
+ (func (export "main") (param i32) (result i32)
+ (table.set $t1 (local.get 0) (cont.new $c1 (ref.func $f42)))
+ (resume $c1 (table.get $t1 (local.get 0)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 42))
+(assert_return (invoke "main" (i32.const 1)) (i32.const 42))
+(assert_return (invoke "main" (i32.const 2)) (i32.const 42))
+(assert_return (invoke "main" (i32.const 3)) (i32.const 42))
+(assert_return (invoke "main" (i32.const 4)) (i32.const 42))
+(assert_trap (invoke "main" (i32.const 5)) "out of bounds table access")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/coret1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/coret1.bin.wast
new file mode 100644
index 0000000..c3bf4e9
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/coret1.bin.wast
@@ -0,0 +1,13 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\92\80\80\80\00\04\60"
+ "\01\7f\01\7c\5d\00\60\01\7d\02\7f\7f\60\01\7f\00"
+ "\03\83\80\80\80\00\02\00\00\0d\83\80\80\80\00\01"
+ "\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01"
+ "\09\85\80\80\80\00\01\03\00\01\00\0a\b9\80\80\80"
+ "\00\02\99\80\80\80\00\01\01\7d\20\00\03\03\b2\20"
+ "\01\92\21\01\20\01\e2\00\0d\00\1a\0b\20\01\bb\0b"
+ "\95\80\80\80\00\01\01\64\01\d2\00\e0\01\21\01\03"
+ "\7c\41\00\20\01\e3\01\00\0b\0b"
+)
+(module instance)
+(assert_suspension (invoke "main" (i32.const 0x0)) "unhandled tag")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/coret1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/coret1.wast
new file mode 100644
index 0000000..567af82
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/coret1.wast
@@ -0,0 +1,31 @@
+(module
+ (type $f1 (func (param i32) (result f64)))
+ (type $c1 (cont $f1))
+
+ (tag $s (param f32) (result i32 i32))
+
+ (func $add (param i32) (result f64)
+ (local $sum f32)
+ (local.get 0)
+ (loop (param i32)
+ (f32.convert_i32_s)
+ (local.set $sum (f32.add (local.get $sum)))
+ (suspend $s (local.get $sum))
+ (br_if 0)
+ drop
+ )
+ (f64.promote_f32 (local.get $sum))
+ )
+
+ (elem declare func $add)
+
+ (func (export "main") (param i32) (result f64)
+ (local $x1 (ref $c1))
+ (local.set $x1 (cont.new $c1 (ref.func $add)))
+ (loop (result f64)
+ (resume $c1 (i32.const 0) (local.get $x1))
+ )
+ )
+)
+
+(assert_suspension (invoke "main" (i32.const 0)) "unhandled tag")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/foo.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/foo.bin.wast
new file mode 100644
index 0000000..ee553fe
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/foo.bin.wast
@@ -0,0 +1,8 @@
+(module definition $f binary
+ "\00\61\73\6d\01\00\00\00\01\84\80\80\80\00\01\60"
+ "\00\00\03\82\80\80\80\00\01\00\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\00\0a\88\80\80\80\00\01\82"
+ "\80\80\80\00\00\0b"
+)
+(module instance $f $f)
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/foo.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/foo.wast
new file mode 100644
index 0000000..6f93fa3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/foo.wast
@@ -0,0 +1,5 @@
+(module $f
+ (func (export "main"))
+)
+
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume0.bin.wast
new file mode 100644
index 0000000..5628a67
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume0.bin.wast
@@ -0,0 +1,8 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\82\80\80\80\00\01\00\07\88\80\80"
+ "\80\00\01\04\6d\61\69\6e\00\00\0a\90\80\80\80\00"
+ "\01\8a\80\80\80\00\01\01\63\01\20\00\e3\01\00\0b"
+)
+(module instance)
+(assert_trap (invoke "main") "null continuation")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume0.wast
new file mode 100644
index 0000000..d639641
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume0.wast
@@ -0,0 +1,10 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func (export "main")
+ (local $x (ref null $c1))
+ (resume $c1 (local.get 0))
+ )
+)
+
+(assert_trap (invoke "main") "null continuation")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume1.bin.wast
new file mode 100644
index 0000000..2785fc3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume1.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09"
+ "\85\80\80\80\00\01\03\00\01\00\0a\98\80\80\80\00"
+ "\02\82\80\80\80\00\00\0b\8b\80\80\80\00\00\d2\00"
+ "\e0\01\e3\01\00\41\2a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume1.wast
new file mode 100644
index 0000000..8c16b99
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume1.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $empty)))
+ i32.const 42
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume10.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume10.bin.wast
new file mode 100644
index 0000000..02235c8
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume10.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\01\6f\01\6f\5d\00\03\83\80\80\80\00\02\00\00\07"
+ "\8c\80\80\80\00\01\08\63\61\6c\6c\5f\65\5f\65\00"
+ "\01\09\85\80\80\80\00\01\03\00\01\00\0a\9a\80\80"
+ "\80\00\02\84\80\80\80\00\00\20\00\0b\8b\80\80\80"
+ "\00\00\20\00\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "call_e_e" (ref.extern 0)) (ref.extern 0))
+(assert_return (invoke "call_e_e" (ref.extern 1)) (ref.extern 1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume10.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume10.wast
new file mode 100644
index 0000000..effa91f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume10.wast
@@ -0,0 +1,21 @@
+;; Test round-tripping externref through a continuation works.
+(module
+ (type $e_e (func (param externref) (result externref)))
+ (type $k_e_e (cont $e_e))
+
+ (func $id_e_e (param externref) (result externref) (local.get 0))
+
+ (elem declare func $id_e_e)
+
+ (func (export "call_e_e") (param externref) (result externref)
+ (resume $k_e_e (local.get 0) (cont.new $k_e_e (ref.func $id_e_e)))
+ )
+)
+
+(assert_return (invoke "call_e_e" (ref.extern 0)) (ref.extern 0))
+(assert_return (invoke "call_e_e" (ref.extern 1)) (ref.extern 1))
+
+;; TODO: host references?
+;;(assert_return (invoke "call_e_e" (ref.host 0)) (ref.host 0))
+;;(assert_return (invoke "call_e_e" (ref.host 1)) (ref.host 1))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume11.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume11.bin.wast
new file mode 100644
index 0000000..5c44eba
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume11.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\00\02\7f\7f\5d\00\03\83\80\80\80\00\02\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\9a\80\80\80\00\02\86"
+ "\80\80\80\00\00\41\2a\41\37\0b\89\80\80\80\00\00"
+ "\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a) (i32.const 0x37))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume11.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume11.wast
new file mode 100644
index 0000000..cd25bd3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume11.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func (result i32 i32)))
+ (type $c1 (cont $f1))
+ (func $f42 (result i32 i32) (i32.const 42) (i32.const 55))
+ (elem declare func $f42)
+ (func (export "main") (result i32 i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42) (i32.const 55))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume12.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume12.bin.wast
new file mode 100644
index 0000000..4c14120
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume12.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\00\02\7f\7e\5d\00\03\83\80\80\80\00\02\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\9a\80\80\80\00\02\86"
+ "\80\80\80\00\00\41\56\42\49\0b\89\80\80\80\00\00"
+ "\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main")
+ (i32.const 0xffff_ffd6)
+ (i64.const 0xffff_ffff_ffff_ffc9)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume12.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume12.wast
new file mode 100644
index 0000000..f1df5ef
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume12.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func (result i32 i64)))
+ (type $c1 (cont $f1))
+ (func $f42 (result i32 i64) (i32.const -42) (i64.const -55))
+ (elem declare func $f42)
+ (func (export "main") (result i32 i64)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const -42) (i64.const -55))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume13.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume13.bin.wast
new file mode 100644
index 0000000..9b2046d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume13.bin.wast
@@ -0,0 +1,25 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\89\80\80\80\00\02\60"
+ "\01\7f\02\7f\7e\5d\00\03\83\80\80\80\00\02\00\00"
+ "\07\8d\80\80\80\00\01\09\63\61\6c\6c\5f\69\5f\69"
+ "\6c\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\9d"
+ "\80\80\80\00\02\87\80\80\80\00\00\20\00\42\bc\03"
+ "\0b\8b\80\80\80\00\00\20\00\d2\00\e0\01\e3\01\00"
+ "\0b"
+)
+(module instance)
+(assert_return
+ (invoke "call_i_il" (i32.const 0xb))
+ (i32.const 0xb)
+ (i64.const 0x1bc)
+)
+(assert_return
+ (invoke "call_i_il" (i32.const 0xffff_ff22))
+ (i32.const 0xffff_ff22)
+ (i64.const 0x1bc)
+)
+(assert_return
+ (invoke "call_i_il" (i32.const 0xffff_face))
+ (i32.const 0xffff_face)
+ (i64.const 0x1bc)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume13.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume13.wast
new file mode 100644
index 0000000..4660a0e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume13.wast
@@ -0,0 +1,17 @@
+;; Test round-tripping integers through a continuation works.
+(module
+ (type $i_il (func (param i32) (result i32 i64)))
+ (type $k_i_il (cont $i_il))
+
+ (func $id_i_il (param i32) (result i32 i64) (local.get 0) (i64.const 444))
+
+ (elem declare func $id_i_il)
+
+ (func (export "call_i_il") (param i32) (result i32 i64)
+ (resume $k_i_il (local.get 0) (cont.new $k_i_il (ref.func $id_i_il)))
+ )
+)
+
+(assert_return (invoke "call_i_il" (i32.const 11)) (i32.const 11) (i64.const 444))
+(assert_return (invoke "call_i_il" (i32.const -222)) (i32.const -222) (i64.const 444))
+(assert_return (invoke "call_i_il" (i32.const 0xFFFF_FACE)) (i32.const 0xFFFF_FACE) (i64.const 444))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume14.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume14.bin.wast
new file mode 100644
index 0000000..50e2648
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume14.bin.wast
@@ -0,0 +1,20 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\02\60"
+ "\02\7f\7f\02\7f\7f\5d\00\03\83\80\80\80\00\02\00"
+ "\00\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09"
+ "\85\80\80\80\00\01\03\00\01\00\0a\a4\80\80\80\00"
+ "\02\8c\80\80\80\00\00\20\00\41\0b\6a\20\01\41\16"
+ "\6a\0b\8d\80\80\80\00\00\20\00\20\01\d2\00\e0\01"
+ "\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i32.const 0x0) (i32.const 0x0))
+ (i32.const 0xb)
+ (i32.const 0x16)
+)
+(assert_return
+ (invoke "main" (i32.const 0xa) (i32.const 0xffff_ffec))
+ (i32.const 0x15)
+ (i32.const 0x2)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume14.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume14.wast
new file mode 100644
index 0000000..824b591
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume14.wast
@@ -0,0 +1,16 @@
+(module
+ (type $f1 (func (param i32 i32) (result i32 i32)))
+ (type $c1 (cont $f1))
+ (func $add (param i32 i32) (result i32 i32)
+ (i32.add (local.get 0) (i32.const 11))
+ (i32.add (local.get 1) (i32.const 22))
+ )
+ (elem declare func $add)
+ (func (export "main") (param i32 i32) (result i32 i32)
+ (resume $c1 (local.get 0) (local.get 1) (cont.new $c1 (ref.func $add)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0) (i32.const 0)) (i32.const 11) (i32.const 22))
+(assert_return (invoke "main" (i32.const 10) (i32.const -20)) (i32.const 21) (i32.const 2))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume15.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume15.bin.wast
new file mode 100644
index 0000000..6f84256
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume15.bin.wast
@@ -0,0 +1,35 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\02\60"
+ "\04\7f\7f\7f\7f\04\7f\7f\7f\7f\5d\00\03\83\80\80"
+ "\80\00\02\00\00\07\88\80\80\80\00\01\04\6d\61\69"
+ "\6e\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\b2"
+ "\80\80\80\00\02\96\80\80\80\00\00\20\00\41\0b\6a"
+ "\20\01\41\16\6a\20\02\41\21\6a\20\03\41\2c\6a\0b"
+ "\91\80\80\80\00\00\20\00\20\01\20\02\20\03\d2\00"
+ "\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main"
+ (i32.const 0x0)
+ (i32.const 0x0)
+ (i32.const 0x0)
+ (i32.const 0x0)
+ )
+ (i32.const 0xb)
+ (i32.const 0x16)
+ (i32.const 0x21)
+ (i32.const 0x2c)
+)
+(assert_return
+ (invoke "main"
+ (i32.const 0xa)
+ (i32.const 0xffff_ffec)
+ (i32.const 0x28)
+ (i32.const 0xffff_ffce)
+ )
+ (i32.const 0x15)
+ (i32.const 0x2)
+ (i32.const 0x49)
+ (i32.const 0xffff_fffa)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume15.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume15.wast
new file mode 100644
index 0000000..50d44cd
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume15.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func (param i32 i32 i32 i32) (result i32 i32 i32 i32)))
+ (type $c1 (cont $f1))
+ (func $add (param i32 i32 i32 i32) (result i32 i32 i32 i32)
+ (i32.add (local.get 0) (i32.const 11))
+ (i32.add (local.get 1) (i32.const 22))
+ (i32.add (local.get 2) (i32.const 33))
+ (i32.add (local.get 3) (i32.const 44))
+ )
+ (elem declare func $add)
+ (func (export "main") (param i32 i32 i32 i32) (result i32 i32 i32 i32)
+ (resume $c1 (local.get 0) (local.get 1) (local.get 2) (local.get 3)
+ (cont.new $c1 (ref.func $add)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0))
+ (i32.const 11) (i32.const 22) (i32.const 33) (i32.const 44))
+(assert_return (invoke "main" (i32.const 10) (i32.const -20) (i32.const 40) (i32.const -50))
+ (i32.const 21) (i32.const 2) (i32.const 73) (i32.const -6))
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume16.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume16.bin.wast
new file mode 100644
index 0000000..6f70e0e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume16.bin.wast
@@ -0,0 +1,53 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\96\80\80\80\00\02\60"
+ "\08\7f\7f\7f\7f\7e\7e\7e\7e\08\7f\7f\7f\7f\7e\7e"
+ "\7e\7e\5d\00\03\83\80\80\80\00\02\00\00\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\d2\80\80\80\00\02\ae\80\80"
+ "\80\00\00\20\00\41\0b\6a\20\01\41\16\6a\20\02\41"
+ "\21\6a\20\03\41\2c\6a\20\04\42\ab\04\7c\20\05\42"
+ "\9a\05\7c\20\06\42\89\06\7c\20\07\42\f8\06\7c\0b"
+ "\99\80\80\80\00\00\20\00\20\01\20\02\20\03\20\04"
+ "\20\05\20\06\20\07\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main"
+ (i32.const 0x0)
+ (i32.const 0x0)
+ (i32.const 0x0)
+ (i32.const 0x0)
+ (i64.const 0x0)
+ (i64.const 0x0)
+ (i64.const 0x0)
+ (i64.const 0x0)
+ )
+ (i32.const 0xb)
+ (i32.const 0x16)
+ (i32.const 0x21)
+ (i32.const 0x2c)
+ (i64.const 0x22b)
+ (i64.const 0x29a)
+ (i64.const 0x309)
+ (i64.const 0x378)
+)
+(assert_return
+ (invoke "main"
+ (i32.const 0x64)
+ (i32.const 0xc8)
+ (i32.const 0x12c)
+ (i32.const 0x190)
+ (i64.const 0x1388)
+ (i64.const 0x1770)
+ (i64.const 0x1b58)
+ (i64.const 0x1f40)
+ )
+ (i32.const 0x6f)
+ (i32.const 0xde)
+ (i32.const 0x14d)
+ (i32.const 0x1bc)
+ (i64.const 0x15b3)
+ (i64.const 0x1a0a)
+ (i64.const 0x1e61)
+ (i64.const 0x22b8)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume16.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume16.wast
new file mode 100644
index 0000000..7bd6309
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume16.wast
@@ -0,0 +1,38 @@
+(module
+ (type $f1 (func (param i32 i32 i32 i32 i64 i64 i64 i64)
+ (result i32 i32 i32 i32 i64 i64 i64 i64)))
+ (type $c1 (cont $f1))
+ (func $add (param i32 i32 i32 i32 i64 i64 i64 i64)
+ (result i32 i32 i32 i32 i64 i64 i64 i64)
+ (i32.add (local.get 0) (i32.const 11))
+ (i32.add (local.get 1) (i32.const 22))
+ (i32.add (local.get 2) (i32.const 33))
+ (i32.add (local.get 3) (i32.const 44))
+ (i64.add (local.get 4) (i64.const 555))
+ (i64.add (local.get 5) (i64.const 666))
+ (i64.add (local.get 6) (i64.const 777))
+ (i64.add (local.get 7) (i64.const 888))
+ )
+ (elem declare func $add)
+ (func (export "main") (param i32 i32 i32 i32 i64 i64 i64 i64)
+ (result i32 i32 i32 i32 i64 i64 i64 i64)
+ (resume $c1 (local.get 0) (local.get 1) (local.get 2) (local.get 3) (local.get 4) (local.get 5) (local.get 6) (local.get 7)
+ (cont.new $c1 (ref.func $add)))
+ )
+)
+
+(assert_return (invoke "main"
+ (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0)
+ (i64.const 0) (i64.const 0) (i64.const 0) (i64.const 0))
+;; results
+ (i32.const 11) (i32.const 22) (i32.const 33) (i32.const 44)
+ (i64.const 555) (i64.const 666) (i64.const 777) (i64.const 888))
+
+(assert_return (invoke "main"
+ (i32.const 100) (i32.const 200) (i32.const 300) (i32.const 400)
+ (i64.const 5000) (i64.const 6000) (i64.const 7000) (i64.const 8000))
+;; results
+ (i32.const 111) (i32.const 222) (i32.const 333) (i32.const 444)
+ (i64.const 5555) (i64.const 6666) (i64.const 7777) (i64.const 8888))
+
+
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume17.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume17.bin.wast
new file mode 100644
index 0000000..c136052
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume17.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8c\80\80\80\00\04\60"
+ "\01\7f\00\5d\00\60\00\00\5d\02\03\83\80\80\80\00"
+ "\02\00\02\0d\83\80\80\80\00\01\00\02\07\88\80\80"
+ "\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00"
+ "\01\03\00\01\00\0a\a7\80\80\80\00\02\83\80\80\80"
+ "\00\00\01\0b\99\80\80\80\00\00\02\63\03\41\c5\00"
+ "\d2\00\e0\01\e3\01\02\00\00\00\00\00\00\d0\03\0b"
+ "\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume17.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume17.wast
new file mode 100644
index 0000000..dc99e15
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume17.wast
@@ -0,0 +1,20 @@
+(module
+ (type $f1 (func (param i32)))
+ (type $c1 (cont $f1))
+ (type $f2 (func))
+ (type $c2 (cont $f2))
+ (tag $ts)
+ (func $f42 (param i32) (nop))
+ (elem declare func $f42)
+ (func (export "main")
+ (block (result (ref null $c2))
+ (i32.const 69)
+ (cont.new $c1 (ref.func $f42))
+ (resume $c1 (on $ts 0) (on $ts 0))
+ (ref.null $c2)
+ )
+ (drop)
+ )
+)
+
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume2.bin.wast
new file mode 100644
index 0000000..4b461df
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume2.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\87\80\80\80\00\02\60"
+ "\00\01\7f\5d\00\03\83\80\80\80\00\02\00\00\07\88"
+ "\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80"
+ "\80\00\01\03\00\01\00\0a\98\80\80\80\00\02\84\80"
+ "\80\80\00\00\41\2a\0b\89\80\80\80\00\00\d2\00\e0"
+ "\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume2.wast
new file mode 100644
index 0000000..5f537dc
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume2.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+ (func $f42 (result i32) (i32.const 42))
+ (elem declare func $f42)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume3.bin.wast
new file mode 100644
index 0000000..7d5c2b2
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume3.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8c\80\80\80\00\03\60"
+ "\01\7f\01\7f\5d\00\60\00\01\7f\03\83\80\80\80\00"
+ "\02\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e\00"
+ "\01\09\85\80\80\80\00\01\03\00\01\00\0a\9d\80\80"
+ "\80\00\02\87\80\80\80\00\00\20\00\41\2a\6a\0b\8b"
+ "\80\80\80\00\00\41\15\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x3f))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume3.wast
new file mode 100644
index 0000000..1402c24
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume3.wast
@@ -0,0 +1,12 @@
+(module
+ (type $f1 (func (param i32) (result i32)))
+ (type $c1 (cont $f1))
+ (func $add42 (param i32) (result i32)
+ (i32.add (local.get 0) (i32.const 42)))
+ (elem declare func $add42)
+ (func (export "main") (result i32)
+ (resume $c1 (i32.const 21) (cont.new $c1 (ref.func $add42)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const 63))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume4.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume4.bin.wast
new file mode 100644
index 0000000..8ea0632
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume4.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\87\80\80\80\00\02\60"
+ "\00\01\7f\5d\00\03\83\80\80\80\00\02\00\00\07\88"
+ "\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80"
+ "\80\00\01\03\00\01\00\0a\99\80\80\80\00\02\85\80"
+ "\80\80\00\00\41\2a\0f\0b\89\80\80\80\00\00\d2\00"
+ "\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume4.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume4.wast
new file mode 100644
index 0000000..78f180f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume4.wast
@@ -0,0 +1,10 @@
+(module
+ (type $f1 (func (result i32)))
+ (type $c1 (cont $f1))
+ (func $f42 (result i32) (return (i32.const 42))) (elem declare func $f42)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume5.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume5.bin.wast
new file mode 100644
index 0000000..e758d69
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume5.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\06\86\80\80\80\00\01\7f\01\41\0f\0b\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\9c\80\80\80\00\02\86\80\80"
+ "\80\00\00\41\2a\24\00\0b\8b\80\80\80\00\00\d2\00"
+ "\e0\01\e3\01\00\23\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume5.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume5.wast
new file mode 100644
index 0000000..701c117
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume5.wast
@@ -0,0 +1,13 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (global $g (mut i32) (i32.const 15))
+ (func $f42 (global.set $g (i32.const 42)))
+ (elem declare func $f42)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ (global.get $g)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume6.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume6.bin.wast
new file mode 100644
index 0000000..771477e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume6.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\00\60\00\01\7f\03\84\80\80"
+ "\80\00\03\02\00\03\06\86\80\80\80\00\01\7f\01\41"
+ "\0f\0b\07\88\80\80\80\00\01\04\6d\61\69\6e\00\02"
+ "\09\85\80\80\80\00\01\03\00\01\01\0a\a7\80\80\80"
+ "\00\03\86\80\80\80\00\00\20\00\24\00\0b\86\80\80"
+ "\80\00\00\41\2a\10\00\0b\8b\80\80\80\00\00\d2\01"
+ "\e0\01\e3\01\00\23\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume6.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume6.wast
new file mode 100644
index 0000000..b77b992
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume6.wast
@@ -0,0 +1,14 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (global $g (mut i32) (i32.const 15))
+ (func $set (param i32) (global.set $g (local.get 0)))
+ (func $f42 (call $set (i32.const 42)))
+ (elem declare func $f42)
+ (func (export "main") (result i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ (global.get $g)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume7.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume7.bin.wast
new file mode 100644
index 0000000..fc1a610
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume7.bin.wast
@@ -0,0 +1,30 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\04\60"
+ "\01\7f\01\7f\5d\00\60\01\7e\01\7e\5d\02\03\85\80"
+ "\80\80\00\04\00\02\00\02\07\97\80\80\80\00\02\08"
+ "\63\61\6c\6c\5f\69\5f\69\00\02\08\63\61\6c\6c\5f"
+ "\6c\5f\6c\00\03\09\86\80\80\80\00\01\03\00\02\00"
+ "\01\0a\b3\80\80\80\00\04\84\80\80\80\00\00\20\00"
+ "\0b\84\80\80\80\00\00\20\00\0b\8b\80\80\80\00\00"
+ "\20\00\d2\00\e0\01\e3\01\00\0b\8b\80\80\80\00\00"
+ "\20\00\d2\01\e0\03\e3\03\00\0b"
+)
+(module instance)
+(assert_return (invoke "call_i_i" (i32.const 0xb)) (i32.const 0xb))
+(assert_return
+ (invoke "call_i_i" (i32.const 0xffff_ff22))
+ (i32.const 0xffff_ff22)
+)
+(assert_return
+ (invoke "call_i_i" (i32.const 0xffff_face))
+ (i32.const 0xffff_face)
+)
+(assert_return (invoke "call_l_l" (i64.const 0x113b)) (i64.const 0x113b))
+(assert_return
+ (invoke "call_l_l" (i64.const 0xffff_ffff_ffff_7e3a))
+ (i64.const 0xffff_ffff_ffff_7e3a)
+)
+(assert_return
+ (invoke "call_l_l" (i64.const 0xdead_ffff_face))
+ (i64.const 0xdead_ffff_face)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume7.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume7.wast
new file mode 100644
index 0000000..a14f0df
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume7.wast
@@ -0,0 +1,29 @@
+;; Test round-tripping integers through a continuation works.
+(module
+ (type $i_i (func (param i32) (result i32)))
+ (type $k_i_i (cont $i_i))
+
+ (type $l_l (func (param i64) (result i64)))
+ (type $k_l_l (cont $l_l))
+
+ (func $id_i_i (param i32) (result i32) (local.get 0))
+ (func $id_l_l (param i64) (result i64) (local.get 0))
+
+ (elem declare func $id_i_i $id_l_l)
+
+ (func (export "call_i_i") (param i32) (result i32)
+ (resume $k_i_i (local.get 0) (cont.new $k_i_i (ref.func $id_i_i)))
+ )
+
+ (func (export "call_l_l") (param i64) (result i64)
+ (resume $k_l_l (local.get 0) (cont.new $k_l_l (ref.func $id_l_l)))
+ )
+)
+
+(assert_return (invoke "call_i_i" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "call_i_i" (i32.const -222)) (i32.const -222))
+(assert_return (invoke "call_i_i" (i32.const 0xFFFF_FACE)) (i32.const 0xFFFF_FACE))
+
+(assert_return (invoke "call_l_l" (i64.const 4411)) (i64.const 4411))
+(assert_return (invoke "call_l_l" (i64.const -33222)) (i64.const -33222))
+(assert_return (invoke "call_l_l" (i64.const 0xDEAD_FFFF_FACE)) (i64.const 0xDEAD_FFFF_FACE))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume8.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume8.bin.wast
new file mode 100644
index 0000000..0410bf4
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume8.bin.wast
@@ -0,0 +1,33 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\04\60"
+ "\01\7d\01\7d\5d\00\60\01\7c\01\7c\5d\02\03\85\80"
+ "\80\80\00\04\00\02\00\02\07\97\80\80\80\00\02\08"
+ "\63\61\6c\6c\5f\66\5f\66\00\02\08\63\61\6c\64\5f"
+ "\64\5f\6c\00\03\09\86\80\80\80\00\01\03\00\02\00"
+ "\01\0a\b3\80\80\80\00\04\84\80\80\80\00\00\20\00"
+ "\0b\84\80\80\80\00\00\20\00\0b\8b\80\80\80\00\00"
+ "\20\00\d2\00\e0\01\e3\01\00\0b\8b\80\80\80\00\00"
+ "\20\00\d2\01\e0\03\e3\03\00\0b"
+)
+(module instance)
+(assert_return (invoke "call_f_f" (f32.const 0x1.6p+3)) (f32.const 0x1.6p+3))
+(assert_return
+ (invoke "call_f_f" (f32.const -0x1.bcp+7))
+ (f32.const -0x1.bcp+7)
+)
+(assert_return
+ (invoke "call_f_f" (f32.const 0x1.ffff_f6p+31))
+ (f32.const 0x1.ffff_f6p+31)
+)
+(assert_return
+ (invoke "cald_d_l" (f64.const 0x1.13bp+12))
+ (f64.const 0x1.13bp+12)
+)
+(assert_return
+ (invoke "cald_d_l" (f64.const -0x1.038cp+15))
+ (f64.const -0x1.038cp+15)
+)
+(assert_return
+ (invoke "cald_d_l" (f64.const 0x1.bd5b_ffff_f59cp+47))
+ (f64.const 0x1.bd5b_ffff_f59cp+47)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume8.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume8.wast
new file mode 100644
index 0000000..635157c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume8.wast
@@ -0,0 +1,29 @@
+;; Test round-tripping floats through a continuation works.
+(module
+ (type $f_f (func (param f32) (result f32)))
+ (type $k_f_f (cont $f_f))
+
+ (type $d_d (func (param f64) (result f64)))
+ (type $k_d_d (cont $d_d))
+
+ (func $id_f_f (param f32) (result f32) (local.get 0))
+ (func $id_d_d (param f64) (result f64) (local.get 0))
+
+ (elem declare func $id_f_f $id_d_d)
+
+ (func (export "call_f_f") (param f32) (result f32)
+ (resume $k_f_f (local.get 0) (cont.new $k_f_f (ref.func $id_f_f)))
+ )
+
+ (func (export "cald_d_l") (param f64) (result f64)
+ (resume $k_d_d (local.get 0) (cont.new $k_d_d (ref.func $id_d_d)))
+ )
+)
+
+(assert_return (invoke "call_f_f" (f32.const 11)) (f32.const 11))
+(assert_return (invoke "call_f_f" (f32.const -222)) (f32.const -222))
+(assert_return (invoke "call_f_f" (f32.const 0xFFFF_FACE)) (f32.const 0xFFFF_FACE))
+
+(assert_return (invoke "cald_d_l" (f64.const 4411)) (f64.const 4411))
+(assert_return (invoke "cald_d_l" (f64.const -33222)) (f64.const -33222))
+(assert_return (invoke "cald_d_l" (f64.const 0xDEAD_FFFF_FACE)) (f64.const 0xDEAD_FFFF_FACE))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume9.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume9.bin.wast
new file mode 100644
index 0000000..87dd64c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume9.bin.wast
@@ -0,0 +1,38 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\01\7b\01\7b\5d\00\03\83\80\80\80\00\02\00\00\07"
+ "\8c\80\80\80\00\01\08\63\61\6c\6c\5f\73\5f\73\00"
+ "\01\09\85\80\80\80\00\01\03\00\01\00\0a\9a\80\80"
+ "\80\00\02\84\80\80\80\00\00\20\00\0b\8b\80\80\80"
+ "\00\00\20\00\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "call_s_s"
+ (v128.const i32x4 0x302_0100 0x706_0504 0xb0a_0908 0xf0e_0d0c)
+ )
+ (v128.const i8x16
+ 0x0
+ 0x1
+ 0x2
+ 0x3
+ 0x4
+ 0x5
+ 0x6
+ 0x7
+ 0x8
+ 0x9
+ 0xa
+ 0xb
+ 0xc
+ 0xd
+ 0xe
+ 0xf
+ )
+)
+(assert_return
+ (invoke "call_s_s"
+ (v128.const i32x4 0x6465_6667 0x6869_6a6b 0x6c6d_6e6f 0x7071_7273)
+ )
+ (v128.const i32x4 0x6465_6667 0x6869_6a6b 0x6c6d_6e6f 0x7071_7273)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume9.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume9.wast
new file mode 100644
index 0000000..d6b8c91
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume9.wast
@@ -0,0 +1,19 @@
+;; Test round-tripping V128 through a continuation works.
+(module
+ (type $s_s (func (param v128) (result v128)))
+ (type $k_s_s (cont $s_s))
+
+ (func $id_s_s (param v128) (result v128) (local.get 0))
+
+ (elem declare func $id_s_s)
+
+ (func (export "call_s_s") (param v128) (result v128)
+ (resume $k_s_s (local.get 0) (cont.new $k_s_s (ref.func $id_s_s)))
+ )
+)
+
+(assert_return (invoke "call_s_s" (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
+ (v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
+
+(assert_return (invoke "call_s_s" (v128.const i32x4 0x64656667 0x68696a6b 0x6c6d6e6f 0x70717273))
+ (v128.const i32x4 0x64656667 0x68696a6b 0x6c6d6e6f 0x70717273))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw0.bin.wast
new file mode 100644
index 0000000..bd97bcc
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw0.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\00\60\00\01\7f\03\83\80\80"
+ "\80\00\02\00\03\0d\83\80\80\80\00\01\00\02\07\88"
+ "\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80"
+ "\80\00\01\03\00\01\00\0a\a3\80\80\80\00\02\86\80"
+ "\80\80\00\00\41\2f\08\00\0b\92\80\80\80\00\00\1f"
+ "\40\01\00\00\00\d2\00\e0\01\e3\01\00\0b\41\2a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2f))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw0.wast
new file mode 100644
index 0000000..46dade3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw0.wast
@@ -0,0 +1,19 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i32))
+ (func $throw
+ (throw $t (i32.const 47))
+ )
+ (elem declare func $throw)
+ (func (export "main") (result i32)
+ (try_table (catch $t 0)
+ (resume
+ $c1
+ (cont.new $c1 (ref.func $throw)))
+ )
+ i32.const 42 ;; unreachable
+ )
+)
+
+(assert_return (invoke "main") (i32.const 47))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw1.bin.wast
new file mode 100644
index 0000000..b1635c6
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw1.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\00\60\01\7f\01\7f\03\83\80"
+ "\80\80\00\02\00\03\0d\83\80\80\80\00\01\00\02\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\a3\80\80\80\00\02\86"
+ "\80\80\80\00\00\41\2f\08\00\0b\92\80\80\80\00\00"
+ "\1f\40\01\00\00\00\d2\00\e0\01\e3\01\00\0b\41\2a"
+ "\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x2c)) (i32.const 0x2f))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw1.wast
new file mode 100644
index 0000000..77aa1c8
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw1.wast
@@ -0,0 +1,19 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i32))
+ (func $throw
+ (throw $t (i32.const 47))
+ )
+ (elem declare func $throw)
+ (func (export "main") (param i32) (result i32)
+ (try_table (catch $t 0)
+ (resume
+ $c1
+ (cont.new $c1 (ref.func $throw)))
+ )
+ i32.const 42 ;; unreachable
+ )
+)
+
+(assert_return (invoke "main" (i32.const 44)) (i32.const 47))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw2.bin.wast
new file mode 100644
index 0000000..1b7eb17
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw2.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8c\80\80\80\00\03\60"
+ "\01\7f\00\5d\00\60\01\7f\01\7f\03\83\80\80\80\00"
+ "\02\00\02\0d\83\80\80\80\00\01\00\00\07\88\80\80"
+ "\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00"
+ "\01\03\00\01\00\0a\a5\80\80\80\00\02\86\80\80\80"
+ "\00\00\20\00\08\00\0b\94\80\80\80\00\00\1f\40\01"
+ "\00\00\00\20\00\d2\00\e0\01\e3\01\00\0b\41\2a\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x2c)) (i32.const 0x2c))
+(assert_return (invoke "main" (i32.const 0xffff_ffd1)) (i32.const 0xffff_ffd1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw2.wast
new file mode 100644
index 0000000..4198f6c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw2.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func (param i32)))
+ (type $c1 (cont $f1))
+ (tag $t (param i32))
+ (func $throw (param i32)
+ (throw $t (local.get 0))
+ )
+ (elem declare func $throw)
+ (func (export "main") (param i32) (result i32)
+ (try_table (catch $t 0)
+ (resume
+ $c1
+ (local.get 0)
+ (cont.new $c1 (ref.func $throw)))
+ )
+ i32.const 42 ;; unreachable
+ )
+)
+
+(assert_return (invoke "main" (i32.const 44)) (i32.const 44))
+(assert_return (invoke "main" (i32.const -47)) (i32.const -47))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw3.bin.wast
new file mode 100644
index 0000000..01eb18e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw3.bin.wast
@@ -0,0 +1,21 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\03\60"
+ "\02\7e\7c\00\5d\00\60\02\7e\7c\02\7e\7c\03\83\80"
+ "\80\80\00\02\00\02\0d\83\80\80\80\00\01\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\b2\80\80\80\00\02\88"
+ "\80\80\80\00\00\20\00\20\01\08\00\0b\9f\80\80\80"
+ "\00\00\1f\40\01\00\00\00\20\00\20\01\d2\00\e0\01"
+ "\e3\01\00\0b\42\2a\44\00\00\00\00\00\80\47\40\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fba9) (f64.const 0x1.a0ap+11))
+ (i64.const 0xffff_ffff_ffff_fba9)
+ (f64.const 0x1.a0ap+11)
+)
+(assert_return
+ (invoke "main" (i64.const 0xface_b00c) (f64.const 0x1.a0ap+11))
+ (i64.const 0xface_b00c)
+ (f64.const 0x1.a0ap+11)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw3.wast
new file mode 100644
index 0000000..3667a61
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw3.wast
@@ -0,0 +1,23 @@
+(module
+ (type $f1 (func (param i64 f64)))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f64))
+ (func $throw (param i64 f64)
+ (throw $t (local.get 0) (local.get 1))
+ )
+ (elem declare func $throw)
+ (func (export "main") (param i64 f64) (result i64 f64)
+ (try_table (catch $t 0)
+ (resume
+ $c1
+ (local.get 0)
+ (local.get 1)
+ (cont.new $c1 (ref.func $throw)))
+ )
+ i64.const 42 ;; unreachable
+ f64.const 47
+ )
+)
+
+(assert_return (invoke "main" (i64.const -1111) (f64.const 3333)) (i64.const -1111) (f64.const 3333))
+(assert_return (invoke "main" (i64.const 0xFACE_B00C) (f64.const 3333)) (i64.const 0xFACE_B00C) (f64.const 3333))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw4.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw4.bin.wast
new file mode 100644
index 0000000..80600ac
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw4.bin.wast
@@ -0,0 +1,22 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\03\60"
+ "\02\7e\7c\00\5d\00\60\02\7e\7c\02\7e\7c\03\84\80"
+ "\80\80\00\03\00\00\02\0d\83\80\80\80\00\01\00\00"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\02\09\85"
+ "\80\80\80\00\01\03\00\01\01\0a\bf\80\80\80\00\03"
+ "\88\80\80\80\00\00\20\00\20\01\08\00\0b\88\80\80"
+ "\80\00\00\20\00\20\01\10\00\0b\9f\80\80\80\00\00"
+ "\1f\40\01\00\00\00\20\00\20\01\d2\01\e0\01\e3\01"
+ "\00\0b\42\2a\44\00\00\00\00\00\80\47\40\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fba9) (f64.const 0x1.a0ap+11))
+ (i64.const 0xffff_ffff_ffff_fba9)
+ (f64.const 0x1.a0ap+11)
+)
+(assert_return
+ (invoke "main" (i64.const 0x5a1a_d1ce_bad1_c0de) (f64.const 0x1.a62p+11))
+ (i64.const 0x5a1a_d1ce_bad1_c0de)
+ (f64.const 0x1.a62p+11)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw4.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw4.wast
new file mode 100644
index 0000000..9e3803e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_and_throw4.wast
@@ -0,0 +1,26 @@
+(module
+ (type $f1 (func (param i64 f64)))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f64))
+ (func $throw (param i64 f64)
+ (throw $t (local.get 0) (local.get 1))
+ )
+ (func $call (param i64 f64)
+ (call $throw (local.get 0) (local.get 1))
+ )
+ (elem declare func $call)
+ (func (export "main") (param i64 f64) (result i64 f64)
+ (try_table (catch $t 0)
+ (resume
+ $c1
+ (local.get 0)
+ (local.get 1)
+ (cont.new $c1 (ref.func $call)))
+ )
+ i64.const 42 ;; unreachable
+ f64.const 47
+ )
+)
+
+(assert_return (invoke "main" (i64.const -1111) (f64.const 3333)) (i64.const -1111) (f64.const 3333))
+(assert_return (invoke "main" (i64.const 0x5A1AD1CEBAD1C0DE) (f64.const 3377)) (i64.const 0x5A1AD1CEBAD1C0DE) (f64.const 3377))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain0.bin.wast
new file mode 100644
index 0000000..f364c77
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain0.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\00\02\7f\7f\5d\00\03\84\80\80\80\00\03\00\00\00"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\02\09\86"
+ "\80\80\80\00\01\03\00\02\00\01\0a\a8\80\80\80\00"
+ "\03\86\80\80\80\00\00\41\2a\41\37\0b\89\80\80\80"
+ "\00\00\d2\00\e0\01\e3\01\00\0b\89\80\80\80\00\00"
+ "\d2\01\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2a) (i32.const 0x37))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain0.wast
new file mode 100644
index 0000000..5ace696
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain0.wast
@@ -0,0 +1,14 @@
+(module
+ (type $f1 (func (result i32 i32)))
+ (type $c1 (cont $f1))
+ (func $f42 (result i32 i32) (i32.const 42) (i32.const 55))
+ (func $cf42 (result i32 i32)
+ (resume $c1 (cont.new $c1 (ref.func $f42)))
+ )
+ (elem declare func $f42 $cf42)
+ (func (export "main") (result i32 i32)
+ (resume $c1 (cont.new $c1 (ref.func $cf42)))
+ )
+)
+
+(assert_return (invoke "main") (i32.const 42) (i32.const 55))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain1.bin.wast
new file mode 100644
index 0000000..e4f1a1d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain1.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\01\7f\01\7f\5d\00\03\84\80\80\80\00\03\00\00\00"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\02\09\86"
+ "\80\80\80\00\01\03\00\02\00\01\0a\b5\80\80\80\00"
+ "\03\87\80\80\80\00\00\20\00\41\0a\6a\0b\93\80\80"
+ "\80\00\00\20\00\41\e4\00\6a\d2\00\e0\01\e3\01\00"
+ "\41\e8\07\6a\0b\8b\80\80\80\00\00\20\00\d2\01\e0"
+ "\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x4)) (i32.const 0x45a))
+(assert_return (invoke "main" (i32.const 0x5)) (i32.const 0x45b))
+(assert_return (invoke "main" (i32.const 0x9)) (i32.const 0x45f))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain1.wast
new file mode 100644
index 0000000..a2cf5dd
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain1.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func (param i32) (result i32)))
+ (type $c1 (cont $f1))
+ (func $f42 (param i32) (result i32)
+ (i32.add (local.get 0) (i32.const 10)))
+ (func $cf42 (param i32) (result i32)
+ (i32.add
+ (resume $c1
+ (i32.add (local.get 0) (i32.const 100))
+ (cont.new $c1 (ref.func $f42)))
+ (i32.const 1000))
+ )
+ (elem declare func $f42 $cf42)
+ (func (export "main") (param i32) (result i32)
+ (resume $c1 (local.get 0) (cont.new $c1 (ref.func $cf42)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 4)) (i32.const 1114))
+(assert_return (invoke "main" (i32.const 5)) (i32.const 1115))
+(assert_return (invoke "main" (i32.const 9)) (i32.const 1119))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain2.bin.wast
new file mode 100644
index 0000000..a802187
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain2.bin.wast
@@ -0,0 +1,21 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\a2\80\80\80\00\09\60"
+ "\02\7f\7d\00\5d\00\60\02\7d\7f\00\5d\02\60\01\7f"
+ "\00\5d\04\60\01\7d\00\5d\06\60\02\7f\7d\02\7d\7f"
+ "\03\86\80\80\80\00\05\04\06\02\00\08\06\8e\80\80"
+ "\80\00\02\7f\01\41\0b\0b\7d\01\43\00\00\30\41\0b"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\04\09\88"
+ "\80\80\80\00\01\03\00\04\00\01\02\03\0a\d8\80\80"
+ "\80\00\05\86\80\80\80\00\00\20\00\24\00\0b\86\80"
+ "\80\80\00\00\20\00\24\01\0b\94\80\80\80\00\00\20"
+ "\01\d2\00\e0\05\e3\05\00\20\00\d2\01\e0\07\e3\07"
+ "\00\0b\8d\80\80\80\00\00\20\01\20\00\d2\02\e0\03"
+ "\e3\03\00\0b\91\80\80\80\00\00\20\00\20\01\d2\03"
+ "\e0\01\e3\01\00\23\01\23\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i32.const 0x16) (f32.const 0x1.6p+4))
+ (f32.const 0x1.6p+4)
+ (i32.const 0x16)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain2.wast
new file mode 100644
index 0000000..a7d582b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain2.wast
@@ -0,0 +1,41 @@
+(module
+ (global $g_i (mut i32) (i32.const 11))
+ (global $g_f (mut f32) (f32.const 11))
+
+ (type $f_if (func (param i32 f32)))
+ (type $c_if (cont $f_if))
+
+ (type $f_fi (func (param f32 i32)))
+ (type $c_fi (cont $f_fi))
+
+ (type $f_i (func (param i32)))
+ (type $c_i (cont $f_i))
+
+ (type $f_f (func (param f32)))
+ (type $c_f (cont $f_f))
+
+ (func $set_i (param i32)
+ (global.set $g_i (local.get 0)))
+
+ (func $set_f (param f32)
+ (global.set $g_f (local.get 0)))
+
+ (func $set_fi (param f32 i32)
+ (resume $c_i (local.get 1) (cont.new $c_i (ref.func $set_i)))
+ (resume $c_f (local.get 0) (cont.new $c_f (ref.func $set_f)))
+ )
+
+ (elem declare func $set_i $set_f $set_fi $set_if)
+
+ (func $set_if (param i32 f32)
+ (resume $c_fi (local.get 1) (local.get 0) (cont.new $c_fi (ref.func $set_fi)))
+ )
+
+ (func (export "main") (param i32 f32) (result f32 i32)
+ (resume $c_if (local.get 0) (local.get 1) (cont.new $c_if (ref.func $set_if)))
+ (global.get $g_f)
+ (global.get $g_i)
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22) (f32.const 22)) (f32.const 22) (i32.const 22))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain3.bin.wast
new file mode 100644
index 0000000..789cb1d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain3.bin.wast
@@ -0,0 +1,16 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\88\80\80\80\00\02\60"
+ "\01\7f\01\7f\5d\00\03\83\80\80\80\00\02\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\b0\80\80\80\00\02\9a"
+ "\80\80\80\00\00\20\00\45\04\7f\41\00\05\41\01\20"
+ "\00\41\01\6b\d2\00\e0\01\e3\01\00\6a\0b\0b\8b\80"
+ "\80\80\00\00\20\00\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x0))
+(assert_return (invoke "main" (i32.const 0x1)) (i32.const 0x1))
+(assert_return (invoke "main" (i32.const 0x2)) (i32.const 0x2))
+(assert_return (invoke "main" (i32.const 0x5)) (i32.const 0x5))
+(assert_return (invoke "main" (i32.const 0x2a)) (i32.const 0x2a))
+(assert_return (invoke "main" (i32.const 0x80)) (i32.const 0x80))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain3.wast
new file mode 100644
index 0000000..fc867db
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_chain3.wast
@@ -0,0 +1,29 @@
+(module
+ (type $f1 (func (param i32) (result i32)))
+ (type $c1 (cont $f1))
+ (func $foo (param i32) (result i32)
+ (if (result i32) (i32.eqz (local.get 0))
+ (then (i32.const 0))
+ (else
+ (i32.add
+ (i32.const 1)
+ (resume $c1
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c1 (ref.func $foo))
+ )
+ )
+ )
+ )
+ )
+ (elem declare func $foo)
+ (func (export "main") (param i32) (result i32)
+ (resume $c1 (local.get 0) (cont.new $c1 (ref.func $foo)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "main" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "main" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "main" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "main" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "main" (i32.const 128)) (i32.const 128))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_expired0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_expired0.bin.wast
new file mode 100644
index 0000000..84878fe
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_expired0.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\06\86\80\80\80\00\01\7f\01\41\0f\0b\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\a8\80\80\80\00\02\86\80\80"
+ "\80\00\00\41\2a\24\00\0b\97\80\80\80\00\01\01\64"
+ "\01\d2\00\e0\01\21\00\20\00\e3\01\00\23\00\20\00"
+ "\e3\01\00\0b"
+)
+(module instance)
+(assert_trap (invoke "main") "continuation already consumed")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_expired0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_expired0.wast
new file mode 100644
index 0000000..31f9f54
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_expired0.wast
@@ -0,0 +1,16 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (global $g (mut i32) (i32.const 15))
+ (func $f42 (global.set $g (i32.const 42)))
+ (elem declare func $f42)
+ (func (export "main") (result i32)
+ (local $x (ref $c1))
+ (local.set $x (cont.new $c1 (ref.func $f42)))
+ (resume $c1 (local.get $x))
+ (global.get $g)
+ (resume $c1 (local.get $x)) ;; must trap
+ )
+)
+
+(assert_trap (invoke "main") "continuation already consumed")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype0.bin.wast
new file mode 100644
index 0000000..00785ac
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype0.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\93\80\80\80\00\04\5f"
+ "\02\7f\00\7f\00\60\01\63\00\01\7f\5d\01\60\00\01"
+ "\7f\03\83\80\80\80\00\02\01\03\07\89\80\80\80\00"
+ "\01\05\67\65\74\5f\30\00\01\09\85\80\80\80\00\01"
+ "\03\00\01\00\0a\a3\80\80\80\00\02\88\80\80\80\00"
+ "\00\20\00\fb\02\00\00\0b\90\80\80\80\00\00\41\2a"
+ "\41\18\fb\00\00\d2\00\e0\02\e3\02\00\0b"
+)
+(module instance)
+(assert_return (invoke "get_0") (i32.const 0x2a))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype0.wast
new file mode 100644
index 0000000..fa19ee1
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype0.wast
@@ -0,0 +1,16 @@
+(module
+ (type $s (struct (field i32) (field i32)))
+ (type $f (func (param (ref null $s)) (result i32)))
+ (type $c (cont $f))
+
+ (func $foo (param (ref null $s)) (result i32)
+ (struct.get $s 0 (local.get 0))
+ )
+ (elem declare func $foo)
+ (func (export "get_0") (result i32)
+ (struct.new $s (i32.const 42) (i32.const 24))
+ (resume $c (cont.new $c (ref.func $foo)))
+ )
+)
+
+(assert_return (invoke "get_0") (i32.const 42))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype1.bin.wast
new file mode 100644
index 0000000..3754e0c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype1.bin.wast
@@ -0,0 +1,15 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\99\80\80\80\00\05\5f"
+ "\02\7f\01\7f\00\60\00\01\7f\5d\01\60\01\63\00\00"
+ "\60\00\02\63\00\63\02\03\83\80\80\80\00\02\01\01"
+ "\0d\83\80\80\80\00\01\00\03\07\89\80\80\80\00\01"
+ "\05\67\65\74\5f\30\00\01\09\85\80\80\80\00\01\03"
+ "\00\01\00\0a\c8\80\80\80\00\02\98\80\80\80\00\01"
+ "\01\63\00\41\2a\41\18\fb\00\00\21\00\20\00\e2\00"
+ "\20\00\fb\02\00\00\0b\a5\80\80\80\00\01\01\63\02"
+ "\02\04\d2\00\e0\02\e3\02\01\00\00\00\1a\d0\00\d0"
+ "\02\0b\21\00\41\80\10\fb\05\00\00\20\00\e3\02\00"
+ "\0b"
+)
+(module instance)
+(assert_return (invoke "get_0") (i32.const 0x800))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype1.wast
new file mode 100644
index 0000000..e463373
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype1.wast
@@ -0,0 +1,31 @@
+(module
+ (type $s (struct (field (mut i32)) (field i32)))
+ (type $f (func (result i32)))
+ (type $c (cont $f))
+ (tag $tag (param (ref null $s)))
+
+ (func $foo (result i32)
+ (local $struct (ref null $s))
+ (local.set $struct (struct.new $s (i32.const 42) (i32.const 24)))
+
+ (suspend $tag (local.get $struct))
+ (struct.get $s 0 (local.get $struct))
+ )
+ (elem declare func $foo)
+ (func (export "get_0") (result i32)
+ (local $temp (ref null $c))
+
+ (block $b (result (ref null $s) (ref null $c))
+ (cont.new $c (ref.func $foo))
+ (resume $c (on $tag $b))
+ (drop)
+ (ref.null $s)
+ (ref.null $c)
+ )
+ (local.set $temp)
+ (struct.set $s 0 (i32.const 2048))
+ (resume $c (local.get $temp))
+ )
+)
+
+(assert_return (invoke "get_0") (i32.const 2048))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype2.bin.wast
new file mode 100644
index 0000000..9628cda
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype2.bin.wast
@@ -0,0 +1,49 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\ac\80\80\80\00\0a\5e"
+ "\7d\01\60\02\7f\7d\01\63\00\5d\01\60\01\7d\01\63"
+ "\00\5d\03\60\00\01\63\00\5d\05\60\00\01\7d\60\01"
+ "\7f\01\7d\60\01\63\04\01\63\00\03\83\80\80\80\00"
+ "\02\01\08\0d\83\80\80\80\00\01\00\07\07\88\80\80"
+ "\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00"
+ "\01\03\00\01\00\0a\99\81\80\80\00\02\af\80\80\80"
+ "\00\02\01\63\00\01\7f\43\00\00\00\00\20\00\fb\06"
+ "\00\21\02\03\40\20\02\20\03\e2\00\fb\0e\00\20\03"
+ "\41\01\6a\21\03\20\03\20\00\49\0d\00\0b\20\02\0b"
+ "\df\80\80\80\00\04\01\63\04\01\63\00\01\7d\01\7f"
+ "\20\00\d2\00\e0\02\e1\02\04\41\00\21\04\03\09\21"
+ "\01\20\04\b3\20\01\e1\04\06\41\01\20\04\6a\21\04"
+ "\e3\06\01\00\00\00\0b\21\02\43\00\00\00\00\21\03"
+ "\41\00\21\04\03\40\20\02\20\04\fb\0b\00\20\03\92"
+ "\21\03\20\04\41\01\6a\21\04\20\04\20\00\49\0d\00"
+ "\0b\20\03\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x1)) (f32.const 0x1p+0))
+(assert_return (invoke "main" (i32.const 0x2)) (f32.const 0x1.8p+1))
+(assert_return (invoke "main" (i32.const 0x3)) (f32.const 0x1.8p+2))
+(assert_return (invoke "main" (i32.const 0x4)) (f32.const 0x1.4p+3))
+(assert_return (invoke "main" (i32.const 0x5)) (f32.const 0x1.ep+3))
+(assert_return (invoke "main" (i32.const 0x6)) (f32.const 0x1.5p+4))
+(assert_return (invoke "main" (i32.const 0x7)) (f32.const 0x1.cp+4))
+(assert_return (invoke "main" (i32.const 0x8)) (f32.const 0x1.2p+5))
+(assert_return (invoke "main" (i32.const 0x9)) (f32.const 0x1.68p+5))
+(assert_return (invoke "main" (i32.const 0xa)) (f32.const 0x1.b8p+5))
+(assert_return (invoke "main" (i32.const 0xb)) (f32.const 0x1.08p+6))
+(assert_return (invoke "main" (i32.const 0xc)) (f32.const 0x1.38p+6))
+(assert_return (invoke "main" (i32.const 0xd)) (f32.const 0x1.6cp+6))
+(assert_return (invoke "main" (i32.const 0xe)) (f32.const 0x1.a4p+6))
+(assert_return (invoke "main" (i32.const 0xf)) (f32.const 0x1.ep+6))
+(assert_return (invoke "main" (i32.const 0x10)) (f32.const 0x1.1p+7))
+(assert_return (invoke "main" (i32.const 0x11)) (f32.const 0x1.32p+7))
+(assert_return (invoke "main" (i32.const 0x12)) (f32.const 0x1.56p+7))
+(assert_return (invoke "main" (i32.const 0x13)) (f32.const 0x1.7cp+7))
+(assert_return (invoke "main" (i32.const 0x14)) (f32.const 0x1.a4p+7))
+(assert_return (invoke "main" (i32.const 0x15)) (f32.const 0x1.cep+7))
+(assert_return (invoke "main" (i32.const 0x16)) (f32.const 0x1.fap+7))
+(assert_return (invoke "main" (i32.const 0x17)) (f32.const 0x1.14p+8))
+(assert_return (invoke "main" (i32.const 0x18)) (f32.const 0x1.2cp+8))
+(assert_return (invoke "main" (i32.const 0x19)) (f32.const 0x1.45p+8))
+(assert_return (invoke "main" (i32.const 0x1a)) (f32.const 0x1.5fp+8))
+(assert_return (invoke "main" (i32.const 0x1b)) (f32.const 0x1.7ap+8))
+(assert_return (invoke "main" (i32.const 0x1c)) (f32.const 0x1.96p+8))
+(assert_return (invoke "main" (i32.const 0x1d)) (f32.const 0x1.b3p+8))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype2.wast
new file mode 100644
index 0000000..0d95cb3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_heaptype2.wast
@@ -0,0 +1,87 @@
+(module
+ (type $vec (array (mut f32)))
+
+ (type $f (func (param i32 f32) (result (ref null $vec))))
+ (type $c (cont $f))
+ (type $f1 (func (param f32) (result (ref null $vec))))
+ (type $c1 (cont $f1))
+ (type $f2 (func (result (ref null $vec))))
+ (type $c2 (cont $f2))
+ (tag $tag (result f32))
+
+ (func $foo (param i32 f32) (result (ref null $vec))
+ (local $v (ref null $vec))
+ (local $i i32)
+ (local.set $v (array.new $vec (f32.const 0) (local.get 0)))
+
+ (loop $l
+ (local.get $v)
+ (local.get $i)
+ (suspend $tag)
+ (array.set $vec)
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
+ (br_if $l (i32.lt_u (local.get $i) (local.get 0)))
+ )
+ (local.get $v)
+ )
+ (elem declare func $foo)
+ (func (export "main") (param i32) (result f32)
+ (local $temp (ref null $c1))
+ (local $v (ref null $vec))
+ (local $sum f32)
+ (local $i i32)
+
+ (cont.bind $c $c1 (local.get 0) (cont.new $c (ref.func $foo)))
+
+ (local.set $i (i32.const 0))
+ (loop $l (param (ref null $c1)) (result (ref null $vec))
+ (local.set $temp)
+ (cont.bind $c1 $c2 (f32.convert_i32_u (local.get $i)) (local.get $temp))
+ (local.set $i (i32.add (i32.const 1) (local.get $i)))
+ (resume $c2 (on $tag $l))
+ )
+
+ (local.set $v)
+ (local.set $sum (f32.const 0))
+ (local.set $i (i32.const 0))
+ (loop $l
+ (array.get $vec (local.get $v) (local.get $i))
+ (f32.add (local.get $sum))
+ (local.set $sum)
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
+ (br_if $l (i32.lt_u (local.get $i) (local.get 0)))
+ )
+
+ (local.get $sum)
+ )
+)
+
+(assert_return (invoke "main" (i32.const 1)) (f32.const 1))
+(assert_return (invoke "main" (i32.const 2)) (f32.const 3))
+(assert_return (invoke "main" (i32.const 3)) (f32.const 6))
+(assert_return (invoke "main" (i32.const 4)) (f32.const 10))
+(assert_return (invoke "main" (i32.const 5)) (f32.const 15))
+(assert_return (invoke "main" (i32.const 6)) (f32.const 21))
+(assert_return (invoke "main" (i32.const 7)) (f32.const 28))
+(assert_return (invoke "main" (i32.const 8)) (f32.const 36))
+(assert_return (invoke "main" (i32.const 9)) (f32.const 45))
+(assert_return (invoke "main" (i32.const 10)) (f32.const 55))
+(assert_return (invoke "main" (i32.const 11)) (f32.const 66))
+(assert_return (invoke "main" (i32.const 12)) (f32.const 78))
+(assert_return (invoke "main" (i32.const 13)) (f32.const 91))
+(assert_return (invoke "main" (i32.const 14)) (f32.const 105))
+(assert_return (invoke "main" (i32.const 15)) (f32.const 120))
+(assert_return (invoke "main" (i32.const 16)) (f32.const 136))
+(assert_return (invoke "main" (i32.const 17)) (f32.const 153))
+(assert_return (invoke "main" (i32.const 18)) (f32.const 171))
+(assert_return (invoke "main" (i32.const 19)) (f32.const 190))
+(assert_return (invoke "main" (i32.const 20)) (f32.const 210))
+(assert_return (invoke "main" (i32.const 21)) (f32.const 231))
+(assert_return (invoke "main" (i32.const 22)) (f32.const 253))
+(assert_return (invoke "main" (i32.const 23)) (f32.const 276))
+(assert_return (invoke "main" (i32.const 24)) (f32.const 300))
+(assert_return (invoke "main" (i32.const 25)) (f32.const 325))
+(assert_return (invoke "main" (i32.const 26)) (f32.const 351))
+(assert_return (invoke "main" (i32.const 27)) (f32.const 378))
+(assert_return (invoke "main" (i32.const 28)) (f32.const 406))
+(assert_return (invoke "main" (i32.const 29)) (f32.const 435))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested0.bin.wast
new file mode 100644
index 0000000..c7c0fb7
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested0.bin.wast
@@ -0,0 +1,16 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\97\80\80\80\00\06\5f"
+ "\02\7f\00\7f\00\60\01\7f\00\5d\01\60\00\00\5d\03"
+ "\60\01\7f\01\7f\03\84\80\80\80\00\03\01\01\05\0d"
+ "\85\80\80\80\00\02\00\03\00\03\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\02\09\89\80\80\80\00\02\03"
+ "\00\01\00\03\00\01\01\0a\c9\80\80\80\00\03\8d\80"
+ "\80\80\00\00\20\00\45\04\40\e2\00\05\e2\01\0b\0b"
+ "\8b\80\80\80\00\00\20\00\d2\00\e0\02\e3\02\00\0b"
+ "\a1\80\80\80\00\00\02\63\04\02\63\04\20\00\d2\01"
+ "\e0\02\e3\02\02\00\00\01\00\01\00\d0\04\0b\41\01"
+ "\0f\0b\41\00\0f\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x0))
+(assert_return (invoke "main" (i32.const 0x1)) (i32.const 0x1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested0.wast
new file mode 100644
index 0000000..d16dfb2
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested0.wast
@@ -0,0 +1,40 @@
+(module
+ (type $s (struct (field i32) (field i32)))
+ (type $f0 (func (param i32)))
+ (type $c0 (cont $f0))
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+
+ (tag $a)
+ (tag $b)
+
+ (func $func_b (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $a))
+ (else (suspend $b))
+ )
+ )
+ (elem declare func $func_b)
+
+ (func $func_a (param i32)
+ (resume $c0 (local.get 0) (cont.new $c0 (ref.func $func_b)))
+ )
+ (elem declare func $func_a)
+
+ (func (export "main") (param i32) (result i32)
+ (block $jump_a (result (ref null $c1))
+ (block $jump_b (result (ref null $c1))
+ (resume $c0 (on $a $jump_a) (on $b $jump_b)
+ (local.get 0)
+ (cont.new $c0 (ref.func $func_a))
+ )
+ (ref.null $c1)
+ )
+ (return (i32.const 1))
+ )
+ (return (i32.const 0))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "main" (i32.const 1)) (i32.const 1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested1.bin.wast
new file mode 100644
index 0000000..02bb1e4
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested1.bin.wast
@@ -0,0 +1,38 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\97\80\80\80\00\06\5f"
+ "\02\7f\00\7f\00\60\01\7f\00\5d\01\60\00\00\5d\03"
+ "\60\01\7f\01\7f\03\89\80\80\80\00\08\01\01\01\01"
+ "\01\01\01\05\0d\8f\80\80\80\00\07\00\03\00\03\00"
+ "\03\00\03\00\03\00\03\00\03\07\88\80\80\80\00\01"
+ "\04\6d\61\69\6e\00\07\09\9d\80\80\80\00\07\03\00"
+ "\01\00\03\00\01\01\03\00\01\02\03\00\01\03\03\00"
+ "\01\04\03\00\01\05\03\00\01\06\0a\8a\82\80\80\00"
+ "\08\84\80\80\80\00\00\e2\06\0b\97\80\80\80\00\00"
+ "\20\00\45\04\40\e2\05\05\20\00\41\01\6b\d2\00\e0"
+ "\02\e3\02\00\0b\0b\97\80\80\80\00\00\20\00\45\04"
+ "\40\e2\04\05\20\00\41\01\6b\d2\01\e0\02\e3\02\00"
+ "\0b\0b\97\80\80\80\00\00\20\00\45\04\40\e2\03\05"
+ "\20\00\41\01\6b\d2\02\e0\02\e3\02\00\0b\0b\97\80"
+ "\80\80\00\00\20\00\45\04\40\e2\02\05\20\00\41\01"
+ "\6b\d2\03\e0\02\e3\02\00\0b\0b\97\80\80\80\00\00"
+ "\20\00\45\04\40\e2\01\05\20\00\41\01\6b\d2\04\e0"
+ "\02\e3\02\00\0b\0b\97\80\80\80\00\00\20\00\45\04"
+ "\40\e2\00\05\20\00\41\01\6b\d2\05\e0\02\e3\02\00"
+ "\0b\0b\d3\80\80\80\00\00\02\63\04\02\63\04\02\63"
+ "\04\02\63\04\02\63\04\02\63\04\02\63\04\20\00\d2"
+ "\06\e0\02\e3\02\07\00\00\06\00\01\05\00\02\04\00"
+ "\03\03\00\04\02\00\05\01\00\06\00\d0\04\0b\41\06"
+ "\0f\0b\41\05\0f\0b\41\04\0f\0b\41\03\0f\0b\41\02"
+ "\0f\0b\41\01\0f\0b\41\00\0f\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x0))
+(assert_return (invoke "main" (i32.const 0x1)) (i32.const 0x1))
+(assert_return (invoke "main" (i32.const 0x2)) (i32.const 0x2))
+(assert_return (invoke "main" (i32.const 0x3)) (i32.const 0x3))
+(assert_return (invoke "main" (i32.const 0x4)) (i32.const 0x4))
+(assert_return (invoke "main" (i32.const 0x5)) (i32.const 0x5))
+(assert_return (invoke "main" (i32.const 0x6)) (i32.const 0x6))
+(assert_return (invoke "main" (i32.const 0x7)) (i32.const 0x6))
+(assert_return (invoke "main" (i32.const 0x8)) (i32.const 0x6))
+(assert_return (invoke "main" (i32.const 0x1_0000)) (i32.const 0x6))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested1.wast
new file mode 100644
index 0000000..eb1d4b9
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_nested1.wast
@@ -0,0 +1,147 @@
+(module
+ (type $s (struct (field i32) (field i32)))
+ (type $f0 (func (param i32)))
+ (type $c0 (cont $f0))
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+
+ (tag $a)
+ (tag $b)
+ (tag $c)
+ (tag $d)
+ (tag $e)
+ (tag $f)
+ (tag $g)
+
+ (func $func_g (param i32)
+ (suspend $g)
+ )
+ (elem declare func $func_g)
+
+ (func $func_f (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $f))
+ (else
+ (resume $c0
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c0 (ref.func $func_g))
+ )
+ )
+ )
+ )
+ (elem declare func $func_f)
+
+ (func $func_e (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $e))
+ (else
+ (resume $c0
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c0 (ref.func $func_f))
+ )
+ )
+ )
+ )
+ (elem declare func $func_e)
+
+ (func $func_d (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $d))
+ (else
+ (resume $c0
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c0 (ref.func $func_e))
+ )
+ )
+ )
+ )
+ (elem declare func $func_d)
+
+ (func $func_c (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $c))
+ (else
+ (resume $c0
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c0 (ref.func $func_d))
+ )
+ )
+ )
+ )
+ (elem declare func $func_c)
+
+ (func $func_b (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $b))
+ (else
+ (resume $c0
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c0 (ref.func $func_c))
+ )
+ )
+ )
+ )
+ (elem declare func $func_b)
+
+ (func $func_a (param i32)
+ (if (i32.eqz (local.get 0))
+ (then (suspend $a))
+ (else
+ (resume $c0
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c0 (ref.func $func_b))
+ )
+ )
+ )
+ )
+ (elem declare func $func_a)
+
+ (func (export "main") (param i32) (result i32)
+
+ (block $jump_a (result (ref null $c1))
+ (block $jump_b (result (ref null $c1))
+ (block $jump_c (result (ref null $c1))
+ (block $jump_d (result (ref null $c1))
+ (block $jump_e (result (ref null $c1))
+ (block $jump_f (result (ref null $c1))
+ (block $jump_g (result (ref null $c1))
+ (resume $c0
+ (on $a $jump_a)
+ (on $b $jump_b)
+ (on $c $jump_c)
+ (on $d $jump_d)
+ (on $e $jump_e)
+ (on $f $jump_f)
+ (on $g $jump_g)
+
+ (local.get 0)
+ (cont.new $c0 (ref.func $func_a))
+ )
+ (ref.null $c1)
+ )
+ (return (i32.const 6))
+ )
+ (return (i32.const 5))
+ )
+ (return (i32.const 4))
+ )
+ (return (i32.const 3))
+ )
+ (return (i32.const 2))
+ )
+ (return (i32.const 1))
+ )
+ (return (i32.const 0))
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "main" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "main" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "main" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "main" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "main" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "main" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "main" (i32.const 7)) (i32.const 6))
+(assert_return (invoke "main" (i32.const 8)) (i32.const 6))
+(assert_return (invoke "main" (i32.const 65536)) (i32.const 6))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw0.bin.wast
new file mode 100644
index 0000000..49fdfb6
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw0.bin.wast
@@ -0,0 +1,9 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\82\80\80\80\00\01\02"
+ "\0d\83\80\80\80\00\01\00\00\07\88\80\80\80\00\01"
+ "\04\6d\61\69\6e\00\00\0a\90\80\80\80\00\01\8a\80"
+ "\80\80\00\00\d0\01\e4\01\00\00\41\2a\0b"
+)
+(module instance)
+(assert_trap (invoke "main") "null continuation")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw0.wast
new file mode 100644
index 0000000..e3633eb
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw0.wast
@@ -0,0 +1,13 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t)
+ (func (export "main") (result i32)
+ (resume_throw
+ $c1 $t
+ (ref.null $c1))
+ i32.const 42
+ )
+)
+
+(assert_trap (invoke "main") "null continuation")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw1.bin.wast
new file mode 100644
index 0000000..c31e65f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw1.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\0d\83\80\80\80\00\01\00\00\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03"
+ "\00\01\00\0a\99\80\80\80\00\02\82\80\80\80\00\00"
+ "\0b\8c\80\80\80\00\00\d2\00\e0\01\e4\01\00\00\41"
+ "\2a\0b"
+)
+(module instance)
+(assert_exception (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw1.wast
new file mode 100644
index 0000000..e7a9bd0
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw1.wast
@@ -0,0 +1,14 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t)
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i32)
+ (resume_throw
+ $c1 $t
+ (cont.new $c1 (ref.func $empty)))
+ i32.const 42
+ )
+)
+
+(assert_exception (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw2.bin.wast
new file mode 100644
index 0000000..482c714
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw2.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\00\60\00\01\7f\03\83\80\80"
+ "\80\00\02\00\03\0d\83\80\80\80\00\01\00\02\07\88"
+ "\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80"
+ "\80\00\01\03\00\01\00\0a\9b\80\80\80\00\02\82\80"
+ "\80\80\00\00\0b\8e\80\80\80\00\00\41\2a\d2\00\e0"
+ "\01\e4\01\00\00\41\2a\0b"
+)
+(module instance)
+(assert_exception (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw2.wast
new file mode 100644
index 0000000..f1b7199
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw2.wast
@@ -0,0 +1,14 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i32))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i32)
+ (resume_throw
+ $c1 $t
+ (i32.const 42) (cont.new $c1 (ref.func $empty)))
+ i32.const 42
+ )
+)
+
+(assert_exception (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw3.bin.wast
new file mode 100644
index 0000000..e76efd6
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw3.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\00\00\5d\00\60\03\7e\7d\7c\00\60\00\01\7f\03\83"
+ "\80\80\80\00\02\00\03\0d\83\80\80\80\00\01\00\02"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85"
+ "\80\80\80\00\01\03\00\01\00\0a\a9\80\80\80\00\02"
+ "\82\80\80\80\00\00\0b\9c\80\80\80\00\00\42\2a\43"
+ "\00\00\30\41\44\00\00\00\00\00\00\36\40\d2\00\e0"
+ "\01\e4\01\00\00\41\2a\0b"
+)
+(module instance)
+(assert_exception (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw3.wast
new file mode 100644
index 0000000..cf2e64d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw3.wast
@@ -0,0 +1,14 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f32 f64))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i32)
+ (resume_throw
+ $c1 $t
+ (i64.const 42) (f32.const 11) (f64.const 22) (cont.new $c1 (ref.func $empty)))
+ i32.const 42
+ )
+)
+
+(assert_exception (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw4.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw4.bin.wast
new file mode 100644
index 0000000..ef99485
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw4.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\00\5d\00\60\01\7f\00\60\00\01\7f\03\83\80\80"
+ "\80\00\02\00\03\0d\83\80\80\80\00\01\00\02\07\88"
+ "\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80"
+ "\80\00\01\03\00\01\00\0a\a2\80\80\80\00\02\82\80"
+ "\80\80\00\00\0b\95\80\80\80\00\00\1f\40\01\00\00"
+ "\00\41\2f\d2\00\e0\01\e4\01\00\00\0b\41\2a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2f))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw4.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw4.wast
new file mode 100644
index 0000000..0912bab
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw4.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i32))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i32)
+ (try_table (catch $t 0)
+ (resume_throw
+ $c1 $t
+ (i32.const 47)
+ (cont.new $c1 (ref.func $empty)))
+ )
+ i32.const 42 ;; unreachable
+ )
+)
+
+(assert_return (invoke "main") (i32.const 47))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw5.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw5.bin.wast
new file mode 100644
index 0000000..9e71a2f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw5.bin.wast
@@ -0,0 +1,17 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\00\00\5d\00\60\02\7e\7c\00\60\00\02\7e\7c\03\83"
+ "\80\80\80\00\02\00\03\0d\83\80\80\80\00\01\00\02"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85"
+ "\80\80\80\00\01\03\00\01\00\0a\b5\80\80\80\00\02"
+ "\82\80\80\80\00\00\0b\a8\80\80\80\00\00\1f\40\01"
+ "\00\00\00\42\51\44\9a\99\99\99\99\99\01\c0\d2\00"
+ "\e0\01\e4\01\00\00\0b\42\bc\03\44\00\00\00\00\00"
+ "\38\8f\40\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main")
+ (i64.const 0xffff_ffff_ffff_ffd1)
+ (f64.const -0x1.1999_9999_9999_ap+1)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw5.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw5.wast
new file mode 100644
index 0000000..5fe24c1
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw5.wast
@@ -0,0 +1,18 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f64))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i64 f64)
+ (try_table (catch $t 0)
+ (resume_throw
+ $c1 $t
+ (i64.const -47) (f64.const -2.2)
+ (cont.new $c1 (ref.func $empty)))
+ )
+ i64.const 444 ;; unreachable
+ f64.const 999
+ )
+)
+
+(assert_return (invoke "main") (i64.const -47) (f64.const -2.2))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw6.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw6.bin.wast
new file mode 100644
index 0000000..f814a16
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw6.bin.wast
@@ -0,0 +1,16 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\00\00\5d\00\60\02\7e\7c\00\60\00\02\7e\7c\03\83"
+ "\80\80\80\00\02\00\03\0d\83\80\80\80\00\01\00\02"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85"
+ "\80\80\80\00\01\03\00\01\00\0a\aa\80\80\80\00\02"
+ "\82\80\80\80\00\00\0b\9d\80\80\80\00\00\1f\40\01"
+ "\00\00\00\42\51\44\9a\99\99\99\99\99\01\c0\d2\00"
+ "\e0\01\e4\01\00\00\0b\00\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main")
+ (i64.const 0xffff_ffff_ffff_ffd1)
+ (f64.const -0x1.1999_9999_9999_ap+1)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw6.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw6.wast
new file mode 100644
index 0000000..8ee9839
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw6.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f64))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i64 f64)
+ (try_table (catch $t 0)
+ (resume_throw
+ $c1 $t
+ (i64.const -47) (f64.const -2.2)
+ (cont.new $c1 (ref.func $empty)))
+ )
+ unreachable
+ )
+)
+
+(assert_return (invoke "main") (i64.const -47) (f64.const -2.2))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw7.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw7.bin.wast
new file mode 100644
index 0000000..278c278
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw7.bin.wast
@@ -0,0 +1,17 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\90\80\80\80\00\04\60"
+ "\00\00\5d\00\60\02\7e\7c\00\60\00\02\7e\7c\03\83"
+ "\80\80\80\00\02\00\03\0d\83\80\80\80\00\01\00\02"
+ "\07\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85"
+ "\80\80\80\00\01\03\00\01\00\0a\b6\80\80\80\00\02"
+ "\82\80\80\80\00\00\0b\a9\80\80\80\00\00\1f\40\01"
+ "\00\00\00\42\51\44\9a\99\99\99\99\99\01\c0\d2\00"
+ "\e0\01\e4\01\00\00\00\0b\42\89\06\44\00\00\00\00"
+ "\00\d0\74\40\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main")
+ (i64.const 0xffff_ffff_ffff_ffd1)
+ (f64.const -0x1.1999_9999_9999_ap+1)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw7.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw7.wast
new file mode 100644
index 0000000..3e34757
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw7.wast
@@ -0,0 +1,19 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f64))
+ (func $empty) (elem declare func $empty)
+ (func (export "main") (result i64 f64)
+ (try_table (catch $t 0)
+ (resume_throw
+ $c1 $t
+ (i64.const -47) (f64.const -2.2)
+ (cont.new $c1 (ref.func $empty)))
+ unreachable
+ )
+ (i64.const 777)
+ (f64.const 333)
+ )
+)
+
+(assert_return (invoke "main") (i64.const -47) (f64.const -2.2))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw8.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw8.bin.wast
new file mode 100644
index 0000000..88eb6ec
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw8.bin.wast
@@ -0,0 +1,27 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\03\60"
+ "\02\7e\7c\00\5d\00\60\02\7e\7c\02\7e\7c\03\83\80"
+ "\80\80\00\02\00\02\0d\83\80\80\80\00\01\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\bb\80\80\80\00\02\90"
+ "\80\80\80\00\00\42\9a\05\44\00\00\00\00\00\48\88"
+ "\40\08\00\0b\a0\80\80\80\00\00\1f\40\01\00\00\00"
+ "\20\00\20\01\d2\00\e0\01\e4\01\00\00\0b\42\2a\44"
+ "\00\00\00\00\00\80\47\40\0b"
+)
+(module instance)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_fba9) (f64.const 0x1.a0ap+11))
+ (i64.const 0xffff_ffff_ffff_fba9)
+ (f64.const 0x1.a0ap+11)
+)
+(assert_return
+ (invoke "main" (i64.const 0xffff_ffff_ffff_f752) (f64.const 0x1.15cp+12))
+ (i64.const 0xffff_ffff_ffff_f752)
+ (f64.const 0x1.15cp+12)
+)
+(assert_return
+ (invoke "main" (i64.const 0xbad_f00d_dead_beef) (f64.const 0x1.15cp+12))
+ (i64.const 0xbad_f00d_dead_beef)
+ (f64.const 0x1.15cp+12)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw8.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw8.wast
new file mode 100644
index 0000000..4585723
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_throw8.wast
@@ -0,0 +1,25 @@
+(module
+ (type $f1 (func (param i64 f64)))
+ (type $c1 (cont $f1))
+ (tag $t (param i64 f64))
+ (func $throw (param i64 f64)
+ (throw $t (i64.const 666) (f64.const 777))
+ )
+ (elem declare func $throw)
+ (func (export "main") (param i64 f64) (result i64 f64)
+ (try_table (catch $t 0)
+ (resume_throw
+ $c1
+ $t
+ (local.get 0)
+ (local.get 1)
+ (cont.new $c1 (ref.func $throw)))
+ )
+ i64.const 42 ;; unreachable
+ f64.const 47
+ )
+)
+
+(assert_return (invoke "main" (i64.const -1111) (f64.const 3333)) (i64.const -1111) (f64.const 3333))
+(assert_return (invoke "main" (i64.const -2222) (f64.const 4444)) (i64.const -2222) (f64.const 4444))
+(assert_return (invoke "main" (i64.const 0x0BAD_F00D_DEAD_BEEF) (f64.const 4444)) (i64.const 0x0BAD_F00D_DEAD_BEEF) (f64.const 4444))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_trap0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_trap0.bin.wast
new file mode 100644
index 0000000..7ab2690
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_trap0.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\83\80\80\80\00\02\00\00\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\97\80\80\80\00\02\83\80\80"
+ "\80\00\00\00\0b\89\80\80\80\00\00\d2\00\e0\01\e3"
+ "\01\00\0b"
+)
+(module instance)
+(assert_trap (invoke "main") "unreachable")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_trap0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_trap0.wast
new file mode 100644
index 0000000..11160ec
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/resume_trap0.wast
@@ -0,0 +1,11 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (func $trap unreachable)
+ (elem declare func $trap)
+ (func (export "main")
+ (resume $c1 (cont.new $c1 (ref.func $trap)))
+ )
+)
+
+(assert_trap (invoke "main") "unreachable")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend0.bin.wast
new file mode 100644
index 0000000..95444e1
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend0.bin.wast
@@ -0,0 +1,10 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\83\80\80\80\00\02\00\00\0d\83\80"
+ "\80\80\00\01\00\00\07\88\80\80\80\00\01\04\6d\61"
+ "\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00\0a"
+ "\98\80\80\80\00\02\84\80\80\80\00\00\e2\00\0b\89"
+ "\80\80\80\00\00\d2\00\e0\01\e3\01\00\0b"
+)
+(module instance)
+(assert_suspension (invoke "main") "unhandled")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend0.wast
new file mode 100644
index 0000000..7b0c96b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend0.wast
@@ -0,0 +1,12 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e)
+ (func $s (suspend $e))
+ (elem declare func $s)
+ (func (export "main")
+ (resume $c1 (cont.new $c1 (ref.func $s)))
+ )
+)
+
+(assert_suspension (invoke "main") "unhandled")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend1.bin.wast
new file mode 100644
index 0000000..6fbbae5
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend1.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\83\80\80\80\00\02\00\00\0d\83\80"
+ "\80\80\00\01\00\00\07\88\80\80\80\00\01\04\6d\61"
+ "\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00\0a"
+ "\a2\80\80\80\00\02\84\80\80\80\00\00\e2\00\0b\93"
+ "\80\80\80\00\00\02\63\01\d2\00\e0\01\e3\01\01\00"
+ "\00\00\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend1.wast
new file mode 100644
index 0000000..d918cf2
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend1.wast
@@ -0,0 +1,16 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e)
+ (func $s (suspend $e))
+ (elem declare func $s)
+ (func (export "main")
+ (block (result (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main"))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend10.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend10.bin.wast
new file mode 100644
index 0000000..4a0955d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend10.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9a\80\80\80\00\06\60"
+ "\01\7d\01\7c\5d\00\60\01\7e\01\7c\5d\02\60\01\7f"
+ "\01\7e\60\00\02\7f\63\03\03\83\80\80\80\00\02\00"
+ "\00\0d\83\80\80\80\00\01\00\04\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03"
+ "\00\01\00\0a\b0\80\80\80\00\02\88\80\80\80\00\00"
+ "\20\00\a8\e2\00\b9\0b\9d\80\80\80\00\01\01\63\03"
+ "\02\05\20\00\d2\00\e0\01\e3\01\01\00\00\00\00\0b"
+ "\21\01\ac\20\01\e3\03\00\0b"
+)
+(module instance)
+(assert_return (invoke "main" (f32.const 0x1.6p+3)) (f64.const 0x1.6p+3))
+(assert_return (invoke "main" (f32.const -0x1.1ep+10)) (f64.const -0x1.1ep+10))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend10.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend10.wast
new file mode 100644
index 0000000..b545d95
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend10.wast
@@ -0,0 +1,29 @@
+(module
+ (type $f_d (func (param f32) (result f64)))
+ (type $k_f_d (cont $f_d))
+ (type $l_d (func (param i64) (result f64)))
+ (type $k_l_d (cont $l_d))
+
+ (tag $t (param i32) (result i64))
+
+ (func $foo (param f32) (result f64)
+ (f64.convert_i64_s (suspend $t (i32.trunc_f32_s (local.get 0))))
+ )
+
+ (elem declare func $foo)
+
+ (func (export "main") (param f32) (result f64)
+ (local $y (ref null $k_l_d))
+ (block (result i32 (ref null $k_l_d))
+ (resume $k_f_d (on $t 0) (local.get 0)
+ (cont.new $k_f_d (ref.func $foo)))
+ unreachable)
+ (local.set $y)
+ (i64.extend_i32_s)
+ (local.get $y)
+ (resume $k_l_d)
+ )
+)
+
+(assert_return (invoke "main" (f32.const 11)) (f64.const 11))
+(assert_return (invoke "main" (f32.const -1144)) (f64.const -1144))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend11.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend11.bin.wast
new file mode 100644
index 0000000..c8dd8d9
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend11.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\03\83\80\80\80\00\02\00\00\0d\85\80"
+ "\80\80\00\02\00\00\00\00\07\88\80\80\80\00\01\04"
+ "\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01"
+ "\00\0a\a2\80\80\80\00\02\84\80\80\80\00\00\e2\01"
+ "\0b\93\80\80\80\00\00\02\63\01\d2\00\e0\01\e3\01"
+ "\01\00\00\00\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_suspension (invoke "main") "unhandled")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend11.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend11.wast
new file mode 100644
index 0000000..f1dc806
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend11.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e)
+ (tag $f)
+ (func $s (suspend $f))
+ (elem declare func $s)
+ (func (export "main")
+ (block (result (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_suspension (invoke "main") "unhandled")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend12.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend12.bin.wast
new file mode 100644
index 0000000..86bf228
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend12.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9b\80\80\80\00\07\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7e\00\60\01"
+ "\7f\01\7e\60\00\02\7e\63\01\03\83\80\80\80\00\02"
+ "\02\05\0d\85\80\80\80\00\02\00\04\00\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\a8\80\80\80\00\02\87\80\80"
+ "\80\00\00\20\00\ac\e2\01\0b\96\80\80\80\00\00\02"
+ "\06\20\00\d2\00\e0\03\e3\03\01\00\00\00\42\0b\d0"
+ "\01\0b\1a\0b"
+)
+(module instance)
+(assert_suspension (invoke "main" (i32.const 0x17)) "unhandled")
+(assert_suspension (invoke "main" (i32.const 0xffff_ffd5)) "unhandled")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend12.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend12.wast
new file mode 100644
index 0000000..7a3e433
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend12.wast
@@ -0,0 +1,23 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (type $f2 (func (param i32)))
+ (type $c2 (cont $f2))
+ (tag $e (param i64))
+ (tag $f (param i64))
+
+ (func $s (param i32) (suspend $f (i64.extend_i32_s (local.get 0))))
+ (elem declare func $s)
+ (func (export "main") (param i32) (result i64)
+ (block (result i64 (ref null $c1))
+ (resume $c2 (on $e 0) (local.get 0)
+ (cont.new $c2 (ref.func $s)))
+ (i64.const 11)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_suspension (invoke "main" (i32.const 23)) "unhandled")
+(assert_suspension (invoke "main" (i32.const -43)) "unhandled")
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend13.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend13.bin.wast
new file mode 100644
index 0000000..0e02aa9
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend13.bin.wast
@@ -0,0 +1,15 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9b\80\80\80\00\07\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7e\00\60\01"
+ "\7f\01\7e\60\00\02\7e\63\01\03\83\80\80\80\00\02"
+ "\02\05\0d\85\80\80\80\00\02\00\04\00\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\b9\80\80\80\00\02\87\80\80"
+ "\80\00\00\20\00\ac\e2\01\0b\a7\80\80\80\00\00\02"
+ "\06\02\06\20\00\d2\00\e0\03\e3\03\02\00\00\00\00"
+ "\01\01\42\0b\d0\01\0b\1a\42\98\78\7d\0f\0b\1a\42"
+ "\b0\70\7d\0f\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0xffff_ffe9)) (i64.const 0x7b9))
+(assert_return (invoke "main" (i32.const 0xffff_ffd5)) (i64.const 0x7a5))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend13.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend13.wast
new file mode 100644
index 0000000..a142bfe
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend13.wast
@@ -0,0 +1,30 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (type $f2 (func (param i32)))
+ (type $c2 (cont $f2))
+ (tag $e (param i64))
+ (tag $f (param i64))
+
+ (func $s (param i32) (suspend $f (i64.extend_i32_s (local.get 0))))
+ (elem declare func $s)
+ (func (export "main") (param i32) (result i64)
+ (block (result i64 (ref null $c1))
+ (block (result i64 (ref null $c1))
+ (resume $c2 (on $e 0) (on $f 1) (local.get 0)
+ (cont.new $c2 (ref.func $s)))
+ (i64.const 11)
+ (ref.null $c1)
+ )
+ ;; $e
+ drop
+ (return (i64.sub (i64.const -1000)))
+ )
+ ;; $f
+ drop
+ (return (i64.sub (i64.const -2000)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const -23)) (i64.const 1977))
+(assert_return (invoke "main" (i32.const -43)) (i64.const 1957))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend14.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend14.bin.wast
new file mode 100644
index 0000000..8c90e8c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend14.bin.wast
@@ -0,0 +1,18 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9b\80\80\80\00\07\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7e\00\60\01"
+ "\7f\01\7e\60\00\02\7e\63\01\03\83\80\80\80\00\02"
+ "\02\05\0d\85\80\80\80\00\02\00\04\00\04\07\88\80"
+ "\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80"
+ "\00\01\03\00\01\00\0a\c7\80\80\80\00\02\95\80\80"
+ "\80\00\00\20\00\41\00\48\04\40\20\00\ac\e2\01\05"
+ "\20\00\ac\e2\00\0b\0b\a7\80\80\80\00\00\02\06\02"
+ "\06\20\00\d2\00\e0\03\e3\03\02\00\00\00\00\01\01"
+ "\42\0b\d0\01\0b\1a\42\98\78\7d\0f\0b\1a\42\b0\70"
+ "\7d\0f\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0xffff_ffe9)) (i64.const 0x7b9))
+(assert_return (invoke "main" (i32.const 0xffff_ffd5)) (i64.const 0x7a5))
+(assert_return (invoke "main" (i32.const 0x17)) (i64.const 0x3ff))
+(assert_return (invoke "main" (i32.const 0x2b)) (i64.const 0x413))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend14.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend14.wast
new file mode 100644
index 0000000..1858108
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend14.wast
@@ -0,0 +1,38 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (type $f2 (func (param i32)))
+ (type $c2 (cont $f2))
+ (tag $e (param i64))
+ (tag $f (param i64))
+
+ (func $s (param i32)
+ (if (i32.lt_s (local.get 0) (i32.const 0))
+ (then (suspend $f (i64.extend_i32_s (local.get 0))))
+ (else (suspend $e (i64.extend_i32_s (local.get 0))))
+ )
+ )
+ (elem declare func $s)
+ (func (export "main") (param i32) (result i64)
+ (block (result i64 (ref null $c1))
+ (block (result i64 (ref null $c1))
+ (resume $c2 (on $e 0) (on $f 1) (local.get 0)
+ (cont.new $c2 (ref.func $s)))
+ (i64.const 11)
+ (ref.null $c1)
+ )
+ ;; $e
+ drop
+ (return (i64.sub (i64.const -1000)))
+ )
+ ;; $f
+ drop
+ (return (i64.sub (i64.const -2000)))
+ )
+)
+
+(assert_return (invoke "main" (i32.const -23)) (i64.const 1977))
+(assert_return (invoke "main" (i32.const -43)) (i64.const 1957))
+
+(assert_return (invoke "main" (i32.const 23)) (i64.const 1023))
+(assert_return (invoke "main" (i32.const 43)) (i64.const 1043))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend15.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend15.bin.wast
new file mode 100644
index 0000000..f1d7fdb
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend15.bin.wast
@@ -0,0 +1,19 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\97\80\80\80\00\06\60"
+ "\01\7f\00\60\00\00\5d\00\5d\01\60\00\02\7f\63\03"
+ "\60\01\7f\01\7f\03\83\80\80\80\00\02\00\05\0d\83"
+ "\80\80\80\00\01\00\00\07\88\80\80\80\00\01\04\6d"
+ "\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00"
+ "\0a\ca\80\80\80\00\02\a9\80\80\80\00\00\20\00\45"
+ "\04\40\41\00\e2\00\05\02\04\20\00\41\01\6b\d2\00"
+ "\e0\02\e3\02\01\00\00\00\41\7f\d0\03\0b\1a\41\01"
+ "\6a\e2\00\0b\0b\96\80\80\80\00\00\02\04\20\00\d2"
+ "\00\e0\02\e3\02\01\00\00\00\41\7f\d0\03\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x0)) (i32.const 0x0))
+(assert_return (invoke "main" (i32.const 0x2)) (i32.const 0x2))
+(assert_return (invoke "main" (i32.const 0x5)) (i32.const 0x5))
+(assert_return (invoke "main" (i32.const 0xa)) (i32.const 0xa))
+(assert_return (invoke "main" (i32.const 0x2a)) (i32.const 0x2a))
+(assert_return (invoke "main" (i32.const 0x80)) (i32.const 0x80))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend15.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend15.wast
new file mode 100644
index 0000000..bf8eb01
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend15.wast
@@ -0,0 +1,43 @@
+(module
+ (type $f1 (func (param i32)))
+ (type $f2 (func))
+ (type $c1 (cont $f1))
+ (type $c2 (cont $f2))
+ (tag $ts (param i32))
+ (func $foo (param i32)
+ (if (i32.eqz (local.get 0))
+ (then
+ (suspend $ts (i32.const 0))
+ )
+ (else
+ (block (result i32 (ref null $c2))
+ (resume $c1 (on $ts 0)
+ (i32.sub (local.get 0) (i32.const 1))
+ (cont.new $c1 (ref.func $foo))
+ )
+ (i32.const -1)
+ (ref.null $c2)
+ )
+ (drop)
+ (i32.add (i32.const 1))
+ (suspend $ts)
+ )
+ )
+ )
+ (elem declare func $foo)
+ (func (export "main") (param i32) (result i32)
+ (block (result i32 (ref null $c2))
+ (resume $c1 (on $ts 0) (local.get 0) (cont.new $c1 (ref.func $foo)))
+ (i32.const -1)
+ (ref.null $c2)
+ )
+ (drop)
+ )
+)
+
+(assert_return (invoke "main" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "main" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "main" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "main" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "main" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "main" (i32.const 128)) (i32.const 128))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend16.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend16.bin.wast
new file mode 100644
index 0000000..aeb8d7a
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend16.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\91\80\80\80\00\05\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\60\00\00\03"
+ "\84\80\80\80\00\03\00\00\00\0d\85\80\80\80\00\02"
+ "\00\04\00\00\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\02\09\89\80\80\80\00\02\03\00\01\00\03\00\01"
+ "\01\0a\bb\80\80\80\00\03\84\80\80\80\00\00\e2\01"
+ "\0b\8d\80\80\80\00\00\d2\00\e0\01\e3\01\00\41\0a"
+ "\6a\0f\0b\9a\80\80\80\00\00\41\ce\00\02\63\03\d2"
+ "\01\e0\01\e3\01\01\00\01\00\41\94\03\0f\0b\e3\03"
+ "\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x58))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend16.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend16.wast
new file mode 100644
index 0000000..8e36efb
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend16.wast
@@ -0,0 +1,30 @@
+(module
+ (type $f (func (result i32)))
+ (type $c (cont $f))
+ (type $fb (func (param i32) (result i32)))
+ (type $cb (cont $fb))
+ (tag $dummy)
+ (tag $fetch (result i32))
+
+ (func $func_b (result i32)
+ (suspend $fetch)
+ )
+ (elem declare func $func_b)
+
+ (func $func_a (result i32)
+ (resume $c (cont.new $c (ref.func $func_b)))
+ (i32.add (i32.const 10))
+ (return)
+ )
+ (elem declare func $func_a)
+ (func (export "main") (result i32)
+ (i32.const 78)
+ (block (result (ref null $cb))
+ (resume $c (on $fetch 0) (cont.new $c (ref.func $func_a)))
+ (return (i32.const 404))
+ )
+ (resume $cb)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 88))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend17.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend17.bin.wast
new file mode 100644
index 0000000..2386fd7
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend17.bin.wast
@@ -0,0 +1,14 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8e\80\80\80\00\04\60"
+ "\00\01\7f\5d\00\60\01\7f\01\7f\5d\02\03\84\80\80"
+ "\80\00\03\00\00\00\0d\83\80\80\80\00\01\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\02\09\89\80"
+ "\80\80\00\02\03\00\01\00\03\00\01\01\0a\c6\80\80"
+ "\80\00\03\84\80\80\80\00\00\e2\00\0b\99\80\80\80"
+ "\00\00\41\0a\02\63\03\d2\00\e0\01\e3\01\01\00\00"
+ "\00\41\e5\00\0f\0b\e3\03\00\0b\99\80\80\80\00\00"
+ "\41\14\02\63\03\d2\01\e0\01\e3\01\01\00\00\00\41"
+ "\ca\01\0f\0b\e3\03\00\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0xca))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend17.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend17.wast
new file mode 100644
index 0000000..ec119de
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend17.wast
@@ -0,0 +1,32 @@
+(module
+ (type $f (func (result i32)))
+ (type $c (cont $f))
+ (type $fb (func (param i32) (result i32)))
+ (type $cb (cont $fb))
+ (tag $fetch (result i32))
+
+ (func $func_b (result i32)
+ (suspend $fetch)
+ )
+ (elem declare func $func_b)
+
+ (func $func_a (result i32)
+ (i32.const 10)
+ (block (result (ref null $cb))
+ (resume $c (on $fetch 0) (cont.new $c (ref.func $func_b)))
+ (return (i32.const 101))
+ )
+ (resume $cb)
+ )
+ (elem declare func $func_a)
+ (func (export "main") (result i32)
+ (i32.const 20)
+ (block (result (ref null $cb))
+ (resume $c (on $fetch 0) (cont.new $c (ref.func $func_a)))
+ (return (i32.const 202))
+ )
+ (resume $cb)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 202))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend18.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend18.bin.wast
new file mode 100644
index 0000000..d6e81df
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend18.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\0d\83\80\80\80\00\01\00\00\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03"
+ "\00\01\00\0a\b1\80\80\80\00\02\84\80\80\80\00\00"
+ "\e2\00\0b\a2\80\80\80\00\00\41\01\02\63\01\41\02"
+ "\41\03\41\04\41\05\d2\00\e0\01\e3\01\01\00\00\00"
+ "\1a\1a\1a\1a\d0\01\0b\1a\0f\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend18.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend18.wast
new file mode 100644
index 0000000..8c3feab
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend18.wast
@@ -0,0 +1,28 @@
+(module
+ (type $f (func))
+ (type $c (cont $f))
+ (tag $t)
+
+ (func $foo (suspend $t))
+ (elem declare func $foo)
+
+ (func (export "main") (result i32)
+ (i32.const 1)
+ (block (result (ref null $c))
+ (i32.const 2)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+ (resume $c (on $t 0) (cont.new $c (ref.func $foo)))
+ (drop)
+ (drop)
+ (drop)
+ (drop)
+ (ref.null $c)
+ )
+ (drop)
+ (return)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend19.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend19.bin.wast
new file mode 100644
index 0000000..df71e43
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend19.bin.wast
@@ -0,0 +1,13 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8f\80\80\80\00\04\60"
+ "\00\00\5d\00\60\00\01\7f\60\01\63\01\00\03\83\80"
+ "\80\80\00\02\00\02\0d\83\80\80\80\00\01\00\00\07"
+ "\88\80\80\80\00\01\04\6d\61\69\6e\00\01\09\85\80"
+ "\80\80\00\01\03\00\01\00\0a\b4\80\80\80\00\02\84"
+ "\80\80\80\00\00\e2\00\0b\a5\80\80\80\00\01\01\63"
+ "\01\41\01\d2\00\e0\01\03\03\21\00\41\02\41\03\41"
+ "\04\41\05\20\00\e3\01\01\00\00\00\1a\1a\1a\1a\0b"
+ "\0f\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend19.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend19.wast
new file mode 100644
index 0000000..e21f9a8
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend19.wast
@@ -0,0 +1,30 @@
+(module
+ (type $f (func))
+ (type $c (cont $f))
+ (tag $t)
+
+ (func $foo (suspend $t))
+ (elem declare func $foo)
+
+ (func (export "main") (result i32)
+ (local $x (ref null $c))
+ (i32.const 1)
+ (cont.new $c (ref.func $foo))
+ (loop (param (ref null $c))
+ (local.set $x)
+ (i32.const 2)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+ (local.get $x)
+ (resume $c (on $t 0))
+ (drop)
+ (drop)
+ (drop)
+ (drop)
+ )
+ (return)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 1))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend2.bin.wast
new file mode 100644
index 0000000..4bea1fe
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend2.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\0d\83\80\80\80\00\01\00\00\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03"
+ "\00\01\00\0a\a2\80\80\80\00\02\84\80\80\80\00\00"
+ "\e2\00\0b\93\80\80\80\00\00\02\63\01\d2\00\e0\01"
+ "\e3\01\01\00\00\00\d0\01\0b\d1\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x0))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend2.wast
new file mode 100644
index 0000000..27acd58
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend2.wast
@@ -0,0 +1,16 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e)
+ (func $s (suspend $e))
+ (elem declare func $s)
+ (func (export "main") (result i32)
+ (block (result (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (ref.null $c1)
+ )
+ (ref.is_null)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 0))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend3.bin.wast
new file mode 100644
index 0000000..bb0deea
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend3.bin.wast
@@ -0,0 +1,11 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\8a\80\80\80\00\03\60"
+ "\00\00\5d\00\60\00\01\7f\03\83\80\80\80\00\02\00"
+ "\02\0d\83\80\80\80\00\01\00\00\07\88\80\80\80\00"
+ "\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01\03"
+ "\00\01\00\0a\a6\80\80\80\00\02\84\80\80\80\00\00"
+ "\e2\00\0b\97\80\80\80\00\00\02\63\01\d2\00\e0\01"
+ "\e3\01\01\00\00\00\d0\01\0b\e3\01\00\41\2c\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x2c))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend3.wast
new file mode 100644
index 0000000..0a21a9f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend3.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e)
+ (func $s (suspend $e))
+ (elem declare func $s)
+ (func (export "main") (result i32)
+ (block (result (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (ref.null $c1)
+ )
+ (resume $c1)
+ (i32.const 44)
+ )
+)
+
+(assert_return (invoke "main") (i32.const 44))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend4.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend4.bin.wast
new file mode 100644
index 0000000..5e1e598
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend4.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\94\80\80\80\00\05\60"
+ "\00\00\5d\00\60\01\7f\00\60\00\01\7f\60\00\02\7f"
+ "\63\01\03\83\80\80\80\00\02\00\03\0d\83\80\80\80"
+ "\00\01\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\a5\80"
+ "\80\80\00\02\86\80\80\80\00\00\41\37\e2\00\0b\94"
+ "\80\80\80\00\00\02\04\d2\00\e0\01\e3\01\01\00\00"
+ "\00\41\2c\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i32.const 0x37))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend4.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend4.wast
new file mode 100644
index 0000000..07fc00b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend4.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e (param i32))
+ (func $s (suspend $e (i32.const 55)))
+ (elem declare func $s)
+ (func (export "main") (result i32)
+ (block (result i32 (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (i32.const 44)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main") (i32.const 55))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend5.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend5.bin.wast
new file mode 100644
index 0000000..00efd60
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend5.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\94\80\80\80\00\05\60"
+ "\00\00\5d\00\60\01\7e\00\60\00\01\7e\60\00\02\7e"
+ "\63\01\03\83\80\80\80\00\02\00\03\0d\83\80\80\80"
+ "\00\01\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\a6\80"
+ "\80\80\00\02\87\80\80\80\00\00\42\ac\54\e2\00\0b"
+ "\94\80\80\80\00\00\02\04\d2\00\e0\01\e3\01\01\00"
+ "\00\00\42\2c\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (i64.const 0xffff_ffff_ffff_ea2c))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend5.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend5.wast
new file mode 100644
index 0000000..c5e1dc1
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend5.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e (param i64))
+ (func $s (suspend $e (i64.const -5588)))
+ (elem declare func $s)
+ (func (export "main") (result i64)
+ (block (result i64 (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (i64.const 44)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main") (i64.const -5588))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend6.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend6.bin.wast
new file mode 100644
index 0000000..19f855e
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend6.bin.wast
@@ -0,0 +1,12 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\94\80\80\80\00\05\60"
+ "\00\00\5d\00\60\01\7d\00\60\00\01\7d\60\00\02\7d"
+ "\63\01\03\83\80\80\80\00\02\00\03\0d\83\80\80\80"
+ "\00\01\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\ab\80"
+ "\80\80\00\02\89\80\80\80\00\00\43\00\a0\ae\c5\e2"
+ "\00\0b\97\80\80\80\00\00\02\04\d2\00\e0\01\e3\01"
+ "\01\00\00\00\43\00\00\30\42\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (f32.const -0x1.5d4p+12))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend6.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend6.wast
new file mode 100644
index 0000000..5a74f39
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend6.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e (param f32))
+ (func $s (suspend $e (f32.const -5588)))
+ (elem declare func $s)
+ (func (export "main") (result f32)
+ (block (result f32 (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (f32.const 44)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main") (f32.const -5588))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend7.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend7.bin.wast
new file mode 100644
index 0000000..fed520b
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend7.bin.wast
@@ -0,0 +1,13 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\94\80\80\80\00\05\60"
+ "\00\00\5d\00\60\01\7c\00\60\00\01\7c\60\00\02\7c"
+ "\63\01\03\83\80\80\80\00\02\00\03\0d\83\80\80\80"
+ "\00\01\00\02\07\88\80\80\80\00\01\04\6d\61\69\6e"
+ "\00\01\09\85\80\80\80\00\01\03\00\01\00\0a\b3\80"
+ "\80\80\00\02\8d\80\80\80\00\00\44\00\00\00\00\00"
+ "\d4\b5\c0\e2\00\0b\9b\80\80\80\00\00\02\04\d2\00"
+ "\e0\01\e3\01\01\00\00\00\44\00\00\00\00\00\00\46"
+ "\40\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main") (f64.const -0x1.5d4p+12))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend7.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend7.wast
new file mode 100644
index 0000000..1b80a1a
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend7.wast
@@ -0,0 +1,17 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (tag $e (param f64))
+ (func $s (suspend $e (f64.const -5588)))
+ (elem declare func $s)
+ (func (export "main") (result f64)
+ (block (result f64 (ref null $c1))
+ (resume $c1 (on $e 0) (cont.new $c1 (ref.func $s)))
+ (f64.const 44)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main") (f64.const -5588))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend8.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend8.bin.wast
new file mode 100644
index 0000000..e174d56
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend8.bin.wast
@@ -0,0 +1,13 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\97\80\80\80\00\06\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7f\01\7f\60"
+ "\00\02\7f\63\01\03\83\80\80\80\00\02\02\04\0d\83"
+ "\80\80\80\00\01\00\02\07\88\80\80\80\00\01\04\6d"
+ "\61\69\6e\00\01\09\85\80\80\80\00\01\03\00\01\00"
+ "\0a\a7\80\80\80\00\02\86\80\80\80\00\00\20\00\e2"
+ "\00\0b\96\80\80\80\00\00\02\05\20\00\d2\00\e0\03"
+ "\e3\03\01\00\00\00\41\0b\d0\01\0b\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x16)) (i32.const 0x16))
+(assert_return (invoke "main" (i32.const 0xffff_ffd4)) (i32.const 0xffff_ffd4))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend8.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend8.wast
new file mode 100644
index 0000000..e9923fb
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend8.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (type $f2 (func (param i32)))
+ (type $c2 (cont $f2))
+ (tag $e (param i32))
+ (func $s (param i32) (suspend $e (local.get 0)))
+ (elem declare func $s)
+ (func (export "main") (param i32) (result i32)
+ (block (result i32 (ref null $c1))
+ (resume $c2 (on $e 0) (local.get 0)
+ (cont.new $c2 (ref.func $s)))
+ (i32.const 11)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main" (i32.const 22)) (i32.const 22))
+(assert_return (invoke "main" (i32.const -44)) (i32.const -44))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend9.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend9.bin.wast
new file mode 100644
index 0000000..c0b00da
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend9.bin.wast
@@ -0,0 +1,17 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9b\80\80\80\00\07\60"
+ "\00\00\5d\00\60\01\7f\00\5d\02\60\01\7e\00\60\01"
+ "\7f\01\7e\60\00\02\7e\63\01\03\83\80\80\80\00\02"
+ "\02\05\0d\83\80\80\80\00\01\00\04\07\88\80\80\80"
+ "\00\01\04\6d\61\69\6e\00\01\09\85\80\80\80\00\01"
+ "\03\00\01\00\0a\a8\80\80\80\00\02\87\80\80\80\00"
+ "\00\20\00\ac\e2\00\0b\96\80\80\80\00\00\02\06\20"
+ "\00\d2\00\e0\03\e3\03\01\00\00\00\42\0b\d0\01\0b"
+ "\1a\0b"
+)
+(module instance)
+(assert_return (invoke "main" (i32.const 0x17)) (i64.const 0x17))
+(assert_return
+ (invoke "main" (i32.const 0xffff_ffd5))
+ (i64.const 0xffff_ffff_ffff_ffd5)
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend9.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend9.wast
new file mode 100644
index 0000000..f6754a7
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/suspend9.wast
@@ -0,0 +1,21 @@
+(module
+ (type $f1 (func))
+ (type $c1 (cont $f1))
+ (type $f2 (func (param i32)))
+ (type $c2 (cont $f2))
+ (tag $e (param i64))
+ (func $s (param i32) (suspend $e (i64.extend_i32_s (local.get 0))))
+ (elem declare func $s)
+ (func (export "main") (param i32) (result i64)
+ (block (result i64 (ref null $c1))
+ (resume $c2 (on $e 0) (local.get 0)
+ (cont.new $c2 (ref.func $s)))
+ (i64.const 11)
+ (ref.null $c1)
+ )
+ drop
+ )
+)
+
+(assert_return (invoke "main" (i32.const 23)) (i64.const 23))
+(assert_return (invoke "main" (i32.const -43)) (i64.const -43))
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont0.bin.wast
new file mode 100644
index 0000000..59e773c
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont0.bin.wast
@@ -0,0 +1,5 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\04\84\80\80\80\00\01\68"
+ "\00\00"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont0.wast
new file mode 100644
index 0000000..84d117f
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont0.wast
@@ -0,0 +1,4 @@
+;; Check that tables can have a continuation type
+(module
+ (table 0 (ref null cont))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont1.bin.wast
new file mode 100644
index 0000000..323c3db
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont1.bin.wast
@@ -0,0 +1,5 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\86\80\80\80\00\02\60"
+ "\00\00\5d\00\04\85\80\80\80\00\01\63\01\00\00"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont1.wast
new file mode 100644
index 0000000..068ff83
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/table_cont1.wast
@@ -0,0 +1,6 @@
+;; Check that tables can have a specific continuation type
+(module
+ (type $f (func))
+ (type $c (cont $f))
+ (table 0 (ref null $c))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag0.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag0.bin.wast
new file mode 100644
index 0000000..d488820
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag0.bin.wast
@@ -0,0 +1,6 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\91\80\80\80\00\04\60"
+ "\01\7f\00\60\00\01\7f\60\01\7f\01\7f\60\00\00\0d"
+ "\89\80\80\80\00\04\00\00\00\01\00\02\00\03"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag0.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag0.wast
new file mode 100644
index 0000000..1c64902
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag0.wast
@@ -0,0 +1,7 @@
+;; Test a module can define a simple tag
+(module
+ (tag $e (param i32))
+ (tag $f (result i32))
+ (tag $g (param i32) (result i32))
+ (tag $h (param) (result))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag1.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag1.bin.wast
new file mode 100644
index 0000000..ec30ca0
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag1.bin.wast
@@ -0,0 +1,6 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\94\80\80\80\00\03\60"
+ "\02\7f\7e\02\7f\7e\60\02\7d\7c\02\7d\7c\60\01\7b"
+ "\01\7b\0d\87\80\80\80\00\03\00\00\00\01\00\02"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag1.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag1.wast
new file mode 100644
index 0000000..edcb358
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag1.wast
@@ -0,0 +1,6 @@
+;; Test that tags can use all basic primitives
+(module
+ (tag $e (param i32 i64) (result i32 i64))
+ (tag $f (param f32 f64) (result f32 f64))
+ (tag $g (param v128) (result v128))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag2.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag2.bin.wast
new file mode 100644
index 0000000..b2233ec
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag2.bin.wast
@@ -0,0 +1,7 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\9f\80\80\80\00\06\60"
+ "\01\6e\01\6e\60\01\6f\01\6f\60\01\70\01\70\60\01"
+ "\6b\01\6b\60\01\6a\01\6a\60\01\6c\01\6c\0d\8d\80"
+ "\80\80\00\06\00\00\00\01\00\02\00\03\00\04\00\05"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag2.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag2.wast
new file mode 100644
index 0000000..77f9e48
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag2.wast
@@ -0,0 +1,9 @@
+;; Test that tags can use all reference types and simple GC types
+(module
+ (tag $e (param anyref) (result anyref))
+ (tag $f (param externref) (result externref))
+ (tag $g (param funcref) (result funcref))
+ (tag $h (param structref) (result structref))
+ (tag $i (param arrayref) (result arrayref))
+ (tag $j (param i31ref) (result i31ref))
+)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag3.bin.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag3.bin.wast
new file mode 100644
index 0000000..574ec0d
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag3.bin.wast
@@ -0,0 +1,9 @@
+(module definition binary
+ "\00\61\73\6d\01\00\00\00\01\b5\80\80\80\00\09\5f"
+ "\00\5e\7f\00\60\01\7f\01\7f\60\01\64\00\01\64\00"
+ "\60\01\63\00\01\63\00\60\01\64\01\01\64\01\60\01"
+ "\63\01\01\63\01\60\01\64\02\01\64\02\60\01\63\02"
+ "\01\63\02\0d\8d\80\80\80\00\06\00\03\00\04\00\05"
+ "\00\06\00\07\00\08"
+)
+(module instance)
diff --git a/benchmarks/wasm/wasmfx/wizard-stack-switching/tag3.wast b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag3.wast
new file mode 100644
index 0000000..f08cec3
--- /dev/null
+++ b/benchmarks/wasm/wasmfx/wizard-stack-switching/tag3.wast
@@ -0,0 +1,13 @@
+;; Test that tags can use all complex GC types
+(module
+ (type $s (struct))
+ (type $a (array i32))
+ (type $f (func (param i32) (result i32)))
+
+ (tag $e (param (ref $s)) (result (ref $s)))
+ (tag $f (param (ref null $s)) (result (ref null $s)))
+ (tag $g (param (ref $a)) (result (ref $a)))
+ (tag $h (param (ref null $a)) (result (ref null $a)))
+ (tag $j (param (ref $f)) (result (ref $f)))
+ (tag $k (param (ref null $f)) (result (ref null $f)))
+)
diff --git a/build.sbt b/build.sbt
index 18a88e8..113165d 100644
--- a/build.sbt
+++ b/build.sbt
@@ -10,9 +10,23 @@ lazy val root = project
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test",
libraryDependencies += "org.scala-lang" %% "scala3-staging" % scalaVersion.value,
- libraryDependencies += "org.antlr" % "antlr4-runtime" % "4.13.0"
+ libraryDependencies += "org.antlr" % "antlr4-runtime" % "4.13.0",
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
)
+fork := true
+val commonJavaOptions = Seq(
+ "-Xms4G",
+ "-Xmx32G",
+ "-Xss1024M",
+ "-XX:MaxMetaspaceSize=8G",
+ "-XX:ReservedCodeCacheSize=2048M"
+)
+run / javaOptions ++= commonJavaOptions
+Test / javaOptions ++= commonJavaOptions
+
+Test / parallelExecution := false
+
scalacOptions ++= Seq(
"-Xcheck-macros",
"-explain"
diff --git a/src/main/java/wasm/WatLexer.java b/src/main/java/wasm/WatLexer.java
index 709a0a3..35fd18f 100644
--- a/src/main/java/wasm/WatLexer.java
+++ b/src/main/java/wasm/WatLexer.java
@@ -20,30 +20,31 @@ public class WatLexer extends Lexer {
LPAR=1, RPAR=2, NAT=3, INT=4, FLOAT=5, STRING_=6, VALUE_TYPE=7, CONST=8,
SYMBOLIC=9, FUNCREF=10, EXTERNREF=11, MUT=12, REF=13, CONT=14, NULL=15,
NOP=16, SYM_ASSERT=17, ALLOC=18, FREE=19, UNREACHABLE=20, DROP=21, BLOCK=22,
- LOOP=23, END=24, BR=25, BR_IF=26, BR_TABLE=27, RETURN=28, IF=29, THEN=30,
- ELSE=31, SELECT=32, CALL=33, CALL_INDIRECT=34, RETURN_CALL=35, RETURN_CALL_INDIRECT=36,
- REFFUNC=37, CALLREF=38, RESUME=39, ON=40, CONTNEW=41, CONTBIND=42, SUSPEND=43,
- REFNULL=44, REFISNULL=45, TRY=46, CATCH=47, THROW=48, RESUME0=49, LOCAL_GET=50,
- LOCAL_SET=51, LOCAL_TEE=52, GLOBAL_GET=53, GLOBAL_SET=54, LOAD=55, STORE=56,
- UNDERSCORE=57, OFFSET_EQ=58, ALIGN_EQ=59, SIGN_POSTFIX=60, MEM_SIZE=61,
- I32=62, I64=63, F32=64, F64=65, IXX=66, FXX=67, OP_EQZ=68, OP_EQ=69, OP_NE=70,
- OP_LT=71, OP_LTS=72, OP_LTU=73, OP_LE=74, OP_LES=75, OP_LEU=76, OP_GT=77,
- OP_GTS=78, OP_GTU=79, OP_GE=80, OP_GES=81, OP_GEU=82, OP_CLZ=83, OP_CTZ=84,
- OP_POPCNT=85, OP_NEG=86, OP_ABS=87, OP_SQRT=88, OP_CEIL=89, OP_FLOOR=90,
- OP_TRUNC=91, OP_NEAREST=92, OP_ADD=93, OP_SUB=94, OP_MUL=95, OP_DIV=96,
- OP_DIV_S=97, OP_DIV_U=98, OP_REM_S=99, OP_REM_U=100, OP_AND=101, OP_OR=102,
- OP_XOR=103, OP_SHL=104, OP_SHR_S=105, OP_SHR_U=106, OP_ROTL=107, OP_ROTR=108,
- OP_MIN=109, OP_MAX=110, OP_COPYSIGN=111, OP_WRAP=112, OP_TRUNC_=113, OP_TRUNC_SAT=114,
- OP_CONVERT=115, OP_EXTEND=116, OP_DEMOTE=117, OP_PROMOTE=118, OP_REINTER=119,
- MEMORY_SIZE=120, MEMORY_GROW=121, MEMORY_FILL=122, MEMORY_COPY=123, MEMORY_INIT=124,
- TEST=125, COMPARE=126, UNARY=127, BINARY=128, CONVERT=129, TYPE=130, FUNC=131,
- EXTERN=132, START_=133, PARAM=134, RESULT=135, LOCAL=136, GLOBAL=137,
- TABLE=138, MEMORY=139, ELEM=140, DATA=141, OFFSET=142, IMPORT=143, EXPORT=144,
- TAG=145, DECLARE=146, MODULE=147, BIN=148, QUOTE=149, DEFINITION=150,
- INSTANCE=151, SCRIPT=152, REGISTER=153, INVOKE=154, GET=155, ASSERT_MALFORMED=156,
- ASSERT_INVALID=157, ASSERT_UNLINKABLE=158, ASSERT_RETURN=159, ASSERT_RETURN_CANONICAL_NAN=160,
- ASSERT_RETURN_ARITHMETIC_NAN=161, ASSERT_TRAP=162, ASSERT_EXHAUSTION=163,
- INPUT=164, OUTPUT=165, VAR=166, V128=167, SPACE=168, COMMENT=169;
+ LOOP=23, FOR=24, VBAR=25, END=26, BR=27, BR_IF=28, BR_TABLE=29, RETURN=30,
+ IF=31, THEN=32, ELSE=33, SELECT=34, CALL=35, CALL_INDIRECT=36, RETURN_CALL=37,
+ RETURN_CALL_INDIRECT=38, REFFUNC=39, CALLREF=40, RESUME=41, ON=42, CONTNEW=43,
+ CONTBIND=44, SUSPEND=45, REFNULL=46, REFISNULL=47, TRY=48, CATCH=49, THROW=50,
+ RESUME0=51, LOCAL_GET=52, LOCAL_SET=53, LOCAL_TEE=54, GLOBAL_GET=55, GLOBAL_SET=56,
+ LOAD=57, STORE=58, UNDERSCORE=59, OFFSET_EQ=60, ALIGN_EQ=61, SIGN_POSTFIX=62,
+ MEM_SIZE=63, I32=64, I64=65, F32=66, F64=67, IXX=68, FXX=69, OP_EQZ=70,
+ OP_EQ=71, OP_NE=72, OP_LT=73, OP_LTS=74, OP_LTU=75, OP_LE=76, OP_LES=77,
+ OP_LEU=78, OP_GT=79, OP_GTS=80, OP_GTU=81, OP_GE=82, OP_GES=83, OP_GEU=84,
+ OP_CLZ=85, OP_CTZ=86, OP_POPCNT=87, OP_NEG=88, OP_ABS=89, OP_SQRT=90,
+ OP_CEIL=91, OP_FLOOR=92, OP_TRUNC=93, OP_NEAREST=94, OP_ADD=95, OP_SUB=96,
+ OP_MUL=97, OP_DIV=98, OP_DIV_S=99, OP_DIV_U=100, OP_REM_S=101, OP_REM_U=102,
+ OP_AND=103, OP_OR=104, OP_XOR=105, OP_SHL=106, OP_SHR_S=107, OP_SHR_U=108,
+ OP_ROTL=109, OP_ROTR=110, OP_MIN=111, OP_MAX=112, OP_COPYSIGN=113, OP_WRAP=114,
+ OP_TRUNC_=115, OP_TRUNC_SAT=116, OP_CONVERT=117, OP_EXTEND=118, OP_DEMOTE=119,
+ OP_PROMOTE=120, OP_REINTER=121, MEMORY_SIZE=122, MEMORY_GROW=123, MEMORY_FILL=124,
+ MEMORY_COPY=125, MEMORY_INIT=126, TEST=127, COMPARE=128, UNARY=129, BINARY=130,
+ CONVERT=131, TYPE=132, FUNC=133, EXTERN=134, START_=135, PARAM=136, RESULT=137,
+ LOCAL=138, GLOBAL=139, TABLE=140, MEMORY=141, ELEM=142, DATA=143, OFFSET=144,
+ IMPORT=145, EXPORT=146, TAG=147, DECLARE=148, MODULE=149, BIN=150, QUOTE=151,
+ DEFINITION=152, INSTANCE=153, SCRIPT=154, REGISTER=155, INVOKE=156, GET=157,
+ ASSERT_MALFORMED=158, ASSERT_INVALID=159, ASSERT_UNLINKABLE=160, ASSERT_RETURN=161,
+ ASSERT_RETURN_CANONICAL_NAN=162, ASSERT_RETURN_ARITHMETIC_NAN=163, ASSERT_TRAP=164,
+ ASSERT_EXHAUSTION=165, INPUT=166, OUTPUT=167, VAR=168, V128=169, SPACE=170,
+ COMMENT=171;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
@@ -57,31 +58,32 @@ private static String[] makeRuleNames() {
"LPAR", "RPAR", "NAT", "INT", "FLOAT", "STRING_", "VALUE_TYPE", "CONST",
"SYMBOLIC", "FUNCREF", "EXTERNREF", "MUT", "REF", "CONT", "NULL", "NOP",
"SYM_ASSERT", "ALLOC", "FREE", "UNREACHABLE", "DROP", "BLOCK", "LOOP",
- "END", "BR", "BR_IF", "BR_TABLE", "RETURN", "IF", "THEN", "ELSE", "SELECT",
- "CALL", "CALL_INDIRECT", "RETURN_CALL", "RETURN_CALL_INDIRECT", "REFFUNC",
- "CALLREF", "RESUME", "ON", "CONTNEW", "CONTBIND", "SUSPEND", "REFNULL",
- "REFISNULL", "TRY", "CATCH", "THROW", "RESUME0", "LOCAL_GET", "LOCAL_SET",
- "LOCAL_TEE", "GLOBAL_GET", "GLOBAL_SET", "LOAD", "STORE", "UNDERSCORE",
- "OFFSET_EQ", "ALIGN_EQ", "SIGN_POSTFIX", "MEM_SIZE", "I32", "I64", "F32",
- "F64", "IXX", "FXX", "OP_EQZ", "OP_EQ", "OP_NE", "OP_LT", "OP_LTS", "OP_LTU",
- "OP_LE", "OP_LES", "OP_LEU", "OP_GT", "OP_GTS", "OP_GTU", "OP_GE", "OP_GES",
- "OP_GEU", "OP_CLZ", "OP_CTZ", "OP_POPCNT", "OP_NEG", "OP_ABS", "OP_SQRT",
- "OP_CEIL", "OP_FLOOR", "OP_TRUNC", "OP_NEAREST", "OP_ADD", "OP_SUB",
- "OP_MUL", "OP_DIV", "OP_DIV_S", "OP_DIV_U", "OP_REM_S", "OP_REM_U", "OP_AND",
- "OP_OR", "OP_XOR", "OP_SHL", "OP_SHR_S", "OP_SHR_U", "OP_ROTL", "OP_ROTR",
- "OP_MIN", "OP_MAX", "OP_COPYSIGN", "OP_WRAP", "OP_TRUNC_", "OP_TRUNC_SAT",
- "OP_CONVERT", "OP_EXTEND", "OP_DEMOTE", "OP_PROMOTE", "OP_REINTER", "MEMORY_SIZE",
- "MEMORY_GROW", "MEMORY_FILL", "MEMORY_COPY", "MEMORY_INIT", "TEST", "COMPARE",
- "UNARY", "BINARY", "CONVERT", "TYPE", "FUNC", "EXTERN", "START_", "PARAM",
- "RESULT", "LOCAL", "GLOBAL", "TABLE", "MEMORY", "ELEM", "DATA", "OFFSET",
- "IMPORT", "EXPORT", "TAG", "DECLARE", "MODULE", "BIN", "QUOTE", "DEFINITION",
- "INSTANCE", "SCRIPT", "REGISTER", "INVOKE", "GET", "ASSERT_MALFORMED",
- "ASSERT_INVALID", "ASSERT_UNLINKABLE", "ASSERT_RETURN", "ASSERT_RETURN_CANONICAL_NAN",
- "ASSERT_RETURN_ARITHMETIC_NAN", "ASSERT_TRAP", "ASSERT_EXHAUSTION", "INPUT",
- "OUTPUT", "VAR", "V128", "SPACE", "COMMENT", "Symbol", "Num", "HexNum",
- "Sign", "Digit", "HexDigit", "Letter", "Nat", "Int", "Frac", "HexFrac",
- "Float", "String_", "Name", "Escape", "NXX", "Char", "Ascii", "Ascii_no_nl",
- "Utf8Cont", "Utf8", "Utf8_no_nl", "Utf8Enc"
+ "FOR", "VBAR", "END", "BR", "BR_IF", "BR_TABLE", "RETURN", "IF", "THEN",
+ "ELSE", "SELECT", "CALL", "CALL_INDIRECT", "RETURN_CALL", "RETURN_CALL_INDIRECT",
+ "REFFUNC", "CALLREF", "RESUME", "ON", "CONTNEW", "CONTBIND", "SUSPEND",
+ "REFNULL", "REFISNULL", "TRY", "CATCH", "THROW", "RESUME0", "LOCAL_GET",
+ "LOCAL_SET", "LOCAL_TEE", "GLOBAL_GET", "GLOBAL_SET", "LOAD", "STORE",
+ "UNDERSCORE", "OFFSET_EQ", "ALIGN_EQ", "SIGN_POSTFIX", "MEM_SIZE", "I32",
+ "I64", "F32", "F64", "IXX", "FXX", "OP_EQZ", "OP_EQ", "OP_NE", "OP_LT",
+ "OP_LTS", "OP_LTU", "OP_LE", "OP_LES", "OP_LEU", "OP_GT", "OP_GTS", "OP_GTU",
+ "OP_GE", "OP_GES", "OP_GEU", "OP_CLZ", "OP_CTZ", "OP_POPCNT", "OP_NEG",
+ "OP_ABS", "OP_SQRT", "OP_CEIL", "OP_FLOOR", "OP_TRUNC", "OP_NEAREST",
+ "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV", "OP_DIV_S", "OP_DIV_U", "OP_REM_S",
+ "OP_REM_U", "OP_AND", "OP_OR", "OP_XOR", "OP_SHL", "OP_SHR_S", "OP_SHR_U",
+ "OP_ROTL", "OP_ROTR", "OP_MIN", "OP_MAX", "OP_COPYSIGN", "OP_WRAP", "OP_TRUNC_",
+ "OP_TRUNC_SAT", "OP_CONVERT", "OP_EXTEND", "OP_DEMOTE", "OP_PROMOTE",
+ "OP_REINTER", "MEMORY_SIZE", "MEMORY_GROW", "MEMORY_FILL", "MEMORY_COPY",
+ "MEMORY_INIT", "TEST", "COMPARE", "UNARY", "BINARY", "CONVERT", "TYPE",
+ "FUNC", "EXTERN", "START_", "PARAM", "RESULT", "LOCAL", "GLOBAL", "TABLE",
+ "MEMORY", "ELEM", "DATA", "OFFSET", "IMPORT", "EXPORT", "TAG", "DECLARE",
+ "MODULE", "BIN", "QUOTE", "DEFINITION", "INSTANCE", "SCRIPT", "REGISTER",
+ "INVOKE", "GET", "ASSERT_MALFORMED", "ASSERT_INVALID", "ASSERT_UNLINKABLE",
+ "ASSERT_RETURN", "ASSERT_RETURN_CANONICAL_NAN", "ASSERT_RETURN_ARITHMETIC_NAN",
+ "ASSERT_TRAP", "ASSERT_EXHAUSTION", "INPUT", "OUTPUT", "VAR", "V128",
+ "SPACE", "COMMENT", "Symbol", "Num", "HexNum", "Sign", "Digit", "HexDigit",
+ "Letter", "Nat", "Int", "Frac", "HexFrac", "Float", "String_", "Name",
+ "Escape", "NXX", "Char", "Ascii", "Ascii_no_nl", "Utf8Cont", "Utf8",
+ "Utf8_no_nl", "Utf8Enc"
};
}
public static final String[] ruleNames = makeRuleNames();
@@ -91,30 +93,30 @@ private static String[] makeLiteralNames() {
null, "'('", "')'", null, null, null, null, null, null, null, "'funcref'",
"'externref'", "'mut'", "'ref'", "'cont'", "'null'", "'nop'", "'sym_assert'",
"'alloc'", "'free'", "'unreachable'", "'drop'", "'block'", "'loop'",
- "'end'", "'br'", "'br_if'", "'br_table'", "'return'", "'if'", "'then'",
- "'else'", "'.select'", "'call'", "'call_indirect'", "'return_call'",
- "'return_call_indirect'", "'ref.func'", "'call_ref'", "'resume'", "'on'",
- "'cont.new'", "'cont.bind'", "'suspend'", "'ref.null'", "'ref.is_null'",
- "'try'", "'catch'", "'throw'", "'resume0'", "'local.get'", "'local.set'",
- "'local.tee'", "'global.get'", "'global.set'", null, null, "'_'", "'offset='",
- "'align='", null, null, "'i32'", "'i64'", "'f32'", "'f64'", null, null,
- "'.eqz'", "'.eq'", "'.ne'", "'.lt'", "'.lt_s'", "'.lt_u'", "'.le'", "'.le_s'",
- "'.le_u'", "'.gt'", "'.gt_s'", "'.gt_u'", "'.ge'", "'.ge_s'", "'.ge_u'",
- "'.clz'", "'.ctz'", "'.popcnt'", "'.neg'", "'.abs'", "'.sqrt'", "'.ceil'",
- "'.floor'", "'.trunc'", "'.nearest'", "'.add'", "'.sub'", "'.mul'", "'.div'",
- "'.div_s'", "'.div_u'", "'.rem_s'", "'.rem_u'", "'.and'", "'.or'", "'.xor'",
- "'.shl'", "'.shr_s'", "'.shr_u'", "'.rotl'", "'.rotr'", "'.min'", "'.max'",
- "'.copysign'", "'.wrap_'", "'.trunc_'", "'.trunc_sat_'", "'.convert_'",
- "'.extend_'", "'.demote_'", "'.promote_'", "'.reinterpret_'", "'memory.size'",
- "'memory.grow'", "'memory.fill'", "'memory.copy'", "'memory.init'", null,
- null, null, null, null, "'type'", "'func'", "'extern'", "'start'", "'param'",
- "'result'", "'local'", "'global'", "'table'", "'memory'", "'elem'", "'data'",
- "'offset'", "'import'", "'export'", "'tag'", "'declare'", "'module'",
- "'binary'", "'quote'", "'definition'", "'instance'", "'script'", "'register'",
- "'invoke'", "'get'", "'assert_malformed'", "'assert_invalid'", "'assert_unlinkable'",
- "'assert_return'", "'assert_return_canonical_nan'", "'assert_return_arithmetic_nan'",
- "'assert_trap'", "'assert_exhaustion'", "'input'", "'output'", null,
- "'v128'"
+ "'for'", "'|'", "'end'", "'br'", "'br_if'", "'br_table'", "'return'",
+ "'if'", "'then'", "'else'", "'.select'", "'call'", "'call_indirect'",
+ "'return_call'", "'return_call_indirect'", "'ref.func'", "'call_ref'",
+ "'resume'", "'on'", "'cont.new'", "'cont.bind'", "'suspend'", "'ref.null'",
+ "'ref.is_null'", "'try'", "'catch'", "'throw'", "'resume0'", "'local.get'",
+ "'local.set'", "'local.tee'", "'global.get'", "'global.set'", null, null,
+ "'_'", "'offset='", "'align='", null, null, "'i32'", "'i64'", "'f32'",
+ "'f64'", null, null, "'.eqz'", "'.eq'", "'.ne'", "'.lt'", "'.lt_s'",
+ "'.lt_u'", "'.le'", "'.le_s'", "'.le_u'", "'.gt'", "'.gt_s'", "'.gt_u'",
+ "'.ge'", "'.ge_s'", "'.ge_u'", "'.clz'", "'.ctz'", "'.popcnt'", "'.neg'",
+ "'.abs'", "'.sqrt'", "'.ceil'", "'.floor'", "'.trunc'", "'.nearest'",
+ "'.add'", "'.sub'", "'.mul'", "'.div'", "'.div_s'", "'.div_u'", "'.rem_s'",
+ "'.rem_u'", "'.and'", "'.or'", "'.xor'", "'.shl'", "'.shr_s'", "'.shr_u'",
+ "'.rotl'", "'.rotr'", "'.min'", "'.max'", "'.copysign'", "'.wrap_'",
+ "'.trunc_'", "'.trunc_sat_'", "'.convert_'", "'.extend_'", "'.demote_'",
+ "'.promote_'", "'.reinterpret_'", "'memory.size'", "'memory.grow'", "'memory.fill'",
+ "'memory.copy'", "'memory.init'", null, null, null, null, null, "'type'",
+ "'func'", "'extern'", "'start'", "'param'", "'result'", "'local'", "'global'",
+ "'table'", "'memory'", "'elem'", "'data'", "'offset'", "'import'", "'export'",
+ "'tag'", "'declare'", "'module'", "'binary'", "'quote'", "'definition'",
+ "'instance'", "'script'", "'register'", "'invoke'", "'get'", "'assert_malformed'",
+ "'assert_invalid'", "'assert_unlinkable'", "'assert_return'", "'assert_return_canonical_nan'",
+ "'assert_return_arithmetic_nan'", "'assert_trap'", "'assert_exhaustion'",
+ "'input'", "'output'", null, "'v128'"
};
}
private static final String[] _LITERAL_NAMES = makeLiteralNames();
@@ -123,8 +125,8 @@ private static String[] makeSymbolicNames() {
null, "LPAR", "RPAR", "NAT", "INT", "FLOAT", "STRING_", "VALUE_TYPE",
"CONST", "SYMBOLIC", "FUNCREF", "EXTERNREF", "MUT", "REF", "CONT", "NULL",
"NOP", "SYM_ASSERT", "ALLOC", "FREE", "UNREACHABLE", "DROP", "BLOCK",
- "LOOP", "END", "BR", "BR_IF", "BR_TABLE", "RETURN", "IF", "THEN", "ELSE",
- "SELECT", "CALL", "CALL_INDIRECT", "RETURN_CALL", "RETURN_CALL_INDIRECT",
+ "LOOP", "FOR", "VBAR", "END", "BR", "BR_IF", "BR_TABLE", "RETURN", "IF",
+ "THEN", "ELSE", "SELECT", "CALL", "CALL_INDIRECT", "RETURN_CALL", "RETURN_CALL_INDIRECT",
"REFFUNC", "CALLREF", "RESUME", "ON", "CONTNEW", "CONTBIND", "SUSPEND",
"REFNULL", "REFISNULL", "TRY", "CATCH", "THROW", "RESUME0", "LOCAL_GET",
"LOCAL_SET", "LOCAL_TEE", "GLOBAL_GET", "GLOBAL_SET", "LOAD", "STORE",
@@ -207,7 +209,7 @@ public WatLexer(CharStream input) {
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
- "\u0004\u0000\u00a9\u0900\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002"+
+ "\u0004\u0000\u00ab\u090a\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002"+
"\u0001\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002"+
"\u0004\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002"+
"\u0007\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002"+
@@ -258,1379 +260,1396 @@ public WatLexer(CharStream input) {
"\u0002\u00b6\u0007\u00b6\u0002\u00b7\u0007\u00b7\u0002\u00b8\u0007\u00b8"+
"\u0002\u00b9\u0007\u00b9\u0002\u00ba\u0007\u00ba\u0002\u00bb\u0007\u00bb"+
"\u0002\u00bc\u0007\u00bc\u0002\u00bd\u0007\u00bd\u0002\u00be\u0007\u00be"+
- "\u0002\u00bf\u0007\u00bf\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+
- "\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004"+
- "\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007"+
- "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+
- "\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+
- "\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+
- "\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+
- "\n\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+
- "\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+
- "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001"+
- "\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+
+ "\u0002\u00bf\u0007\u00bf\u0002\u00c0\u0007\u00c0\u0002\u00c1\u0007\u00c1"+
+ "\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0002\u0001\u0002"+
+ "\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005"+
+ "\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+
+ "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001"+
+ "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+
+ "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001"+
+ "\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+
+ "\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001"+
+ "\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001"+
+ "\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+
+ "\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+
"\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+
- "\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+
- "\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+
- "\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+
+ "\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+
+ "\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001"+
"\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+
- "\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001"+
- "\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001"+
- "\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001"+
- "\u0017\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+
- "\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001"+
- "\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+
- "\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+
+ "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0001"+
+ "\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001"+
+ "\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001"+
+ "\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001"+
+ "\u0017\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0001"+
+ "\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001"+
"\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001"+
+ "\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001"+
"\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001"+
- "\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0001"+
- "\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001"+
- "\u001f\u0001 \u0001 \u0001 \u0001 \u0001 \u0001!\u0001!\u0001!\u0001!"+
- "\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001"+
- "!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001"+
- "\"\u0001\"\u0001\"\u0001\"\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001"+
- "#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001"+
- "#\u0001#\u0001#\u0001#\u0001#\u0001$\u0001$\u0001$\u0001$\u0001$\u0001"+
- "$\u0001$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001"+
+ "\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0001"+
+ "\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001 \u0001"+
+ " \u0001 \u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001"+
+ "\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001#\u0001#\u0001#\u0001#\u0001#"+
+ "\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001"+
+ "$\u0001$\u0001$\u0001$\u0001$\u0001$\u0001$\u0001$\u0001$\u0001$\u0001"+
+ "$\u0001$\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001"+
+ "%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001"+
"%\u0001%\u0001%\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001"+
- "\'\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001"+
- "(\u0001(\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0001"+
+ "&\u0001&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001"+
+ "\'\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001)\u0001"+
")\u0001)\u0001*\u0001*\u0001*\u0001*\u0001*\u0001*\u0001*\u0001*\u0001"+
- "+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001,\u0001"+
- ",\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001"+
- ",\u0001-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001.\u0001.\u0001.\u0001"+
- ".\u0001/\u0001/\u0001/\u0001/\u0001/\u0001/\u00010\u00010\u00010\u0001"+
- "0\u00010\u00010\u00010\u00010\u00011\u00011\u00011\u00011\u00011\u0001"+
- "1\u00011\u00011\u00011\u00011\u00012\u00012\u00012\u00012\u00012\u0001"+
- "2\u00012\u00012\u00012\u00012\u00013\u00013\u00013\u00013\u00013\u0001"+
- "3\u00013\u00013\u00013\u00013\u00014\u00014\u00014\u00014\u00014\u0001"+
- "4\u00014\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00015\u0001"+
- "5\u00015\u00015\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u0001"+
- "6\u00016\u00016\u00016\u00016\u00016\u00016\u00036\u0305\b6\u00017\u0001"+
- "7\u00017\u00017\u00017\u00017\u00017\u00017\u00037\u030f\b7\u00018\u0001"+
- "8\u00019\u00019\u00019\u00019\u00019\u00019\u00019\u00019\u0001:\u0001"+
- ":\u0001:\u0001:\u0001:\u0001:\u0001:\u0001;\u0001;\u0001<\u0001<\u0001"+
- "<\u0001<\u0001<\u0001<\u0001<\u0003<\u032b\b<\u0001=\u0001=\u0001=\u0001"+
- "=\u0001>\u0001>\u0001>\u0001>\u0001?\u0001?\u0001?\u0001?\u0001@\u0001"+
- "@\u0001@\u0001@\u0001A\u0001A\u0003A\u033f\bA\u0001B\u0001B\u0003B\u0343"+
- "\bB\u0001C\u0001C\u0001C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001D\u0001"+
- "E\u0001E\u0001E\u0001E\u0001F\u0001F\u0001F\u0001F\u0001G\u0001G\u0001"+
- "G\u0001G\u0001G\u0001G\u0001H\u0001H\u0001H\u0001H\u0001H\u0001H\u0001"+
- "I\u0001I\u0001I\u0001I\u0001J\u0001J\u0001J\u0001J\u0001J\u0001J\u0001"+
- "K\u0001K\u0001K\u0001K\u0001K\u0001K\u0001L\u0001L\u0001L\u0001L\u0001"+
- "M\u0001M\u0001M\u0001M\u0001M\u0001M\u0001N\u0001N\u0001N\u0001N\u0001"+
- "N\u0001N\u0001O\u0001O\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001"+
- "P\u0001P\u0001Q\u0001Q\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001R\u0001"+
- "R\u0001R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001"+
- "T\u0001T\u0001T\u0001T\u0001T\u0001T\u0001U\u0001U\u0001U\u0001U\u0001"+
- "U\u0001V\u0001V\u0001V\u0001V\u0001V\u0001W\u0001W\u0001W\u0001W\u0001"+
- "W\u0001W\u0001X\u0001X\u0001X\u0001X\u0001X\u0001X\u0001Y\u0001Y\u0001"+
- "Y\u0001Y\u0001Y\u0001Y\u0001Y\u0001Z\u0001Z\u0001Z\u0001Z\u0001Z\u0001"+
- "Z\u0001Z\u0001[\u0001[\u0001[\u0001[\u0001[\u0001[\u0001[\u0001[\u0001"+
- "[\u0001\\\u0001\\\u0001\\\u0001\\\u0001\\\u0001]\u0001]\u0001]\u0001]"+
- "\u0001]\u0001^\u0001^\u0001^\u0001^\u0001^\u0001_\u0001_\u0001_\u0001"+
- "_\u0001_\u0001`\u0001`\u0001`\u0001`\u0001`\u0001`\u0001`\u0001a\u0001"+
- "a\u0001a\u0001a\u0001a\u0001a\u0001a\u0001b\u0001b\u0001b\u0001b\u0001"+
- "b\u0001b\u0001b\u0001c\u0001c\u0001c\u0001c\u0001c\u0001c\u0001c\u0001"+
- "d\u0001d\u0001d\u0001d\u0001d\u0001e\u0001e\u0001e\u0001e\u0001f\u0001"+
- "f\u0001f\u0001f\u0001f\u0001g\u0001g\u0001g\u0001g\u0001g\u0001h\u0001"+
- "h\u0001h\u0001h\u0001h\u0001h\u0001h\u0001i\u0001i\u0001i\u0001i\u0001"+
- "i\u0001i\u0001i\u0001j\u0001j\u0001j\u0001j\u0001j\u0001j\u0001k\u0001"+
- "k\u0001k\u0001k\u0001k\u0001k\u0001l\u0001l\u0001l\u0001l\u0001l\u0001"+
- "m\u0001m\u0001m\u0001m\u0001m\u0001n\u0001n\u0001n\u0001n\u0001n\u0001"+
- "n\u0001n\u0001n\u0001n\u0001n\u0001o\u0001o\u0001o\u0001o\u0001o\u0001"+
- "o\u0001o\u0001p\u0001p\u0001p\u0001p\u0001p\u0001p\u0001p\u0001p\u0001"+
- "q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001"+
- "q\u0001q\u0001r\u0001r\u0001r\u0001r\u0001r\u0001r\u0001r\u0001r\u0001"+
- "r\u0001r\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001"+
+ "*\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001"+
+ "+\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001,\u0001-\u0001"+
+ "-\u0001-\u0001-\u0001-\u0001-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001"+
+ ".\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0001"+
+ "/\u0001/\u0001/\u0001/\u00010\u00010\u00010\u00010\u00010\u00010\u0001"+
+ "1\u00011\u00011\u00011\u00011\u00011\u00012\u00012\u00012\u00012\u0001"+
+ "2\u00012\u00012\u00012\u00013\u00013\u00013\u00013\u00013\u00013\u0001"+
+ "3\u00013\u00013\u00013\u00014\u00014\u00014\u00014\u00014\u00014\u0001"+
+ "4\u00014\u00014\u00014\u00015\u00015\u00015\u00015\u00015\u00015\u0001"+
+ "5\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u00016\u00016\u0001"+
+ "6\u00016\u00016\u00016\u00016\u00017\u00017\u00017\u00017\u00017\u0001"+
+ "7\u00017\u00017\u00017\u00017\u00017\u00018\u00018\u00018\u00018\u0001"+
+ "8\u00018\u00018\u00018\u00018\u00018\u00038\u030f\b8\u00019\u00019\u0001"+
+ "9\u00019\u00019\u00019\u00019\u00019\u00039\u0319\b9\u0001:\u0001:\u0001"+
+ ";\u0001;\u0001;\u0001;\u0001;\u0001;\u0001;\u0001;\u0001<\u0001<\u0001"+
+ "<\u0001<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001>\u0001>\u0001>\u0001"+
+ ">\u0001>\u0001>\u0001>\u0003>\u0335\b>\u0001?\u0001?\u0001?\u0001?\u0001"+
+ "@\u0001@\u0001@\u0001@\u0001A\u0001A\u0001A\u0001A\u0001B\u0001B\u0001"+
+ "B\u0001B\u0001C\u0001C\u0003C\u0349\bC\u0001D\u0001D\u0003D\u034d\bD\u0001"+
+ "E\u0001E\u0001E\u0001E\u0001E\u0001F\u0001F\u0001F\u0001F\u0001G\u0001"+
+ "G\u0001G\u0001G\u0001H\u0001H\u0001H\u0001H\u0001I\u0001I\u0001I\u0001"+
+ "I\u0001I\u0001I\u0001J\u0001J\u0001J\u0001J\u0001J\u0001J\u0001K\u0001"+
+ "K\u0001K\u0001K\u0001L\u0001L\u0001L\u0001L\u0001L\u0001L\u0001M\u0001"+
+ "M\u0001M\u0001M\u0001M\u0001M\u0001N\u0001N\u0001N\u0001N\u0001O\u0001"+
+ "O\u0001O\u0001O\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001P\u0001"+
+ "P\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001R\u0001R\u0001"+
+ "R\u0001S\u0001S\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001T\u0001"+
+ "T\u0001T\u0001U\u0001U\u0001U\u0001U\u0001U\u0001V\u0001V\u0001V\u0001"+
+ "V\u0001V\u0001V\u0001V\u0001V\u0001W\u0001W\u0001W\u0001W\u0001W\u0001"+
+ "X\u0001X\u0001X\u0001X\u0001X\u0001Y\u0001Y\u0001Y\u0001Y\u0001Y\u0001"+
+ "Y\u0001Z\u0001Z\u0001Z\u0001Z\u0001Z\u0001Z\u0001[\u0001[\u0001[\u0001"+
+ "[\u0001[\u0001[\u0001[\u0001\\\u0001\\\u0001\\\u0001\\\u0001\\\u0001\\"+
+ "\u0001\\\u0001]\u0001]\u0001]\u0001]\u0001]\u0001]\u0001]\u0001]\u0001"+
+ "]\u0001^\u0001^\u0001^\u0001^\u0001^\u0001_\u0001_\u0001_\u0001_\u0001"+
+ "_\u0001`\u0001`\u0001`\u0001`\u0001`\u0001a\u0001a\u0001a\u0001a\u0001"+
+ "a\u0001b\u0001b\u0001b\u0001b\u0001b\u0001b\u0001b\u0001c\u0001c\u0001"+
+ "c\u0001c\u0001c\u0001c\u0001c\u0001d\u0001d\u0001d\u0001d\u0001d\u0001"+
+ "d\u0001d\u0001e\u0001e\u0001e\u0001e\u0001e\u0001e\u0001e\u0001f\u0001"+
+ "f\u0001f\u0001f\u0001f\u0001g\u0001g\u0001g\u0001g\u0001h\u0001h\u0001"+
+ "h\u0001h\u0001h\u0001i\u0001i\u0001i\u0001i\u0001i\u0001j\u0001j\u0001"+
+ "j\u0001j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001k\u0001k\u0001k\u0001"+
+ "k\u0001k\u0001l\u0001l\u0001l\u0001l\u0001l\u0001l\u0001m\u0001m\u0001"+
+ "m\u0001m\u0001m\u0001m\u0001n\u0001n\u0001n\u0001n\u0001n\u0001o\u0001"+
+ "o\u0001o\u0001o\u0001o\u0001p\u0001p\u0001p\u0001p\u0001p\u0001p\u0001"+
+ "p\u0001p\u0001p\u0001p\u0001q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001"+
+ "q\u0001r\u0001r\u0001r\u0001r\u0001r\u0001r\u0001r\u0001r\u0001s\u0001"+
+ "s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001s\u0001"+
"s\u0001t\u0001t\u0001t\u0001t\u0001t\u0001t\u0001t\u0001t\u0001t\u0001"+
- "u\u0001u\u0001u\u0001u\u0001u\u0001u\u0001u\u0001u\u0001u\u0001u\u0001"+
- "v\u0001v\u0001v\u0001v\u0001v\u0001v\u0001v\u0001v\u0001v\u0001v\u0001"+
- "v\u0001v\u0001v\u0001v\u0001w\u0001w\u0001w\u0001w\u0001w\u0001w\u0001"+
- "w\u0001w\u0001w\u0001w\u0001w\u0001w\u0001x\u0001x\u0001x\u0001x\u0001"+
- "x\u0001x\u0001x\u0001x\u0001x\u0001x\u0001x\u0001x\u0001y\u0001y\u0001"+
- "y\u0001y\u0001y\u0001y\u0001y\u0001y\u0001y\u0001y\u0001y\u0001y\u0001"+
- "z\u0001z\u0001z\u0001z\u0001z\u0001z\u0001z\u0001z\u0001z\u0001z\u0001"+
- "z\u0001z\u0001{\u0001{\u0001{\u0001{\u0001{\u0001{\u0001{\u0001{\u0001"+
- "{\u0001{\u0001{\u0001{\u0001|\u0001|\u0001|\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001}\u0001"+
- "}\u0001}\u0001}\u0003}\u0530\b}\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001"+
- "~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0001~\u0003~\u057b\b~\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001"+
- "\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f\u0003"+
- "\u007f\u0613\b\u007f\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080\u0001"+
- "\u0080\u0001\u0080\u0003\u0080\u06b7\b\u0080\u0001\u0081\u0001\u0081\u0001"+
- "\u0081\u0001\u0081\u0001\u0081\u0001\u0082\u0001\u0082\u0001\u0082\u0001"+
- "\u0082\u0001\u0082\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0083\u0001"+
- "\u0083\u0001\u0083\u0001\u0083\u0001\u0084\u0001\u0084\u0001\u0084\u0001"+
- "\u0084\u0001\u0084\u0001\u0084\u0001\u0085\u0001\u0085\u0001\u0085\u0001"+
- "\u0085\u0001\u0085\u0001\u0085\u0001\u0086\u0001\u0086\u0001\u0086\u0001"+
- "\u0086\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0087\u0001\u0087\u0001"+
- "\u0087\u0001\u0087\u0001\u0087\u0001\u0087\u0001\u0088\u0001\u0088\u0001"+
- "\u0088\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0089\u0001"+
- "\u0089\u0001\u0089\u0001\u0089\u0001\u0089\u0001\u0089\u0001\u008a\u0001"+
- "\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001"+
- "\u008b\u0001\u008b\u0001\u008b\u0001\u008b\u0001\u008b\u0001\u008c\u0001"+
- "\u008c\u0001\u008c\u0001\u008c\u0001\u008c\u0001\u008d\u0001\u008d\u0001"+
- "\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008e\u0001"+
- "\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001"+
- "\u008f\u0001\u008f\u0001\u008f\u0001\u008f\u0001\u008f\u0001\u008f\u0001"+
- "\u008f\u0001\u0090\u0001\u0090\u0001\u0090\u0001\u0090\u0001\u0091\u0001"+
- "\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001"+
- "\u0091\u0001\u0092\u0001\u0092\u0001\u0092\u0001\u0092\u0001\u0092\u0001"+
- "\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001\u0093\u0001\u0093\u0001"+
- "\u0093\u0001\u0093\u0001\u0093\u0001\u0094\u0001\u0094\u0001\u0094\u0001"+
- "\u0094\u0001\u0094\u0001\u0094\u0001\u0095\u0001\u0095\u0001\u0095\u0001"+
- "\u0095\u0001\u0095\u0001\u0095\u0001\u0095\u0001\u0095\u0001\u0095\u0001"+
- "\u0095\u0001\u0095\u0001\u0096\u0001\u0096\u0001\u0096\u0001\u0096\u0001"+
- "\u0096\u0001\u0096\u0001\u0096\u0001\u0096\u0001\u0096\u0001\u0097\u0001"+
- "\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001"+
- "\u0098\u0001\u0098\u0001\u0098\u0001\u0098\u0001\u0098\u0001\u0098\u0001"+
- "\u0098\u0001\u0098\u0001\u0098\u0001\u0099\u0001\u0099\u0001\u0099\u0001"+
- "\u0099\u0001\u0099\u0001\u0099\u0001\u0099\u0001\u009a\u0001\u009a\u0001"+
- "\u009a\u0001\u009a\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001"+
- "\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001"+
- "\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001"+
- "\u009b\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001"+
- "\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001"+
- "\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009d\u0001\u009d\u0001"+
- "\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001"+
- "\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001"+
- "\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009e\u0001\u009e\u0001"+
- "\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001"+
- "\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001"+
- "\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001"+
- "\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001"+
- "\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001"+
- "\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001"+
- "\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u00a0\u0001\u00a0\u0001"+
- "\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001"+
- "\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001"+
- "\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001"+
- "\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001"+
- "\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001"+
- "\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001"+
- "\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001"+
- "\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001"+
- "\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001"+
- "\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a3\u0001\u00a3\u0001\u00a3\u0001"+
- "\u00a3\u0001\u00a3\u0001\u00a3\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001"+
- "\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a5\u0001\u00a5\u0001"+
- "\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a7\u0004"+
- "\u00a7\u0811\b\u00a7\u000b\u00a7\f\u00a7\u0812\u0001\u00a7\u0001\u00a7"+
- "\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0005\u00a8\u081b\b\u00a8"+
- "\n\u00a8\f\u00a8\u081e\t\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001"+
- "\u00a8\u0001\u00a8\u0001\u00a8\u0005\u00a8\u0826\b\u00a8\n\u00a8\f\u00a8"+
- "\u0829\t\u00a8\u0001\u00a8\u0003\u00a8\u082c\b\u00a8\u0001\u00a8\u0001"+
- "\u00a8\u0001\u00a9\u0001\u00a9\u0001\u00aa\u0001\u00aa\u0003\u00aa\u0834"+
- "\b\u00aa\u0001\u00aa\u0005\u00aa\u0837\b\u00aa\n\u00aa\f\u00aa\u083a\t"+
- "\u00aa\u0001\u00ab\u0001\u00ab\u0003\u00ab\u083e\b\u00ab\u0001\u00ab\u0005"+
- "\u00ab\u0841\b\u00ab\n\u00ab\f\u00ab\u0844\t\u00ab\u0001\u00ac\u0001\u00ac"+
- "\u0001\u00ad\u0001\u00ad\u0001\u00ae\u0001\u00ae\u0001\u00af\u0001\u00af"+
- "\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0003\u00b0"+
- "\u0853\b\u00b0\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b2\u0001\u00b2"+
- "\u0001\u00b3\u0001\u00b3\u0001\u00b4\u0003\u00b4\u085d\b\u00b4\u0001\u00b4"+
- "\u0001\u00b4\u0001\u00b4\u0003\u00b4\u0862\b\u00b4\u0001\u00b4\u0003\u00b4"+
- "\u0865\b\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4\u086a\b"+
- "\u00b4\u0003\u00b4\u086c\b\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4\u0870"+
- "\b\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4\u0875\b\u00b4"+
- "\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4"+
- "\u0003\u00b4\u087d\b\u00b4\u0001\u00b4\u0003\u00b4\u0880\b\u00b4\u0001"+
- "\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003"+
- "\u00b4\u0888\b\u00b4\u0003\u00b4\u088a\b\u00b4\u0001\u00b4\u0001\u00b4"+
- "\u0003\u00b4\u088e\b\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4"+
- "\u0893\b\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4"+
- "\u0899\b\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4"+
- "\u089f\b\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4"+
- "\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0003\u00b4\u08aa\b\u00b4"+
- "\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5"+
- "\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5"+
- "\u0004\u00b5\u08b8\b\u00b5\u000b\u00b5\f\u00b5\u08b9\u0001\u00b5\u0001"+
- "\u00b5\u0005\u00b5\u08be\b\u00b5\n\u00b5\f\u00b5\u08c1\t\u00b5\u0001\u00b5"+
- "\u0001\u00b5\u0001\u00b6\u0001\u00b6\u0001\u00b6\u0001\u00b6\u0001\u00b6"+
- "\u0004\u00b6\u08ca\b\u00b6\u000b\u00b6\f\u00b6\u08cb\u0001\u00b7\u0001"+
- "\u00b7\u0001\u00b8\u0001\u00b8\u0003\u00b8\u08d2\b\u00b8\u0001\u00b9\u0001"+
- "\u00b9\u0001\u00ba\u0001\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bc\u0001"+
- "\u00bc\u0001\u00bd\u0001\u00bd\u0003\u00bd\u08de\b\u00bd\u0001\u00be\u0001"+
- "\u00be\u0003\u00be\u08e2\b\u00be\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001"+
- "\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001"+
- "\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001"+
- "\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001"+
- "\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0003"+
- "\u00bf\u08ff\b\u00bf\u0002\u081c\u0827\u0000\u00c0\u0001\u0001\u0003\u0002"+
- "\u0005\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013"+
- "\n\u0015\u000b\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011"+
- "#\u0012%\u0013\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b"+
- "7\u001c9\u001d;\u001e=\u001f? A!C\"E#G$I%K&M\'O(Q)S*U+W,Y-[.]/_0a1c2e"+
- "3g4i5k6m7o8q9s:u;w The default implementation does nothing. The default implementation does nothing. The default implementation does nothing.
The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.
+ */ + @Override public T visitForLoop(WatParser.ForLoopContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * diff --git a/src/main/java/wasm/WatParserListener.java b/src/main/java/wasm/WatParserListener.java index c59545f..7866a87 100644 --- a/src/main/java/wasm/WatParserListener.java +++ b/src/main/java/wasm/WatParserListener.java @@ -197,6 +197,16 @@ public interface WatParserListener extends ParseTreeListener { * @param ctx the parse tree */ void exitInstr(WatParser.InstrContext ctx); + /** + * Enter a parse tree produced by {@link WatParser#forLoop}. + * @param ctx the parse tree + */ + void enterForLoop(WatParser.ForLoopContext ctx); + /** + * Exit a parse tree produced by {@link WatParser#forLoop}. + * @param ctx the parse tree + */ + void exitForLoop(WatParser.ForLoopContext ctx); /** * Enter a parse tree produced by {@link WatParser#plainInstr}. * @param ctx the parse tree diff --git a/src/main/java/wasm/WatParserVisitor.java b/src/main/java/wasm/WatParserVisitor.java index a593c24..751741d 100644 --- a/src/main/java/wasm/WatParserVisitor.java +++ b/src/main/java/wasm/WatParserVisitor.java @@ -124,6 +124,12 @@ public interface WatParserVisitor