summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm-ir-builder.h23
-rw-r--r--src/wasm/wasm-ir-builder.cpp63
2 files changed, 43 insertions, 43 deletions
diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h
index 5803f0c61..addbd1a30 100644
--- a/src/wasm-ir-builder.h
+++ b/src/wasm-ir-builder.h
@@ -298,6 +298,10 @@ private:
// The branch label name for this scope. Always fresh, never shadowed.
Name label;
+ // For Try/Catch/CatchAll scopes, we need to separately track a label used
+ // for branches, since the normal label is only used for delegates.
+ Name branchLabel;
+
bool labelUsed = false;
std::vector<Expression*> exprStack;
@@ -308,6 +312,8 @@ private:
ScopeCtx() : scope(NoScope{}) {}
ScopeCtx(Scope scope) : scope(scope) {}
ScopeCtx(Scope scope, Name label) : scope(scope), label(label) {}
+ ScopeCtx(Scope scope, Name label, Name branchLabel)
+ : scope(scope), label(label), branchLabel(branchLabel) {}
static ScopeCtx makeFunc(Function* func) {
return ScopeCtx(FuncScope{func});
@@ -325,11 +331,13 @@ private:
static ScopeCtx makeTry(Try* tryy, Name originalLabel = {}) {
return ScopeCtx(TryScope{tryy, originalLabel});
}
- static ScopeCtx makeCatch(Try* tryy, Name originalLabel, Name label) {
- return ScopeCtx(CatchScope{tryy, originalLabel}, label);
+ static ScopeCtx
+ makeCatch(Try* tryy, Name originalLabel, Name label, Name branchLabel) {
+ return ScopeCtx(CatchScope{tryy, originalLabel}, label, branchLabel);
}
- static ScopeCtx makeCatchAll(Try* tryy, Name originalLabel, Name label) {
- return ScopeCtx(CatchAllScope{tryy, originalLabel}, label);
+ static ScopeCtx
+ makeCatchAll(Try* tryy, Name originalLabel, Name label, Name branchLabel) {
+ return ScopeCtx(CatchAllScope{tryy, originalLabel}, label, branchLabel);
}
static ScopeCtx makeTryTable(TryTable* trytable, Name originalLabel = {}) {
return ScopeCtx(TryTableScope{trytable, originalLabel});
@@ -507,8 +515,11 @@ private:
// `block`, but otherwise we will have to allocate a new block.
Result<Expression*> finishScope(Block* block = nullptr);
- [[nodiscard]] Result<Name> getLabelName(Index label);
- [[nodiscard]] Result<Name> getDelegateLabelName(Index label);
+ [[nodiscard]] Result<Name> getLabelName(Index label,
+ bool forDelegate = false);
+ [[nodiscard]] Result<Name> getDelegateLabelName(Index label) {
+ return getLabelName(label, true);
+ }
[[nodiscard]] Result<Index> addScratchLocal(Type);
struct HoistedVal {
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index 78ce07f8d..ccd2ee77a 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -235,6 +235,10 @@ void IRBuilder::dump() {
std::cerr << " (label: " << scope.label << ")";
}
+ if (scope.branchLabel) {
+ std::cerr << " (branch label: " << scope.branchLabel << ")";
+ }
+
if (scope.unreachable) {
std::cerr << " (unreachable)";
}
@@ -703,9 +707,6 @@ Result<> IRBuilder::visitLoopStart(Loop* loop) {
Result<> IRBuilder::visitTryStart(Try* tryy, Name label) {
applyDebugLoc(tryy);
- // The delegate label will be regenerated if we need it. See
- // `getDelegateLabelName` for details.
- tryy->name = Name();
pushScope(ScopeCtx::makeTry(tryy, label));
return Ok{};
}
@@ -829,6 +830,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
}
auto originalLabel = scope.getOriginalLabel();
auto label = scope.label;
+ auto branchLabel = scope.branchLabel;
auto expr = finishScope();
CHECK_ERR(expr);
if (wasTry) {
@@ -837,7 +839,7 @@ Result<> IRBuilder::visitCatch(Name tag) {
tryy->catchBodies.push_back(*expr);
}
tryy->catchTags.push_back(tag);
- pushScope(ScopeCtx::makeCatch(tryy, originalLabel, label));
+ pushScope(ScopeCtx::makeCatch(tryy, originalLabel, label, branchLabel));
// Push a pop for the exception payload.
auto params = wasm.getTag(tag)->sig.params;
if (params != Type::none) {
@@ -859,6 +861,7 @@ Result<> IRBuilder::visitCatchAll() {
}
auto originalLabel = scope.getOriginalLabel();
auto label = scope.label;
+ auto branchLabel = scope.branchLabel;
auto expr = finishScope();
CHECK_ERR(expr);
if (wasTry) {
@@ -866,37 +869,10 @@ Result<> IRBuilder::visitCatchAll() {
} else {
tryy->catchBodies.push_back(*expr);
}
- pushScope(ScopeCtx::makeCatchAll(tryy, originalLabel, label));
+ pushScope(ScopeCtx::makeCatchAll(tryy, originalLabel, label, branchLabel));
return Ok{};
}
-Result<Name> IRBuilder::getDelegateLabelName(Index label) {
- if (label >= scopeStack.size()) {
- return Err{"invalid label: " + std::to_string(label)};
- }
- auto& scope = scopeStack[scopeStack.size() - label - 1];
- auto* delegateTry = scope.getTry();
- if (!delegateTry) {
- delegateTry = scope.getCatch();
- }
- if (!delegateTry) {
- delegateTry = scope.getCatchAll();
- }
- if (!delegateTry) {
- return Err{"expected try scope at label " + std::to_string(label)};
- }
- // Only delegate and rethrow can reference the try name in Binaryen IR, so
- // trys might need two labels: one for delegate/rethrow and one for all
- // other control flow. These labels must be different to satisfy the
- // Binaryen validator. To keep this complexity contained within the
- // handling of trys and delegates, pretend there is just the single normal
- // label and add a prefix to it to generate the delegate label.
- auto delegateName =
- Name(std::string("__delegate__") + getLabelName(label)->toString());
- delegateTry->name = delegateName;
- return delegateName;
-}
-
Result<> IRBuilder::visitDelegate(Index label) {
auto& scope = getScope();
auto* tryy = scope.getTry();
@@ -946,8 +922,10 @@ Result<> IRBuilder::visitEnd() {
// type of the scope expression.
auto originalScopeType = scope.getResultType();
auto maybeWrapForLabel = [&](Expression* curr) -> Expression* {
- if (scope.label) {
- return builder.makeBlock(scope.label,
+ bool isTry = scope.getTry() || scope.getCatch() || scope.getCatchAll();
+ auto& label = isTry ? scope.branchLabel : scope.label;
+ if (label) {
+ return builder.makeBlock(label,
{curr},
scope.labelUsed ? originalScopeType
: scope.getResultType());
@@ -981,11 +959,13 @@ Result<> IRBuilder::visitEnd() {
push(maybeWrapForLabel(iff));
} else if (auto* tryy = scope.getTry()) {
tryy->body = *expr;
+ tryy->name = scope.label;
tryy->finalize(tryy->type);
push(maybeWrapForLabel(tryy));
} else if (Try * tryy;
(tryy = scope.getCatch()) || (tryy = scope.getCatchAll())) {
tryy->catchBodies.push_back(*expr);
+ tryy->name = scope.label;
tryy->finalize(tryy->type);
push(maybeWrapForLabel(tryy));
} else if (auto* trytable = scope.getTryTable()) {
@@ -1029,10 +1009,17 @@ Result<Index> IRBuilder::getLabelIndex(Name label, bool inDelegate) {
return index;
}
-Result<Name> IRBuilder::getLabelName(Index label) {
+Result<Name> IRBuilder::getLabelName(Index label, bool forDelegate) {
auto scope = getScope(label);
CHECK_ERR(scope);
- auto& scopeLabel = (*scope)->label;
+
+ // For normal branches to try blocks, we need to use the secondary label.
+ bool useTryBranchLabel =
+ !forDelegate &&
+ ((*scope)->getTry() || (*scope)->getCatch() || (*scope)->getCatchAll());
+ auto& scopeLabel =
+ useTryBranchLabel ? (*scope)->branchLabel : (*scope)->label;
+
if (!scopeLabel) {
// The scope does not already have a name, so we need to create one.
if ((*scope)->getBlock()) {
@@ -1041,7 +1028,9 @@ Result<Name> IRBuilder::getLabelName(Index label) {
scopeLabel = makeFresh("label");
}
}
- (*scope)->labelUsed = true;
+ if (!forDelegate) {
+ (*scope)->labelUsed = true;
+ }
return scopeLabel;
}