summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Asyncify.cpp53
-rw-r--r--test/lit/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast81
2 files changed, 123 insertions, 11 deletions
diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp
index 365891db4..7b2d57574 100644
--- a/src/passes/Asyncify.cpp
+++ b/src/passes/Asyncify.cpp
@@ -921,9 +921,6 @@ struct AsyncifyFlow : public Pass {
// If the function cannot change our state, we have nothing to do -
// we will never unwind or rewind the stack here.
if (!analyzer->needsInstrumentation(func)) {
- if (analyzer->asserts) {
- addAssertsInNonInstrumented(func);
- }
return;
}
// Rewrite the function body.
@@ -947,7 +944,6 @@ struct AsyncifyFlow : public Pass {
private:
std::unique_ptr<AsyncifyBuilder> builder;
-
Module* module;
Function* func;
@@ -1216,6 +1212,41 @@ private:
// don't want it to be seen by asyncify itself.
return builder->makeCall(ASYNCIFY_GET_CALL_INDEX, {}, Type::none);
}
+};
+
+// Add asserts in non-instrumented code.
+struct AsyncifyAssertInNonInstrumented : public Pass {
+ bool isFunctionParallel() override { return true; }
+
+ ModuleAnalyzer* analyzer;
+ Type pointerType;
+ Name asyncifyMemory;
+
+ std::unique_ptr<Pass> create() override {
+ return std::make_unique<AsyncifyAssertInNonInstrumented>(
+ analyzer, pointerType, asyncifyMemory);
+ }
+
+ AsyncifyAssertInNonInstrumented(ModuleAnalyzer* analyzer,
+ Type pointerType,
+ Name asyncifyMemory)
+ : analyzer(analyzer), pointerType(pointerType),
+ asyncifyMemory(asyncifyMemory) {}
+
+ void runOnFunction(Module* module_, Function* func) override {
+ // FIXME: This looks like it was never right, as it should ignore the top-
+ // most runtime, but it will actually instrument it (as it needs no
+ // instrumentation, like random code - but the top-most runtime is
+ // actually a place that needs neither instrumentation *nor*
+ // assertions, as the assertions will error when it changes the
+ // state).
+ if (!analyzer->needsInstrumentation(func)) {
+ module = module_;
+ builder =
+ make_unique<AsyncifyBuilder>(*module, pointerType, asyncifyMemory);
+ addAssertsInNonInstrumented(func);
+ }
+ }
// Given a function that is not instrumented - because we proved it doesn't
// need it, or depending on the only-list / remove-list - add assertions that
@@ -1275,6 +1306,10 @@ private:
walker.oldState = oldState;
walker.walk(func->body);
}
+
+private:
+ std::unique_ptr<AsyncifyBuilder> builder;
+ Module* module;
};
// Instrument local saving/restoring.
@@ -1689,6 +1724,16 @@ struct Asyncify : public Pass {
runner.setValidateGlobally(false);
runner.run();
}
+ if (asserts) {
+ // Add asserts in non-instrumented code. Note we do not use an
+ // instrumented pass runner here as we do want to run on all functions.
+ PassRunner runner(module);
+ runner.add(make_unique<AsyncifyAssertInNonInstrumented>(
+ &analyzer, pointerType, asyncifyMemory));
+ runner.setIsNested(true);
+ runner.setValidateGlobally(false);
+ runner.run();
+ }
// Next, add local saving/restoring logic. We optimize before doing this,
// to undo the extra code generated by flattening, and to arrive at the
// minimal amount of locals (which is important as we must save and
diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast b/test/lit/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast
index cd42c9c2d..a43f13013 100644
--- a/test/lit/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast
+++ b/test/lit/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast
@@ -3,6 +3,11 @@
;; RUN: foreach %s %t wasm-opt --asyncify --pass-arg=asyncify-asserts --pass-arg=asyncify-onlylist@waka -S -o - | filecheck %s
+;; This test has an only-list, and that list has a non-existent function, so we
+;; do not actually instrument anything. But we should still add the assertions
+;; we add in non-instrumented code, namely asserts that they don't change the
+;; state.
+
(module
(memory 1 2)
;; CHECK: (type $f (func))
@@ -39,14 +44,44 @@
;; CHECK: (export "asyncify_get_state" (func $asyncify_get_state))
;; CHECK: (func $calls-import
- ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $calls-import
(call $import)
)
;; CHECK: (func $calls-import2-drop
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (call $import2)
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (call $import2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $calls-import2-drop
@@ -54,10 +89,29 @@
)
;; CHECK: (func $returns (result i32)
;; CHECK-NEXT: (local $x i32)
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (call $import2)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (call $import2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $returns (result i32)
(local $x i32)
@@ -65,8 +119,21 @@
(local.get $x)
)
;; CHECK: (func $calls-indirect (param $x i32)
- ;; CHECK-NEXT: (call_indirect (type $f)
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (call_indirect (type $f)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.ne
+ ;; CHECK-NEXT: (global.get $__asyncify_state)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $calls-indirect (param $x i32)