summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Bysyncify.cpp64
-rw-r--r--test/passes/bysyncify.txt372
-rw-r--r--test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.txt478
-rw-r--r--test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.wast26
-rw-r--r--test/passes/bysyncify_pass-arg=bysyncify-imports@env.import,env.import2.txt346
-rw-r--r--test/unit/input/bysyncify-pure.txt17
-rw-r--r--test/unit/input/bysyncify-pure.wast59
-rw-r--r--test/unit/test_bysyncify.py11
8 files changed, 678 insertions, 695 deletions
diff --git a/src/passes/Bysyncify.cpp b/src/passes/Bysyncify.cpp
index dcc543c5e..29b3cf242 100644
--- a/src/passes/Bysyncify.cpp
+++ b/src/passes/Bysyncify.cpp
@@ -155,7 +155,14 @@
// around that, you can create imports to bysyncify.start_unwind,
// bysyncify.stop_unwind, bysyncify.start_rewind, and bysyncify.stop_rewind;
// if those exist when this pass runs then it will turn those into direct
-// calls to the functions that it creates.
+// calls to the functions that it creates. Note that when doing everything
+// in wasm like this, Bysyncify must not instrument your "runtime" support
+// code, that is, the code that initiates unwinds and rewinds and stops them.
+// If it did, the unwind would not stop until you left the wasm module
+// entirely, etc. Therefore we do not instrument a function if it has
+// a call to the four bysyncify_* methods. Note that you may need to disable
+// inlining if that would cause code that does need to be instrumented
+// show up in that runtime code.
//
// To use this API, call bysyncify_start_unwind when you want to. The call
// stack will then be unwound, and so execution will resume in the JS or
@@ -237,7 +244,19 @@ class ModuleAnalyzer {
bool canIndirectChangeState;
struct Info {
+ // If this function can start an unwind/rewind.
bool canChangeState = false;
+ // If this function is part of the runtime that receives an unwinding
+ // and starts a rewinding. If so, we do not instrument it, see above.
+ // This is only relevant when handling things entirely inside wasm,
+ // as opposed to imports.
+ bool isBottomMostRuntime = false;
+ // If this function is part of the runtime that starts an unwinding
+ // and stops a rewinding. If so, we do not instrument it, see above.
+ // The difference between the top-most and bottom-most runtime is that
+ // the top-most part is still marked as changing the state; so things
+ // that call it are instrumented. This is not done for the bottom.
+ bool isTopMostRuntime = false;
std::set<Function*> callsTo;
std::set<Function*> calledBy;
};
@@ -257,10 +276,9 @@ public:
ModuleUtils::ParallelFunctionMap<Info> scanner(
module, [&](Function* func, Info& info) {
if (func->imported()) {
- // The bysyncify imports can definitely change the state.
+ // The relevant bysyncify imports can definitely change the state.
if (func->module == BYSYNCIFY &&
- (func->base == START_UNWIND || func->base == STOP_UNWIND ||
- func->base == START_REWIND || func->base == STOP_REWIND)) {
+ (func->base == START_UNWIND || func->base == STOP_REWIND)) {
info.canChangeState = true;
} else {
info.canChangeState =
@@ -275,18 +293,22 @@ public:
// Redirect the imports to the functions we'll add later.
if (target->base == START_UNWIND) {
curr->target = BYSYNCIFY_START_UNWIND;
+ info->canChangeState = true;
+ info->isTopMostRuntime = true;
} else if (target->base == STOP_UNWIND) {
curr->target = BYSYNCIFY_STOP_UNWIND;
+ info->isBottomMostRuntime = true;
} else if (target->base == START_REWIND) {
curr->target = BYSYNCIFY_START_REWIND;
+ info->isBottomMostRuntime = true;
} else if (target->base == STOP_REWIND) {
curr->target = BYSYNCIFY_STOP_REWIND;
- // TODO: in theory, this does not change the state
+ info->canChangeState = true;
+ info->isTopMostRuntime = true;
} else {
Fatal() << "call to unidenfied bysyncify import: "
<< target->base;
}
- info->canChangeState = true;
return;
}
info->callsTo.insert(target);
@@ -306,7 +328,15 @@ public:
walker.module = &module;
walker.canIndirectChangeState = canIndirectChangeState;
walker.walk(func->body);
+
+ if (info.isBottomMostRuntime) {
+ info.canChangeState = false;
+ // TODO: issue warnings on suspicious things, like a function in
+ // the bottom-most runtime also doing top-most runtime stuff
+ // like starting and unwinding.
+ }
});
+
map.swap(scanner.map);
// Remove the bysyncify imports, if any.
@@ -338,7 +368,7 @@ public:
while (!work.empty()) {
auto* func = work.pop();
for (auto* caller : map[func].calledBy) {
- if (!map[caller].canChangeState) {
+ if (!map[caller].canChangeState && !map[caller].isBottomMostRuntime) {
map[caller].canChangeState = true;
work.push(caller);
}
@@ -346,7 +376,10 @@ public:
}
}
- bool canChangeState(Function* func) { return map[func].canChangeState; }
+ bool needsInstrumentation(Function* func) {
+ auto& info = map[func];
+ return info.canChangeState && !info.isTopMostRuntime;
+ }
bool canChangeState(Expression* curr) {
// Look inside to see if we call any of the things we know can change the
@@ -357,14 +390,17 @@ public:
// We only implement these at the very end, but we know that they
// definitely change the state.
if (curr->target == BYSYNCIFY_START_UNWIND ||
- curr->target == BYSYNCIFY_STOP_UNWIND ||
- curr->target == BYSYNCIFY_START_REWIND ||
curr->target == BYSYNCIFY_STOP_REWIND ||
curr->target == BYSYNCIFY_GET_CALL_INDEX ||
curr->target == BYSYNCIFY_CHECK_CALL_INDEX) {
canChangeState = true;
return;
}
+ if (curr->target == BYSYNCIFY_STOP_UNWIND ||
+ curr->target == BYSYNCIFY_START_REWIND) {
+ isBottomMostRuntime = true;
+ return;
+ }
// The target may not exist if it is one of our temporary intrinsics.
auto* target = module->getFunctionOrNull(curr->target);
if (target && (*map)[target].canChangeState) {
@@ -381,12 +417,16 @@ public:
Map* map;
bool canIndirectChangeState;
bool canChangeState = false;
+ bool isBottomMostRuntime = false;
};
Walker walker;
walker.module = &module;
walker.map = &map;
walker.canIndirectChangeState = canIndirectChangeState;
walker.walk(curr);
+ if (walker.isBottomMostRuntime) {
+ walker.canChangeState = false;
+ }
return walker.canChangeState;
}
};
@@ -451,7 +491,7 @@ struct BysyncifyFlow : public Pass {
module = module_;
// If the function cannot change our state, we have nothing to do -
// we will never unwind or rewind the stack here.
- if (!analyzer->canChangeState(func)) {
+ if (!analyzer->needsInstrumentation(func)) {
return;
}
// Rewrite the function body.
@@ -670,7 +710,7 @@ struct BysyncifyLocals : public WalkerPass<PostWalker<BysyncifyLocals>> {
void doWalkFunction(Function* func) {
// If the function cannot change our state, we have nothing to do -
// we will never unwind or rewind the stack here.
- if (!analyzer->canChangeState(func->body)) {
+ if (!analyzer->needsInstrumentation(func)) {
return;
}
// Note the locals we want to preserve, before we add any more helpers.
diff --git a/test/passes/bysyncify.txt b/test/passes/bysyncify.txt
index 2ab682149..814dd05d0 100644
--- a/test/passes/bysyncify.txt
+++ b/test/passes/bysyncify.txt
@@ -12,229 +12,29 @@
(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 $0
+ (global.get $sleeping)
)
- (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)
- )
- )
- (block
- (if
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 0)
- )
- (global.set $sleeping
- (i32.const 0)
- )
- )
- (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 $bysyncify_stop_rewind)
- (if
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 1)
- )
- (br $__bysyncify_unwind
- (i32.const 1)
- )
- )
- )
- )
- )
- )
- )
- )
- )
- (return)
- )
+ (local.set $1
+ (i32.eqz
+ (local.get $0)
)
)
- (block
- (i32.store
- (i32.load
- (global.get $__bysyncify_data)
+ (if
+ (local.get $1)
+ (block
+ (global.set $sleeping
+ (i32.const 1)
)
- (local.get $2)
- )
- (i32.store
- (global.get $__bysyncify_data)
- (i32.add
- (i32.load
- (global.get $__bysyncify_data)
- )
+ (call $bysyncify_start_unwind
(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)
+ (block
+ (global.set $sleeping
+ (i32.const 0)
)
+ (call $bysyncify_stop_rewind)
)
)
)
@@ -432,145 +232,11 @@
(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_stop_unwind)
- (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 $bysyncify_start_rewind
- (i32.const 4)
- )
- (if
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 1)
- )
- (br $__bysyncify_unwind
- (i32.const 1)
- )
- )
- )
- )
- (if
- (if (result i32)
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 0)
- )
- (i32.const 1)
- (i32.eq
- (local.get $1)
- (i32.const 2)
- )
- )
- (block
- (call $work)
- (if
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 1)
- )
- (br $__bysyncify_unwind
- (i32.const 2)
- )
- )
- )
- )
- )
- )
- (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)
- )
- )
+ (call $bysyncify_stop_unwind)
+ (call $bysyncify_start_rewind
+ (i32.const 4)
)
- (nop)
+ (call $work)
)
(func $never_sleep (; 5 ;) (type $FUNCSIG$v)
(call $stuff)
diff --git a/test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.txt b/test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.txt
new file mode 100644
index 000000000..0534e827a
--- /dev/null
+++ b/test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.txt
@@ -0,0 +1,478 @@
+(module
+ (type $f (func))
+ (type $FUNCSIG$i (func (result i32)))
+ (type $FUNCSIG$vi (func (param i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $calls-import2-drop $calls-import2-drop)
+ (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_stop_unwind" (func $bysyncify_stop_unwind))
+ (export "bysyncify_start_rewind" (func $bysyncify_start_rewind))
+ (export "bysyncify_stop_rewind" (func $bysyncify_stop_rewind))
+ (func $calls-import (; 3 ;) (type $f)
+ (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-drop (; 4 ;) (type $f)
+ (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-import2-if-else (; 5 ;) (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-indirect (; 6 ;) (type $FUNCSIG$vi) (param $x i32)
+ (local $1 i32)
+ (call_indirect (type $f)
+ (local.get $x)
+ )
+ )
+ (func $bysyncify_start_unwind (; 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 1)
+ )
+ (global.set $__bysyncify_data
+ (local.get $0)
+ )
+ )
+ (func $bysyncify_stop_unwind (; 8 ;)
+ (global.set $__bysyncify_state
+ (i32.const 0)
+ )
+ )
+ (func $bysyncify_start_rewind (; 9 ;) (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 (; 10 ;)
+ (global.set $__bysyncify_state
+ (i32.const 0)
+ )
+ )
+)
diff --git a/test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.wast b/test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.wast
new file mode 100644
index 000000000..33500baba
--- /dev/null
+++ b/test/passes/bysyncify_pass-arg=bysyncify-ignore-indirect.wast
@@ -0,0 +1,26 @@
+(module
+ (memory 1 2)
+ (type $f (func))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (table 1 1)
+ (func $calls-import
+ (call $import)
+ )
+ (func $calls-import2-drop
+ (drop (call $import2))
+ )
+ (func $calls-import2-if-else (param $x i32)
+ (if (local.get $x)
+ (call $import3 (i32.const 1))
+ (call $import3 (i32.const 2))
+ )
+ )
+ (func $calls-indirect (param $x i32)
+ (call_indirect (type $f)
+ (local.get $x)
+ )
+ )
+)
+
diff --git a/test/passes/bysyncify_pass-arg=bysyncify-imports@env.import,env.import2.txt b/test/passes/bysyncify_pass-arg=bysyncify-imports@env.import,env.import2.txt
index 81a37a643..b75e59d88 100644
--- a/test/passes/bysyncify_pass-arg=bysyncify-imports@env.import,env.import2.txt
+++ b/test/passes/bysyncify_pass-arg=bysyncify-imports@env.import,env.import2.txt
@@ -12,229 +12,29 @@
(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 $0
+ (global.get $sleeping)
)
- (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)
- )
- )
- (block
- (if
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 0)
- )
- (global.set $sleeping
- (i32.const 0)
- )
- )
- (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 $bysyncify_stop_rewind)
- (if
- (i32.eq
- (global.get $__bysyncify_state)
- (i32.const 1)
- )
- (br $__bysyncify_unwind
- (i32.const 1)
- )
- )
- )
- )
- )
- )
- )
- )
- )
- (return)
- )
+ (local.set $1
+ (i32.eqz
+ (local.get $0)
)
)
- (block
- (i32.store
- (i32.load
- (global.get $__bysyncify_data)
+ (if
+ (local.get $1)
+ (block
+ (global.set $sleeping
+ (i32.const 1)
)
- (local.get $2)
- )
- (i32.store
- (global.get $__bysyncify_data)
- (i32.add
- (i32.load
- (global.get $__bysyncify_data)
- )
+ (call $bysyncify_start_unwind
(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)
+ (block
+ (global.set $sleeping
+ (i32.const 0)
)
+ (call $bysyncify_stop_rewind)
)
)
)
@@ -432,120 +232,10 @@
(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)
+ (call $bysyncify_start_rewind
+ (i32.const 4)
)
- (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)
+ (call $work)
)
(func $never_sleep (; 5 ;) (type $FUNCSIG$v)
(call $stuff)
diff --git a/test/unit/input/bysyncify-pure.txt b/test/unit/input/bysyncify-pure.txt
new file mode 100644
index 000000000..1f85db1f1
--- /dev/null
+++ b/test/unit/input/bysyncify-pure.txt
@@ -0,0 +1,17 @@
+(i32.const 100)
+(i32.const 10)
+(i32.const 1)
+(i32.const 20)
+(i32.const 1000)
+(i32.const 2000)
+(i32.const 4000)
+(i32.const 200)
+(i32.const 300)
+(i32.const 400)
+(i32.const 1000)
+(i32.const 3000)
+(i32.const 4000)
+(i32.const 30)
+(i32.const 2)
+(i32.const 40)
+(i32.const 500)
diff --git a/test/unit/input/bysyncify-pure.wast b/test/unit/input/bysyncify-pure.wast
new file mode 100644
index 000000000..b79bfe2b0
--- /dev/null
+++ b/test/unit/input/bysyncify-pure.wast
@@ -0,0 +1,59 @@
+(module
+ (memory 1 1)
+ (import "spectest" "print" (func $print (param i32)))
+ (import "bysyncify" "start_unwind" (func $bysyncify_start_unwind (param i32)))
+ (import "bysyncify" "stop_unwind" (func $bysyncify_stop_unwind))
+ (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))
+ (start $runtime)
+ (func $main
+ (call $print (i32.const 10))
+ (call $before)
+ (call $print (i32.const 20))
+ (call $sleep)
+ (call $print (i32.const 30))
+ (call $after)
+ (call $print (i32.const 40))
+ )
+ (func $before
+ (call $print (i32.const 1))
+ )
+ (func $sleep
+ (call $print (i32.const 1000))
+ (if
+ (i32.eqz (global.get $sleeping))
+ (block
+ (call $print (i32.const 2000))
+ (global.set $sleeping (i32.const 1))
+ (i32.store (i32.const 16) (i32.const 24))
+ (i32.store (i32.const 20) (i32.const 1024))
+ (call $bysyncify_start_unwind (i32.const 16))
+ )
+ (block
+ (call $print (i32.const 3000))
+ (call $bysyncify_stop_rewind)
+ (global.set $sleeping (i32.const 0))
+ )
+ )
+ (call $print (i32.const 4000))
+ )
+ (func $after
+ (call $print (i32.const 2))
+ )
+ (func $runtime
+ (call $print (i32.const 100))
+ ;; call main the first time, let the stack unwind
+ (call $main)
+ (call $print (i32.const 200))
+ (call $bysyncify_stop_unwind)
+ (call $print (i32.const 300))
+ ;; ...can do some async stuff around here...
+ ;; set the rewind in motion
+ (call $bysyncify_start_rewind (i32.const 16))
+ (call $print (i32.const 400))
+ (call $main)
+ (call $print (i32.const 500))
+ )
+)
+
diff --git a/test/unit/test_bysyncify.py b/test/unit/test_bysyncify.py
index 29a8ae7cb..8d5a780e8 100644
--- a/test/unit/test_bysyncify.py
+++ b/test/unit/test_bysyncify.py
@@ -1,11 +1,11 @@
import os
-from scripts.test.shared import WASM_OPT, NODEJS, run_process
+from scripts.test.shared import WASM_OPT, WASM_DIS, WASM_SHELL, NODEJS, run_process
from utils import BinaryenTestCase
class BysyncifyTest(BinaryenTestCase):
- def test_bysyncify(self):
+ def test_bysyncify_js(self):
def test(args):
print(args)
run_process(WASM_OPT + args + [self.input_path('bysyncify-sleep.wast'), '--bysyncify', '-o', 'a.wasm'])
@@ -19,3 +19,10 @@ class BysyncifyTest(BinaryenTestCase):
test(['--optimize-level=1'])
test(['-O3'])
test(['-Os', '-g'])
+
+ def test_bysyncify_pure_wasm(self):
+ run_process(WASM_OPT + [self.input_path('bysyncify-pure.wast'), '--bysyncify', '-o', 'a.wasm'])
+ run_process(WASM_DIS + ['a.wasm', '-o', 'a.wast'])
+ output = run_process(WASM_SHELL + ['a.wast'], capture_output=True).stdout
+ with open(self.input_path('bysyncify-pure.txt')) as f:
+ self.assertEqual(f.read(), output)