summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-ir-builder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-ir-builder.cpp')
-rw-r--r--src/wasm/wasm-ir-builder.cpp54
1 files changed, 40 insertions, 14 deletions
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index a95329f7d..5301b75dc 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -499,8 +499,8 @@ Result<> IRBuilder::visitLoopStart(Loop* loop) {
}
Result<> IRBuilder::visitTryStart(Try* tryy, Name label) {
- // The delegate label will be regenerated if we need it. See `visitDelegate`
- // for details.
+ // The delegate label will be regenerated if we need it. See
+ // `getDelegateLabelName` for details.
tryy->name = Name();
pushScope(ScopeCtx::makeTry(tryy, label));
return Ok{};
@@ -663,6 +663,33 @@ Result<> IRBuilder::visitCatchAll() {
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();
@@ -676,17 +703,10 @@ Result<> IRBuilder::visitDelegate(Index label) {
++label;
for (size_t size = scopeStack.size(); label < size; ++label) {
auto& delegateScope = scopeStack[size - label - 1];
- if (auto* delegateTry = delegateScope.getTry()) {
- // Only delegates can reference the try name in Binaryen IR, so trys might
- // need two labels: one for delegates 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;
- tryy->delegateTarget = delegateName;
+ if (delegateScope.getTry()) {
+ auto delegateName = getDelegateLabelName(label);
+ CHECK_ERR(delegateName);
+ tryy->delegateTarget = *delegateName;
break;
} else if (delegateScope.getFunction()) {
tryy->delegateTarget = DELEGATE_CALLER_TARGET;
@@ -1215,7 +1235,13 @@ Result<> IRBuilder::makeThrow(Name tag) {
return Ok{};
}
-// Result<> IRBuilder::makeRethrow() {}
+Result<> IRBuilder::makeRethrow(Index label) {
+ // Rethrow references `Try` labels directly, just like `delegate`.
+ auto name = getDelegateLabelName(label);
+ CHECK_ERR(name);
+ push(builder.makeRethrow(*name));
+ return Ok{};
+}
// Result<> IRBuilder::makeTupleMake() {}