summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-emscripten.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-03-27 17:25:49 -0700
committerGitHub <noreply@github.com>2020-03-27 17:25:49 -0700
commitd595a45b66cbb4d59472d2954131ee1f4cf6ad8e (patch)
treeaa4c8116f9d57d8b1018b77b1db7ad7e3018ccc4 /src/wasm/wasm-emscripten.cpp
parent9101f65c7b18ab607c472a3d50b52db66497402f (diff)
downloadbinaryen-d595a45b66cbb4d59472d2954131ee1f4cf6ad8e.tar.gz
binaryen-d595a45b66cbb4d59472d2954131ee1f4cf6ad8e.tar.bz2
binaryen-d595a45b66cbb4d59472d2954131ee1f4cf6ad8e.zip
Avoid fp$ access in MAIN_MODULES (#2704)
Depends on emscripten-core/emscripten#10741 which ensures that table indexes are unique. With that guarantee, a main module can just add its function pointers into the table, and use them based on that index. The loader will then see them in the table and then give other modules the identical function pointer for a function, ensuring function pointer equality. This avoids calling fp$ functions during startup for the main module's own functions (which are slow). We do still call fp$s of things we import from outside, as we don't have anything to put in the table for them, we depend on the loader for that. I suspect this can also be done with SIDE_MODULES, but did not want to try too much at once.
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);
}