diff options
-rw-r--r-- | src/passes/PostEmscripten.cpp | 180 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 95 | ||||
-rw-r--r-- | test/lit/passes/post-emscripten.wast | 28 | ||||
-rw-r--r-- | test/lit/wasm-emscripten-finalize/em_asm.wat | 7 | ||||
-rw-r--r-- | test/lit/wasm-emscripten-finalize/em_asm_partial.wat | 24 | ||||
-rw-r--r-- | test/lit/wasm-emscripten-finalize/em_js.wat | 10 | ||||
-rw-r--r-- | test/lld/em_asm.wat.mem.mem | bin | 6 -> 97 bytes | |||
-rw-r--r-- | test/lld/em_asm.wat.mem.out | 4 | ||||
-rw-r--r-- | test/lld/em_asm.wat.out | 6 | ||||
-rw-r--r-- | test/lld/em_asm64.wat.out | 6 | ||||
-rw-r--r-- | test/lld/em_asm_O0.wat.out | 6 | ||||
-rw-r--r-- | test/lld/em_asm_main_thread.wat.out | 6 | ||||
-rw-r--r-- | test/lld/em_asm_pthread.wasm.out | 48 | ||||
-rw-r--r-- | test/lld/em_asm_shared.wat.out | 8 | ||||
-rw-r--r-- | test/lld/em_js_O0.wat.out | 12 |
15 files changed, 278 insertions, 162 deletions
diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index f3ad35783..b4828a852 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -41,14 +41,194 @@ static bool isInvoke(Function* F) { return F->imported() && F->module == ENV && F->base.startsWith("invoke_"); } +struct SegmentRemover : WalkerPass<PostWalker<SegmentRemover>> { + SegmentRemover(Index segment) : segment(segment) {} + + bool isFunctionParallel() override { return true; } + + Pass* create() override { return new SegmentRemover(segment); } + + void visitMemoryInit(MemoryInit* curr) { + if (segment == curr->segment) { + Builder builder(*getModule()); + replaceCurrent(builder.blockify(builder.makeDrop(curr->dest), + builder.makeDrop(curr->offset), + builder.makeDrop(curr->size))); + } + } + + void visitDataDrop(DataDrop* curr) { + if (segment == curr->segment) { + Builder builder(*getModule()); + replaceCurrent(builder.makeNop()); + } + } + + Index segment; +}; + +static void calcSegmentOffsets(Module& wasm, + std::vector<Address>& segmentOffsets) { + const Address UNKNOWN_OFFSET(uint32_t(-1)); + + std::unordered_map<Index, Address> passiveOffsets; + if (wasm.features.hasBulkMemory()) { + // Fetch passive segment offsets out of memory.init instructions + struct OffsetSearcher : PostWalker<OffsetSearcher> { + std::unordered_map<Index, Address>& offsets; + OffsetSearcher(std::unordered_map<unsigned, Address>& offsets) + : offsets(offsets) {} + void visitMemoryInit(MemoryInit* curr) { + // The desitination of the memory.init is either a constant + // or the result of an addition with __memory_base in the + // case of PIC code. + auto* dest = curr->dest->dynCast<Const>(); + if (!dest) { + auto* add = curr->dest->dynCast<Binary>(); + if (!add) { + return; + } + dest = add->left->dynCast<Const>(); + if (!dest) { + return; + } + } + auto it = offsets.find(curr->segment); + if (it != offsets.end()) { + Fatal() << "Cannot get offset of passive segment initialized " + "multiple times"; + } + offsets[curr->segment] = dest->value.getInteger(); + } + } searcher(passiveOffsets); + searcher.walkModule(&wasm); + } + for (unsigned i = 0; i < wasm.dataSegments.size(); ++i) { + auto& segment = wasm.dataSegments[i]; + if (segment->isPassive) { + auto it = passiveOffsets.find(i); + if (it != passiveOffsets.end()) { + segmentOffsets.push_back(it->second); + } else { + // This was a non-constant offset (perhaps TLS) + segmentOffsets.push_back(UNKNOWN_OFFSET); + } + } else if (auto* addrConst = segment->offset->dynCast<Const>()) { + auto address = addrConst->value.getUnsigned(); + segmentOffsets.push_back(address); + } else { + // TODO(sbc): Wasm shared libraries have data segments with non-const + // offset. + segmentOffsets.push_back(0); + } + } +} + +static void removeSegment(Module& wasm, Index segment) { + PassRunner runner(&wasm); + SegmentRemover(segment).run(&runner, &wasm); + // Resize the segment to zero. In theory we should completely remove it + // but that would mean re-numbering the segments that follow which is + // non-trivial. + wasm.dataSegments[segment]->data.resize(0); +} + +static Address getExportedAddress(Module& wasm, Export* export_) { + Global* g = wasm.getGlobal(export_->value); + auto* addrConst = g->init->dynCast<Const>(); + return addrConst->value.getUnsigned(); +} + +static void removeData(Module& wasm, + const std::vector<Address>& segmentOffsets, + Name start_sym, + Name end_sym) { + Export* start = wasm.getExportOrNull(start_sym); + Export* end = wasm.getExportOrNull(end_sym); + if (!start && !end) { + BYN_TRACE("removeData: start/stop symbols not found (" << start_sym << ", " + << end_sym << ")\n"); + return; + } + + if (!start || !end) { + Fatal() << "Found only one of " << start_sym << " and " << end_sym; + } + + Address startAddress = getExportedAddress(wasm, start); + Address endAddress = getExportedAddress(wasm, end); + for (Index i = 0; i < wasm.dataSegments.size(); i++) { + Address segmentStart = segmentOffsets[i]; + size_t segmentSize = wasm.dataSegments[i]->data.size(); + if (segmentStart <= startAddress && + segmentStart + segmentSize >= endAddress) { + + if (segmentStart == startAddress && + segmentStart + segmentSize == endAddress) { + BYN_TRACE("removeData: removing whole segment\n"); + removeSegment(wasm, i); + } else { + // If we can't remove the whole segment then just set the string + // data to zero. + BYN_TRACE("removeData: removing part of segment\n"); + size_t segmentOffset = startAddress - segmentStart; + char* startElem = &wasm.dataSegments[i]->data[segmentOffset]; + memset(startElem, 0, endAddress - startAddress); + } + return; + } + } + Fatal() << "Segment data not found between symbols " << start_sym << " (" + << startAddress << ") and " << end_sym << " (" << endAddress << ")"; +} + +cashew::IString EM_JS_PREFIX("__em_js__"); + +struct EmJsWalker : public PostWalker<EmJsWalker> { + std::vector<Export> toRemove; + + void visitExport(Export* curr) { + if (curr->name.startsWith(EM_JS_PREFIX.str)) { + toRemove.push_back(*curr); + } + } +}; + } // namespace struct PostEmscripten : public Pass { void run(PassRunner* runner, Module* module) override { + removeExports(runner, *module); + removeEmJsExports(runner, *module); // Optimize exceptions optimizeExceptions(runner, module); } + void removeExports(PassRunner* runner, Module& module) { + std::vector<Address> segmentOffsets; // segment index => address offset + calcSegmentOffsets(module, segmentOffsets); + + removeData(module, segmentOffsets, "__start_em_asm", "__stop_em_asm"); + removeData(module, segmentOffsets, "__start_em_js", "__stop_em_js"); + module.removeExport("__start_em_asm"); + module.removeExport("__stop_em_asm"); + module.removeExport("__start_em_js"); + module.removeExport("__stop_em_js"); + } + + void removeEmJsExports(PassRunner* runner, Module& module) { + EmJsWalker walker; + walker.walkModule(&module); + for (const Export& exp : walker.toRemove) { + if (exp.kind == ExternalKind::Function) { + module.removeFunction(exp.value); + } else { + module.removeGlobal(exp.value); + } + module.removeExport(exp.name); + } + } + // Optimize exceptions (and setjmp) by removing unnecessary invoke* calls. // An invoke is a call to JS with a function pointer; JS does a try-catch // and calls the pointer, catching and reporting any error. If we know no diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 29cf367d4..4daf51410 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -188,41 +188,6 @@ struct AsmConst { std::string code; }; -struct SegmentRemover : WalkerPass<PostWalker<SegmentRemover>> { - SegmentRemover(Index segment) : segment(segment) {} - - bool isFunctionParallel() override { return true; } - - Pass* create() override { return new SegmentRemover(segment); } - - void visitMemoryInit(MemoryInit* curr) { - if (segment == curr->segment) { - Builder builder(*getModule()); - replaceCurrent(builder.blockify(builder.makeDrop(curr->dest), - builder.makeDrop(curr->offset), - builder.makeDrop(curr->size))); - } - } - - void visitDataDrop(DataDrop* curr) { - if (segment == curr->segment) { - Builder builder(*getModule()); - replaceCurrent(builder.makeNop()); - } - } - - Index segment; -}; - -static void removeSegment(Module& wasm, Index segment) { - PassRunner runner(&wasm); - SegmentRemover(segment).run(&runner, &wasm); - // Resize the segment to zero. In theory we should completely remove it - // but that would mean re-numbering the segments that follow which is - // non-trivial. - wasm.dataSegments[segment]->data.resize(0); -} - static Address getExportedAddress(Module& wasm, Export* export_) { Global* g = wasm.getGlobal(export_->value); auto* addrConst = g->init->dynCast<Const>(); @@ -246,7 +211,6 @@ static std::vector<AsmConst> findEmAsmConsts(Module& wasm, Fatal() << "Found only one of __start_em_asm and __stop_em_asm"; } - std::vector<AsmConst> asmConsts; StringConstantTracker stringTracker(wasm); Address startAddress = getExportedAddress(wasm, start); Address endAddress = getExportedAddress(wasm, end); @@ -255,40 +219,26 @@ static std::vector<AsmConst> findEmAsmConsts(Module& wasm, 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; } - - if (segmentStart == startAddress && - segmentStart + segmentSize == endAddress) { - removeSegment(wasm, i); - } else { - // If we can't remove the whole segment then just set the string - // data to zero. - size_t segmentOffset = startAddress - segmentStart; - char* startElem = &wasm.dataSegments[i]->data[segmentOffset]; - memset(startElem, 0, endAddress - startAddress); - } - break; + assert(asmConsts.size()); + return asmConsts; } } - - assert(asmConsts.size()); - wasm.removeExport("__start_em_asm"); - wasm.removeExport("__stop_em_asm"); - 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::vector<Export> toRemove; std::map<std::string, std::string> codeByName; - std::map<Address, size_t> codeAddresses; // map from address to string len EmJsWalker(Module& _wasm) : wasm(_wasm), stringTracker(_wasm) {} @@ -318,50 +268,15 @@ struct EmJsWalker : public PostWalker<EmJsWalker> { return; } - toRemove.push_back(*curr); auto code = stringTracker.stringAtAddr(address); auto funcName = std::string(curr->name.stripPrefix(EM_JS_PREFIX.str)); codeByName[funcName] = code; - codeAddresses[address] = strlen(code) + 1; } }; EmJsWalker findEmJsFuncsAndReturnWalker(Module& wasm) { EmJsWalker walker(wasm); walker.walkModule(&wasm); - - for (const Export& exp : walker.toRemove) { - if (exp.kind == ExternalKind::Function) { - wasm.removeFunction(exp.value); - } else { - wasm.removeGlobal(exp.value); - } - wasm.removeExport(exp.name); - } - - wasm.removeExport("__start_em_js"); - wasm.removeExport("__stop_em_js"); - - // With newer versions of emscripten/llvm we pack all EM_JS strings into - // single segment. - // We can detect this by checking for segments that contain only JS strings. - // When we find such segements we remove them from the final binary. - for (Index i = 0; i < wasm.dataSegments.size(); i++) { - Address start = walker.stringTracker.segmentOffsets[i]; - Address cur = start; - - while (cur < start + wasm.dataSegments[i]->data.size()) { - if (walker.codeAddresses.count(cur) == 0) { - break; - } - cur.addr += walker.codeAddresses[cur]; - } - - if (cur == start + wasm.dataSegments[i]->data.size()) { - // Entire segment is contains JS strings. Remove it. - removeSegment(wasm, i); - } - } return walker; } diff --git a/test/lit/passes/post-emscripten.wast b/test/lit/passes/post-emscripten.wast new file mode 100644 index 000000000..259a16729 --- /dev/null +++ b/test/lit/passes/post-emscripten.wast @@ -0,0 +1,28 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: wasm-opt %s --post-emscripten -S -o - | filecheck %s + +;; Checks that the start/stop exports are removed and that the data they +;; refer to is either zero'd out, or the segment emptied. + +(module + ;; CHECK: (global $g1 i32 (i32.const 1000)) + (global $g1 i32 (i32.const 1000)) + ;; CHECK: (global $g2 i32 (i32.const 1011)) + (global $g2 i32 (i32.const 1011)) + ;; CHECK: (global $g3 i32 (i32.const 2006)) + (global $g3 i32 (i32.const 2006)) + ;; CHECK: (global $g4 i32 (i32.const 2015)) + (global $g4 i32 (i32.const 2015)) + (memory 10 10) + ;; CHECK: (memory $0 10 10) + + ;; CHECK: (data $data1 (i32.const 1000) "") + (data $data1 (i32.const 1000) "hello world") + ;; CHECK: (data $data2 (i32.const 2000) "hello \00\00\00\00\00\00\00\00\00 world") + (data $data2 (i32.const 2000) "hello DELETE ME world") + (export "__start_em_asm" (global $g1)) + (export "__stop_em_asm" (global $g2)) + (export "__start_em_js" (global $g3)) + (export "__stop_em_js" (global $g4)) +) + diff --git a/test/lit/wasm-emscripten-finalize/em_asm.wat b/test/lit/wasm-emscripten-finalize/em_asm.wat index 43dbfb9ae..195c4b9af 100644 --- a/test/lit/wasm-emscripten-finalize/em_asm.wat +++ b/test/lit/wasm-emscripten-finalize/em_asm.wat @@ -6,18 +6,11 @@ ;; Check that the data segment that contains only EM_ASM strings resized to ;; zero, and that the string are extracted into the metadata. -;; CHECK: (data (i32.const 100) "normal data") -;; CHECK-NEXT: (data (i32.const 512) "") -;; CHECK-NEXT: (data (i32.const 1024) "more data") - ;; CHECK: "asmConsts": { ;; CHECK-NEXT: "512": "{ console.log('JS hello'); }", ;; CHECK-NEXT: "541": "{ console.log('hello again'); }" ;; CHECK-NEXT: }, -;; Check that the exports are removed -;; CHECK-NOT: export - (module (memory 1 1) (global (export "__start_em_asm") i32 (i32.const 512)) diff --git a/test/lit/wasm-emscripten-finalize/em_asm_partial.wat b/test/lit/wasm-emscripten-finalize/em_asm_partial.wat deleted file mode 100644 index 6432f1689..000000000 --- a/test/lit/wasm-emscripten-finalize/em_asm_partial.wat +++ /dev/null @@ -1,24 +0,0 @@ -;; Test that em_asm string are extraced correctly when the __start_em_asm -;; and __stop_em_asm globals are exported. - -;; RUN: wasm-emscripten-finalize %s -S | filecheck %s - -;; Check for the case when __start_em_asm and __stop_em_asm don't define an -;; entire segment. In this case we preserve the segment but zero the data. - -;; CHECK: (data (i32.const 512) "xx\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00yy") - -;; CHECK: "asmConsts": { -;; CHECK-NEXT: "514": "{ console.log('JS hello'); }", -;; CHECK-NEXT: "543": "{ console.log('hello again'); }" -;; CHECK-NEXT: }, - -;; Check that the exports are removed -;; CHECK-NOT: export - -(module - (memory 1 1) - (global (export "__start_em_asm") i32 (i32.const 514)) - (global (export "__stop_em_asm") i32 (i32.const 575)) - (data (i32.const 512) "xx{ console.log('JS hello'); }\00{ console.log('hello again'); }\00yy") -) diff --git a/test/lit/wasm-emscripten-finalize/em_js.wat b/test/lit/wasm-emscripten-finalize/em_js.wat index 02fc32bfc..b10774ed3 100644 --- a/test/lit/wasm-emscripten-finalize/em_js.wat +++ b/test/lit/wasm-emscripten-finalize/em_js.wat @@ -3,16 +3,6 @@ ;; RUN: wasm-emscripten-finalize %s -S | filecheck %s -;; All functions should be stripped from the binary, regardless -;; of internal name -;; CHECK-NOT: (global - -;; The data section that contains only em_js strings should -;; be stripped (shrunk to zero size): -;; CHECK: (data (i32.const 1024) "some JS string data\00xxx") -;; CHECK: (data (i32.const 512) "") -;; CHECK: (data (i32.const 2048) "more JS string data\00yyy") - ;; CHECK: "emJsFuncs": { ;; CHECK-NEXT: "bar": "more JS string data", ;; CHECK-NEXT: "baz": "Only em_js strings here", diff --git a/test/lld/em_asm.wat.mem.mem b/test/lld/em_asm.wat.mem.mem Binary files differindex 0059fdcca..bc55b6452 100644 --- a/test/lld/em_asm.wat.mem.mem +++ b/test/lld/em_asm.wat.mem.mem diff --git a/test/lld/em_asm.wat.mem.out b/test/lld/em_asm.wat.mem.out index 07c9aa3e8..7730bcee2 100644 --- a/test/lld/em_asm.wat.mem.out +++ b/test/lld/em_asm.wat.mem.out @@ -12,6 +12,8 @@ (export "memory" (memory $0)) (export "__wasm_call_ctors" (func $__wasm_call_ctors)) (export "main" (func $main)) + (export "__start_em_asm" (global $global$1)) + (export "__stop_em_asm" (global $global$2)) (func $__wasm_call_ctors (nop) ) @@ -84,6 +86,8 @@ "main" ], "namedGlobals": { + "__start_em_asm" : "574", + "__stop_em_asm" : "665" }, "invokeFuncs": [ ], diff --git a/test/lld/em_asm.wat.out b/test/lld/em_asm.wat.out index 5a32e4bad..8afbfda3d 100644 --- a/test/lld/em_asm.wat.out +++ b/test/lld/em_asm.wat.out @@ -9,11 +9,13 @@ (global $global$2 i32 (i32.const 665)) (memory $0 2) (data $.rodata (i32.const 568) "\00ii\00i\00") - (data $em_asm (i32.const 574) "") + (data $em_asm (i32.const 574) "{ Module.print(\"Hello \\\\ world\\t\\n\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") (table $0 1 1 funcref) (export "memory" (memory $0)) (export "__wasm_call_ctors" (func $__wasm_call_ctors)) (export "main" (func $main)) + (export "__start_em_asm" (global $global$1)) + (export "__stop_em_asm" (global $global$2)) (func $__wasm_call_ctors (nop) ) @@ -86,6 +88,8 @@ "main" ], "namedGlobals": { + "__start_em_asm" : "574", + "__stop_em_asm" : "665" }, "invokeFuncs": [ ], diff --git a/test/lld/em_asm64.wat.out b/test/lld/em_asm64.wat.out index 8b0f18174..bac187c23 100644 --- a/test/lld/em_asm64.wat.out +++ b/test/lld/em_asm64.wat.out @@ -9,11 +9,13 @@ (global $global$2 i64 (i64.const 658)) (memory $0 i64 2) (data $.rodata (i64.const 568) "\00ii\00i\00") - (data $em_asm (i64.const 574) "") + (data $em_asm (i64.const 574) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") (table $0 1 1 funcref) (export "memory" (memory $0)) (export "__wasm_call_ctors" (func $__wasm_call_ctors)) (export "main" (func $main)) + (export "__start_em_asm" (global $global$1)) + (export "__stop_em_asm" (global $global$2)) (func $__wasm_call_ctors (nop) ) @@ -86,6 +88,8 @@ "main" ], "namedGlobals": { + "__start_em_asm" : "574", + "__stop_em_asm" : "658" }, "invokeFuncs": [ ], diff --git a/test/lld/em_asm_O0.wat.out b/test/lld/em_asm_O0.wat.out index 910ae1a56..5a533cdef 100644 --- a/test/lld/em_asm_O0.wat.out +++ b/test/lld/em_asm_O0.wat.out @@ -8,11 +8,13 @@ (global $global$1 i32 (i32.const 568)) (global $global$2 i32 (i32.const 652)) (memory $0 2) - (data $em_asm (i32.const 568) "") + (data $em_asm (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") (table $0 1 1 funcref) (export "memory" (memory $0)) (export "__wasm_call_ctors" (func $__wasm_call_ctors)) (export "main" (func $main)) + (export "__start_em_asm" (global $global$1)) + (export "__stop_em_asm" (global $global$2)) (func $__wasm_call_ctors (nop) ) @@ -114,6 +116,8 @@ "main" ], "namedGlobals": { + "__start_em_asm" : "568", + "__stop_em_asm" : "652" }, "invokeFuncs": [ ], diff --git a/test/lld/em_asm_main_thread.wat.out b/test/lld/em_asm_main_thread.wat.out index fdb75c98f..5c279a598 100644 --- a/test/lld/em_asm_main_thread.wat.out +++ b/test/lld/em_asm_main_thread.wat.out @@ -13,8 +13,10 @@ (global $global$1 i32 (i32.const 66192)) (global $global$2 i32 (i32.const 652)) (memory $0 2) - (data (i32.const 568) "") + (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") (table $0 1 1 funcref) + (export "__start_em_asm" (global $0)) + (export "__stop_em_asm" (global $1)) (export "memory" (memory $0)) (export "__wasm_call_ctors" (func $__wasm_call_ctors)) (export "__heap_base" (global $global$1)) @@ -210,6 +212,8 @@ "main" ], "namedGlobals": { + "__start_em_asm" : "568", + "__stop_em_asm" : "652", "__heap_base" : "66192", "__data_end" : "652" }, diff --git a/test/lld/em_asm_pthread.wasm.out b/test/lld/em_asm_pthread.wasm.out index d1913d655..0f684e224 100644 --- a/test/lld/em_asm_pthread.wasm.out +++ b/test/lld/em_asm_pthread.wasm.out @@ -66,25 +66,29 @@ (global $global$5 (mut i32) (i32.const 0)) (global $global$6 (mut i32) (i32.const 0)) (global $global$7 (mut i32) (i32.const 0)) + (global $global$8 i32 (i32.const 1588)) + (global $global$9 i32 (i32.const 1621)) (global $global$10 i32 (i32.const 1432)) (global $global$11 i32 (i32.const 1836)) (global $global$12 i32 (i32.const 1658)) (global $global$13 i32 (i32.const 1782)) (data "\00/home/azakai/Dev/emscripten/system/lib/pthread/library_pthread.c\00call\00_emscripten_do_dispatch_to_thread\00target_thread\00num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS\00emscripten_run_in_main_runtime_thread_js\00q\00_emscripten_call_on_thread\00EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(q->functionEnum) <= EM_QUEUED_CALL_MAX_ARGS\00_do_call\000 && \"Invalid Emscripten pthread _do_call opcode!\"\00target\00GetQueue\00em_queued_call_malloc\00") (data "\01\00\00\00\d0\0fP\00\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00x\t\00\00\00\04\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\n\ff\ff\ff\ff\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\a0\05\00\00") - (data "") - (data "") + (data "()<::>{ console.log(\"World.\"); }\00(void)<::>{ PThread.initRuntime(); }\00") + (data "{ console.log(\"Hello.\"); }\00throw \'Canceled!\'\00{ setTimeout(function() { __emscripten_do_dispatch_to_thread($0, $1); }, 0); }\00") (data "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") (table $0 5 5 funcref) (elem (i32.const 1) $6 $73 $72 $74) (export "__wasm_call_ctors" (func $0)) (export "main" (func $4)) + (export "__em_js__world" (global $global$8)) (export "__indirect_function_table" (table $0)) (export "emscripten_tls_init" (func $5)) (export "emscripten_get_global_libc" (func $82)) (export "__errno_location" (func $25)) (export "fflush" (func $80)) (export "__emscripten_pthread_data_constructor" (func $83)) + (export "__em_js__initPthreadsJS" (global $global$9)) (export "pthread_self" (func $14)) (export "__pthread_tsd_run_dtors" (func $84)) (export "emscripten_current_thread_process_queued_calls" (func $31)) @@ -109,6 +113,8 @@ (export "malloc" (func $60)) (export "free" (func $62)) (export "memalign" (func $63)) + (export "__start_em_asm" (global $global$12)) + (export "__stop_em_asm" (global $global$13)) (export "dynCall_vi" (func $dynCall_vi)) (export "dynCall_ii" (func $dynCall_ii)) (export "dynCall_iiii" (func $dynCall_iiii)) @@ -146,27 +152,15 @@ (i32.const 0) (i32.const 156) ) - (block - (drop - (i32.const 1588) - ) - (drop - (i32.const 0) - ) - (drop - (i32.const 70) - ) + (memory.init 2 + (i32.const 1588) + (i32.const 0) + (i32.const 70) ) - (block - (drop - (i32.const 1658) - ) - (drop - (i32.const 0) - ) - (drop - (i32.const 124) - ) + (memory.init 3 + (i32.const 1658) + (i32.const 0) + (i32.const 124) ) (memory.init 4 (i32.const 1792) @@ -187,8 +181,8 @@ ) (data.drop 0) (data.drop 1) - (nop) - (nop) + (data.drop 2) + (data.drop 3) (data.drop 4) ) (func $3 (result i32) @@ -12904,8 +12898,12 @@ "dynCall_jiji" ], "namedGlobals": { + "__em_js__world" : "1588", + "__em_js__initPthreadsJS" : "1621", "_emscripten_allow_main_runtime_queued_calls" : "1432", - "_emscripten_main_thread_futex" : "1836" + "_emscripten_main_thread_futex" : "1836", + "__start_em_asm" : "1658", + "__stop_em_asm" : "1782" }, "invokeFuncs": [ ], diff --git a/test/lld/em_asm_shared.wat.out b/test/lld/em_asm_shared.wat.out index d7d480866..ac15b0fd9 100644 --- a/test/lld/em_asm_shared.wat.out +++ b/test/lld/em_asm_shared.wat.out @@ -17,7 +17,7 @@ (global $global$2 i32 (i32.const 4)) (global $global$3 i32 (i32.const 6)) (global $global$4 i32 (i32.const 90)) - (data $.data (global.get $__memory_base) "\00ii\00i\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $.data (global.get $__memory_base) "\00ii\00i\00{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") (export "__wasm_call_ctors" (func $__wasm_call_ctors)) (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) (export "__original_main" (func $__original_main)) @@ -25,6 +25,8 @@ (export "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" (global $global$1)) (export "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" (global $global$2)) (export "main" (func $main)) + (export "__start_em_asm" (global $global$3)) + (export "__stop_em_asm" (global $global$4)) (func $__wasm_call_ctors (nop) ) @@ -122,7 +124,9 @@ "namedGlobals": { "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" : "0", "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" : "1", - "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" : "4" + "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" : "4", + "__start_em_asm" : "6", + "__stop_em_asm" : "90" }, "invokeFuncs": [ ], diff --git a/test/lld/em_js_O0.wat.out b/test/lld/em_js_O0.wat.out index 6f36ce6bc..e3271166b 100644 --- a/test/lld/em_js_O0.wat.out +++ b/test/lld/em_js_O0.wat.out @@ -1,4 +1,5 @@ (module + (type $none_=>_i32 (func (result i32))) (import "env" "memory" (memory $0 256 256)) (global $global$0 (mut i32) (i32.const 5250112)) (global $global$1 i32 (i32.const 5250112)) @@ -6,8 +7,18 @@ (data (i32.const 1024) "(void)<::>{ out(\"no args works\"); }\00(void)<::>{ out(\"no args returning int\"); return 12; }\00(void)<::>{ out(\"no args returning double\"); return 12.25; }\00(int x)<::>{ out(\" takes ints: \" + x);}\00(double d)<::>{ out(\" takes doubles: \" + d);}\00(char* str)<::>{ out(\" takes strings: \" + UTF8ToString(str)); return 7.75; }\00(int x, int y)<::>{ out(\" takes multiple ints: \" + x + \", \" + y); return 6; }\00(int x, const char* str, double d)<::>{ out(\" mixed arg types: \" + x + \", \" + UTF8ToString(str) + \", \" + d); return 8.125; }\00(int unused)<::>{ out(\" ignores unused args\"); return 5.5; }\00(int x, int y)<::>{ out(\" skips unused args: \" + y); return 6; }\00(double x, double y, double z)<::>{ out(\" \" + x + \" + \" + z); return x + z; }\00(void)<::>{ out(\" can use <::> separator in user code\"); return 15; }\00(void)<::>{ var x, y; x = {}; y = 3; x[y] = [1, 2, 3]; out(\" can have commas in user code: \" + x[y]); return x[y][1]; }\00(void)<::>{ var jsString = \'\e3\81\93\e3\82\93\e3\81\ab\e3\81\a1\e3\81\af\'; var lengthBytes = lengthBytesUTF8(jsString); var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1); return stringOnWasmHeap; }\00(void)<::>{ var jsString = \'hello from js\'; var lengthBytes = jsString.length+1; var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1); return stringOnWasmHeap; }\00BEGIN\n\00 noarg_int returned: %d\n\00 noarg_double returned: %f\n\00 stringarg returned: %f\n\00string arg\00 multi_intarg returned: %d\n\00 multi_mixedarg returned: %f\n\00hello\00 unused_args returned: %d\n\00 skip_args returned: %f\n\00 add_outer returned: %f\n\00 user_separator returned: %d\n\00 user_comma returned: %d\n\00 return_str returned: %s\n\00 return_utf8_str returned: %s\n\00END\n\00\00\cc\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00T!\"\19\0d\01\02\03\11K\1c\0c\10\04\0b\1d\12\1e\'hnopqb \05\06\0f\13\14\15\1a\08\16\07($\17\18\t\n\0e\1b\1f%#\83\82}&*+<=>?CGJMXYZ[\\]^_`acdefgijklrstyz{|\00\00\00\00\00\00\00\00\00Illegal byte sequence\00Domain error\00Result not representable\00Not a tty\00Permission denied\00Operation not permitted\00No such file or directory\00No such process\00File exists\00Value too large for data type\00No space left on device\00Out of memory\00Resource busy\00Interrupted system call\00Resource temporarily unavailable\00Invalid seek\00Cross-device link\00Read-only file system\00Directory not empty\00Connection reset by peer\00Operation timed out\00Connection refused\00Host is down\00Host is unreachable\00Address in use\00Broken pipe\00I/O error\00No such device or address\00Block device required\00No such device\00Not a directory\00Is a directory\00Text file busy\00Exec format error\00Invalid argument\00Argument list too long\00Symbolic link loop\00Filename too long\00Too many open files in system\00No file descriptors available\00Bad file descriptor\00No child process\00Bad address\00File too large\00Too many links\00No locks available\00Resource deadlock would occur\00State not recoverable\00Previous owner died\00Operation canceled\00Function not implemented\00No message of desired type\00Identifier removed\00Device not a stream\00No data available\00Device timeout\00Out of streams resources\00Link has been severed\00Protocol error\00Bad message\00File descriptor in bad state\00Not a socket\00Destination address required\00Message too large\00Protocol wrong type for socket\00Protocol not available\00Protocol not supported\00Socket type not supported\00Not supported\00Protocol family not supported\00Address family not supported by protocol\00Address not available\00Network is down\00Network unreachable\00Connection reset by network\00Connection aborted\00No buffer space available\00Socket is connected\00Socket not connected\00Cannot send after socket shutdown\00Operation already in progress\00Operation in progress\00Stale file handle\00Remote I/O error\00Quota exceeded\00No medium found\00Wrong medium type\00No error information\00\00-+ 0X0x\00(null)\00\00\00\00\11\00\n\00\11\11\11\00\00\00\00\05\00\00\00\00\00\00\t\00\00\00\00\0b\00\00\00\00\00\00\00\00\11\00\0f\n\11\11\11\03\n\07\00\01\13\t\0b\0b\00\00\t\06\0b\00\00\0b\00\06\11\00\00\00\11\11\11\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0b\00\00\00\00\00\00\00\00\11\00\n\n\11\11\11\00\n\00\00\02\00\t\0b\00\00\00\t\00\0b\00\00\0b\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\0c\00\00\00\00\t\0c\00\00\00\00\00\0c\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0e\00\00\00\00\00\00\00\00\00\00\00\0d\00\00\00\04\0d\00\00\00\00\t\0e\00\00\00\00\00\0e\00\00\0e\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\00\00\00\00\0f\00\00\00\00\0f\00\00\00\00\t\10\00\00\00\00\00\10\00\00\10\00\00\12\00\00\00\12\12\12\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\12\00\00\00\12\12\12\00\00\00\00\00\00\t\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0b\00\00\00\00\00\00\00\00\00\00\00\n\00\00\00\00\n\00\00\00\00\t\0b\00\00\00\00\00\0b\00\00\0b\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\0c\00\00\00\00\t\0c\00\00\00\00\00\0c\00\00\0c\00\000123456789ABCDEF-0X+0X 0X-0x+0x 0x\00inf\00INF\00nan\00NAN\00.\00") (data (i32.const 5232) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") (data (i32.const 6860) "\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00\88\14\00\00\00\04\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\n\ff\ff\ff\ff\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\cc\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\b0\18\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (export "__em_js__noarg" (func $__em_js__noarg)) (export "__heap_base" (global $global$1)) (export "__data_end" (global $global$2)) + (func $__em_js__noarg (result i32) + (local $0 i32) + (local.set $0 + (i32.const 1024) + ) + (return + (local.get $0) + ) + ) ) (; --BEGIN METADATA -- @@ -20,6 +31,7 @@ "globalImports": [ ], "exports": [ + "__em_js__noarg" ], "namedGlobals": { "__heap_base" : "5250112", |