From f0ec4b02fb797387040c65d63f690b3856b1183e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 12 Mar 2019 12:06:58 -0700 Subject: wasm-emscripten-finalize: Remove JSCall thunk generation (#1938) We now implement addFunction by creating a wasm module to wrap that JS function and simply adding it to the table. --- src/wasm/wasm-emscripten.cpp | 121 +------------------------------------------ 1 file changed, 2 insertions(+), 119 deletions(-) (limited to 'src/wasm/wasm-emscripten.cpp') diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 390266d44..a21c45476 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -270,109 +270,6 @@ void EmscriptenGlueGenerator::replaceStackPointerGlobal() { wasm.removeGlobal(stackPointer->name); } -struct JSCallWalker : public PostWalker { - Module &wasm; - JSCallWalker(Module &_wasm) : wasm(_wasm) { - if (wasm.table.segments.size() == 0) { - auto emptySegment = - wasm.allocator.alloc()->set(Literal(uint32_t(0))); - wasm.table.segments.emplace_back(emptySegment); - } - const auto& tableSegmentData = wasm.table.segments[0].data; - - jsCallStartIndex = - wasm.table.segments[0].offset->cast()->value.getInteger(); - // Check if jsCalls have already been created - for (Index i = 0; i < tableSegmentData.size(); ++i) { - if (tableSegmentData[i].startsWith("jsCall_")) { - jsCallStartIndex += i; - return; - } - } - jsCallStartIndex += tableSegmentData.size(); - } - - // Gather all function signatures used in call_indirect, because any of them - // can be used to call function pointers created by emscripten's addFunction. - void visitCallIndirect(CallIndirect *curr) { - // dynCall thunks are generated in binaryen and call_indirect instructions - // within them cannot be used to call function pointers returned by - // emscripten's addFunction. - if (!getFunction()->name.startsWith("dynCall_")) { - indirectlyCallableSigs.insert( - getSig(wasm.getFunctionType(curr->fullType))); - } - } - - bool createJSCallThunks; - Index jsCallStartIndex; - // Function type signatures used in call_indirect instructions - std::set indirectlyCallableSigs; -}; - -JSCallWalker getJSCallWalker(Module& wasm) { - JSCallWalker walker(wasm); - walker.walkModule(&wasm); - return walker; -} - -void EmscriptenGlueGenerator::generateJSCallThunks( - unsigned numReservedFunctionPointers) { - if (numReservedFunctionPointers == 0) - return; - - JSCallWalker walker = getJSCallWalker(wasm); - auto& tableSegmentData = wasm.table.segments[0].data; - unsigned numEntriesAdded = 0; - for (std::string sig : walker.indirectlyCallableSigs) { - // Add imports for jsCall_sig (e.g. jsCall_vi). - // Imported jsCall_sig functions have their first parameter as an index to - // the function table, so we should prepend an 'i' to parameters' signature - // (e.g. If the signature of the callee is 'vi', the imported jsCall_vi - // function would have signature 'vii'.) - std::string importSig = std::string(1, sig[0]) + 'i' + sig.substr(1); - FunctionType *importType = ensureFunctionType(importSig, &wasm); - auto import = new Function; - import->name = import->base = "jsCall_" + sig; - import->module = ENV; - import->type = importType->name; - FunctionTypeUtils::fillFunction(import, importType); - wasm.addFunction(import); - FunctionType *funcType = ensureFunctionType(sig, &wasm); - - // Create jsCall_sig_index thunks (e.g. jsCall_vi_0, jsCall_vi_1, ...) - // e.g. If # of reserved function pointers (given by a command line - // argument) is 3 and there are two possible signature 'vi' and 'ii', the - // genereated thunks will be jsCall_vi_0, jsCall_vi_1, jsCall_vi_2, - // jsCall_ii_0, jsCall_ii_1, and jsCall_ii_2. - for (unsigned fp = 0; fp < numReservedFunctionPointers; ++fp) { - std::vector params; - int p = 0; - for (const auto& ty : funcType->params) { - params.emplace_back(std::to_string(p++), ty); - } - Function* f = builder.makeFunction( - std::string("jsCall_") + sig + "_" + std::to_string(fp), - std::move(params), funcType->result, {}); - std::vector args; - args.push_back(builder.makeConst(Literal(fp))); - for (unsigned i = 0; i < funcType->params.size(); ++i) { - args.push_back(builder.makeGetLocal(i, funcType->params[i])); - } - Expression* call = - builder.makeCall(import->name, args, funcType->result); - f->body = call; - wasm.addFunction(f); - tableSegmentData.push_back(f->name); - numEntriesAdded++; - } - } - wasm.table.initial.addr += numEntriesAdded; - if (wasm.table.max != Table::kUnlimitedSize) { - wasm.table.max.addr += numEntriesAdded; - } -} - std::vector
getSegmentOffsets(Module& wasm) { std::vector
segmentOffsets; for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) { @@ -780,8 +677,7 @@ void printSet(std::ostream& o, C& c) { } std::string EmscriptenGlueGenerator::generateEmscriptenMetadata( - Address staticBump, std::vector const& initializerFunctions, - unsigned numReservedFunctionPointers) { + Address staticBump, std::vector const& initializerFunctions) { bool commaFirst; auto nextElement = [&commaFirst]() { if (commaFirst) { @@ -844,18 +740,6 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata( meta << "\n ],\n"; } - if (numReservedFunctionPointers) { - JSCallWalker jsCallWalker = getJSCallWalker(wasm); - meta << " \"jsCallStartIndex\": " << jsCallWalker.jsCallStartIndex << ",\n"; - meta << " \"jsCallFuncType\": ["; - commaFirst = true; - for (std::string sig : jsCallWalker.indirectlyCallableSigs) { - meta << nextElement(); - meta << "\"" << sig << "\""; - } - meta << "\n ],\n"; - } - // Avoid adding duplicate imports to `declares' or `invokeFuncs`. Even // though we might import the same function multiple times (i.e. with // different sigs) we only need to list is in the metadata once. @@ -870,8 +754,7 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata( ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) { if (emJsWalker.codeByName.count(import->base.str) == 0 && !import->base.startsWith(EMSCRIPTEN_ASM_CONST.str) && - !import->base.startsWith("invoke_") && - !import->base.startsWith("jsCall_")) { + !import->base.startsWith("invoke_")) { if (declares.insert(import->base.str).second) { meta << nextElement() << '"' << import->base.str << '"'; } -- cgit v1.2.3 From e18ab2a0cd8b36144578d37585e8a67af618ecd1 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 13 Mar 2019 14:19:40 -0700 Subject: Add some checking in EmscriptenGlueGenerator::generateStackInitialization (#1944) We expect the stack pointer to be of a certain type. This fixes a segfault we are seeing when passed a binary which doesn't quite meet our expectations. --- src/wasm/wasm-emscripten.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/wasm/wasm-emscripten.cpp') diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index a21c45476..ea24b945d 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -47,10 +47,15 @@ void addExportedFunction(Module& wasm, Function* function) { } Global* EmscriptenGlueGenerator::getStackPointerGlobal() { - // Assumption: first global is __stack_pointer - // TODO(sbc): Once mutable globals are a thing we shouldn't need this - // at all since we can simply export __stack_pointer. - return wasm.globals[0].get(); + // Assumption: The first non-imported global is global is __stack_pointer + // TODO(sbc): Find a better way to discover the stack pointer. Perhaps the + // linker could export it by name? + for (auto& g : wasm.globals) { + if (!g->imported()) { + return g.get(); + } + } + Fatal() << "stack pointer global not found"; } Expression* EmscriptenGlueGenerator::generateLoadStackPointer() { @@ -157,6 +162,9 @@ Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() { void EmscriptenGlueGenerator::generateStackInitialization(Address addr) { auto* stackPointer = getStackPointerGlobal(); + assert(!stackPointer->imported()); + if (!stackPointer->init || !stackPointer->init->is()) + Fatal() << "stack pointer global is not assignable"; stackPointer->init->cast()->value = Literal(int32_t(addr)); } -- cgit v1.2.3