diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp index d477061ae32..6c568270357 100644 --- a/src/tools/wasm-emscripten-finalize.cpp +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -187,6 +187,7 @@ int main(int argc, const char *argv[]) { } else { generator.generateRuntimeFunctions(); generator.generateMemoryGrowthFunction(); + generator.generateStackInitialization(); // emscripten calls this by default for side libraries so we only need // to include in as a static ctor for main module case. if (wasm.getExportOrNull("__post_instantiate")) { diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index c15a4b8afdd..a5de5a12822 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -36,6 +36,7 @@ class EmscriptenGlueGenerator { void generateRuntimeFunctions(); Function* generateMemoryGrowthFunction(); + void generateStackInitialization(); // Create thunks for use with emscripten Runtime.dynCall. Creates one for each // signature in the indirect function table. diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 09a93a8fe07..3c78ce866d3 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -36,6 +36,7 @@ cashew::IString EM_JS_PREFIX("__em_js__"); static Name STACK_SAVE("stackSave"), STACK_RESTORE("stackRestore"), STACK_ALLOC("stackAlloc"), + STACK_INIT("stack$init"), DUMMY_FUNC("__wasm_nullptr"); void addExportedFunction(Module& wasm, Function* function) { @@ -155,6 +156,21 @@ Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() { return growFunction; } +void EmscriptenGlueGenerator::generateStackInitialization() { + // Replace a global with a constant initial value with an imported + // initial value, which emscripten JS will send us. + // TODO: with mutable imported globals, we can avoid adding another + // global for the import. + Builder builder(wasm); + auto* import = builder.makeGlobal(STACK_INIT, i32, nullptr, Builder::Immutable); + import->module = ENV; + import->base = STACKTOP; + wasm.addGlobal(import); + auto* stackPointer = getStackPointerGlobal(); + assert(stackPointer->init->is()); + stackPointer->init = builder.makeGetGlobal(import->name, i32); +} + static bool hasI64ResultOrParam(FunctionType* ft) { if (ft->result == i64) return true; for (auto ty : ft->params) { @@ -227,10 +243,10 @@ static Function* ensureFunctionImport(Module* module, Name name, std::string sig } struct RemoveStackPointer : public PostWalker { - RemoveStackPointer(Global* StackPointer) : StackPointer(StackPointer) {} + RemoveStackPointer(Global* stackPointer) : stackPointer(stackPointer) {} void visitGetGlobal(GetGlobal* curr) { - if (getModule()->getGlobalOrNull(curr->name) == StackPointer) { + if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { ensureFunctionImport(getModule(), STACK_SAVE, "i"); if (!builder) builder = make_unique(*getModule()); replaceCurrent(builder->makeCall(STACK_SAVE, {}, i32)); @@ -238,7 +254,7 @@ struct RemoveStackPointer : public PostWalker { } void visitSetGlobal(SetGlobal* curr) { - if (getModule()->getGlobalOrNull(curr->name) == StackPointer) { + if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { ensureFunctionImport(getModule(), STACK_RESTORE, "vi"); if (!builder) builder = make_unique(*getModule()); replaceCurrent(builder->makeCall(STACK_RESTORE, {curr->value}, none)); @@ -247,7 +263,7 @@ struct RemoveStackPointer : public PostWalker { private: std::unique_ptr builder; - Global* StackPointer; + Global* stackPointer; }; void EmscriptenGlueGenerator::replaceStackPointerGlobal() { @@ -833,7 +849,9 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata( meta << " \"externs\": ["; commaFirst = true; ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) { - meta << nextElement() << "\"_" << import->base.str << '"'; + if (!(import->module == ENV && import->name == STACK_INIT)) { + meta << nextElement() << "\"_" << import->base.str << '"'; + } }); meta << "\n ],\n"; diff --git a/test/lld/duplicate_imports.wast.out b/test/lld/duplicate_imports.wast.out index 3edf1a8a75e..98cd37651a6 100644 --- a/test/lld/duplicate_imports.wast.out +++ b/test/lld/duplicate_imports.wast.out @@ -9,6 +9,7 @@ (type $legaltype$puts2 (func (param i32 i32) (result i32))) (type $legaltype$invoke_ffd (func (param i32 f64 f64) (result f64))) (type $legaltype$invoke_ffd2 (func (param i32 f64 f64) (result f64))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "puts" (func $puts1 (param i32) (result i32))) (import "env" "puts" (func $legalimport$puts2 (param i32 i32) (result i32))) (import "env" "invoke_ffd" (func $legalimport$invoke_ffd (param i32 f64 f64) (result f64))) @@ -16,7 +17,7 @@ (memory $0 2) (data (i32.const 568) "Hello, world\00") (table $0 1 1 anyfunc) - (global $global$0 (mut i32) (i32.const 66128)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66128)) (global $global$2 i32 (i32.const 581)) (export "memory" (memory $0)) diff --git a/test/lld/em_asm.wast.out b/test/lld/em_asm.wast.out index bceda9a7509..a4112fba555 100644 --- a/test/lld/em_asm.wast.out +++ b/test/lld/em_asm.wast.out @@ -7,13 +7,14 @@ (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "emscripten_asm_const_i" (func $emscripten_asm_const_i (param i32) (result i32))) (import "env" "emscripten_asm_const_iii" (func $emscripten_asm_const_iii (param i32 i32 i32) (result i32))) (import "env" "emscripten_asm_const_ii" (func $emscripten_asm_const_ii (param i32 i32) (result i32))) (memory $0 2) (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") (table $0 1 1 anyfunc) - (global $global$0 (mut i32) (i32.const 66192)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66192)) (global $global$2 i32 (i32.const 652)) (export "memory" (memory $0)) diff --git a/test/lld/em_asm_table.wast.out b/test/lld/em_asm_table.wast.out index be0d1a7946a..628cf20d5c5 100644 --- a/test/lld/em_asm_table.wast.out +++ b/test/lld/em_asm_table.wast.out @@ -4,11 +4,12 @@ (type $FUNCSIG$vii (func (param i32 i32))) (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) (import "env" "memory" (memory $0 8192)) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "emscripten_log" (func $fimport$0 (param i32 i32))) (import "env" "emscripten_asm_const_iii" (func $emscripten_asm_const_iii (param i32 i32 i32) (result i32))) (table $0 159609 anyfunc) (elem (i32.const 1) $fimport$0 $emscripten_asm_const_iii) - (global $global$0 (mut i32) (i32.const 1024)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 1048)) (export "__data_end" (global $global$1)) (export "stackSave" (func $stackSave)) diff --git a/test/lld/hello_world.wast.mem.out b/test/lld/hello_world.wast.mem.out index 2a8a0a0629d..32eab7450de 100644 --- a/test/lld/hello_world.wast.mem.out +++ b/test/lld/hello_world.wast.mem.out @@ -3,10 +3,11 @@ (type $1 (func (result i32))) (type $2 (func)) (type $FUNCSIG$ii (func (param i32) (result i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "puts" (func $puts (param i32) (result i32))) (memory $0 2) (table $0 1 1 anyfunc) - (global $global$0 (mut i32) (i32.const 66128)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66128)) (global $global$2 i32 (i32.const 581)) (export "memory" (memory $0)) diff --git a/test/lld/hello_world.wast.out b/test/lld/hello_world.wast.out index e20a58d1663..d7b5dfaeb46 100644 --- a/test/lld/hello_world.wast.out +++ b/test/lld/hello_world.wast.out @@ -3,11 +3,12 @@ (type $1 (func (result i32))) (type $2 (func)) (type $FUNCSIG$ii (func (param i32) (result i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "puts" (func $puts (param i32) (result i32))) (memory $0 2) (data (i32.const 568) "Hello, world\00") (table $0 1 1 anyfunc) - (global $global$0 (mut i32) (i32.const 66128)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66128)) (global $global$2 i32 (i32.const 581)) (export "memory" (memory $0)) diff --git a/test/lld/init.wast.out b/test/lld/init.wast.out index fb944aff413..4152ef2ac14 100644 --- a/test/lld/init.wast.out +++ b/test/lld/init.wast.out @@ -1,10 +1,11 @@ (module (type $0 (func)) (type $1 (func (result i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (memory $0 2) (data (i32.const 568) "\00\00\00\00\00\00\00\00") (table $0 1 1 anyfunc) - (global $global$0 (mut i32) (i32.const 66112)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66112)) (global $global$2 i32 (i32.const 576)) (export "memory" (memory $0)) diff --git a/test/lld/recursive.wast.out b/test/lld/recursive.wast.out index 6a705085e63..08f7dfa3fc9 100644 --- a/test/lld/recursive.wast.out +++ b/test/lld/recursive.wast.out @@ -3,11 +3,12 @@ (type $1 (func (result i32))) (type $2 (func)) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "printf" (func $printf (param i32 i32) (result i32))) (memory $0 2) (data (i32.const 568) "%d:%d\n\00Result: %d\n\00") (table $0 1 1 anyfunc) - (global $global$0 (mut i32) (i32.const 66128)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66128)) (global $global$2 i32 (i32.const 587)) (export "memory" (memory $0)) diff --git a/test/lld/reserved_func_ptr.wast.jscall.out b/test/lld/reserved_func_ptr.wast.jscall.out index 7e95fb080e8..c796a025cc0 100644 --- a/test/lld/reserved_func_ptr.wast.jscall.out +++ b/test/lld/reserved_func_ptr.wast.jscall.out @@ -18,6 +18,7 @@ (type $FUNCSIG$v (func)) (type $FUNCSIG$vii (func (param i32 i32))) (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32))) (import "env" "jsCall_ddi" (func $jsCall_ddi (param i32 f64 i32) (result f64))) (import "env" "jsCall_fffi" (func $jsCall_fffi (param i32 f32 f32 i32) (result f32))) @@ -28,7 +29,7 @@ (memory $0 2) (table $0 21 21 anyfunc) (elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii $jsCall_ddi_0 $jsCall_ddi_1 $jsCall_ddi_2 $jsCall_fffi_0 $jsCall_fffi_1 $jsCall_fffi_2 $jsCall_iii_0 $jsCall_iii_1 $jsCall_iii_2 $jsCall_v_0 $jsCall_v_1 $jsCall_v_2 $jsCall_vi_0 $jsCall_vi_1 $jsCall_vi_2 $jsCall_viii_0 $jsCall_viii_1 $jsCall_viii_2) - (global $global$0 (mut i32) (i32.const 66112)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66112)) (global $global$2 i32 (i32.const 568)) (export "memory" (memory $0)) diff --git a/test/lld/reserved_func_ptr.wast.out b/test/lld/reserved_func_ptr.wast.out index 1c448d4ed37..7c80307b4bc 100644 --- a/test/lld/reserved_func_ptr.wast.out +++ b/test/lld/reserved_func_ptr.wast.out @@ -8,11 +8,12 @@ (type $6 (func (param i32) (result i32))) (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$viii (func (param i32 i32 i32))) + (import "env" "STACKTOP" (global $stack$init i32)) (import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32))) (memory $0 2) (table $0 3 3 anyfunc) (elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii) - (global $global$0 (mut i32) (i32.const 66112)) + (global $global$0 (mut i32) (get_global $stack$init)) (global $global$1 i32 (i32.const 66112)) (global $global$2 i32 (i32.const 568)) (export "memory" (memory $0))