summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm-binary.h6
-rw-r--r--src/wasm/wasm-binary.cpp68
2 files changed, 66 insertions, 8 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 55a97743f..9724bc93d 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -855,9 +855,15 @@ public:
std::vector<Expression*> expressionStack;
+ bool definitelyUnreachable; // set when we know code is definitely unreachable. this helps parse
+ // stacky wasm code, which can be unsuitable for our IR when unreachable
+
BinaryConsts::ASTNodes lastSeparator = BinaryConsts::End;
+ // process a block-type scope, until an end or else marker, or the end of the function
void processExpressions();
+ void skipUnreachableCode();
+
Expression* popExpression();
Expression* popNonVoidExpression();
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index eb41ae8a7..b114b81fb 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1807,12 +1807,61 @@ void WasmBinaryBuilder::readGlobals() {
}
}
-void WasmBinaryBuilder::processExpressions() { // until an end or else marker, or the end of the function
+void WasmBinaryBuilder::processExpressions() {
+ if (debug) std::cerr << "== processExpressions" << std::endl;
+ definitelyUnreachable = false;
while (1) {
Expression* curr;
auto ret = readExpression(curr);
if (!curr) {
lastSeparator = ret;
+ if (debug) std::cerr << "== processExpressions finished" << std::endl;
+ return;
+ }
+ expressionStack.push_back(curr);
+ if (curr->type == unreachable) {
+ // once we see something unreachable, we don't want to add anything else
+ // to the stack, as it could be stacky code that is non-representable in
+ // our AST. but we do need to skip it
+ // if there is nothing else here, just stop. otherwise, go into unreachable
+ // mode. peek to see what to do
+ if (pos == endOfFunction) {
+ throw ParseException("Reached function end without seeing End opcode");
+ }
+ auto peek = input[pos];
+ if (peek == BinaryConsts::End || peek == BinaryConsts::Else) {
+ if (debug) std::cerr << "== processExpressions finished with unreachable" << std::endl;
+ lastSeparator = BinaryConsts::ASTNodes(peek);
+ pos++;
+ return;
+ } else {
+ skipUnreachableCode();
+ return;
+ }
+ }
+ }
+}
+
+void WasmBinaryBuilder::skipUnreachableCode() {
+ if (debug) std::cerr << "== skipUnreachableCode" << std::endl;
+ // preserve the stack, and restore it. it contains the instruction that made us
+ // unreachable, and we can ignore anything after it. things after it may pop,
+ // we want to undo that
+ auto savedStack = expressionStack;
+ // clear the stack. nothing should be popped from there anyhow, just stuff
+ // can be pushed and then popped. Popping past the top of the stack will
+ // result in uneachables being returned
+ expressionStack.clear();
+ while (1) {
+ // set the definitelyUnreachable flag each time, as sub-blocks may set and unset it
+ definitelyUnreachable = true;
+ Expression* curr;
+ auto ret = readExpression(curr);
+ if (!curr) {
+ if (debug) std::cerr << "== skipUnreachableCode finished" << std::endl;
+ lastSeparator = ret;
+ definitelyUnreachable = false;
+ expressionStack = savedStack;
return;
}
expressionStack.push_back(curr);
@@ -1820,15 +1869,19 @@ void WasmBinaryBuilder::processExpressions() { // until an end or else marker, o
}
Expression* WasmBinaryBuilder::popExpression() {
+ if (debug) std::cerr << "== popExpression" << std::endl;
if (expressionStack.empty()) {
- throw ParseException("attempted pop from empty stack at " + std::to_string(pos));
+ if (definitelyUnreachable) {
+ // in unreachable code, trying to pop past the polymorphic stack
+ // area results in receiving unreachables
+ if (debug) std::cerr << "== popping unreachable from polymorphic stack" << std::endl;
+ return allocator.alloc<Unreachable>();
+ }
+ throw ParseException("attempted pop from empty stack / beyond block start boundary at " + std::to_string(pos));
}
+ // the stack is not empty, and we would not be going out of the current block
auto ret = expressionStack.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();
- }
+ expressionStack.pop_back();
return ret;
}
@@ -2222,7 +2275,6 @@ void WasmBinaryBuilder::visitBreak(Break *curr, uint8_t code) {
void WasmBinaryBuilder::visitSwitch(Switch *curr) {
if (debug) std::cerr << "zz node: Switch" << std::endl;
curr->condition = popNonVoidExpression();
-
auto numTargets = getU32LEB();
if (debug) std::cerr << "targets: "<< numTargets<<std::endl;
for (size_t i = 0; i < numTargets; i++) {