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.cpp236
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;