diff options
-rw-r--r-- | src/s2wasm.h | 59 | ||||
-rw-r--r-- | test/dot_s/fix_em_ehsjlj_names.s (renamed from test/dot_s/invoke_wrapper.s) | 30 | ||||
-rw-r--r-- | test/dot_s/fix_em_ehsjlj_names.wast (renamed from test/dot_s/invoke_wrapper.wast) | 6 |
3 files changed, 74 insertions, 21 deletions
diff --git a/src/s2wasm.h b/src/s2wasm.h index a45f3aab4..08343cb25 100644 --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -248,7 +248,8 @@ class S2WasmBuilder { s++; offset = -getInt(); } - linkerObj->addRelocation(kind, target, cleanFunction(name), offset); + linkerObj->addRelocation(kind, target, + fixEmEHSjLjNames(cleanFunction(name)), offset); return true; } } @@ -566,7 +567,7 @@ class S2WasmBuilder { decl->name = "FUNCSIG$" + sig; FunctionType *ty = wasm->checkFunctionType(decl->name); - Name name = fixEmExceptionInvoke(rawName, sig); + Name name = fixEmEHSjLjNames(rawName, sig); if (!ty) { // The wasm module takes ownership of the FunctionType if we insert it. // Otherwise it's already in the module and ours is freed. @@ -891,7 +892,7 @@ class S2WasmBuilder { } } Name target = linkerObj->resolveAlias( - fixEmExceptionInvoke(rawTarget, curr->type, curr->operands), + fixEmEHSjLjNames(rawTarget, curr->type, curr->operands), LinkerObject::Relocation::kFunction); curr->target = target; if (!linkerObj->isFunctionImplemented(target)) { @@ -1347,6 +1348,52 @@ class S2WasmBuilder { } } + // Fixes function name hacks caused by LLVM exception & setjmp/longjmp + // handling pass for wasm. + // This does two things: + // 1. Change emscripten_longjmp_jmpbuf to emscripten_longjmp. + // In setjmp/longjmp handling pass in wasm backend, what we want to do is + // to change all function calls to longjmp to calls to emscripten_longjmp. + // Because we replace all calls to longjmp to emscripten_longjmp, the + // signature of that function should be the same as longjmp: + // emscripten_longjmp(jmp_buf, int) + // But after calling a function that might longjmp, while we test whether + // a longjmp occurred, we have to load an int address value and call + // emscripten_longjmp again with that address as the first argument. (Refer + // to lib/Target/WebAssembly/WebAssemblyEmscriptenEHSjLj.cpp in LLVM for + // details.) + // In this case we need the signature of emscripten_longjmp to be (int, + // int). So we need two different kinds of emscripten_longjmp signatures in + // LLVM IR. Both signatures will be lowered to (int, int) eventually, but + // in LLVM IR, types are not lowered yet. + // So we declare two functions in LLVM: + // emscripten_longjmp_jmpbuf(jmp_buf, int) + // emscripten_longjmp(int, int) + // And we change the name of emscripten_longjmp_jmpbuf to + // emscripten_longjmp here. + // 2. Converts invoke wrapper names. + // Refer to the comments in fixEmExceptionInvoke below. + template<typename ListType> + Name fixEmEHSjLjNames(const Name &name, WasmType result, + const ListType &operands) { + return fixEmEHSjLjNames(name, getSig(result, operands)); + } + + Name fixEmEHSjLjNames(const Name &name, const std::string &sig) { + if (name == "emscripten_longjmp_jmpbuf") + return "emscripten_longjmp"; + return fixEmExceptionInvoke(name, sig); + } + + // This version only converts emscripten_longjmp_jmpbuf and does not deal + // with invoke wrappers. This is used when we only have a function name as + // relocatable constant. + Name fixEmEHSjLjNames(const Name &name) { + if (name == "emscripten_longjmp_jmpbuf") + return "emscripten_longjmp"; + return name; + } + // Converts invoke wrapper names generated by LLVM backend to real invoke // wrapper names that are expected by JavaScript glue code. // This is required to support wasm exception handling (asm.js style). @@ -1366,12 +1413,6 @@ class S2WasmBuilder { // This function converts the names of invoke wrappers based on their lowered // argument types and a return type. In the example above, the resulting new // wrapper name becomes "invoke_vii". - template<typename ListType> - Name fixEmExceptionInvoke(const Name &name, WasmType result, - const ListType &operands) { - return fixEmExceptionInvoke(name, getSig(result, operands)); - } - Name fixEmExceptionInvoke(const Name &name, const std::string &sig) { std::string nameStr = name.c_str(); if (nameStr.front() == '"' && nameStr.back() == '"') { diff --git a/test/dot_s/invoke_wrapper.s b/test/dot_s/fix_em_ehsjlj_names.s index 6de2f8b4c..15d4452b1 100644 --- a/test/dot_s/invoke_wrapper.s +++ b/test/dot_s/fix_em_ehsjlj_names.s @@ -1,5 +1,5 @@ .text - .file "invoke_wrapper.bc" + .file "fix_em_ehsjlj_names.bc" .type _Z5func1v,@function _Z5func1v: .endfunc @@ -46,17 +46,20 @@ main: i32.const $push3=, 2 i32.const $push2=, 3 i32.call $drop=, __invoke_i32_i32_i32_i32@FUNCTION, $pop5, $pop4, $pop3, $pop2 - i32.const $push9=, _Z5func3fd@FUNCTION - f32.const $push8=, 0x1.8p0 - f64.const $push7=, 0x1.b333333333333p1 - f32.call $drop=, __invoke_float_float_double@FUNCTION, $pop9, $pop8, $pop7 - i32.const $push21=, _Z5func4P8mystructS_@FUNCTION - i32.const $push37=, 32 - i32.add $push38=, $1, $pop37 - i32.const $push39=, 4 - i32.add $push40=, $1, $pop39 - i32.call $drop=, "__invoke_%struct.mystruct*_%struct.mystruct*_%struct.mystruct*"@FUNCTION, $pop21, $pop38, $pop40 - i32.const $push23=, 0 + i32.const $push8=, _Z5func3fd@FUNCTION + f32.const $push7=, 0x1.8p0 + f64.const $push6=, 0x1.b333333333333p1 + f32.call $drop=, __invoke_float_float_double@FUNCTION, $pop8, $pop7, $pop6 + i32.const $push9=, _Z5func4P8mystructS_@FUNCTION + i32.const $push10=, 32 + i32.add $push11=, $1, $pop10 + i32.const $push12=, 4 + i32.add $push13=, $1, $pop12 + i32.call $drop=, "__invoke_%struct.mystruct*_%struct.mystruct*_%struct.mystruct*"@FUNCTION, $pop9, $pop11, $pop13 + i32.const $push14=, 5 + i32.const $push15=, 6 + call emscripten_longjmp_jmpbuf@FUNCTION, $pop15, $pop14 + i32.const $push16=, 0 .endfunc .Lfunc_end4: .size main, .Lfunc_end4-main @@ -65,3 +68,6 @@ main: .functype __invoke_i32_i32_i32_i32, i32, i32, i32, i32, i32 .functype __invoke_float_float_double, f32, i32, f32, f64 .functype __invoke_%struct.mystruct*_%struct.mystruct*_%struct.mystruct*, i32, i32, i32, i32 + .functype emscripten_longjmp_jmpbuf, void, i32, i32 + .functype emscripten_longjmp, void, i32, i32 + diff --git a/test/dot_s/invoke_wrapper.wast b/test/dot_s/fix_em_ehsjlj_names.wast index d54e94d03..61ae5ef5e 100644 --- a/test/dot_s/invoke_wrapper.wast +++ b/test/dot_s/fix_em_ehsjlj_names.wast @@ -5,9 +5,11 @@ (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32))) (type $FUNCSIG$fifd (func (param i32 f32 f64) (result f32))) (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) + (type $FUNCSIG$vii (func (param i32 i32))) (type $FUNCSIG$v (func)) (type $FUNCSIG$ffd (func (param f32 f64) (result f32))) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (import $emscripten_longjmp "env" "emscripten_longjmp" (param i32 i32)) (import $invoke_ffd "env" "invoke_ffd" (param i32 f32 f64) (result f32)) (import $invoke_iii "env" "invoke_iii" (param i32 i32 i32) (result i32)) (import $invoke_iiii "env" "invoke_iiii" (param i32 i32 i32 i32) (result i32)) @@ -60,6 +62,10 @@ (i32.const 4) ) ) + (call_import $emscripten_longjmp + (i32.const 5) + (i32.const 6) + ) (i32.const 0) ) (func $__wasm_nullptr (type $FUNCSIG$v) |