From 2b9ba4a957b1155d0076d53fef608c1536b73046 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Nov 2025 15:05:43 -0800 Subject: [PATCH] Add asyncify-export-globals argument In the past emscripten would build the main module as relocatable, but these days we build it statically and in that case it makes sense for the main module to define and export these globals, rather than defining them in JS. --- src/passes/Asyncify.cpp | 17 ++++++++++++++--- ...yncify_pass-arg=asyncify-export-globals.wast | 11 +++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 test/lit/passes/asyncify_pass-arg=asyncify-export-globals.wast diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index cadf0871b4d..3ee62b7d737 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -1759,7 +1759,8 @@ struct Asyncify : public Pass { String::Split::NewLineOr(",")); auto asserts = hasArgument("asyncify-asserts"); auto verbose = hasArgument("asyncify-verbose"); - auto relocatable = hasArgument("asyncify-relocatable"); + auto importGlobals = hasArgument("asyncify-relocatable"); + auto exportGlobals = hasArgument("asyncify-export-globals"); auto secondaryMemory = hasArgument("asyncify-in-secondary-memory"); auto propagateAddList = hasArgument("asyncify-propagate-addlist"); @@ -1826,7 +1827,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 +1905,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 +1930,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))