summaryrefslogtreecommitdiff
path: root/src/s2wasm.h
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@users.noreply.github.com>2016-08-11 21:02:33 -0700
committerAlon Zakai <alonzakai@gmail.com>2016-08-11 21:02:33 -0700
commit1448c6bb26a60b26e70f7e913e56e0d0bf03b5da (patch)
tree6af5b7a0d34a7278a695112db41c1af1a45965c3 /src/s2wasm.h
parent8e8c311aaeecf9b5433e4a651585914465731f0c (diff)
downloadbinaryen-1448c6bb26a60b26e70f7e913e56e0d0bf03b5da.tar.gz
binaryen-1448c6bb26a60b26e70f7e913e56e0d0bf03b5da.tar.bz2
binaryen-1448c6bb26a60b26e70f7e913e56e0d0bf03b5da.zip
Implement asm.js style exception handling for Wasm (#664)
* Implement asm.js style exception handling for Wasm 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). LLVM backend lowers invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad into ... (some code) call @invoke_SIG(func, arg1, arg2) ... (some code) SIG is a mangled string generated based on the LLVM IR-level function signature. In LLVM IR, types are not lowered yet, so this mangling scheme simply takes LLVM's string representtion of parameter types and concatenate them with '_'. For example, the name of an invoke wrapper for function void foo(struct mystruct*, int) will be "__invoke_void_%struct.mystruct*_int". 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". * Address comments Change variable names to camelcase Add a small (semi-)handwritten test case * Export malloc and free from wasm when available * Add a test case for exporting malloc/free feature + cosmetic 'file' name change in text_before_type.s * fixInvokeWrapper -> fixEmExceptionInvoke * Add a TODO
Diffstat (limited to 'src/s2wasm.h')
-rw-r--r--src/s2wasm.h56
1 files changed, 48 insertions, 8 deletions
diff --git a/src/s2wasm.h b/src/s2wasm.h
index b17ed0702..3a7cf31db 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -554,7 +554,7 @@ class S2WasmBuilder {
void parseFuncType() {
auto decl = make_unique<FunctionType>();
- Name name = getCommaSeparated();
+ Name rawName = getCommaSeparated();
skipComma();
if(match("void")) {
decl->result = none;
@@ -562,9 +562,11 @@ class S2WasmBuilder {
decl->result = getType();
}
while (*s && skipComma()) decl->params.push_back(getType());
- decl->name = "FUNCSIG$" + getSig(decl.get());
+ std::string sig = getSig(decl.get());
+ decl->name = "FUNCSIG$" + sig;
FunctionType *ty = wasm->checkFunctionType(decl->name);
+ Name name = fixEmExceptionInvoke(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.
@@ -876,14 +878,9 @@ class S2WasmBuilder {
} else {
// non-indirect call
Name assign = getAssign();
- Name target = linkerObj->resolveAlias(cleanFunction(getCommaSeparated()), LinkerObject::Relocation::kFunction);
-
+ Name rawTarget = cleanFunction(getCommaSeparated());
Call* curr = allocator->alloc<Call>();
- curr->target = target;
curr->type = type;
- if (!linkerObj->isFunctionImplemented(target)) {
- linkerObj->addUndefinedFunctionCall(curr);
- }
skipWhitespace();
if (*s == ',') {
skipComma();
@@ -893,6 +890,13 @@ class S2WasmBuilder {
curr->operands.push_back(inputs[i]);
}
}
+ Name target = linkerObj->resolveAlias(
+ fixEmExceptionInvoke(rawTarget, curr->type, curr->operands),
+ LinkerObject::Relocation::kFunction);
+ curr->target = target;
+ if (!linkerObj->isFunctionImplemented(target)) {
+ linkerObj->addUndefinedFunctionCall(curr);
+ }
setOutput(curr, assign);
}
};
@@ -1342,6 +1346,42 @@ class S2WasmBuilder {
}
}
+ // 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).
+ //
+ // LLVM backend lowers
+ // invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
+ // into
+ // ... (some code)
+ // call @invoke_SIG(func, arg1, arg2)
+ // ... (some code)
+ // SIG is a mangled string generated based on the LLVM IR-level function
+ // signature. In LLVM IR, types are not lowered yet, so this mangling scheme
+ // simply takes LLVM's string representtion of parameter types and concatenate
+ // them with '_'. For example, the name of an invoke wrapper for function
+ // void foo(struct mystruct*, int) will be
+ // "__invoke_void_%struct.mystruct*_int".
+ // 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() == '"') {
+ nameStr = nameStr.substr(1, nameStr.size() - 2);
+ }
+ if (nameStr.find("__invoke_") != 0) {
+ return name;
+ }
+ std::string sigWoOrigFunc = sig.front() + sig.substr(2, sig.size() - 2);
+ return Name("invoke_" + sigWoOrigFunc);
+ }
};