Skip to content

Commit c0e688e

Browse files
authored
[Parser] Parse try_table (#6237)
1 parent 6453fd5 commit c0e688e

File tree

5 files changed

+452
-142
lines changed

5 files changed

+452
-142
lines changed

src/parser/contexts.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ template<typename Ctx> struct TypeParserCtx {
297297

298298
struct NullInstrParserCtx {
299299
using ExprT = Ok;
300+
using CatchT = Ok;
301+
using CatchListT = Ok;
300302

301303
using FieldIdxT = Ok;
302304
using FuncIdxT = Ok;
@@ -362,6 +364,17 @@ struct NullInstrParserCtx {
362364
Result<> visitDelegate(Index, LabelIdxT) { return Ok{}; }
363365
Result<> visitEnd() { return Ok{}; }
364366

367+
CatchListT makeCatchList() { return Ok{}; }
368+
void appendCatch(CatchListT&, CatchT) {}
369+
CatchT makeCatch(TagIdxT, LabelIdxT) { return Ok{}; }
370+
CatchT makeCatchRef(TagIdxT, LabelIdxT) { return Ok{}; }
371+
CatchT makeCatchAll(LabelIdxT) { return Ok{}; }
372+
CatchT makeCatchAllRef(LabelIdxT) { return Ok{}; }
373+
template<typename BlockTypeT>
374+
Result<> makeTryTable(Index, std::optional<Name>, BlockTypeT, CatchListT) {
375+
return Ok{};
376+
}
377+
365378
Result<> makeUnreachable(Index) { return Ok{}; }
366379
Result<> makeNop(Index) { return Ok{}; }
367380
Result<> makeBinary(Index, BinaryOp) { return Ok{}; }
@@ -1023,6 +1036,10 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
10231036
using ExprT = Expression*;
10241037
using ElemListT = std::vector<Expression*>;
10251038

1039+
struct CatchInfo;
1040+
using CatchT = CatchInfo;
1041+
using CatchListT = std::vector<CatchInfo>;
1042+
10261043
using FieldIdxT = Index;
10271044
using FuncIdxT = Name;
10281045
using LocalIdxT = Index;
@@ -1106,6 +1123,21 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
11061123

11071124
TableTypeT makeTableType(LimitsT, Type) { return Ok{}; }
11081125

1126+
struct CatchInfo {
1127+
Name tag;
1128+
Index label;
1129+
bool isRef;
1130+
};
1131+
1132+
std::vector<CatchInfo> makeCatchList() { return {}; }
1133+
void appendCatch(std::vector<CatchInfo>& list, CatchInfo info) {
1134+
list.push_back(info);
1135+
}
1136+
CatchInfo makeCatch(Name tag, Index label) { return {tag, label, false}; }
1137+
CatchInfo makeCatchRef(Name tag, Index label) { return {tag, label, true}; }
1138+
CatchInfo makeCatchAll(Index label) { return {{}, label, false}; }
1139+
CatchInfo makeCatchAllRef(Index label) { return {{}, label, true}; }
1140+
11091141
Result<HeapTypeT> getHeapTypeFromIdx(Index idx) {
11101142
if (idx >= types.size()) {
11111143
return in.err("type index out of bounds");
@@ -1374,6 +1406,26 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
13741406
irBuilder.makeTry(label ? *label : Name{}, type.getSignature().results));
13751407
}
13761408

1409+
Result<> makeTryTable(Index pos,
1410+
std::optional<Name> label,
1411+
HeapType type,
1412+
const std::vector<CatchInfo>& info) {
1413+
std::vector<Name> tags;
1414+
std::vector<Index> labels;
1415+
std::vector<bool> isRefs;
1416+
for (auto& info : info) {
1417+
tags.push_back(info.tag);
1418+
labels.push_back(info.label);
1419+
isRefs.push_back(info.isRef);
1420+
}
1421+
return withLoc(pos,
1422+
irBuilder.makeTryTable(label ? *label : Name{},
1423+
type.getSignature().results,
1424+
tags,
1425+
labels,
1426+
isRefs));
1427+
}
1428+
13771429
Result<> visitCatch(Index pos, Name tag) {
13781430
return withLoc(pos, irBuilder.visitCatch(tag));
13791431
}

src/parser/parsers.h

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ template<typename Ctx> MaybeResult<> block(Ctx&, bool);
6060
template<typename Ctx> MaybeResult<> ifelse(Ctx&, bool);
6161
template<typename Ctx> MaybeResult<> loop(Ctx&, bool);
6262
template<typename Ctx> MaybeResult<> trycatch(Ctx&, bool);
63+
template<typename Ctx> MaybeResult<typename Ctx::CatchT> catchinstr(Ctx&);
64+
template<typename Ctx> MaybeResult<> trytable(Ctx&, bool);
6365
template<typename Ctx> Result<> makeUnreachable(Ctx&, Index);
6466
template<typename Ctx> Result<> makeNop(Ctx&, Index);
6567
template<typename Ctx> Result<> makeBinary(Ctx&, Index, BinaryOp op);
@@ -657,7 +659,7 @@ template<typename Ctx> Result<uint32_t> tupleArity(Ctx& ctx) {
657659
// Instructions
658660
// ============
659661

660-
// blockinstr ::= block | loop | if-else | try-catch
662+
// blockinstr ::= block | loop | if-else | try-catch | try_table
661663
template<typename Ctx> MaybeResult<> foldedBlockinstr(Ctx& ctx) {
662664
if (auto i = block(ctx, true)) {
663665
return i;
@@ -671,7 +673,9 @@ template<typename Ctx> MaybeResult<> foldedBlockinstr(Ctx& ctx) {
671673
if (auto i = trycatch(ctx, true)) {
672674
return i;
673675
}
674-
// TODO: Other block instructions
676+
if (auto i = trytable(ctx, true)) {
677+
return i;
678+
}
675679
return {};
676680
}
677681

@@ -688,7 +692,9 @@ template<typename Ctx> MaybeResult<> unfoldedBlockinstr(Ctx& ctx) {
688692
if (auto i = trycatch(ctx, false)) {
689693
return i;
690694
}
691-
// TODO: Other block instructions
695+
if (auto i = trytable(ctx, false)) {
696+
return i;
697+
}
692698
return {};
693699
}
694700

@@ -1159,6 +1165,81 @@ template<typename Ctx> MaybeResult<> trycatch(Ctx& ctx, bool folded) {
11591165
return ctx.visitEnd();
11601166
}
11611167

1168+
template<typename Ctx> MaybeResult<typename Ctx::CatchT> catchinstr(Ctx& ctx) {
1169+
typename Ctx::CatchT result;
1170+
if (ctx.in.takeSExprStart("catch"sv)) {
1171+
auto tag = tagidx(ctx);
1172+
CHECK_ERR(tag);
1173+
auto label = labelidx(ctx);
1174+
CHECK_ERR(label);
1175+
result = ctx.makeCatch(*tag, *label);
1176+
} else if (ctx.in.takeSExprStart("catch_ref"sv)) {
1177+
auto tag = tagidx(ctx);
1178+
CHECK_ERR(tag);
1179+
auto label = labelidx(ctx);
1180+
CHECK_ERR(label);
1181+
result = ctx.makeCatchRef(*tag, *label);
1182+
} else if (ctx.in.takeSExprStart("catch_all"sv)) {
1183+
auto label = labelidx(ctx);
1184+
CHECK_ERR(label);
1185+
result = ctx.makeCatchAll(*label);
1186+
} else if (ctx.in.takeSExprStart("catch_all_ref"sv)) {
1187+
auto label = labelidx(ctx);
1188+
CHECK_ERR(label);
1189+
result = ctx.makeCatchAllRef(*label);
1190+
} else {
1191+
return {};
1192+
}
1193+
1194+
if (!ctx.in.takeRParen()) {
1195+
return ctx.in.err("expected ')' at end of catch clause");
1196+
}
1197+
1198+
return result;
1199+
}
1200+
1201+
// trytable ::= 'try_table' label blocktype catchinstr* instr* end id?
1202+
// | '(' 'try_table' label blocktype catchinstr* instr* ')'
1203+
template<typename Ctx> MaybeResult<> trytable(Ctx& ctx, bool folded) {
1204+
auto pos = ctx.in.getPos();
1205+
1206+
if ((folded && !ctx.in.takeSExprStart("try_table"sv)) ||
1207+
(!folded && !ctx.in.takeKeyword("try_table"sv))) {
1208+
return {};
1209+
}
1210+
1211+
auto label = ctx.in.takeID();
1212+
1213+
auto type = blocktype(ctx);
1214+
CHECK_ERR(type);
1215+
1216+
auto catches = ctx.makeCatchList();
1217+
while (auto c = catchinstr(ctx)) {
1218+
CHECK_ERR(c);
1219+
ctx.appendCatch(catches, *c);
1220+
}
1221+
1222+
CHECK_ERR(ctx.makeTryTable(pos, label, *type, catches));
1223+
1224+
CHECK_ERR(instrs(ctx));
1225+
1226+
if (folded) {
1227+
if (!ctx.in.takeRParen()) {
1228+
return ctx.in.err("expected ')' at end of try_table");
1229+
}
1230+
} else {
1231+
if (!ctx.in.takeKeyword("end"sv)) {
1232+
return ctx.in.err("expected 'end' at end of try_table");
1233+
}
1234+
1235+
auto id = ctx.in.takeID();
1236+
if (id && id != label) {
1237+
return ctx.in.err("end label does not match try_table label");
1238+
}
1239+
}
1240+
return ctx.visitEnd();
1241+
}
1242+
11621243
template<typename Ctx> Result<> makeUnreachable(Ctx& ctx, Index pos) {
11631244
return ctx.makeUnreachable(pos);
11641245
}

src/wasm-ir-builder.h

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
6565
[[nodiscard]] Result<> visitElse();
6666
[[nodiscard]] Result<> visitLoopStart(Loop* iff);
6767
[[nodiscard]] Result<> visitTryStart(Try* tryy, Name label = {});
68+
[[nodiscard]] Result<> visitTryTableStart(TryTable* trytable,
69+
Name label = {});
6870
[[nodiscard]] Result<> visitCatch(Name tag);
6971
[[nodiscard]] Result<> visitCatchAll();
7072
[[nodiscard]] Result<> visitDelegate(Index label);
@@ -155,7 +157,11 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
155157
[[nodiscard]] Result<> makeTableFill(Name table);
156158
[[nodiscard]] Result<> makeTableCopy(Name destTable, Name srcTable);
157159
[[nodiscard]] Result<> makeTry(Name label, Type type);
158-
// [[nodiscard]] Result<> makeTryTable();
160+
[[nodiscard]] Result<> makeTryTable(Name label,
161+
Type type,
162+
const std::vector<Name>& tags,
163+
const std::vector<Index>& labels,
164+
const std::vector<bool>& isRefs);
159165
[[nodiscard]] Result<> makeThrow(Name tag);
160166
[[nodiscard]] Result<> makeRethrow(Index label);
161167
// [[nodiscard]] Result<> makeThrowRef();
@@ -264,6 +270,10 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
264270
Try* tryy;
265271
Name originalLabel;
266272
};
273+
struct TryTableScope {
274+
TryTable* trytable;
275+
Name originalLabel;
276+
};
267277
using Scope = std::variant<NoScope,
268278
FuncScope,
269279
BlockScope,
@@ -272,7 +282,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
272282
LoopScope,
273283
TryScope,
274284
CatchScope,
275-
CatchAllScope>;
285+
CatchAllScope,
286+
TryTableScope>;
276287

277288
// The control flow structure we are building expressions for.
278289
Scope scope;
@@ -312,6 +323,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
312323
static ScopeCtx makeCatchAll(Try* tryy, Name originalLabel, Name label) {
313324
return ScopeCtx(CatchAllScope{tryy, originalLabel}, label);
314325
}
326+
static ScopeCtx makeTryTable(TryTable* trytable, Name originalLabel = {}) {
327+
return ScopeCtx(TryTableScope{trytable, originalLabel});
328+
}
315329

316330
bool isNone() { return std::get_if<NoScope>(&scope); }
317331
Function* getFunction() {
@@ -362,6 +376,12 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
362376
}
363377
return nullptr;
364378
}
379+
TryTable* getTryTable() {
380+
if (auto* tryTableScope = std::get_if<TryTableScope>(&scope)) {
381+
return tryTableScope->trytable;
382+
}
383+
return nullptr;
384+
}
365385
Type getResultType() {
366386
if (auto* func = getFunction()) {
367387
return func->type.getSignature().results;
@@ -387,6 +407,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
387407
if (auto* tryy = getCatchAll()) {
388408
return tryy->type;
389409
}
410+
if (auto* trytable = getTryTable()) {
411+
return trytable->type;
412+
}
390413
WASM_UNREACHABLE("unexpected scope kind");
391414
}
392415
Name getOriginalLabel() {
@@ -414,6 +437,9 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
414437
if (auto* catchAllScope = std::get_if<CatchAllScope>(&scope)) {
415438
return catchAllScope->originalLabel;
416439
}
440+
if (auto* tryTableScope = std::get_if<TryTableScope>(&scope)) {
441+
return tryTableScope->originalLabel;
442+
}
417443
WASM_UNREACHABLE("unexpected scope kind");
418444
}
419445
};

src/wasm/wasm-ir-builder.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,11 @@ Result<> IRBuilder::visitTryStart(Try* tryy, Name label) {
624624
return Ok{};
625625
}
626626

627+
Result<> IRBuilder::visitTryTableStart(TryTable* trytable, Name label) {
628+
pushScope(ScopeCtx::makeTryTable(trytable, label));
629+
return Ok{};
630+
}
631+
627632
Result<Expression*> IRBuilder::finishScope(Block* block) {
628633
if (scopeStack.empty() || scopeStack.back().isNone()) {
629634
return Err{"unexpected end of scope"};
@@ -895,6 +900,10 @@ Result<> IRBuilder::visitEnd() {
895900
tryy->catchBodies.push_back(*expr);
896901
tryy->finalize(tryy->type);
897902
push(maybeWrapForLabel(tryy));
903+
} else if (auto* trytable = scope.getTryTable()) {
904+
trytable->body = *expr;
905+
trytable->finalize(trytable->type, &wasm);
906+
push(maybeWrapForLabel(trytable));
898907
} else {
899908
WASM_UNREACHABLE("unexpected scope kind");
900909
}
@@ -1347,7 +1356,23 @@ Result<> IRBuilder::makeTry(Name label, Type type) {
13471356
return visitTryStart(tryy, label);
13481357
}
13491358

1350-
// Result<> IRBuilder::makeTryTable() {}
1359+
Result<> IRBuilder::makeTryTable(Name label,
1360+
Type type,
1361+
const std::vector<Name>& tags,
1362+
const std::vector<Index>& labels,
1363+
const std::vector<bool>& isRefs) {
1364+
auto* trytable = wasm.allocator.alloc<TryTable>();
1365+
trytable->type = type;
1366+
trytable->catchTags.set(tags);
1367+
trytable->catchRefs.set(isRefs);
1368+
trytable->catchDests.reserve(labels.size());
1369+
for (auto label : labels) {
1370+
auto name = getLabelName(label);
1371+
CHECK_ERR(name);
1372+
trytable->catchDests.push_back(*name);
1373+
}
1374+
return visitTryTableStart(trytable, label);
1375+
}
13511376

13521377
Result<> IRBuilder::makeThrow(Name tag) {
13531378
Throw curr(wasm.allocator);

0 commit comments

Comments
 (0)