From 2f9d019267bd792e1df09a00648eb4d8edb39ac1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 8 Apr 2020 13:59:21 -0700 Subject: 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. --- src/wasm/wasm-emscripten.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'src') 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); -- cgit v1.2.3