diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/table-utils.h | 43 | ||||
-rw-r--r-- | src/passes/Directize.cpp | 6 | ||||
-rw-r--r-- | src/passes/PostEmscripten.cpp | 7 | ||||
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 13 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 2 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 49 | ||||
-rw-r--r-- | src/wasm2js.h | 2 |
7 files changed, 98 insertions, 24 deletions
diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h index d2dc3a7d5..3c49ab16a 100644 --- a/src/ir/table-utils.h +++ b/src/ir/table-utils.h @@ -17,11 +17,14 @@ #ifndef wasm_ir_table_h #define wasm_ir_table_h +#include "ir/literal-utils.h" #include "wasm-traversal.h" #include "wasm.h" namespace wasm { +namespace TableUtils { + struct FlatTable { std::vector<Name> names; bool valid; @@ -47,6 +50,46 @@ struct FlatTable { } }; +// Ensure one table segment exists. This adds the table if necessary, then +// adds a segment if we need one. +inline Table::Segment& ensureTableWithOneSegment(Table& table, Module& wasm) { + table.exists = true; + if (table.segments.size() == 0) { + table.segments.resize(1); + table.segments[0].offset = LiteralUtils::makeZero(Type::i32, wasm); + } + if (table.segments.size() != 1) { + Fatal() << "can't ensure 1 segment"; + } + return table.segments[0]; +} + +// Appends a name to the table. This assumes the table has 0 or 1 segments, +// as with 2 or more it's ambiguous what we should do (use a hole in the middle +// or not). +inline Index append(Table& table, Name name, Module& wasm) { + auto& segment = ensureTableWithOneSegment(table, wasm); + table.segments[0]; + auto tableIndex = segment.data.size(); + segment.data.push_back(name); + table.initial = table.initial + 1; + return tableIndex; +} + +// Checks if a function is already in the table. Returns that index if so, +// otherwise appends it. +inline Index getOrAppend(Table& table, Name name, Module& wasm) { + auto& segment = ensureTableWithOneSegment(table, wasm); + for (Index i = 0; i < segment.data.size(); i++) { + if (segment.data[i] == name) { + return i; + } + } + return append(table, name, wasm); +} + +} // namespace TableUtils + } // namespace wasm #endif // wasm_ir_table_h diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 52aa7e087..037eca0da 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -39,7 +39,7 @@ struct FunctionDirectizer : public WalkerPass<PostWalker<FunctionDirectizer>> { Pass* create() override { return new FunctionDirectizer(flatTable); } - FunctionDirectizer(FlatTable* flatTable) : flatTable(flatTable) {} + FunctionDirectizer(TableUtils::FlatTable* flatTable) : flatTable(flatTable) {} void visitCallIndirect(CallIndirect* curr) { if (auto* c = curr->target->dynCast<Const>()) { @@ -77,7 +77,7 @@ struct FunctionDirectizer : public WalkerPass<PostWalker<FunctionDirectizer>> { } private: - FlatTable* flatTable; + TableUtils::FlatTable* flatTable; bool changedTypes = false; void replaceWithUnreachable(CallIndirect* call) { @@ -104,7 +104,7 @@ struct Directize : public Pass { return; } } - FlatTable flatTable(module->table); + TableUtils::FlatTable flatTable(module->table); if (!flatTable.valid) { return; } diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index ccf985c50..8efaae8c5 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -135,7 +135,7 @@ struct PostEmscripten : public Pass { // Next, see if the Table is flat, which we need in order to see where // invokes go statically. (In dynamic linking, the table is not flat, // and we can't do this.) - FlatTable flatTable(module->table); + TableUtils::FlatTable flatTable(module->table); if (!flatTable.valid) { return; } @@ -167,9 +167,10 @@ struct PostEmscripten : public Pass { Pass* create() override { return new OptimizeInvokes(map, flatTable); } std::map<Function*, Info>& map; - FlatTable& flatTable; + TableUtils::FlatTable& flatTable; - OptimizeInvokes(std::map<Function*, Info>& map, FlatTable& flatTable) + OptimizeInvokes(std::map<Function*, Info>& map, + TableUtils::FlatTable& flatTable) : map(map), flatTable(flatTable) {} void visitCall(Call* curr) { diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp index 9ade001ef..576b64a1a 100644 --- a/src/tools/wasm-emscripten-finalize.cpp +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -50,7 +50,7 @@ int main(int argc, const char* argv[]) { bool emitBinary = true; bool debugInfo = false; bool DWARF = false; - bool isSideModule = false; + bool sideModule = false; bool legalizeJavaScriptFFI = true; bool checkStackOverflow = false; uint64_t globalBase = INVALID_BASE; @@ -100,8 +100,8 @@ int main(int argc, const char* argv[]) { "", "Input is an emscripten side module", Options::Arguments::Zero, - [&isSideModule](Options* o, const std::string& argument) { - isSideModule = true; + [&sideModule](Options* o, const std::string& argument) { + sideModule = true; }) .add("--input-source-map", "-ism", @@ -191,7 +191,7 @@ int main(int argc, const char* argv[]) { uint32_t dataSize = 0; - if (!isSideModule) { + if (!sideModule) { if (globalBase == INVALID_BASE) { Fatal() << "globalBase must be set"; } @@ -215,6 +215,7 @@ int main(int argc, const char* argv[]) { EmscriptenGlueGenerator generator(wasm); generator.setStandalone(standaloneWasm); + generator.setSideModule(sideModule); generator.fixInvokeFunctionNames(); @@ -232,11 +233,11 @@ int main(int argc, const char* argv[]) { } wasm.updateMaps(); - if (checkStackOverflow && !isSideModule) { + if (checkStackOverflow && !sideModule) { generator.enforceStackLimit(); } - if (isSideModule) { + if (sideModule) { BYN_TRACE("finalizing as side module\n"); generator.replaceStackPointerGlobal(); generator.generatePostInstantiateFunction(); diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index c7689b4bc..80277cb18 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -32,6 +32,7 @@ public: useStackPointerGlobal(stackPointerOffset == 0) {} void setStandalone(bool standalone_) { standalone = standalone_; } + void setSideModule(bool sideModule_) { sideModule = sideModule_; } void generateRuntimeFunctions(); Function* generateMemoryGrowthFunction(); @@ -72,6 +73,7 @@ private: Address stackPointerOffset; bool useStackPointerGlobal; bool standalone; + bool sideModule; // Used by generateDynCallThunk to track all the dynCall functions created // so far. std::unordered_set<Signature> sigs; 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); } diff --git a/src/wasm2js.h b/src/wasm2js.h index cdc109cfa..cc2cfa128 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -530,7 +530,7 @@ void Wasm2JSBuilder::addGlobalImport(Ref ast, Global* import) { void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) { // Emit a simple flat table as a JS array literal. Otherwise, // emit assignments separately for each index. - FlatTable flat(wasm->table); + TableUtils::FlatTable flat(wasm->table); if (flat.valid && !wasm->table.imported()) { Ref theVar = ValueBuilder::makeVar(); ast->push_back(theVar); |