summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm-ir-builder.h25
-rw-r--r--src/wasm/wasm-ir-builder.cpp16
2 files changed, 38 insertions, 3 deletions
diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h
index d7a1dde87..40689a879 100644
--- a/src/wasm-ir-builder.h
+++ b/src/wasm-ir-builder.h
@@ -259,6 +259,10 @@ private:
struct NoScope {};
struct FuncScope {
Function* func;
+ // Used to determine whether we need to run a fixup after creating the
+ // function.
+ bool hasSyntheticBlock = false;
+ bool hasPop = false;
};
struct BlockScope {
Block* block;
@@ -369,6 +373,27 @@ private:
}
return nullptr;
}
+ void noteSyntheticBlock() {
+ if (auto* funcScope = std::get_if<FuncScope>(&scope)) {
+ funcScope->hasSyntheticBlock = true;
+ }
+ }
+ void notePop() {
+ if (auto* funcScope = std::get_if<FuncScope>(&scope)) {
+ funcScope->hasPop = true;
+ }
+ }
+ bool needsPopFixup() {
+ // If the function has a synthetic block and it has a pop, then it's
+ // possible that the pop is inside the synthetic block and we should run
+ // the fixup. Determining more precisely that a pop is inside the
+ // synthetic block when it is created would be complicated and expensive,
+ // so we are conservative here.
+ if (auto* funcScope = std::get_if<FuncScope>(&scope)) {
+ return funcScope->hasSyntheticBlock && funcScope->hasPop;
+ }
+ return false;
+ }
Block* getBlock() {
if (auto* blockScope = std::get_if<BlockScope>(&scope)) {
return blockScope->block;
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index b238a926c..4cb9514f5 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -17,6 +17,7 @@
#include <cassert>
#include "ir/child-typer.h"
+#include "ir/eh-utils.h"
#include "ir/names.h"
#include "ir/properties.h"
#include "ir/utils.h"
@@ -98,7 +99,10 @@ Result<> IRBuilder::packageHoistedValue(const HoistedVal& hoisted,
auto packageAsBlock = [&](Type type) {
// Create a block containing the producer of the hoisted value, the final
- // get of the hoisted value, and everything in between.
+ // get of the hoisted value, and everything in between. Record the fact that
+ // we are synthesizing a block to help us determine later whether we need to
+ // run the nested pop fixup.
+ scopeStack[0].noteSyntheticBlock();
std::vector<Expression*> exprs(scope.exprStack.begin() + hoisted.valIndex,
scope.exprStack.end());
auto* block = builder.makeBlock(exprs, type);
@@ -865,9 +869,12 @@ Result<> IRBuilder::visitCatch(Name tag) {
tryy->catchTags.push_back(tag);
pushScope(
ScopeCtx::makeCatch(tryy, originalLabel, label, labelUsed, branchLabel));
- // Push a pop for the exception payload.
+ // Push a pop for the exception payload if necessary.
auto params = wasm.getTag(tag)->sig.params;
if (params != Type::none) {
+ // Note that we have a pop to help determine later whether we need to run
+ // the fixup for pops within blocks.
+ scopeStack[0].notePop();
push(builder.makePop(params));
}
return Ok{};
@@ -935,7 +942,7 @@ Result<> IRBuilder::visitEnd() {
if (scope.isNone()) {
return Err{"unexpected end"};
}
- if (auto* func = scope.getFunction(); func) {
+ if (auto* func = scope.getFunction()) {
if (auto* loc = std::get_if<Function::DebugLocation>(&debugLoc)) {
func->epilogLocation.insert(*loc);
}
@@ -970,6 +977,9 @@ Result<> IRBuilder::visitEnd() {
if (auto* func = scope.getFunction()) {
func->body = maybeWrapForLabel(*expr);
labelDepths.clear();
+ if (scope.needsPopFixup()) {
+ EHUtils::handleBlockNestedPops(func, wasm);
+ }
} else if (auto* block = scope.getBlock()) {
assert(*expr == block);
block->name = scope.label;