summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2017-07-31 15:10:38 -0700
committerGitHub <noreply@github.com>2017-07-31 15:10:38 -0700
commit76751bf1f9df4eb2ee6c216744af9ed1e097132e (patch)
tree99bfc7c6b5231dc2367865a8de5f2691d9b400a8 /src/wasm
parent4d46a7e2c37299d5a9b9d9d6323ce9fca3a1cf3a (diff)
downloadbinaryen-76751bf1f9df4eb2ee6c216744af9ed1e097132e.tar.gz
binaryen-76751bf1f9df4eb2ee6c216744af9ed1e097132e.tar.bz2
binaryen-76751bf1f9df4eb2ee6c216744af9ed1e097132e.zip
Polymophic stack support (#1117)
Emit valid wasm binaries even for corner cases of unreachable code. * emit an unreachable after a node that pushes a value that has unreachable type (where wasm type checking would have pushed a concrete type) * conversely, as a hack, emulate the wasm polymorphic stack mode by not emptying the stack when it has one element and that element is unreachable. this lets further pops work (all returning an unreachable element)
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/wasm-binary.cpp34
1 files changed, 33 insertions, 1 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 2df7f2e26..346018c7d 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -648,6 +648,16 @@ void WasmBinaryWriter::visitBreak(Break *curr) {
if (curr->condition) recurse(curr->condition);
o << int8_t(curr->condition ? BinaryConsts::BrIf : BinaryConsts::Br)
<< U32LEB(getBreakIndex(curr->name));
+ if (curr->condition && curr->type == unreachable) {
+ // a br_if is normally none or emits a value. if it is unreachable,
+ // then either the condition or the value is unreachable, which is
+ // extremely rare, and may require us to make the stack polymorphic
+ // (if the block we branch to has a value, we may lack one as we
+ // are not a taken branch; the wasm spec on the other hand does
+ // presume the br_if emits a value of the right type, even if it
+ // popped unreachable)
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitSwitch(Switch *curr) {
@@ -669,6 +679,9 @@ void WasmBinaryWriter::visitCall(Call *curr) {
recurse(operand);
}
o << int8_t(BinaryConsts::CallFunction) << U32LEB(getFunctionIndex(curr->target));
+ if (curr->type == unreachable) {
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitCallImport(CallImport *curr) {
@@ -689,6 +702,9 @@ void WasmBinaryWriter::visitCallIndirect(CallIndirect *curr) {
o << int8_t(BinaryConsts::CallIndirect)
<< U32LEB(getFunctionTypeIndex(curr->fullType))
<< U32LEB(0); // Reserved flags field
+ if (curr->type == unreachable) {
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitGetLocal(GetLocal *curr) {
@@ -700,6 +716,9 @@ void WasmBinaryWriter::visitSetLocal(SetLocal *curr) {
if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl;
recurse(curr->value);
o << int8_t(curr->isTee() ? BinaryConsts::TeeLocal : BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]);
+ if (curr->type == unreachable) {
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitGetGlobal(GetGlobal *curr) {
@@ -986,6 +1005,9 @@ void WasmBinaryWriter::visitUnary(Unary *curr) {
case ReinterpretInt64: o << int8_t(BinaryConsts::F64ReinterpretI64); break;
default: abort();
}
+ if (curr->type == unreachable) {
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitBinary(Binary *curr) {
@@ -1075,6 +1097,9 @@ void WasmBinaryWriter::visitBinary(Binary *curr) {
case GeFloat64: o << int8_t(BinaryConsts::F64Ge); break;
default: abort();
}
+ if (curr->type == unreachable) {
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitSelect(Select *curr) {
@@ -1083,6 +1108,9 @@ void WasmBinaryWriter::visitSelect(Select *curr) {
recurse(curr->ifFalse);
recurse(curr->condition);
o << int8_t(BinaryConsts::Select);
+ if (curr->type == unreachable) {
+ o << int8_t(BinaryConsts::Unreachable);
+ }
}
void WasmBinaryWriter::visitReturn(Return *curr) {
@@ -1771,7 +1799,11 @@ Expression* WasmBinaryBuilder::popExpression() {
throw ParseException("attempted pop from empty stack");
}
auto ret = expressionStack.back();
- expressionStack.pop_back();
+ // to simulate the wasm polymorphic stack mode, leave a final
+ // unreachable, don't empty the stack in that case
+ if (!(expressionStack.size() == 1 && ret->type == unreachable)) {
+ expressionStack.pop_back();
+ }
return ret;
}