diff options
author | Alon Zakai <azakai@google.com> | 2019-06-15 12:04:16 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-15 12:04:16 -0700 |
commit | 1cd34c211dffa66fa2f2e45f3f9291e8ad836e07 (patch) | |
tree | 74fc2c7c15872d2c23d8b7eed7865486069549ce /test | |
parent | 22ba24118ef04720e6c7605dbaf90b22cdba006f (diff) | |
download | binaryen-1cd34c211dffa66fa2f2e45f3f9291e8ad836e07.tar.gz binaryen-1cd34c211dffa66fa2f2e45f3f9291e8ad836e07.tar.bz2 binaryen-1cd34c211dffa66fa2f2e45f3f9291e8ad836e07.zip |
Bysyncify: async transform for wasm (#2172)
This adds a new pass, Bysyncify, which transforms code to allow unwind and rewinding the call stack and local state. This allows things like coroutines, turning synchronous code asynchronous, etc.
The new pass file itself has a large comment on top with docs.
So far the tests here seem to show this works, but this hasn't been tested heavily yet. My next step is to hook this up to emscripten as a replacement for asyncify/emterpreter, see emscripten-core/emscripten#8561
Note that this is completely usable by itself, so it could be useful for any language that needs coroutines etc., and not just ones using LLVM and/or emscripten. See docs on the ABI in the pass source.
Diffstat (limited to 'test')
-rw-r--r-- | test/passes/bysyncify.txt | 2710 | ||||
-rw-r--r-- | test/passes/bysyncify.wast | 146 | ||||
-rw-r--r-- | test/passes/bysyncify_optimize-level=1.txt | 1541 | ||||
-rw-r--r-- | test/passes/bysyncify_optimize-level=1.wast | 97 | ||||
-rw-r--r-- | test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.txt | 1998 | ||||
-rw-r--r-- | test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast | 146 | ||||
-rw-r--r-- | test/unit/input/bysyncify.js | 155 | ||||
-rw-r--r-- | test/unit/input/bysyncify.wast | 200 | ||||
-rw-r--r-- | test/unit/test_bysyncify.py | 20 |
9 files changed, 7013 insertions, 0 deletions
diff --git a/test/passes/bysyncify.txt b/test/passes/bysyncify.txt new file mode 100644 index 000000000..1ec35057e --- /dev/null +++ b/test/passes/bysyncify.txt @@ -0,0 +1,2710 @@ +(module + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$v (func)) + (memory $0 1 2) + (global $sleeping (mut i32) (i32.const 0)) + (global $__bysyncify_state (mut i32) (i32.const 0)) + (global $__bysyncify_data (mut i32) (i32.const 0)) + (export "bysyncify_start_unwind" (func $bysyncify_start_unwind)) + (export "bysyncify_start_rewind" (func $bysyncify_start_rewind)) + (export "bysyncify_stop_rewind" (func $bysyncify_stop_rewind)) + (func $do_sleep (; 0 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -8) + ) + ) + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $4) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $4) + ) + ) + ) + ) + (local.set $2 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (block + (local.set $0 + (global.get $sleeping) + ) + (local.set $1 + (i32.eqz + (local.get $0) + ) + ) + ) + ) + (nop) + (block + (if + (i32.or + (local.get $1) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (global.set $sleeping + (i32.const 1) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $3) + (i32.const 0) + ) + ) + (block + (call $bysyncify_start_unwind + (i32.const 4) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $1) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (block + (global.set $sleeping + (i32.const 0) + ) + (call $bysyncify_stop_rewind) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $2) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $0) + ) + (i32.store offset=4 + (local.get $5) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 8) + ) + ) + ) + ) + (func $work (; 1 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $stuff) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $do_sleep) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $stuff) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $stuff (; 2 ;) (type $FUNCSIG$v) + (nop) + ) + (func $first_event (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $work) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $second_event (; 4 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $bysyncify_start_rewind + (i32.const 4) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 1) + ) + ) + (block + (call $work) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $never_sleep (; 5 ;) (type $FUNCSIG$v) + (call $stuff) + (call $stuff) + (call $stuff) + ) + (func $bysyncify_start_unwind (; 6 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 1) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_start_rewind (; 7 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 2) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_stop_rewind (; 8 ;) + (global.set $__bysyncify_state + (i32.const 0) + ) + ) +) +(module + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (memory $0 1 2) + (global $__bysyncify_state (mut i32) (i32.const 0)) + (global $__bysyncify_data (mut i32) (i32.const 0)) + (export "bysyncify_start_unwind" (func $bysyncify_start_unwind)) + (export "bysyncify_start_rewind" (func $bysyncify_start_rewind)) + (export "bysyncify_stop_rewind" (func $bysyncify_stop_rewind)) + (func $calls-import (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $calls-import2 (; 4 ;) (type $FUNCSIG$i) (result i32) + (local $temp i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -20) + ) + ) + (local.set $7 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $temp + (i32.load + (local.get $7) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $7) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $7) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $7) + ) + ) + (local.set $4 + (i32.load offset=16 + (local.get $7) + ) + ) + ) + ) + (local.set $5 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $6 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $6) + (i32.const 0) + ) + ) + (block + (local.set $2 + (call $import2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (local.get $2) + ) + ) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $5) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $8 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $8) + (local.get $temp) + ) + (i32.store offset=4 + (local.get $8) + (local.get $1) + ) + (i32.store offset=8 + (local.get $8) + (local.get $2) + ) + (i32.store offset=12 + (local.get $8) + (local.get $3) + ) + (i32.store offset=16 + (local.get $8) + (local.get $4) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 20) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-drop (; 5 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $3) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $2) + (i32.const 0) + ) + ) + (block + (local.set $0 + (call $import2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $4) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + ) + (func $calls-nothing (; 6 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (i32.eqz + (i32.const 17) + ) + ) + ) + (func $many-locals (; 7 ;) (type $FUNCSIG$ii) (param $x i32) (result i32) + (local $y i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + (local $12 i32) + (local $13 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -40) + ) + ) + (local.set $12 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $12) + ) + ) + (local.set $y + (i32.load offset=4 + (local.get $12) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $12) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $12) + ) + ) + (local.set $4 + (i32.load offset=16 + (local.get $12) + ) + ) + (local.set $5 + (i32.load offset=20 + (local.get $12) + ) + ) + (local.set $6 + (i32.load offset=24 + (local.get $12) + ) + ) + (local.set $7 + (i32.load offset=28 + (local.get $12) + ) + ) + (local.set $8 + (i32.load offset=32 + (local.get $12) + ) + ) + (local.set $9 + (i32.load offset=36 + (local.get $12) + ) + ) + ) + ) + (local.set $10 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $11 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (loop $l + (local.set $4 + (i32.add + (local.get $y) + (i32.const 1) + ) + ) + (local.set $y + (i32.div_s + (local.get $4) + (i32.const 3) + ) + ) + (br_if $l + (local.get $y) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $11) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (local.get $y) + ) + ) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $10) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $13 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $13) + (local.get $x) + ) + (i32.store offset=4 + (local.get $13) + (local.get $y) + ) + (i32.store offset=8 + (local.get $13) + (local.get $2) + ) + (i32.store offset=12 + (local.get $13) + (local.get $3) + ) + (i32.store offset=16 + (local.get $13) + (local.get $4) + ) + (i32.store offset=20 + (local.get $13) + (local.get $5) + ) + (i32.store offset=24 + (local.get $13) + (local.get $6) + ) + (i32.store offset=28 + (local.get $13) + (local.get $7) + ) + (i32.store offset=32 + (local.get $13) + (local.get $8) + ) + (i32.store offset=36 + (local.get $13) + (local.get $9) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 40) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-if (; 8 ;) (type $FUNCSIG$vi) (param $x i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -8) + ) + ) + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $4) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $4) + ) + ) + ) + ) + (local.set $2 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.or + (local.get $x) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $3) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $2) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $x) + ) + (i32.store offset=4 + (local.get $5) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 8) + ) + ) + ) + ) + (func $calls-import2-if-else (; 9 ;) (type $FUNCSIG$vi) (param $x i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -8) + ) + ) + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $4) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $4) + ) + ) + ) + ) + (local.set $2 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.or + (local.get $x) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $3) + (i32.const 0) + ) + ) + (block + (call $import3 + (i32.const 1) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $x) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $3) + (i32.const 1) + ) + ) + (block + (call $import3 + (i32.const 2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $2) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $x) + ) + (i32.store offset=4 + (local.get $5) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 8) + ) + ) + ) + ) + (func $calls-import2-if-else-oneside (; 10 ;) (type $FUNCSIG$ii) (param $x i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -16) + ) + ) + (local.set $6 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $6) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $6) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $6) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $6) + ) + ) + ) + ) + (local.set $4 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $5 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (block + (if + (i32.or + (local.get $x) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (i32.const 1) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $x) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $5) + (i32.const 0) + ) + ) + (block + (call $import3 + (i32.const 2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (i32.const 3) + ) + ) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $4) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $7 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $7) + (local.get $x) + ) + (i32.store offset=4 + (local.get $7) + (local.get $1) + ) + (i32.store offset=8 + (local.get $7) + (local.get $2) + ) + (i32.store offset=12 + (local.get $7) + (local.get $3) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 16) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-if-else-oneside2 (; 11 ;) (type $FUNCSIG$ii) (param $x i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -16) + ) + ) + (local.set $6 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $6) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $6) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $6) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $6) + ) + ) + ) + ) + (local.set $4 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $5 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (block + (if + (i32.or + (local.get $x) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $5) + (i32.const 0) + ) + ) + (block + (call $import3 + (i32.const 1) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $x) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (i32.const 2) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (i32.const 3) + ) + ) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $4) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $7 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $7) + (local.get $x) + ) + (i32.store offset=4 + (local.get $7) + (local.get $1) + ) + (i32.store offset=8 + (local.get $7) + (local.get $2) + ) + (i32.store offset=12 + (local.get $7) + (local.get $3) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 16) + ) + ) + ) + (i32.const 0) + ) + (func $calls-loop (; 12 ;) (type $FUNCSIG$vi) (param $x i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -16) + ) + ) + (local.set $6 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $6) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $6) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $6) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $6) + ) + ) + ) + ) + (local.set $4 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $5 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (loop $l + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $5) + (i32.const 0) + ) + ) + (block + (call $import3 + (i32.const 1) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (block + (local.set $x + (i32.add + (local.get $x) + (i32.const 1) + ) + ) + (br_if $l + (local.get $x) + ) + ) + ) + (nop) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $4) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $7 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $7) + (local.get $x) + ) + (i32.store offset=4 + (local.get $7) + (local.get $1) + ) + (i32.store offset=8 + (local.get $7) + (local.get $2) + ) + (i32.store offset=12 + (local.get $7) + (local.get $3) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 16) + ) + ) + ) + ) + (func $calls-loop2 (; 13 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $3) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (loop $l + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $2) + (i32.const 0) + ) + ) + (block + (local.set $0 + (call $import2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (br_if $l + (local.get $0) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $4) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + ) + (func $calls-mix (; 14 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 1) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $boring (; 15 ;) (type $FUNCSIG$v) + (nop) + ) + (func $calls-mix-deep (; 16 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring-deep) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import-deep) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 1) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $boring-deep (; 17 ;) (type $FUNCSIG$v) + (call $boring) + ) + (func $import-deep (; 18 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $bysyncify_start_unwind (; 19 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 1) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_start_rewind (; 20 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 2) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_stop_rewind (; 21 ;) + (global.set $__bysyncify_state + (i32.const 0) + ) + ) +) diff --git a/test/passes/bysyncify.wast b/test/passes/bysyncify.wast new file mode 100644 index 000000000..7c92bd86f --- /dev/null +++ b/test/passes/bysyncify.wast @@ -0,0 +1,146 @@ +;; Pre-existing imports that the pass turns into the implementations. +(module + (memory 1 2) + (import "bysyncify" "start_unwind" (func $bysyncify_start_unwind (param i32))) + (import "bysyncify" "start_rewind" (func $bysyncify_start_rewind (param i32))) + (import "bysyncify" "stop_rewind" (func $bysyncify_stop_rewind)) + (global $sleeping (mut i32) (i32.const 0)) + ;; do a sleep operation: start a sleep if running, or resume after a sleep + ;; if we just rewound. + (func $do_sleep + (if + (i32.eqz (global.get $sleeping)) + (block + (global.set $sleeping (i32.const 1)) + ;; we should set up the data at address 4 around here + (call $bysyncify_start_unwind (i32.const 4)) + ) + (block + (global.set $sleeping (i32.const 0)) + (call $bysyncify_stop_rewind) + ) + ) + ) + ;; a function that does some work and has a sleep (async pause/resume) in the middle + (func $work + (call $stuff) ;; do some work + (call $do_sleep) ;; take a break + (call $stuff) ;; do some more work + ) + (func $stuff) + ;; the first event called from the main event loop: just call into $work + (func $first_event + (call $work) + ;; work will sleep, so we exit through here while it is paused + ) + ;; the second event called from the main event loop: to resume $work, + ;; initiate a rewind, and then do the call to start things back up + (func $second_event + (call $bysyncify_start_rewind (i32.const 4)) + (call $work) + ) + ;; a function that can't do a sleep + (func $never_sleep + (call $stuff) + (call $stuff) + (call $stuff) + ) +) +;; Calls to imports that will call into bysyncify themselves. +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) + (func $many-locals (param $x i32) (result i32) + (local $y i32) + (loop $l + (local.set $x + (i32.add (local.get $y) (i32.const 1)) + ) + (local.set $y + (i32.div_s (local.get $x) (i32.const 3)) + ) + (br_if $l (local.get $y)) + ) + (call $import) + (return (local.get $y)) + ) + (func $calls-import2-if (param $x i32) + (if (local.get $x) + (call $import) + ) + ) + (func $calls-import2-if-else (param $x i32) + (if (local.get $x) + (call $import3 (i32.const 1)) + (call $import3 (i32.const 2)) + ) + ) + (func $calls-import2-if-else-oneside (param $x i32) (result i32) + (if (local.get $x) + (return (i32.const 1)) + (call $import3 (i32.const 2)) + ) + (return (i32.const 3)) + ) + (func $calls-import2-if-else-oneside2 (param $x i32) (result i32) + (if (local.get $x) + (call $import3 (i32.const 1)) + (return (i32.const 2)) + ) + (return (i32.const 3)) + ) + (func $calls-loop (param $x i32) + (loop $l + (call $import3 (i32.const 1)) + (local.set $x + (i32.add (local.get $x) (i32.const 1)) + ) + (br_if $l + (local.get $x) + ) + ) + ) + (func $calls-loop2 + (loop $l + (br_if $l + (call $import2) + ) + ) + ) + (func $calls-mix + (call $boring) + (call $import) + (call $boring) + (call $import) + ) + (func $boring) + (func $calls-mix-deep + (call $boring-deep) + (call $import-deep) + (call $boring) + (call $import) + ) + (func $boring-deep + (call $boring) + ) + (func $import-deep + (call $import) + ) +) + diff --git a/test/passes/bysyncify_optimize-level=1.txt b/test/passes/bysyncify_optimize-level=1.txt new file mode 100644 index 000000000..6eb7217e4 --- /dev/null +++ b/test/passes/bysyncify_optimize-level=1.txt @@ -0,0 +1,1541 @@ +(module + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (memory $0 1 2) + (global $__bysyncify_state (mut i32) (i32.const 0)) + (global $__bysyncify_data (mut i32) (i32.const 0)) + (export "bysyncify_start_unwind" (func $bysyncify_start_unwind)) + (export "bysyncify_start_rewind" (func $bysyncify_start_rewind)) + (export "bysyncify_stop_rewind" (func $bysyncify_stop_rewind)) + (func $calls-import (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (if + (select + (i32.eqz + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block (result i32) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + (local.get $0) + ) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $calls-import2 (; 4 ;) (type $FUNCSIG$i) (result i32) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (select + (i32.eqz + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block (result i32) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + (local.get $1) + ) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (local.set $0 + (call $import2) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (return + (local.get $0) + ) + ) + (unreachable) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.const 0) + ) + (func $calls-import2-drop (; 5 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (if + (select + (i32.eqz + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block (result i32) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + (local.get $0) + ) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (drop + (call $import2) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $calls-nothing (; 6 ;) (type $FUNCSIG$v) + (nop) + ) + (func $many-locals (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -8) + ) + ) + (local.set $0 + (i32.load + (local.tee $1 + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $1) + ) + ) + ) + ) + (local.set $2 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (loop $l + (br_if $l + (local.tee $1 + (i32.div_s + (i32.add + (local.get $1) + (i32.const 1) + ) + (i32.const 3) + ) + ) + ) + ) + ) + (if + (select + (i32.eqz + (local.get $2) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (return + (local.get $1) + ) + ) + (unreachable) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $2) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (local.tee $2 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.get $0) + ) + (i32.store offset=4 + (local.get $2) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 8) + ) + ) + (i32.const 0) + ) + (func $calls-import2-if (; 8 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.or + (local.get $0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (select + (i32.eqz + (local.get $1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $calls-import2-if-else (; 9 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.or + (local.get $0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (select + (i32.eqz + (local.get $1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import3 + (i32.const 1) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $0) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (select + (i32.eq + (local.get $1) + (i32.const 1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import3 + (i32.const 2) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 1) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $calls-import2-if-else-oneside (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.or + (local.get $0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (return + (i32.const 1) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $0) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (select + (i32.eqz + (local.get $1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import3 + (i32.const 2) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (return + (i32.const 3) + ) + ) + (unreachable) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.const 0) + ) + (func $calls-import2-if-else-oneside2 (; 11 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.or + (local.get $0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (select + (i32.eqz + (local.get $1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import3 + (i32.const 1) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $0) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (return + (i32.const 2) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (return + (i32.const 3) + ) + ) + (unreachable) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.const 0) + ) + (func $calls-loop (; 12 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (loop $l + (if + (select + (i32.eqz + (local.get $1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import3 + (i32.const 1) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (br_if $l + (local.tee $0 + (i32.add + (local.get $0) + (i32.const 1) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $calls-loop2 (; 13 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (loop $l + (if + (select + (i32.eqz + (local.get $1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (local.set $0 + (call $import2) + ) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (br_if $l + (local.get $0) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $calls-mix (; 14 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (call $boring) + ) + (if + (select + (i32.eqz + (local.get $0) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (call $boring) + ) + (if + (select + (i32.eq + (local.get $0) + (i32.const 1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 1) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $boring (; 15 ;) (type $FUNCSIG$v) + (nop) + ) + (func $calls-mix-deep (; 16 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $0 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (call $boring-deep) + ) + (if + (select + (i32.eqz + (local.get $0) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import-deep) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (if + (i32.eqz + (global.get $__bysyncify_state) + ) + (call $boring) + ) + (if + (select + (i32.eq + (local.get $0) + (i32.const 1) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 1) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $boring-deep (; 17 ;) (type $FUNCSIG$v) + (call $boring) + ) + (func $import-deep (; 18 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (if + (select + (i32.eqz + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block (result i32) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + (local.get $0) + ) + ) + (i32.const 1) + (global.get $__bysyncify_state) + ) + (block + (call $import) + (drop + (br_if $__bysyncify_unwind + (i32.const 0) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + ) + ) + ) + ) + (return) + ) + ) + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $bysyncify_start_unwind (; 19 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 1) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_start_rewind (; 20 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 2) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_stop_rewind (; 21 ;) + (global.set $__bysyncify_state + (i32.const 0) + ) + ) +) diff --git a/test/passes/bysyncify_optimize-level=1.wast b/test/passes/bysyncify_optimize-level=1.wast new file mode 100644 index 000000000..a89103e8a --- /dev/null +++ b/test/passes/bysyncify_optimize-level=1.wast @@ -0,0 +1,97 @@ +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) + (func $many-locals (param $x i32) (result i32) + (local $y i32) + (loop $l + (local.set $x + (i32.add (local.get $y) (i32.const 1)) + ) + (local.set $y + (i32.div_s (local.get $x) (i32.const 3)) + ) + (br_if $l (local.get $y)) + ) + (call $import) + (return (local.get $y)) + ) + (func $calls-import2-if (param $x i32) + (if (local.get $x) + (call $import) + ) + ) + (func $calls-import2-if-else (param $x i32) + (if (local.get $x) + (call $import3 (i32.const 1)) + (call $import3 (i32.const 2)) + ) + ) + (func $calls-import2-if-else-oneside (param $x i32) (result i32) + (if (local.get $x) + (return (i32.const 1)) + (call $import3 (i32.const 2)) + ) + (return (i32.const 3)) + ) + (func $calls-import2-if-else-oneside2 (param $x i32) (result i32) + (if (local.get $x) + (call $import3 (i32.const 1)) + (return (i32.const 2)) + ) + (return (i32.const 3)) + ) + (func $calls-loop (param $x i32) + (loop $l + (call $import3 (i32.const 1)) + (local.set $x + (i32.add (local.get $x) (i32.const 1)) + ) + (br_if $l + (local.get $x) + ) + ) + ) + (func $calls-loop2 + (loop $l + (br_if $l + (call $import2) + ) + ) + ) + (func $calls-mix + (call $boring) + (call $import) + (call $boring) + (call $import) + ) + (func $boring) + (func $calls-mix-deep + (call $boring-deep) + (call $import-deep) + (call $boring) + (call $import) + ) + (func $boring-deep + (call $boring) + ) + (func $import-deep + (call $import) + ) +) + diff --git a/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.txt b/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.txt new file mode 100644 index 000000000..e850da6cf --- /dev/null +++ b/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.txt @@ -0,0 +1,1998 @@ +(module + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$v (func)) + (memory $0 1 2) + (global $sleeping (mut i32) (i32.const 0)) + (global $__bysyncify_state (mut i32) (i32.const 0)) + (global $__bysyncify_data (mut i32) (i32.const 0)) + (export "bysyncify_start_unwind" (func $bysyncify_start_unwind)) + (export "bysyncify_start_rewind" (func $bysyncify_start_rewind)) + (export "bysyncify_stop_rewind" (func $bysyncify_stop_rewind)) + (func $do_sleep (; 0 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -8) + ) + ) + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $4) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $4) + ) + ) + ) + ) + (local.set $2 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (block + (local.set $0 + (global.get $sleeping) + ) + (local.set $1 + (i32.eqz + (local.get $0) + ) + ) + ) + ) + (nop) + (block + (if + (i32.or + (local.get $1) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (global.set $sleeping + (i32.const 1) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $3) + (i32.const 0) + ) + ) + (block + (call $bysyncify_start_unwind + (i32.const 4) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + ) + (if + (i32.or + (i32.eqz + (local.get $1) + ) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (block + (global.set $sleeping + (i32.const 0) + ) + (call $bysyncify_stop_rewind) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $2) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $0) + ) + (i32.store offset=4 + (local.get $5) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 8) + ) + ) + ) + ) + (func $work (; 1 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $stuff) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $do_sleep) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $stuff) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $stuff (; 2 ;) (type $FUNCSIG$v) + (nop) + ) + (func $first_event (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $work) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $second_event (; 4 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $bysyncify_start_rewind + (i32.const 4) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 1) + ) + ) + (block + (call $work) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $never_sleep (; 5 ;) (type $FUNCSIG$v) + (call $stuff) + (call $stuff) + (call $stuff) + ) + (func $bysyncify_start_unwind (; 6 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 1) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_start_rewind (; 7 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 2) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_stop_rewind (; 8 ;) + (global.set $__bysyncify_state + (i32.const 0) + ) + ) +) +(module + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (memory $0 1 2) + (global $__bysyncify_state (mut i32) (i32.const 0)) + (global $__bysyncify_data (mut i32) (i32.const 0)) + (export "bysyncify_start_unwind" (func $bysyncify_start_unwind)) + (export "bysyncify_start_rewind" (func $bysyncify_start_rewind)) + (export "bysyncify_stop_rewind" (func $bysyncify_stop_rewind)) + (func $calls-import (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $calls-import2 (; 4 ;) (type $FUNCSIG$i) (result i32) + (local $temp i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -20) + ) + ) + (local.set $7 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $temp + (i32.load + (local.get $7) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $7) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $7) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $7) + ) + ) + (local.set $4 + (i32.load offset=16 + (local.get $7) + ) + ) + ) + ) + (local.set $5 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $6 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $6) + (i32.const 0) + ) + ) + (block + (local.set $2 + (call $import2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (local.get $2) + ) + ) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $5) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $8 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $8) + (local.get $temp) + ) + (i32.store offset=4 + (local.get $8) + (local.get $1) + ) + (i32.store offset=8 + (local.get $8) + (local.get $2) + ) + (i32.store offset=12 + (local.get $8) + (local.get $3) + ) + (i32.store offset=16 + (local.get $8) + (local.get $4) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 20) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-drop (; 5 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $3) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $2) + (i32.const 0) + ) + ) + (block + (local.set $0 + (call $import2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $4) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + ) + (func $calls-nothing (; 6 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (i32.eqz + (i32.const 17) + ) + ) + ) + (func $many-locals (; 7 ;) (type $FUNCSIG$ii) (param $x i32) (result i32) + (local $y i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + (local $12 i32) + (local $13 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -40) + ) + ) + (local.set $12 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $12) + ) + ) + (local.set $y + (i32.load offset=4 + (local.get $12) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $12) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $12) + ) + ) + (local.set $4 + (i32.load offset=16 + (local.get $12) + ) + ) + (local.set $5 + (i32.load offset=20 + (local.get $12) + ) + ) + (local.set $6 + (i32.load offset=24 + (local.get $12) + ) + ) + (local.set $7 + (i32.load offset=28 + (local.get $12) + ) + ) + (local.set $8 + (i32.load offset=32 + (local.get $12) + ) + ) + (local.set $9 + (i32.load offset=36 + (local.get $12) + ) + ) + ) + ) + (local.set $10 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $11 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (loop $l + (local.set $4 + (i32.add + (local.get $y) + (i32.const 1) + ) + ) + (local.set $y + (i32.div_s + (local.get $4) + (i32.const 3) + ) + ) + (br_if $l + (local.get $y) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $11) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (return + (local.get $y) + ) + ) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $10) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $13 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $13) + (local.get $x) + ) + (i32.store offset=4 + (local.get $13) + (local.get $y) + ) + (i32.store offset=8 + (local.get $13) + (local.get $2) + ) + (i32.store offset=12 + (local.get $13) + (local.get $3) + ) + (i32.store offset=16 + (local.get $13) + (local.get $4) + ) + (i32.store offset=20 + (local.get $13) + (local.get $5) + ) + (i32.store offset=24 + (local.get $13) + (local.get $6) + ) + (i32.store offset=28 + (local.get $13) + (local.get $7) + ) + (i32.store offset=32 + (local.get $13) + (local.get $8) + ) + (i32.store offset=36 + (local.get $13) + (local.get $9) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 40) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-if (; 8 ;) (type $FUNCSIG$vi) (param $x i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -8) + ) + ) + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $x + (i32.load + (local.get $4) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $4) + ) + ) + ) + ) + (local.set $2 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (i32.or + (local.get $x) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $3) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $2) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $x) + ) + (i32.store offset=4 + (local.get $5) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 8) + ) + ) + ) + ) + (func $calls-import2-if-else (; 9 ;) (type $FUNCSIG$vi) (param $x i32) + (local $1 i32) + (if + (local.get $x) + (call $import3 + (i32.const 1) + ) + (call $import3 + (i32.const 2) + ) + ) + ) + (func $calls-import2-if-else-oneside (; 10 ;) (type $FUNCSIG$ii) (param $x i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (if + (local.get $x) + (return + (i32.const 1) + ) + (call $import3 + (i32.const 2) + ) + ) + (return + (i32.const 3) + ) + ) + (func $calls-import2-if-else-oneside2 (; 11 ;) (type $FUNCSIG$ii) (param $x i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (if + (local.get $x) + (call $import3 + (i32.const 1) + ) + (return + (i32.const 2) + ) + ) + (return + (i32.const 3) + ) + ) + (func $calls-loop (; 12 ;) (type $FUNCSIG$vi) (param $x i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (loop $l + (call $import3 + (i32.const 1) + ) + (local.set $x + (i32.add + (local.get $x) + (i32.const 1) + ) + ) + (br_if $l + (local.get $x) + ) + ) + ) + (func $calls-loop2 (; 13 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $3 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $3) + ) + ) + ) + ) + (local.set $1 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (loop $l + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $2) + (i32.const 0) + ) + ) + (block + (local.set $0 + (call $import2) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (br_if $l + (local.get $0) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $4 + (i32.load + (global.get $__bysyncify_data) + ) + ) + (i32.store + (local.get $4) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + ) + (func $calls-mix (; 14 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 1) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $boring (; 15 ;) (type $FUNCSIG$v) + (nop) + ) + (func $calls-mix-deep (; 16 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring-deep) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import-deep) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (call $boring) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 1) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 1) + ) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $boring-deep (; 17 ;) (type $FUNCSIG$v) + (call $boring) + ) + (func $import-deep (; 18 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__bysyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__bysyncify_data) + ) + ) + ) + ) + ) + (if + (if (result i32) + (i32.eq + (global.get $__bysyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.eq + (global.get $__bysyncify_state) + (i32.const 1) + ) + (br $__bysyncify_unwind + (i32.const 0) + ) + ) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__bysyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__bysyncify_data) + (i32.add + (i32.load + (global.get $__bysyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $bysyncify_start_unwind (; 19 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 1) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_start_rewind (; 20 ;) (param $0 i32) + (if + (i32.gt_u + (i32.load + (local.get $0) + ) + (i32.load offset=4 + (local.get $0) + ) + ) + (unreachable) + ) + (global.set $__bysyncify_state + (i32.const 2) + ) + (global.set $__bysyncify_data + (local.get $0) + ) + ) + (func $bysyncify_stop_rewind (; 21 ;) + (global.set $__bysyncify_state + (i32.const 0) + ) + ) +) diff --git a/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast b/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast new file mode 100644 index 000000000..7c92bd86f --- /dev/null +++ b/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast @@ -0,0 +1,146 @@ +;; Pre-existing imports that the pass turns into the implementations. +(module + (memory 1 2) + (import "bysyncify" "start_unwind" (func $bysyncify_start_unwind (param i32))) + (import "bysyncify" "start_rewind" (func $bysyncify_start_rewind (param i32))) + (import "bysyncify" "stop_rewind" (func $bysyncify_stop_rewind)) + (global $sleeping (mut i32) (i32.const 0)) + ;; do a sleep operation: start a sleep if running, or resume after a sleep + ;; if we just rewound. + (func $do_sleep + (if + (i32.eqz (global.get $sleeping)) + (block + (global.set $sleeping (i32.const 1)) + ;; we should set up the data at address 4 around here + (call $bysyncify_start_unwind (i32.const 4)) + ) + (block + (global.set $sleeping (i32.const 0)) + (call $bysyncify_stop_rewind) + ) + ) + ) + ;; a function that does some work and has a sleep (async pause/resume) in the middle + (func $work + (call $stuff) ;; do some work + (call $do_sleep) ;; take a break + (call $stuff) ;; do some more work + ) + (func $stuff) + ;; the first event called from the main event loop: just call into $work + (func $first_event + (call $work) + ;; work will sleep, so we exit through here while it is paused + ) + ;; the second event called from the main event loop: to resume $work, + ;; initiate a rewind, and then do the call to start things back up + (func $second_event + (call $bysyncify_start_rewind (i32.const 4)) + (call $work) + ) + ;; a function that can't do a sleep + (func $never_sleep + (call $stuff) + (call $stuff) + (call $stuff) + ) +) +;; Calls to imports that will call into bysyncify themselves. +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) + (func $many-locals (param $x i32) (result i32) + (local $y i32) + (loop $l + (local.set $x + (i32.add (local.get $y) (i32.const 1)) + ) + (local.set $y + (i32.div_s (local.get $x) (i32.const 3)) + ) + (br_if $l (local.get $y)) + ) + (call $import) + (return (local.get $y)) + ) + (func $calls-import2-if (param $x i32) + (if (local.get $x) + (call $import) + ) + ) + (func $calls-import2-if-else (param $x i32) + (if (local.get $x) + (call $import3 (i32.const 1)) + (call $import3 (i32.const 2)) + ) + ) + (func $calls-import2-if-else-oneside (param $x i32) (result i32) + (if (local.get $x) + (return (i32.const 1)) + (call $import3 (i32.const 2)) + ) + (return (i32.const 3)) + ) + (func $calls-import2-if-else-oneside2 (param $x i32) (result i32) + (if (local.get $x) + (call $import3 (i32.const 1)) + (return (i32.const 2)) + ) + (return (i32.const 3)) + ) + (func $calls-loop (param $x i32) + (loop $l + (call $import3 (i32.const 1)) + (local.set $x + (i32.add (local.get $x) (i32.const 1)) + ) + (br_if $l + (local.get $x) + ) + ) + ) + (func $calls-loop2 + (loop $l + (br_if $l + (call $import2) + ) + ) + ) + (func $calls-mix + (call $boring) + (call $import) + (call $boring) + (call $import) + ) + (func $boring) + (func $calls-mix-deep + (call $boring-deep) + (call $import-deep) + (call $boring) + (call $import) + ) + (func $boring-deep + (call $boring) + ) + (func $import-deep + (call $import) + ) +) + diff --git a/test/unit/input/bysyncify.js b/test/unit/input/bysyncify.js new file mode 100644 index 000000000..97d7a0da5 --- /dev/null +++ b/test/unit/input/bysyncify.js @@ -0,0 +1,155 @@ + +function assert(x, y) { + if (!x) throw (y || 'assertion failed') + '\n' + new Error().stack; +} + +var fs = require('fs'); + +// Get and compile the wasm. + +var binary = fs.readFileSync('a.wasm'); + +var module = new WebAssembly.Module(binary); + +var DATA_ADDR = 4; + +var sleeps = 0; + +var sleeping = false; + +var instance = new WebAssembly.Instance(module, { + env: { + sleep: function() { + logMemory(); +assert(view[0] == 0); + if (!sleeping) { + // We are called in order to start a sleep/unwind. + console.log('sleep...'); + sleeps++; + // Unwinding. + exports.bysyncify_start_unwind(DATA_ADDR); + // Fill in the data structure. The first value has the stack location, + // which for simplicity we can start right after the data structure itself. + view[DATA_ADDR >> 2] = DATA_ADDR + 8; + // The end of the stack will not be reached here anyhow. + view[DATA_ADDR + 4 >> 2] = 1024; + sleeping = true; + } else { + // We are called as part of a resume/rewind. Stop sleeping. + console.log('resume...'); + exports.bysyncify_stop_rewind(); + // The stack should have been all used up, and so returned to the original state. + assert(view[DATA_ADDR >> 2] == DATA_ADDR + 8); + assert(view[DATA_ADDR + 4 >> 2] == 1024); + sleeping = false; + } + logMemory(); + }, + tunnel: function(x) { + console.log('tunneling, sleep == ' + sleeping); + return exports.end_tunnel(x); + } + } +}); + +var exports = instance.exports; +var view = new Int32Array(exports.memory.buffer); + +function logMemory() { + // Log the relevant memory locations for debugging purposes. + console.log('memory: ', view[0 >> 2], view[4 >> 2], view[8 >> 2], view[12 >> 2], view[16 >> 2], view[20 >> 2], view[24 >> 2]); +} + +function runTest(name, expectedSleeps, expectedResult, params) { + params = params || []; + + console.log('\n==== testing ' + name + ' ===='); + + sleeps = 0; + + logMemory(); + + // Run until the sleep. + var result = exports[name].apply(null, params); + logMemory(); + + if (expectedSleeps > 0) { + assert(!result, 'results during sleep are meaningless, just 0'); + + for (var i = 0; i < expectedSleeps - 1; i++) { + console.log('rewind, run until the next sleep'); + exports.bysyncify_start_rewind(DATA_ADDR); + result = exports[name](); // no need for params on later times + assert(!result, 'results during sleep are meaningless, just 0'); + assert(!result, 'bad first sleep result'); + logMemory(); + } + + console.log('rewind and run til the end.'); + exports.bysyncify_start_rewind(DATA_ADDR); + result = exports[name](); + } + + console.log('final result: ' + result); + assert(result == expectedResult, 'bad final result'); + logMemory(); + + assert(sleeps == expectedSleeps, 'expectedSleeps'); +} + +//================ +// Tests +//================ + +// A minimal single sleep. +runTest('minimal', 1, 21); + +// Two sleeps. +runTest('repeat', 2, 42); + +// A value in a local is preserved across a sleep. +runTest('local', 1, 10); + +// A local with more operations done on it. +runTest('local2', 1, 22); + +// A local with more operations done on it. +runTest('params', 1, 18); +runTest('params', 1, 21, [1, 2]); + +// Calls to multiple other functions, only one of whom +// sleeps, and keep locals and globals valid throughout. +runTest('deeper', 0, 27, [0]); +runTest('deeper', 1, 3, [1]); + +// A recursive factorial, that sleeps on each iteration +// above 1. +runTest('factorial-recursive', 0, 1, [1]); +runTest('factorial-recursive', 1, 2, [2]); +runTest('factorial-recursive', 2, 6, [3]); +runTest('factorial-recursive', 3, 24, [4]); +runTest('factorial-recursive', 4, 120, [5]); + +// A looping factorial, that sleeps on each iteration +// above 1. +runTest('factorial-loop', 0, 1, [1]); +runTest('factorial-loop', 1, 2, [2]); +runTest('factorial-loop', 2, 6, [3]); +runTest('factorial-loop', 3, 24, [4]); +runTest('factorial-loop', 4, 120, [5]); + +// Test calling into JS in the middle (which can work if +// the JS just forwards the call and has no side effects or +// state of its own that needs to be saved). +runTest('do_tunnel', 2, 72, [1]); + +// Test indirect function calls. +runTest('call_indirect', 3, 432, [1, 2]); + +// Test indirect function calls. +runTest('if_else', 3, 1460, [1, 1000]); +runTest('if_else', 3, 2520, [2, 2000]); + +// All done. +console.log('\ntests completed successfully'); + diff --git a/test/unit/input/bysyncify.wast b/test/unit/input/bysyncify.wast new file mode 100644 index 000000000..91fb5a327 --- /dev/null +++ b/test/unit/input/bysyncify.wast @@ -0,0 +1,200 @@ +(module + (memory 1 2) + (type $ii (func (param i32) (result i32))) + (import "env" "sleep" (func $sleep)) + (import "env" "tunnel" (func $tunnel (param $x i32) (result i32))) + (export "memory" (memory 0)) + (export "factorial-recursive" (func $factorial-recursive)) + (global $temp (mut i32) (i32.const 0)) + (table 10 funcref) + (elem (i32.const 5) $tablefunc) + (func "minimal" (result i32) + (call $sleep) + (i32.const 21) + ) + (func "repeat" (result i32) + ;; sleep twice, then return 42 + (call $sleep) + (call $sleep) + (i32.const 42) + ) + (func "local" (result i32) + (local $x i32) + (local.set $x (i32.load (i32.const 0))) ;; a zero that the optimizer won't see + (local.set $x + (i32.add (local.get $x) (i32.const 10)) ;; add 10 + ) + (call $sleep) + (local.get $x) + ) + (func "local2" (result i32) + (local $x i32) + (local.set $x (i32.load (i32.const 0))) ;; a zero that the optimizer won't see + (local.set $x + (i32.add (local.get $x) (i32.const 10)) ;; add 10 + ) + (call $sleep) + (local.set $x + (i32.add (local.get $x) (i32.const 12)) ;; add 12 more + ) + (local.get $x) + ) + (func "params" (param $x i32) (param $y i32) (result i32) + (local.set $x + (i32.add (local.get $x) (i32.const 17)) ;; add 10 + ) + (local.set $y + (i32.add (local.get $y) (i32.const 1)) ;; add 12 more + ) + (call $sleep) + (i32.add (local.get $x) (local.get $y)) + ) + (func $pre + (global.set $temp (i32.const 1)) + ) + (func $inner (param $x i32) + (if (i32.eqz (local.get $x)) (call $post)) + (if (local.get $x) (call $sleep)) + (if (i32.eqz (local.get $x)) (call $post)) + ) + (func $post + (global.set $temp + (i32.mul + (global.get $temp) + (i32.const 3) + ) + ) + ) + (func "deeper" (param $x i32) (result i32) + (call $pre) + (call $inner (local.get $x)) + (call $post) + (global.get $temp) + ) + (func $factorial-recursive (param $x i32) (result i32) + (if + (i32.eq + (local.get $x) + (i32.const 1) + ) + (return (i32.const 1)) + ) + (call $sleep) + (return + (i32.mul + (local.get $x) + (call $factorial-recursive + (i32.sub + (local.get $x) + (i32.const 1) + ) + ) + ) + ) + ) + (func "factorial-loop" (param $x i32) (result i32) + (local $i i32) + (local $ret i32) + (local.set $ret (i32.const 1)) + (local.set $i (i32.const 2)) + (loop $l + (if + (i32.gt_u + (local.get $i) + (local.get $x) + ) + (return (local.get $ret)) + ) + (local.set $ret + (i32.mul + (local.get $ret) + (local.get $i) + ) + ) + (call $sleep) + (local.set $i + (i32.add + (local.get $i) + (i32.const 1) + ) + ) + (br $l) + ) + ) + (func "end_tunnel" (param $x i32) (result i32) + (local.set $x + (i32.add (local.get $x) (i32.const 22)) + ) + (call $sleep) + (i32.add (local.get $x) (i32.const 5)) + ) + (func "do_tunnel" (param $x i32) (result i32) + (local.set $x + (i32.add (local.get $x) (i32.const 11)) + ) + (local.set $x + (call $tunnel (local.get $x)) ;; calls js which calls back into wasm for end_tunnel + ) + (call $sleep) + (i32.add (local.get $x) (i32.const 33)) + ) + (func $tablefunc (param $y i32) (result i32) + (local.set $y + (i32.add (local.get $y) (i32.const 10)) + ) + (call $sleep) + (i32.add (local.get $y) (i32.const 30)) + ) + (func "call_indirect" (param $x i32) (param $y i32) (result i32) + (local.set $x + (i32.add (local.get $x) (i32.const 1)) + ) + (call $sleep) + (local.set $x + (i32.add (local.get $x) (i32.const 3)) + ) + (local.set $y + (call_indirect (type $ii) (local.get $y) (local.get $x)) ;; call function pointer x + 4, which will be 5 + ) + (local.set $y + (i32.add (local.get $y) (i32.const 90)) + ) + (call $sleep) + (i32.add (local.get $y) (i32.const 300)) ;; total is 10+30+90+300=430 + y's original value + ) + (func "if_else" (param $x i32) (param $y i32) (result i32) + (if (i32.eq (local.get $x) (i32.const 1)) + (local.set $y + (i32.add (local.get $y) (i32.const 10)) + ) + (local.set $y + (i32.add (local.get $y) (i32.const 20)) + ) + ) + (if (i32.eq (local.get $x) (i32.const 1)) + (local.set $y + (i32.add (local.get $y) (i32.const 40)) + ) + (call $sleep) + ) + (if (i32.eq (local.get $x) (i32.const 1)) + (call $sleep) + (local.set $y + (i32.add (local.get $y) (i32.const 90)) + ) + ) + (if (i32.eq (local.get $x) (i32.const 1)) + (call $sleep) + (call $sleep) + ) + (local.set $y + (i32.add (local.get $y) (i32.const 160)) + ) + (call $sleep) + (local.set $y + (i32.add (local.get $y) (i32.const 250)) + ) + (local.get $y) + ) +) + diff --git a/test/unit/test_bysyncify.py b/test/unit/test_bysyncify.py new file mode 100644 index 000000000..5373a4def --- /dev/null +++ b/test/unit/test_bysyncify.py @@ -0,0 +1,20 @@ +import os + +from scripts.test.shared import WASM_OPT, NODEJS, run_process +from utils import BinaryenTestCase + + +class BysyncifyTest(BinaryenTestCase): + def test_bysyncify(self): + def test(args): + print(args) + run_process(WASM_OPT + args + [self.input_path('bysyncify.wast'), '--bysyncify', '-o', 'a.wasm']) + print(' file size: %d' % os.path.getsize('a.wasm')) + run_process([NODEJS, self.input_path('bysyncify.js')]) + + test(['-g']) + test([]) + test(['-O1']) + test(['--optimize-level=1']) + test(['-O3']) + test(['-Os', '-g']) |