diff options
author | Alon Zakai <alonzakai@gmail.com> | 2019-01-16 13:22:39 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-16 13:22:39 -0800 |
commit | 777d33d40ff030f1711c40bf3cd5bc4bc36af313 (patch) | |
tree | 343d05d218b55dfd6e453f90d76d896cd84d1865 /src | |
parent | cbb24eb4a0810640c9dcee2f6682c64f9bc6c512 (diff) | |
download | binaryen-777d33d40ff030f1711c40bf3cd5bc4bc36af313.tar.gz binaryen-777d33d40ff030f1711c40bf3cd5bc4bc36af313.tar.bz2 binaryen-777d33d40ff030f1711c40bf3cd5bc4bc36af313.zip |
Emscripten stack simplification (#1870)
This takes advantage of the recent memory simplification in emscripten, where JS static allocation is done at compile time. That means we know the stack's initial location at compile time, and can apply it. This is the binaryen side of that:
* asm2wasm support for asm.js globals with an initial value var X = Y; where Y is not 0 (which is what the stack now is).
* wasm-emscripten-finalize support for a flag --initial-stack-pointer=X, and remove the old code to import the stack's initial location.
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 10 | ||||
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 20 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 2 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 14 |
4 files changed, 26 insertions, 20 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index d958c4b6a..c193791f8 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -426,13 +426,16 @@ public: std::map<IString, MappedGlobal> mappedGlobals; private: - void allocateGlobal(IString name, Type type) { + void allocateGlobal(IString name, Type type, Literal value=Literal()) { assert(mappedGlobals.find(name) == mappedGlobals.end()); + if (value.type == none) { + value = Literal::makeZero(type); + } mappedGlobals.emplace(name, MappedGlobal(type)); wasm.addGlobal(builder.makeGlobal( name, type, - LiteralUtils::makeZero(type, wasm), + builder.makeConst(value), Builder::Mutable )); } @@ -986,8 +989,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { Ref value = pair[1]; if (value->isNumber()) { // global int - assert(value->getNumber() == 0); - allocateGlobal(name, Type::i32); + allocateGlobal(name, Type::i32, Literal(int32_t(value->getInteger()))); } else if (value[0] == BINARY) { // int import assert(value[1] == OR && value[3]->isNumber() && value[3]->getNumber() == 0); diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp index 3d74138cc..3ea3629c5 100644 --- a/src/tools/wasm-emscripten-finalize.cpp +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -36,6 +36,8 @@ using namespace cashew; using namespace wasm; int main(int argc, const char *argv[]) { + const uint64_t INVALID_BASE = -1; + std::string infile; std::string outfile; std::string inputSourceMapFilename; @@ -46,7 +48,8 @@ int main(int argc, const char *argv[]) { bool debugInfo = false; bool legalizeJavaScriptFFI = true; unsigned numReservedFunctionPointers = 0; - uint64_t globalBase; + uint64_t globalBase = INVALID_BASE; + uint64_t initialStackPointer = INVALID_BASE; Options options("wasm-emscripten-finalize", "Performs Emscripten-specific transforms on .wasm files"); options @@ -75,11 +78,16 @@ int main(int argc, const char *argv[]) { const std::string &argument) { numReservedFunctionPointers = std::stoi(argument); }) - .add("--global-base", "", "Where lld started to place globals", + .add("--global-base", "", "The address at which static globals were placed", Options::Arguments::One, [&globalBase](Options*, const std::string&argument ) { globalBase = std::stoull(argument); }) + .add("--initial-stack-pointer", "", "The initial location of the stack pointer", + Options::Arguments::One, + [&initialStackPointer](Options*, const std::string&argument ) { + initialStackPointer = std::stoull(argument); + }) .add("--input-source-map", "-ism", "Consume source map from the specified file", Options::Arguments::One, @@ -141,6 +149,12 @@ int main(int argc, const char *argv[]) { uint32_t dataSize = 0; if (!isSideModule) { + if (globalBase == INVALID_BASE) { + Fatal() << "globalBase must be set"; + } + if (initialStackPointer == INVALID_BASE) { + Fatal() << "initialStackPointer must be set"; + } Export* dataEndExport = wasm.getExport("__data_end"); if (dataEndExport == nullptr) { Fatal() << "__data_end export not found"; @@ -189,7 +203,7 @@ int main(int argc, const char *argv[]) { } else { generator.generateRuntimeFunctions(); generator.generateMemoryGrowthFunction(); - generator.generateStackInitialization(); + generator.generateStackInitialization(initialStackPointer); // 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 2b626a7c9..d078cafbf 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -36,7 +36,7 @@ public: void generateRuntimeFunctions(); Function* generateMemoryGrowthFunction(); - void generateStackInitialization(); + void generateStackInitialization(Address addr); // 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 b18fe0c76..88e66ea07 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -156,19 +156,9 @@ 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); +void EmscriptenGlueGenerator::generateStackInitialization(Address addr) { auto* stackPointer = getStackPointerGlobal(); - assert(stackPointer->init->is<Const>()); - stackPointer->init = builder.makeGetGlobal(import->name, i32); + stackPointer->init->cast<Const>()->value = Literal(int32_t(addr)); } static bool hasI64ResultOrParam(FunctionType* ft) { |