diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index cadf0871b4d..48f9cc59419 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -323,6 +323,20 @@ // model where you can specify "instrument, but not indirect calls from me" // would likely have little benefit.) // +// In addition, there are arguments for controlling the import/export of the +// internal globals used by Asyncify. These can be useful in dynamic linking. +// By default these globals are are internal and neither imported nor exported. +// +// --pass-arg=import-globals +// +// Import the internal globals used by Asyncify. This allows them to be +// defined in another module. +// +// --pass-arg=export-globals +// +// Export the internal globals used by Asyncify. This allows them to be +// imported into anther module built with --pass-arg=import-globals +// // TODO When wasm has GC, extending the live ranges of locals can keep things // alive unnecessarily. We may want to set locals to null at the end // of their original range. @@ -1759,7 +1773,11 @@ struct Asyncify : public Pass { String::Split::NewLineOr(",")); auto asserts = hasArgument("asyncify-asserts"); auto verbose = hasArgument("asyncify-verbose"); - auto relocatable = hasArgument("asyncify-relocatable"); + // TODO: Remove the legacy asyncify-relocatable name once emscripten is + // updated. + auto importGlobals = hasArgument("asyncify-import-globals") || + hasArgument("asyncify-relocatable"); + auto exportGlobals = hasArgument("asyncify-export-globals"); auto secondaryMemory = hasArgument("asyncify-in-secondary-memory"); auto propagateAddList = hasArgument("asyncify-propagate-addlist"); @@ -1826,7 +1844,7 @@ struct Asyncify : public Pass { verbose); // Add necessary globals before we emit code to use them. - addGlobals(module, relocatable); + addGlobals(module, importGlobals, exportGlobals); // Compute the set of functions we will instrument. All of the passes we run // below only need to run there. @@ -1904,8 +1922,11 @@ struct Asyncify : public Pass { } private: - void addGlobals(Module* module, bool imported) { + void addGlobals(Module* module, bool imported, bool exported) { Builder builder(*module); + // It doesn't make sense to both import and export these globals at the + // same time. + assert(!(imported && exported)); auto asyncifyState = builder.makeGlobal(ASYNCIFY_STATE, Type::i32, @@ -1926,6 +1947,13 @@ struct Asyncify : public Pass { asyncifyData->base = ASYNCIFY_DATA; } module->addGlobal(std::move(asyncifyData)); + + if (exported) { + module->addExport(builder.makeExport( + ASYNCIFY_STATE, ASYNCIFY_STATE, ExternalKind::Global)); + module->addExport( + builder.makeExport(ASYNCIFY_DATA, ASYNCIFY_DATA, ExternalKind::Global)); + } } void addFunctions(Module* module) { diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-export-globals.wast b/test/lit/passes/asyncify_pass-arg=asyncify-export-globals.wast new file mode 100644 index 00000000000..e50e5b65902 --- /dev/null +++ b/test/lit/passes/asyncify_pass-arg=asyncify-export-globals.wast @@ -0,0 +1,11 @@ +;; RUN: wasm-opt --enable-mutable-globals --asyncify --pass-arg=asyncify-export-globals -S -o - | filecheck %s + +(module +) +;; CHECK: (global $__asyncify_state (mut i32) (i32.const 0)) + +;; CHECK: (global $__asyncify_data (mut i32) (i32.const 0)) + +;; CHECK: (export "__asyncify_state" (global $__asyncify_state)) + +;; CHECK: (export "__asyncify_data" (global $__asyncify_data)) diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-import-globals.wast b/test/lit/passes/asyncify_pass-arg=asyncify-import-globals.wast new file mode 100644 index 00000000000..30059fc0a69 --- /dev/null +++ b/test/lit/passes/asyncify_pass-arg=asyncify-import-globals.wast @@ -0,0 +1,10 @@ +;; RUN: wasm-opt --enable-mutable-globals --asyncify --pass-arg=asyncify-import-globals -S -o - | filecheck %s + +;; Also test asyncify-relocatable which is an alias for asyncify-import-globals +;; RUN: wasm-opt --enable-mutable-globals --asyncify --pass-arg=asyncify-relocatable -S -o - | filecheck %s + +(module +) + +;; CHECK: (import "env" "__asyncify_state" (global $__asyncify_state (mut i32))) +;; CHECK: (import "env" "__asyncify_data" (global $__asyncify_data (mut i32))) diff --git a/test/lit/passes/asyncify_pass-arg=asyncify-side-module.wast b/test/lit/passes/asyncify_pass-arg=asyncify-side-module.wast deleted file mode 100644 index 9dee0f8c011..00000000000 --- a/test/lit/passes/asyncify_pass-arg=asyncify-side-module.wast +++ /dev/null @@ -1,114 +0,0 @@ -;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. -;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. - -;; RUN: foreach %s %t wasm-opt --enable-mutable-globals --asyncify --pass-arg=asyncify-relocatable -S -o - | filecheck %s - -(module -) -;; CHECK: (type $0 (func (param i32))) - -;; CHECK: (type $1 (func)) - -;; CHECK: (type $2 (func (result i32))) - -;; CHECK: (import "env" "__asyncify_state" (global $__asyncify_state (mut i32))) - -;; CHECK: (import "env" "__asyncify_data" (global $__asyncify_data (mut i32))) - -;; CHECK: (memory $0 1 1) - -;; CHECK: (export "asyncify_start_unwind" (func $asyncify_start_unwind)) - -;; CHECK: (export "asyncify_stop_unwind" (func $asyncify_stop_unwind)) - -;; CHECK: (export "asyncify_start_rewind" (func $asyncify_start_rewind)) - -;; CHECK: (export "asyncify_stop_rewind" (func $asyncify_stop_rewind)) - -;; CHECK: (export "asyncify_get_state" (func $asyncify_get_state)) - -;; CHECK: (func $asyncify_start_unwind (param $0 i32) -;; CHECK-NEXT: (global.set $__asyncify_state -;; CHECK-NEXT: (i32.const 1) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (global.set $__asyncify_data -;; CHECK-NEXT: (local.get $0) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (if -;; CHECK-NEXT: (i32.gt_u -;; CHECK-NEXT: (i32.load -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.load offset=4 -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (then -;; CHECK-NEXT: (unreachable) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $asyncify_stop_unwind -;; CHECK-NEXT: (global.set $__asyncify_state -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (if -;; CHECK-NEXT: (i32.gt_u -;; CHECK-NEXT: (i32.load -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.load offset=4 -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (then -;; CHECK-NEXT: (unreachable) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $asyncify_start_rewind (param $0 i32) -;; CHECK-NEXT: (global.set $__asyncify_state -;; CHECK-NEXT: (i32.const 2) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (global.set $__asyncify_data -;; CHECK-NEXT: (local.get $0) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (if -;; CHECK-NEXT: (i32.gt_u -;; CHECK-NEXT: (i32.load -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.load offset=4 -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (then -;; CHECK-NEXT: (unreachable) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $asyncify_stop_rewind -;; CHECK-NEXT: (global.set $__asyncify_state -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (if -;; CHECK-NEXT: (i32.gt_u -;; CHECK-NEXT: (i32.load -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.load offset=4 -;; CHECK-NEXT: (global.get $__asyncify_data) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (then -;; CHECK-NEXT: (unreachable) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $asyncify_get_state (result i32) -;; CHECK-NEXT: (global.get $__asyncify_state) -;; CHECK-NEXT: )