diff options
Diffstat (limited to 'src/s2wasm.h')
-rw-r--r-- | src/s2wasm.h | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/src/s2wasm.h b/src/s2wasm.h index a45f3aab4..a23cbb549 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, + fixEmLongjmp(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 fixEmLongjmp(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() == '"') { |