diff options
author | Alon Zakai <azakai@google.com> | 2020-04-08 13:59:21 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-08 13:59:21 -0700 |
commit | 2f9d019267bd792e1df09a00648eb4d8edb39ac1 (patch) | |
tree | 5542994773bf4d34a53bd938fa8c628cf3c8dd5f /src | |
parent | 95a66b5b3ad34b47703131207bbab739366408c4 (diff) | |
download | binaryen-2f9d019267bd792e1df09a00648eb4d8edb39ac1.tar.gz binaryen-2f9d019267bd792e1df09a00648eb4d8edb39ac1.tar.bz2 binaryen-2f9d019267bd792e1df09a00648eb4d8edb39ac1.zip |
Avoid g$ in main modules where possible (#2721)
We realized it is not valid to do these f$, g$ optimizations in
main and side modules, as a symbol might appear in both (like
RTTI or a weak symbol). We do need one of the appearances
to "win". This does the g$ optimization in main modules only,
that is, if a global appears in a main module then we can avoid
a g$ import and instead compute its location directly in the
module, since we will "win" over other modules with the same
symbol anyhow.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 75598875c..5a4bda0a7 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -288,8 +288,35 @@ Function* EmscriptenGlueGenerator::generateAssignGOTEntriesFunction() { Block* block = builder.makeBlock(); assignFunc->body = block; + bool hasSingleMemorySegment = + wasm.memory.exists && wasm.memory.segments.size() == 1; + for (Global* g : gotMemEntries) { - Name getter(std::string("g$") + g->base.c_str()); + // If this global is defined in this module, we export its address relative + // to the relocatable memory. If we are in a main module, we can just use + // that location (since if other modules have this symbol too, we will "win" + // as we are loaded first). Otherwise, import a g$ getter. + // Note that this depends on memory having a single segment, so we know the + // offset, and that the export is a global. + auto base = g->base; + if (hasSingleMemorySegment && !sideModule) { + if (auto* ex = wasm.getExportOrNull(base)) { + if (ex->kind == ExternalKind::Global) { + // The base relative to which we are computed is the offset of the + // singleton segment. + auto* relativeBase = + ExpressionManipulator::copy(wasm.memory.segments[0].offset, wasm); + + auto* offset = + builder.makeGlobalGet(ex->value, wasm.getGlobal(ex->value)->type); + auto* add = builder.makeBinary(AddInt32, relativeBase, offset); + GlobalSet* globalSet = builder.makeGlobalSet(g->name, add); + block->list.push_back(globalSet); + continue; + } + } + } + Name getter(std::string("g$") + base.c_str()); ensureFunctionImport(&wasm, getter, Signature(Type::none, Type::i32)); Expression* call = builder.makeCall(getter, {}, Type::i32); GlobalSet* globalSet = builder.makeGlobalSet(g->name, call); |