summaryrefslogtreecommitdiff
path: root/test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2019-06-15 12:04:16 -0700
committerGitHub <noreply@github.com>2019-06-15 12:04:16 -0700
commit1cd34c211dffa66fa2f2e45f3f9291e8ad836e07 (patch)
tree74fc2c7c15872d2c23d8b7eed7865486069549ce /test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast
parent22ba24118ef04720e6c7605dbaf90b22cdba006f (diff)
downloadbinaryen-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/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast')
-rw-r--r--test/passes/bysyncify_pass-arg=bysyncify@env.import,env.import2.wast146
1 files changed, 146 insertions, 0 deletions
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)
+ )
+)
+