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.cpp49
1 files changed, 38 insertions, 11 deletions
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index 8357983b2..5c411b454 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -22,7 +22,9 @@
#include "asmjs/shared-constants.h"
#include "ir/import-utils.h"
#include "ir/literal-utils.h"
+#include "ir/manipulation.h"
#include "ir/module-utils.h"
+#include "ir/table-utils.h"
#include "shared-constants.h"
#include "support/debug.h"
#include "wasm-builder.h"
@@ -214,12 +216,12 @@ void EmscriptenGlueGenerator::generateRuntimeFunctions() {
static Function*
ensureFunctionImport(Module* module, Name name, Signature sig) {
- // Then see if its already imported
+ // See if its already imported.
ImportInfo info(*module);
- if (Function* f = info.getImportedFunction(ENV, name)) {
+ if (auto* f = info.getImportedFunction(ENV, name)) {
return f;
}
- // Failing that create a new function import.
+ // Failing that create a new import.
auto import = new Function;
import->name = name;
import->module = ENV;
@@ -277,6 +279,8 @@ Function* EmscriptenGlueGenerator::generateAssignGOTEntriesFunction() {
block->list.push_back(globalSet);
}
+ ImportInfo importInfo(wasm);
+
for (Global* g : gotFuncEntries) {
Function* f = nullptr;
// The function has to exist either as export or an import.
@@ -286,20 +290,43 @@ Function* EmscriptenGlueGenerator::generateAssignGOTEntriesFunction() {
if (ex) {
assert(ex->kind == ExternalKind::Function);
f = wasm.getFunction(ex->value);
- } else {
- ImportInfo info(wasm);
- f = info.getImportedFunction(ENV, g->base);
- if (!f) {
- Fatal() << "GOT.func entry with no import/export: " << g->base;
+ if (!sideModule) {
+ // This is exported, so must be one of the functions implemented here.
+ // Simply add it to the table, and use that index. The loader will
+ // know to reuse that index for other modules so they all share the
+ // same index and function pointer equality works.
+ // We may be able to do something for side modules as well, however,
+ // that would require at least updating the dylink section.
+ if (f->imported()) {
+ Fatal() << "GOT.func entry is both imported and exported: "
+ << g->base;
+ }
+ auto tableIndex = TableUtils::getOrAppend(wasm.table, f->name, wasm);
+ auto* c = LiteralUtils::makeFromInt32(tableIndex, Type::i32, wasm);
+ // The base relative to which we are computed is the offset of the
+ // singleton segment.
+ auto* getBase =
+ ExpressionManipulator::copy(wasm.table.segments[0].offset, wasm);
+ auto* add = builder.makeBinary(AddInt32, getBase, c);
+ auto* globalSet = builder.makeGlobalSet(g->name, add);
+ block->list.push_back(globalSet);
+ continue;
}
+ // Otherwise, this is a side module, and fall through to join the case
+ // of an import.
+ } else {
+ // This is imported. Create an fp$ import to get the function table index.
+ f = importInfo.getImportedFunction(ENV, g->base);
+ }
+ if (!f) {
+ Fatal() << "GOT.func entry with no import/export: " << g->base;
}
-
Name getter(
(std::string("fp$") + g->base.c_str() + std::string("$") + getSig(f))
.c_str());
ensureFunctionImport(&wasm, getter, Signature(Type::none, Type::i32));
- Expression* call = builder.makeCall(getter, {}, Type::i32);
- GlobalSet* globalSet = builder.makeGlobalSet(g->name, call);
+ auto* call = builder.makeCall(getter, {}, Type::i32);
+ auto* globalSet = builder.makeGlobalSet(g->name, call);
block->list.push_back(globalSet);
}