summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r--src/wasm/wasm-binary.cpp98
1 files changed, 96 insertions, 2 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 039cef5e5..7047b674e 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1754,7 +1754,8 @@ void WasmBinaryBuilder::processExpressions() {
throwError("unexpected end of input");
}
auto peek = input[pos];
- if (peek == BinaryConsts::End || peek == BinaryConsts::Else) {
+ if (peek == BinaryConsts::End || peek == BinaryConsts::Else ||
+ peek == BinaryConsts::Catch) {
if (debug) {
std::cerr << "== processExpressions finished with unreachable"
<< std::endl;
@@ -2260,8 +2261,21 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
break;
case BinaryConsts::End:
case BinaryConsts::Else:
+ case BinaryConsts::Catch:
curr = nullptr;
break;
+ case BinaryConsts::Try:
+ visitTry((curr = allocator.alloc<Try>())->cast<Try>());
+ break;
+ case BinaryConsts::Throw:
+ visitThrow((curr = allocator.alloc<Throw>())->cast<Throw>());
+ break;
+ case BinaryConsts::Rethrow:
+ visitRethrow((curr = allocator.alloc<Rethrow>())->cast<Rethrow>());
+ break;
+ case BinaryConsts::BrOnExn:
+ visitBrOnExn((curr = allocator.alloc<BrOnExn>())->cast<BrOnExn>());
+ break;
case BinaryConsts::AtomicPrefix: {
code = static_cast<uint8_t>(getU32LEB());
if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) {
@@ -2420,6 +2434,7 @@ void WasmBinaryBuilder::visitBlock(Block* curr) {
if (debug) {
std::cerr << "zz node: Block" << std::endl;
}
+
// special-case Block and de-recurse nested blocks in their first position, as
// that is a common pattern that can be very highly nested.
std::vector<Block*> stack;
@@ -2467,10 +2482,22 @@ void WasmBinaryBuilder::visitBlock(Block* curr) {
}
}
-Expression* WasmBinaryBuilder::getBlockOrSingleton(Type type) {
+// Gets a block of expressions. If it's just one, return that singleton.
+// numPops is the number of pop instructions we add before starting to parse the
+// block. Can be used when we need to assume certain number of values are on top
+// of the stack in the beginning.
+Expression* WasmBinaryBuilder::getBlockOrSingleton(Type type,
+ unsigned numPops) {
Name label = getNextLabel();
breakStack.push_back({label, type != none && type != unreachable});
auto start = expressionStack.size();
+
+ Builder builder(wasm);
+ for (unsigned i = 0; i < numPops; i++) {
+ auto* pop = builder.makePop(exnref);
+ expressionStack.push_back(pop);
+ }
+
processExpressions();
size_t end = expressionStack.size();
if (end < start) {
@@ -4347,6 +4374,73 @@ void WasmBinaryBuilder::visitDrop(Drop* curr) {
curr->finalize();
}
+void WasmBinaryBuilder::visitTry(Try* curr) {
+ if (debug) {
+ std::cerr << "zz node: Try" << std::endl;
+ }
+ // For simplicity of implementation, like if scopes, we create a hidden block
+ // within each try-body and catch-body, and let branches target those inner
+ // blocks instead.
+ curr->type = getType();
+ curr->body = getBlockOrSingleton(curr->type);
+ if (lastSeparator != BinaryConsts::Catch) {
+ throwError("No catch instruction within a try scope");
+ }
+ curr->catchBody = getBlockOrSingleton(curr->type, 1);
+ curr->finalize(curr->type);
+ if (lastSeparator != BinaryConsts::End) {
+ throwError("try should end with end");
+ }
+}
+
+void WasmBinaryBuilder::visitThrow(Throw* curr) {
+ if (debug) {
+ std::cerr << "zz node: Throw" << std::endl;
+ }
+ auto index = getU32LEB();
+ if (index >= wasm.events.size()) {
+ throwError("bad event index");
+ }
+ auto* event = wasm.events[index].get();
+ curr->event = event->name;
+ size_t num = event->params.size();
+ curr->operands.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ curr->operands[num - i - 1] = popNonVoidExpression();
+ }
+ curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRethrow(Rethrow* curr) {
+ if (debug) {
+ std::cerr << "zz node: Rethrow" << std::endl;
+ }
+ curr->exnref = popNonVoidExpression();
+ curr->finalize();
+}
+
+void WasmBinaryBuilder::visitBrOnExn(BrOnExn* curr) {
+ if (debug) {
+ std::cerr << "zz node: BrOnExn" << std::endl;
+ }
+ BreakTarget target = getBreakTarget(getU32LEB());
+ curr->name = target.name;
+ auto index = getU32LEB();
+ if (index >= wasm.events.size()) {
+ throwError("bad event index");
+ }
+ curr->event = wasm.events[index]->name;
+ curr->exnref = popNonVoidExpression();
+
+ Event* event = wasm.getEventOrNull(curr->event);
+ assert(event && "br_on_exn's event must exist");
+
+ // Copy params info into BrOnExn, because it is necessary when BrOnExn is
+ // refinalized without the module.
+ curr->eventParams = event->params;
+ curr->finalize();
+}
+
void WasmBinaryBuilder::throwError(std::string text) {
throw ParseException(text, 0, pos);
}