Skip to content

Commit d48529d

Browse files
authored
[Outlining] Add Try/Catch/CatchAll (#7472)
Supports try/catch/catchAll in the stringify of the module. Its contents can now be outlined.
1 parent 3b0ab2c commit d48529d

File tree

7 files changed

+182
-38
lines changed

7 files changed

+182
-38
lines changed

src/passes/Outlining.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,20 @@ struct ReconstructStringifyWalker
137137
} else if (auto curr = reason.getLoopStart()) {
138138
ODBG(desc = "Loop Start at ");
139139
ASSERT_OK(existingBuilder.visitLoopStart(curr->loop));
140+
} else if (auto curr = reason.getTryStart()) {
141+
// We preserve the name of the tryy because IRBuilder expects
142+
// visitTryStart() to be called on an empty Try, during the normal case of
143+
// parsing. TODO: Fix this.
144+
auto name = curr->tryy->name;
145+
ASSERT_OK(existingBuilder.visitTryStart(curr->tryy, Name()));
146+
ODBG(desc = "Try Start at ");
147+
curr->tryy->name = name;
148+
} else if (auto curr = reason.getCatchStart()) {
149+
ASSERT_OK(existingBuilder.visitCatch(curr->tag));
150+
ODBG(desc = "Catch Start at ");
151+
} else if (reason.getCatchAllStart()) {
152+
ASSERT_OK(existingBuilder.visitCatchAll());
153+
ODBG(desc = "Catch All Start at");
140154
} else if (reason.getEnd()) {
141155
ODBG(desc = "End at ");
142156
ASSERT_OK(existingBuilder.visitEnd());

src/passes/stringify-walker-impl.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,18 @@ template<typename SubType> void StringifyWalker<SubType>::dequeueControlFlow() {
9797
}
9898
case Expression::Id::TryId: {
9999
auto* tryy = curr->cast<Try>();
100-
addUniqueSymbol(SeparatorReason::makeTryBodyStart());
100+
101+
addUniqueSymbol(SeparatorReason::makeTryStart(tryy));
101102
Super::walk(tryy->body);
102-
addUniqueSymbol(SeparatorReason::makeEnd());
103-
for (auto& child : tryy->catchBodies) {
104-
addUniqueSymbol(SeparatorReason::makeTryCatchStart());
105-
Super::walk(child);
106-
addUniqueSymbol(SeparatorReason::makeEnd());
103+
for (size_t i = 0; i < tryy->catchBodies.size(); i++) {
104+
if (tryy->hasCatchAll() && i == tryy->catchBodies.size() - 1) {
105+
addUniqueSymbol(SeparatorReason::makeCatchAllStart());
106+
} else {
107+
addUniqueSymbol(SeparatorReason::makeCatchStart(tryy->catchTags[i]));
108+
}
109+
Super::walk(tryy->catchBodies[i]);
107110
}
111+
addUniqueSymbol(SeparatorReason::makeEnd());
108112
break;
109113
}
110114
case Expression::Id::LoopId: {

src/passes/stringify-walker.h

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,15 @@ struct StringifyWalker
8989
Loop* loop;
9090
};
9191

92-
struct TryBodyStart {};
92+
struct TryStart {
93+
Try* tryy;
94+
};
95+
96+
struct CatchStart {
97+
Name tag;
98+
};
9399

94-
struct TryCatchStart {};
100+
struct CatchAllStart {};
95101

96102
struct End {
97103
Expression* curr;
@@ -101,8 +107,9 @@ struct StringifyWalker
101107
IfStart,
102108
ElseStart,
103109
LoopStart,
104-
TryBodyStart,
105-
TryCatchStart,
110+
TryStart,
111+
CatchStart,
112+
CatchAllStart,
106113
End>;
107114

108115
Separator reason;
@@ -124,23 +131,25 @@ struct StringifyWalker
124131
static SeparatorReason makeLoopStart(Loop* loop) {
125132
return SeparatorReason(LoopStart{loop});
126133
}
127-
static SeparatorReason makeTryCatchStart() {
128-
return SeparatorReason(TryCatchStart{});
134+
static SeparatorReason makeTryStart(Try* tryy) {
135+
return SeparatorReason(TryStart{tryy});
129136
}
130-
static SeparatorReason makeTryBodyStart() {
131-
return SeparatorReason(TryBodyStart{});
137+
static SeparatorReason makeCatchStart(Name tag) {
138+
return SeparatorReason(CatchStart{tag});
139+
}
140+
static SeparatorReason makeCatchAllStart() {
141+
return SeparatorReason(CatchAllStart{});
132142
}
133143
static SeparatorReason makeEnd() { return SeparatorReason(End{}); }
134144
FuncStart* getFuncStart() { return std::get_if<FuncStart>(&reason); }
135145
BlockStart* getBlockStart() { return std::get_if<BlockStart>(&reason); }
136146
IfStart* getIfStart() { return std::get_if<IfStart>(&reason); }
137147
ElseStart* getElseStart() { return std::get_if<ElseStart>(&reason); }
138148
LoopStart* getLoopStart() { return std::get_if<LoopStart>(&reason); }
139-
TryBodyStart* getTryBodyStart() {
140-
return std::get_if<TryBodyStart>(&reason);
141-
}
142-
TryCatchStart* getTryCatchStart() {
143-
return std::get_if<TryCatchStart>(&reason);
149+
TryStart* getTryStart() { return std::get_if<TryStart>(&reason); }
150+
CatchStart* getCatchStart() { return std::get_if<CatchStart>(&reason); }
151+
CatchAllStart* getCatchAllStart() {
152+
return std::get_if<CatchAllStart>(&reason);
144153
}
145154
End* getEnd() { return std::get_if<End>(&reason); }
146155
};
@@ -158,10 +167,12 @@ struct StringifyWalker
158167
return o << "Else Start";
159168
} else if (reason.getLoopStart()) {
160169
return o << "Loop Start";
161-
} else if (reason.getTryBodyStart()) {
162-
return o << "Try Body Start";
163-
} else if (reason.getTryCatchStart()) {
164-
return o << "Try Catch Start";
170+
} else if (reason.getTryStart()) {
171+
return o << "Try Start";
172+
} else if (reason.getCatchStart()) {
173+
return o << "Catch Start";
174+
} else if (reason.getCatchAllStart()) {
175+
return o << "Catch All Start";
165176
} else if (reason.getEnd()) {
166177
return o << "End";
167178
}

src/wasm-ir-builder.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,14 +306,17 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
306306
struct TryScope {
307307
Try* tryy;
308308
Name originalLabel;
309+
Index index;
309310
};
310311
struct CatchScope {
311312
Try* tryy;
312313
Name originalLabel;
314+
Index index;
313315
};
314316
struct CatchAllScope {
315317
Try* tryy;
316318
Name originalLabel;
319+
Index index;
317320
};
318321
struct TryTableScope {
319322
TryTable* trytable;
@@ -396,15 +399,17 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
396399
return ScopeCtx(LoopScope{loop}, inputType);
397400
}
398401
static ScopeCtx makeTry(Try* tryy, Name originalLabel, Type inputType) {
399-
return ScopeCtx(TryScope{tryy, originalLabel}, inputType);
402+
return ScopeCtx(TryScope{tryy, originalLabel, 0}, inputType);
400403
}
401404
static ScopeCtx makeCatch(ScopeCtx&& scope, Try* tryy) {
402-
scope.scope = CatchScope{tryy, scope.getOriginalLabel()};
405+
scope.scope =
406+
CatchScope{tryy, scope.getOriginalLabel(), scope.getIndex() + 1};
403407
scope.resetForDelimiter(/*keepInput=*/false);
404408
return scope;
405409
}
406410
static ScopeCtx makeCatchAll(ScopeCtx&& scope, Try* tryy) {
407-
scope.scope = CatchAllScope{tryy, scope.getOriginalLabel()};
411+
scope.scope =
412+
CatchAllScope{tryy, scope.getOriginalLabel(), scope.getIndex() + 1};
408413
scope.resetForDelimiter(/*keepInput=*/false);
409414
return scope;
410415
}
@@ -530,6 +535,18 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
530535
}
531536
WASM_UNREACHABLE("unexpected scope kind");
532537
}
538+
Index getIndex() {
539+
if (auto* tryScope = std::get_if<TryScope>(&scope)) {
540+
return tryScope->index;
541+
}
542+
if (auto* catchScope = std::get_if<CatchScope>(&scope)) {
543+
return catchScope->index;
544+
}
545+
if (auto* catchAllScope = std::get_if<CatchAllScope>(&scope)) {
546+
return catchAllScope->index;
547+
}
548+
WASM_UNREACHABLE("unexpected scope kind");
549+
}
533550
Type getLabelType() {
534551
// Loops receive their input type rather than their output type.
535552
return getLoop() ? inputType : getResultType();

src/wasm/wasm-ir-builder.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,21 @@ Result<> IRBuilder::visitElse() {
931931
return pushScope(ScopeCtx::makeElse(std::move(scope)));
932932
}
933933

934+
void setCatchBody(Try* tryy, Expression* expr, Index index) {
935+
// Indexes are managed manually to support Outlining.
936+
// Its prepopulated try catchBodies and catchTags vectors
937+
// cannot be appended to, as in the case of the empty try
938+
// used during parsing.
939+
if (tryy->catchBodies.size() < index) {
940+
tryy->catchBodies.resize(tryy->catchBodies.size() + 1);
941+
}
942+
// The first time visitCatch is called: the body of the
943+
// try is set and catchBodies is not appended to, but the tag
944+
// for the following catch is appended. So, catchTags uses
945+
// index as-is, but catchBodies uses index-1.
946+
tryy->catchBodies[index - 1] = expr;
947+
}
948+
934949
Result<> IRBuilder::visitCatch(Name tag) {
935950
auto scope = getScope();
936951
bool wasTry = true;
@@ -942,14 +957,18 @@ Result<> IRBuilder::visitCatch(Name tag) {
942957
if (!tryy) {
943958
return Err{"unexpected catch"};
944959
}
960+
auto index = scope.getIndex();
945961
auto expr = finishScope();
946962
CHECK_ERR(expr);
947963
if (wasTry) {
948964
tryy->body = *expr;
949965
} else {
950-
tryy->catchBodies.push_back(*expr);
966+
setCatchBody(tryy, *expr, index);
967+
}
968+
if (tryy->catchTags.size() == index) {
969+
tryy->catchTags.resize(tryy->catchTags.size() + 1);
951970
}
952-
tryy->catchTags.push_back(tag);
971+
tryy->catchTags[index] = tag;
953972

954973
if (binaryPos && func) {
955974
auto& delimiterLocs = func->delimiterLocations[tryy];
@@ -980,12 +999,13 @@ Result<> IRBuilder::visitCatchAll() {
980999
if (!tryy) {
9811000
return Err{"unexpected catch"};
9821001
}
1002+
auto index = scope.getIndex();
9831003
auto expr = finishScope();
9841004
CHECK_ERR(expr);
9851005
if (wasTry) {
9861006
tryy->body = *expr;
9871007
} else {
988-
tryy->catchBodies.push_back(*expr);
1008+
setCatchBody(tryy, *expr, index);
9891009
}
9901010

9911011
if (binaryPos && func) {
@@ -1123,7 +1143,8 @@ Result<> IRBuilder::visitEnd() {
11231143
push(maybeWrapForLabel(tryy));
11241144
} else if (Try * tryy;
11251145
(tryy = scope.getCatch()) || (tryy = scope.getCatchAll())) {
1126-
tryy->catchBodies.push_back(*expr);
1146+
auto index = scope.getIndex();
1147+
setCatchBody(tryy, *expr, index);
11271148
tryy->name = scope.label;
11281149
tryy->finalize(tryy->type);
11291150
push(maybeWrapForLabel(tryy));

test/gtest/stringify.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,16 @@ adding unique symbol for End
9898
adding unique symbol for If Start
9999
in visitExpression for i32.const 30
100100
adding unique symbol for End
101-
adding unique symbol for Try Body Start
101+
adding unique symbol for Try Start
102102
in visitExpression for nop
103-
adding unique symbol for End
104-
adding unique symbol for Try Catch Start
103+
adding unique symbol for Catch Start
105104
in visitExpression for block
106-
adding unique symbol for End
107-
adding unique symbol for Try Catch Start
105+
adding unique symbol for Catch Start
108106
in visitExpression for block
109107
adding unique symbol for End
110-
adding unique symbol for Try Body Start
108+
adding unique symbol for Try Start
111109
in visitExpression for nop
112-
adding unique symbol for End
113-
adding unique symbol for Try Catch Start
110+
adding unique symbol for Catch Start
114111
in visitExpression for block
115112
adding unique symbol for End
116113
adding unique symbol for Block Start

test/lit/passes/outlining.wast

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,3 +1164,83 @@
11641164
)
11651165
)
11661166
)
1167+
1168+
;; Tests that the contents of Catch are outlined
1169+
(module
1170+
;; CHECK: (type $1 (func (result i32)))
1171+
1172+
;; CHECK: (type $0 (func))
1173+
(type $0 (func))
1174+
(type $1 (func (result i32)))
1175+
;; CHECK: (tag $eimport$1 (type $0))
1176+
(tag $eimport$1 (type $0))
1177+
;; CHECK: (func $outline$ (type $1) (result i32)
1178+
;; CHECK-NEXT: (drop
1179+
;; CHECK-NEXT: (i32.const -12)
1180+
;; CHECK-NEXT: )
1181+
;; CHECK-NEXT: (i32.const -2147483647)
1182+
;; CHECK-NEXT: )
1183+
1184+
;; CHECK: (func $a (type $1) (result i32)
1185+
;; CHECK-NEXT: (local $0 externref)
1186+
;; CHECK-NEXT: (try (result i32)
1187+
;; CHECK-NEXT: (do
1188+
;; CHECK-NEXT: (i32.const -20)
1189+
;; CHECK-NEXT: )
1190+
;; CHECK-NEXT: (catch $eimport$1
1191+
;; CHECK-NEXT: (call $outline$)
1192+
;; CHECK-NEXT: )
1193+
;; CHECK-NEXT: (catch_all
1194+
;; CHECK-NEXT: (i32.const -15)
1195+
;; CHECK-NEXT: )
1196+
;; CHECK-NEXT: )
1197+
;; CHECK-NEXT: )
1198+
(func $a (result i32)
1199+
(local $0 externref)
1200+
(try (result i32)
1201+
(do
1202+
(i32.const -20)
1203+
)
1204+
(catch $eimport$1
1205+
(drop
1206+
(i32.const -12)
1207+
)
1208+
(i32.const -2147483647)
1209+
)
1210+
(catch_all
1211+
(i32.const -15)
1212+
)
1213+
)
1214+
)
1215+
;; CHECK: (func $b (type $1) (result i32)
1216+
;; CHECK-NEXT: (local $0 externref)
1217+
;; CHECK-NEXT: (try (result i32)
1218+
;; CHECK-NEXT: (do
1219+
;; CHECK-NEXT: (i32.const -20)
1220+
;; CHECK-NEXT: )
1221+
;; CHECK-NEXT: (catch $eimport$1
1222+
;; CHECK-NEXT: (call $outline$)
1223+
;; CHECK-NEXT: )
1224+
;; CHECK-NEXT: (catch_all
1225+
;; CHECK-NEXT: (i32.const -15)
1226+
;; CHECK-NEXT: )
1227+
;; CHECK-NEXT: )
1228+
;; CHECK-NEXT: )
1229+
(func $b (result i32)
1230+
(local $0 externref)
1231+
(try (result i32)
1232+
(do
1233+
(i32.const -20)
1234+
)
1235+
(catch $eimport$1
1236+
(drop
1237+
(i32.const -12)
1238+
)
1239+
(i32.const -2147483647)
1240+
)
1241+
(catch_all
1242+
(i32.const -15)
1243+
)
1244+
)
1245+
)
1246+
)

0 commit comments

Comments
 (0)