diff options
Diffstat (limited to 'src/wasm/wasm-emscripten.cpp')
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 176 |
1 files changed, 1 insertions, 175 deletions
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 8e0c15aeb..c0b4f6437 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -41,7 +41,6 @@ static Name STACK_INIT("stack$init"); static Name STACK_LIMIT("__stack_limit"); static Name SET_STACK_LIMIT("__set_stack_limit"); static Name POST_INSTANTIATE("__post_instantiate"); -static Name ASSIGN_GOT_ENTIRES("__assign_got_enties"); static Name STACK_OVERFLOW_IMPORT("__handle_stack_overflow"); void addExportedFunction(Module& wasm, Function* function) { @@ -79,179 +78,6 @@ Global* getStackPointerGlobal(Module& wasm) { return nullptr; } -static Function* -ensureFunctionImport(Module* module, Name name, Signature sig) { - // See if its already imported. - // FIXME: O(N) - ImportInfo info(*module); - if (auto* f = info.getImportedFunction(ENV, name)) { - return f; - } - // Failing that create a new import. - auto import = new Function; - import->name = name; - import->module = ENV; - import->base = name; - import->sig = sig; - module->addFunction(import); - return import; -} - -static Global* ensureGlobalImport(Module* module, Name name, Type type) { - // See if its already imported. - // FIXME: O(N) - ImportInfo info(*module); - if (auto* g = info.getImportedGlobal(ENV, name)) { - return g; - } - // Failing that create a new import. - auto import = new Global; - import->name = name; - import->module = ENV; - import->base = name; - import->type = type; - module->addGlobal(import); - return import; -} - -// Convert LLVM PIC ABI to emscripten ABI -// -// When generating -fPIC code llvm will generate imports call GOT.mem and -// GOT.func in order to access the addresses of external global data and -// functions. -// -// However emscripten uses a different ABI where function and data addresses -// are available at runtime via special `g$foo` and `fp$bar` function calls. -// -// Here we internalize all such wasm globals and generte code that sets their -// value based on the result of call `g$foo` and `fp$bar` functions at runtime. -Function* EmscriptenGlueGenerator::generateAssignGOTEntriesFunction() { - BYN_TRACE("generateAssignGOTEntriesFunction\n"); - std::vector<Global*> gotFuncEntries; - std::vector<Global*> gotMemEntries; - for (auto& g : wasm.globals) { - if (!g->imported()) { - continue; - } - if (g->module == "GOT.func") { - gotFuncEntries.push_back(g.get()); - } else if (g->module == "GOT.mem") { - gotMemEntries.push_back(g.get()); - } else { - continue; - } - // Make this an internal, non-imported, global. - g->module.clear(); - g->init = Builder(wasm).makeConst(int32_t(0)); - } - - if (!gotFuncEntries.size() && !gotMemEntries.size()) { - return nullptr; - } - - Function* assignFunc = builder.makeFunction( - ASSIGN_GOT_ENTIRES, std::vector<NameType>{}, Type::none, {}); - Block* block = builder.makeBlock(); - assignFunc->body = block; - - bool hasSingleMemorySegment = - wasm.memory.exists && wasm.memory.segments.size() == 1; - - for (Global* g : gotMemEntries) { - // 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); - block->list.push_back(globalSet); - } - - ImportInfo importInfo(wasm); - - // We may have to add things to the table. - Global* tableBase = nullptr; - - for (Global* g : gotFuncEntries) { - // The function has to exist either as export or an import. - // Note that we don't search for the function by name since its internal - // name may be different. - auto* ex = wasm.getExportOrNull(g->base); - // If this is exported then it must be one of the functions implemented - // here, and if this is a main module, then we can simply place the function - // in the table: the loader will see it there and resolve all other uses - // to this one. - if (ex && !sideModule) { - assert(ex->kind == ExternalKind::Function); - auto* f = wasm.getFunction(ex->value); - if (f->imported()) { - Fatal() << "GOT.func entry is both imported and exported: " << g->base; - } - // The base relative to which we are computed is the offset of the - // singleton segment, which we must ensure exists - if (!tableBase) { - tableBase = ensureGlobalImport(&wasm, TABLE_BASE, Type::i32); - } - if (!wasm.table.exists) { - wasm.table.exists = true; - } - if (wasm.table.segments.empty()) { - wasm.table.segments.resize(1); - wasm.table.segments[0].offset = - builder.makeGlobalGet(tableBase->name, Type::i32); - } - auto tableIndex = TableUtils::getOrAppend(wasm.table, f->name, wasm); - auto* c = LiteralUtils::makeFromInt32(tableIndex, Type::i32, wasm); - auto* getBase = builder.makeGlobalGet(tableBase->name, Type::i32); - auto* add = builder.makeBinary(AddInt32, getBase, c); - auto* globalSet = builder.makeGlobalSet(g->name, add); - block->list.push_back(globalSet); - continue; - } - // This is imported or in a side module. Create an fp$ import to get the - // function table index from the dynamic loader. - auto* f = importInfo.getImportedFunction(ENV, g->base); - if (!f) { - if (!ex) { - Fatal() << "GOT.func entry with no import/export: " << g->base; - } - f = wasm.getFunction(ex->value); - } - Name getter( - (std::string("fp$") + g->base.c_str() + std::string("$") + getSig(f)) - .c_str()); - ensureFunctionImport(&wasm, getter, Signature(Type::none, Type::i32)); - auto* call = builder.makeCall(getter, {}, Type::i32); - auto* globalSet = builder.makeGlobalSet(g->name, call); - block->list.push_back(globalSet); - } - - wasm.addFunction(assignFunc); - return assignFunc; -} - // For emscripten SIDE_MODULE we generate a single exported function called // __post_instantiate which calls two functions: // @@ -271,7 +97,7 @@ void EmscriptenGlueGenerator::generatePostInstantiateFunction() { POST_INSTANTIATE, std::vector<NameType>{}, Type::none, {}); wasm.addFunction(post_instantiate); - if (Function* F = generateAssignGOTEntriesFunction()) { + if (Function* F = wasm.getFunctionOrNull(ASSIGN_GOT_ENTRIES)) { // call __assign_got_enties from post_instantiate Expression* call = builder.makeCall(F->name, {}, Type::none); post_instantiate->body = builder.blockify(post_instantiate->body, call); |