summaryrefslogtreecommitdiff
path: root/src/s2wasm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/s2wasm.h')
-rw-r--r--src/s2wasm.h59
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() == '"') {