diff options
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 136 | ||||
-rw-r--r-- | test/lit/wasm-emscripten-finalize/passive-pic.wat | 2 | ||||
-rw-r--r-- | test/lld/em_asm_main_thread.wat | 2 | ||||
-rw-r--r-- | test/lld/em_asm_main_thread.wat.out | 4 | ||||
-rw-r--r-- | test/unit/input/em_asm_mangled_string.wat | 11 | ||||
-rw-r--r-- | test/unit/test_finalize.py | 10 |
6 files changed, 16 insertions, 149 deletions
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index d97121544..684c789c3 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -185,123 +185,6 @@ struct AsmConst { std::string code; }; -struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> { - Module& wasm; - bool minimizeWasmChanges; - StringConstantTracker stringTracker; - - std::vector<AsmConst> asmConsts; - // last sets in the current basic block, per index - std::map<Index, LocalSet*> sets; - - AsmConstWalker(Module& _wasm, bool minimizeWasmChanges) - : wasm(_wasm), minimizeWasmChanges(minimizeWasmChanges), - stringTracker(_wasm) {} - - void noteNonLinear(Expression* curr); - - void visitLocalSet(LocalSet* curr); - void visitCall(Call* curr); - - void process(); - -private: - void createAsmConst(uint64_t id, std::string code); - void addImports(); - - std::vector<std::unique_ptr<Function>> queuedImports; -}; - -void AsmConstWalker::noteNonLinear(Expression* curr) { - // End of this basic block; clear sets. - sets.clear(); -} - -void AsmConstWalker::visitLocalSet(LocalSet* curr) { sets[curr->index] = curr; } - -void AsmConstWalker::visitCall(Call* curr) { - auto* import = wasm.getFunction(curr->target); - // Find calls to emscripten_asm_const* functions whose first argument is - // is always a string constant. - if (!import->imported()) { - return; - } - auto importName = import->base; - if (!importName.hasSubstring(EM_ASM_PREFIX)) { - return; - } - - auto* arg = curr->operands[0]; - while (!arg->dynCast<Const>()) { - if (auto* get = arg->dynCast<LocalGet>()) { - // The argument may be a local.get, in which case, the last set in this - // basic block has the value. - auto* set = sets[get->index]; - if (set) { - assert(set->index == get->index); - arg = set->value; - } else { - Fatal() << "local.get of unknown in arg0 of call to " << importName - << " (used by EM_ASM* macros) in function " - << getFunction()->name - << ".\nThis might be caused by aggressive compiler " - "transformations. Consider using EM_JS instead."; - } - continue; - } - - if (auto* setlocal = arg->dynCast<LocalSet>()) { - // The argument may be a local.tee, in which case we take first child - // which is the value being copied into the local. - if (setlocal->isTee()) { - arg = setlocal->value; - continue; - } - } - - if (auto* bin = arg->dynCast<Binary>()) { - if (bin->op == AddInt32 || bin->op == AddInt64) { - // In the dynamic linking case the address of the string constant - // is the result of adding its offset to __memory_base. - // In this case are only looking for the offset from __memory_base - // the RHS of the addition is just what we want. - arg = bin->right; - continue; - } - } - - if (auto* unary = arg->dynCast<Unary>()) { - if (unary->op == WrapInt64) { - // This cast may be inserted around the string constant in the - // Memory64Lowering pass. - arg = unary->value; - continue; - } - } - - Fatal() << "Unexpected arg0 type (" << *arg - << ") in call to: " << importName; - } - - auto* value = arg->cast<Const>(); - Address address = value->value.getUnsigned(); - asmConsts.push_back({address, stringTracker.stringAtAddr(address)}); -} - -void AsmConstWalker::process() { - // Find and queue necessary imports - walkModule(&wasm); - // Add them after the walk, to avoid iterator invalidation on - // the list of functions. - addImports(); -} - -void AsmConstWalker::addImports() { - for (auto& import : queuedImports) { - wasm.addFunction(import.release()); - } -} - struct SegmentRemover : WalkerPass<PostWalker<SegmentRemover>> { SegmentRemover(Index segment) : segment(segment) {} @@ -345,22 +228,21 @@ static Address getExportedAddress(Module& wasm, Export* export_) { 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 {}; + } - // Older versions of emscripten don't export these symbols. Instead - // we run AsmConstWalker in an attempt to derive the string addresses - // from the code. if (!start || !end) { - AsmConstWalker walker(wasm, minimizeWasmChanges); - walker.process(); - return walker.asmConsts; + Fatal() << "Found only one of __start_em_asm and __stop_em_asm"; } - // Newer version of emscripten export this symbols and we - // can use it ot 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. std::vector<AsmConst> asmConsts; StringConstantTracker stringTracker(wasm); Address startAddress = getExportedAddress(wasm, start); diff --git a/test/lit/wasm-emscripten-finalize/passive-pic.wat b/test/lit/wasm-emscripten-finalize/passive-pic.wat index 14e6842a3..8b6ccb6d4 100644 --- a/test/lit/wasm-emscripten-finalize/passive-pic.wat +++ b/test/lit/wasm-emscripten-finalize/passive-pic.wat @@ -12,6 +12,8 @@ (import "env" "__memory_base" (global $__memory_base i32)) (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32))) (data passive "xxxhello\00yyy") + (global (export "__start_em_asm") i32 (i32.const 3)) + (global (export "__stop_em_asm") i32 (i32.const 9)) ;; memory init function similar to those generated by wasm-ld (start $__wasm_init_memory) (func $__wasm_init_memory diff --git a/test/lld/em_asm_main_thread.wat b/test/lld/em_asm_main_thread.wat index 0435e9be0..65f530d69 100644 --- a/test/lld/em_asm_main_thread.wat +++ b/test/lld/em_asm_main_thread.wat @@ -12,6 +12,8 @@ (import "env" "emscripten_asm_const_int_sync_on_main_thread" (func $emscripten_asm_const_int_sync_on_main_thread (param i32 i32 i32) (result i32))) (memory $0 2) (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") + (global (export "__start_em_asm") i32 (i32.const 568)) + (global (export "__stop_em_asm") i32 (i32.const 652)) (table $0 1 1 funcref) (global $global$0 (mut i32) (i32.const 66192)) (global $global$1 i32 (i32.const 66192)) diff --git a/test/lld/em_asm_main_thread.wat.out b/test/lld/em_asm_main_thread.wat.out index 8fc99e081..91a022dbc 100644 --- a/test/lld/em_asm_main_thread.wat.out +++ b/test/lld/em_asm_main_thread.wat.out @@ -8,8 +8,10 @@ (type $0 (func (param i32 i32 i32) (result i32))) (import "env" "emscripten_asm_const_int_sync_on_main_thread" (func $emscripten_asm_const_int_sync_on_main_thread (param i32 i32 i32) (result i32))) (memory $0 2) - (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00") + (data (i32.const 568) "") (table $0 1 1 funcref) + (global $0 i32 (i32.const 568)) + (global $1 i32 (i32.const 652)) (global $global$0 (mut i32) (i32.const 66192)) (global $global$1 i32 (i32.const 66192)) (global $global$2 i32 (i32.const 652)) diff --git a/test/unit/input/em_asm_mangled_string.wat b/test/unit/input/em_asm_mangled_string.wat deleted file mode 100644 index aa856270d..000000000 --- a/test/unit/input/em_asm_mangled_string.wat +++ /dev/null @@ -1,11 +0,0 @@ -(module - (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32))) - (global $global$0 (mut i32) (i32.const 66192)) - (global $global$1 i32 (i32.const 652)) - (export "__data_end" (global $global$1)) - (export "main" (func $main)) - (func $main (param $0 i32) (param $1 i32) (result i32) - (drop (call $emscripten_asm_const_int (local.get $0) (i32.const 0) (i32.const 0))) - (i32.const 0) - ) -) diff --git a/test/unit/test_finalize.py b/test/unit/test_finalize.py index b393177bd..6733155cb 100644 --- a/test/unit/test_finalize.py +++ b/test/unit/test_finalize.py @@ -1,18 +1,8 @@ -import os - from scripts.test import shared from . import utils class EmscriptenFinalizeTest(utils.BinaryenTestCase): - def test_em_asm_mangled_string(self): - p = shared.run_process(shared.WASM_EMSCRIPTEN_FINALIZE + [ - self.input_path('em_asm_mangled_string.wat'), '-o', os.devnull, '--global-base=1024' - ], check=False, capture_output=True) - self.assertNotEqual(p.returncode, 0) - self.assertIn('Fatal: local.get of unknown in arg0 of call to emscripten_asm_const_int (used by EM_ASM* macros) in function main.', p.stderr) - self.assertIn('This might be caused by aggressive compiler transformations. Consider using EM_JS instead.', p.stderr) - def do_output_test(self, args): # without any output file specified, don't error, don't write the wasm, # but do emit metadata |