summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-emscripten.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-emscripten.cpp')
-rw-r--r--src/wasm/wasm-emscripten.cpp176
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);