diff options
Diffstat (limited to 'src/wasm/wasm-emscripten.cpp')
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 236 |
1 files changed, 0 insertions, 236 deletions
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index f143310ce..0bc74580d 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -188,242 +188,6 @@ struct AsmConst { std::string code; }; -static Address getExportedAddress(Module& wasm, Export* export_) { - Global* g = wasm.getGlobal(export_->value); - auto* addrConst = g->init->dynCast<Const>(); - return addrConst->value.getUnsigned(); -} - -static std::vector<AsmConst> findEmAsmConsts(Module& wasm, - bool minimizeWasmChanges) { - // Newer version of emscripten/llvm export these symbols so we can use them to - // find all the EM_ASM constants. Sadly __start_em_asm and __stop_em_asm - // don't alwasy mark the start and end of segment because in dynamic linking - // we merge all data segments into one. - Export* start = wasm.getExportOrNull("__start_em_asm"); - Export* end = wasm.getExportOrNull("__stop_em_asm"); - if (!start && !end) { - BYN_TRACE("findEmAsmConsts: no start/stop symbols\n"); - return {}; - } - - if (!start || !end) { - Fatal() << "Found only one of __start_em_asm and __stop_em_asm"; - } - - StringConstantTracker stringTracker(wasm); - Address startAddress = getExportedAddress(wasm, start); - Address endAddress = getExportedAddress(wasm, end); - for (Index i = 0; i < wasm.dataSegments.size(); i++) { - Address segmentStart = stringTracker.segmentOffsets[i]; - size_t segmentSize = wasm.dataSegments[i]->data.size(); - if (segmentStart <= startAddress && - segmentStart + segmentSize >= endAddress) { - std::vector<AsmConst> asmConsts; - Address address = startAddress; - while (address < endAddress) { - auto code = stringTracker.stringAtAddr(address); - asmConsts.push_back({address, code}); - address.addr += strlen(code) + 1; - } - assert(asmConsts.size()); - return asmConsts; - } - } - Fatal() << "Segment data not found between symbols __start_em_asm and " - "__stop_em_asm"; -} - -struct EmJsWalker : public PostWalker<EmJsWalker> { - Module& wasm; - StringConstantTracker stringTracker; - - std::map<std::string, std::string> codeByName; - - EmJsWalker(Module& _wasm) : wasm(_wasm), stringTracker(_wasm) {} - - void visitExport(Export* curr) { - if (!curr->name.startsWith(EM_JS_PREFIX.str)) { - return; - } - - Address address; - if (curr->kind == ExternalKind::Global) { - auto* global = wasm.getGlobal(curr->value); - Const* const_ = global->init->cast<Const>(); - address = const_->value.getUnsigned(); - } else if (curr->kind == ExternalKind::Function) { - auto* func = wasm.getFunction(curr->value); - // An EM_JS has a single const in the body. Typically it is just returned, - // but in unoptimized code it might be stored to a local and loaded from - // there, and in relocatable code it might get added to __memory_base etc. - FindAll<Const> consts(func->body); - if (consts.list.size() != 1) { - Fatal() << "Unexpected generated __em_js__ function body: " - << curr->name; - } - auto* addrConst = consts.list[0]; - address = addrConst->value.getUnsigned(); - } else { - return; - } - - auto code = stringTracker.stringAtAddr(address); - auto funcName = std::string(curr->name.stripPrefix(EM_JS_PREFIX.str)); - codeByName[funcName] = code; - } -}; - -EmJsWalker findEmJsFuncsAndReturnWalker(Module& wasm) { - EmJsWalker walker(wasm); - walker.walkModule(&wasm); - return walker; -} - -std::string EmscriptenGlueGenerator::generateEmscriptenMetadata() { - bool commaFirst; - auto nextElement = [&commaFirst]() { - if (commaFirst) { - commaFirst = false; - return "\n "; - } else { - return ",\n "; - } - }; - - std::stringstream meta; - meta << "{\n"; - - std::vector<AsmConst> asmConsts = findEmAsmConsts(wasm, minimizeWasmChanges); - - // print - commaFirst = true; - if (!asmConsts.empty()) { - meta << " \"asmConsts\": {"; - for (auto& asmConst : asmConsts) { - meta << nextElement(); - meta << '"' << asmConst.id << "\": \"" << escape(asmConst.code) << "\""; - } - meta << "\n },\n"; - } - - EmJsWalker emJsWalker = findEmJsFuncsAndReturnWalker(wasm); - if (!emJsWalker.codeByName.empty()) { - meta << " \"emJsFuncs\": {"; - commaFirst = true; - for (auto& [name, code] : emJsWalker.codeByName) { - meta << nextElement(); - meta << '"' << name << "\": \"" << escape(code) << '"'; - } - 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. - std::set<std::string> declares; - std::set<std::string> invokeFuncs; - - // We use the `base` rather than the `name` of the imports here and below - // becasue this is the externally visible name that the embedder (JS) will - // see. - meta << " \"declares\": ["; - commaFirst = true; - ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) { - if (emJsWalker.codeByName.count(import->base.str) == 0 && - !import->base.startsWith("invoke_")) { - if (declares.insert(import->base.str).second) { - meta << nextElement() << '"' << import->base.str << '"'; - } - } - }); - meta << "\n ],\n"; - - meta << " \"globalImports\": ["; - commaFirst = true; - ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) { - meta << nextElement() << '"' << import->base.str << '"'; - }); - meta << "\n ],\n"; - - if (!wasm.exports.empty()) { - meta << " \"exports\": ["; - commaFirst = true; - for (const auto& ex : wasm.exports) { - if (ex->kind == ExternalKind::Function || ex->kind == ExternalKind::Tag) { - meta << nextElement() << '"' << ex->name.str << '"'; - } - } - meta << "\n ],\n"; - - meta << " \"namedGlobals\": {"; - commaFirst = true; - for (const auto& ex : wasm.exports) { - if (ex->kind == ExternalKind::Global) { - const Global* g = wasm.getGlobal(ex->value); - assert(g->type == Type::i32 || g->type == Type::i64); - Const* init = g->init->cast<Const>(); - uint64_t addr = init->value.getInteger(); - meta << nextElement() << '"' << ex->name.str << "\" : \"" << addr - << '"'; - } - } - meta << "\n },\n"; - } - - meta << " \"invokeFuncs\": ["; - commaFirst = true; - ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) { - if (import->module == ENV && import->base.startsWith("invoke_")) { - if (invokeFuncs.insert(import->base.str).second) { - meta << nextElement() << '"' << import->base.str << '"'; - } - } - }); - meta << "\n ],\n"; - - // In normal mode we attempt to determine if main takes argumnts or not - // In standalone mode we export _start instead and rely on the presence - // of the __wasi_args_get and __wasi_args_sizes_get syscalls allow us to - // DCE to the argument handling JS code instead. - if (!standalone) { - auto mainReadsParams = false; - auto* exp = wasm.getExportOrNull("main"); - if (!exp) { - exp = wasm.getExportOrNull("__main_argc_argv"); - } - if (exp) { - if (exp->kind == ExternalKind::Function) { - auto* main = wasm.getFunction(exp->value); - mainReadsParams = main->getNumParams() > 0; - if (mainReadsParams) { - // Main could also be stub that just calls __original_main with - // no parameters. - // TODO(sbc): Remove this once https://reviews.llvm.org/D75277 - // lands. - if (auto* call = main->body->dynCast<Call>()) { - if (call->operands.empty()) { - mainReadsParams = false; - } - } - } - } - } - meta << " \"mainReadsParams\": " << int(mainReadsParams) << ",\n"; - } - - meta << " \"features\": ["; - commaFirst = true; - wasm.features.iterFeatures([&](FeatureSet::Feature f) { - meta << nextElement() << "\"--enable-" << FeatureSet::toString(f) << '"'; - }); - meta << "\n ]\n"; - - meta << "}\n"; - - return meta.str(); -} - void EmscriptenGlueGenerator::separateDataSegments(Output* outfile, Address base) { size_t lastEnd = 0; |