Skip to content

Commit b4dee3d

Browse files
authored
Typed continuations: resume instructions (#6083)
This PR is part of a series that adds basic support for the [typed continuations proposal](https://github.com/wasmfx/specfx). This particular PR adds support for the `resume` instruction. The most notable missing feature is validation, which is not implemented, yet.
1 parent e5948a9 commit b4dee3d

27 files changed

+489
-0
lines changed

scripts/fuzz_opt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ def is_git_repo():
315315
'multi-memory-lowering-import-error.wast',
316316
# the fuzzer does not support typed continuations
317317
'typed_continuations.wast',
318+
'typed_continuations_resume.wast',
318319
# New EH implementation is in progress
319320
'exception-handling.wast',
320321
]

scripts/gen-s-parser.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,8 @@
566566
# Typed function references instructions
567567
("call_ref", "makeCallRef(s, /*isReturn=*/false)"),
568568
("return_call_ref", "makeCallRef(s, /*isReturn=*/true)"),
569+
# Typed continuations instructions
570+
("resume", "makeResume(s)"),
569571
# GC
570572
("i31.new", "makeRefI31(s)"), # deprecated
571573
("ref.i31", "makeRefI31(s)"),

src/gen-s-parser.inc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,6 +3004,9 @@ switch (buf[0]) {
30043004
default: goto parse_error;
30053005
}
30063006
}
3007+
case 's':
3008+
if (op == "resume"sv) { return makeResume(s); }
3009+
goto parse_error;
30073010
case 't': {
30083011
switch (buf[3]) {
30093012
case 'h':
@@ -8104,6 +8107,12 @@ switch (buf[0]) {
81048107
default: goto parse_error;
81058108
}
81068109
}
8110+
case 's':
8111+
if (op == "resume"sv) {
8112+
CHECK_ERR(makeResume(ctx, pos));
8113+
return Ok{};
8114+
}
8115+
goto parse_error;
81078116
case 't': {
81088117
switch (buf[3]) {
81098118
case 'h':

src/ir/ReFinalize.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ void ReFinalize::visitStringSliceIter(StringSliceIter* curr) {
182182
curr->finalize();
183183
}
184184

185+
void ReFinalize::visitResume(Resume* curr) { curr->finalize(); }
186+
185187
void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
186188
void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
187189
void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); }

src/ir/branch-utils.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ void operateOnScopeNameUsesAndSentTypes(Expression* expr, T func) {
8282
func(name, tt->sentTypes[i]);
8383
}
8484
}
85+
} else if (auto* r = expr->dynCast<Resume>()) {
86+
for (Index i = 0; i < r->handlerTags.size(); i++) {
87+
auto dest = r->handlerTags[i];
88+
if (dest == name) {
89+
func(name, r->sentTypes[i]);
90+
}
91+
}
8592
} else {
8693
assert(expr->is<Try>() || expr->is<Rethrow>()); // delegate or rethrow
8794
}
@@ -106,6 +113,10 @@ void operateOnScopeNameUsesAndSentValues(Expression* expr, T func) {
106113
// The values are supplied by throwing instructions, so we are unable to
107114
// know what they will be here.
108115
func(name, nullptr);
116+
} else if (auto* res = expr->dynCast<Resume>()) {
117+
// The values are supplied by suspend instructions executed while running
118+
// the continuation, so we are unable to know what they will be here.
119+
func(name, nullptr);
109120
} else {
110121
assert(expr->is<Try>() || expr->is<Rethrow>()); // delegate or rethrow
111122
}

src/ir/cost.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,11 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
726726
return 8 + visit(curr->ref) + visit(curr->num);
727727
}
728728

729+
CostType visitResume(Resume* curr) {
730+
// Inspired by indirect calls, but twice the cost.
731+
return 12 + visit(curr->cont);
732+
}
733+
729734
private:
730735
CostType nullCheckCost(Expression* ref) {
731736
// A nullable type requires a bounds check in most VMs.

src/ir/effects.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,19 @@ class EffectAnalyzer {
973973
// traps when ref is null.
974974
parent.implicitTrap = true;
975975
}
976+
977+
void visitResume(Resume* curr) {
978+
// This acts as a kitchen sink effect.
979+
parent.calls = true;
980+
981+
// resume instructions accept nullable continuation references and trap
982+
// on null.
983+
parent.implicitTrap = true;
984+
985+
if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) {
986+
parent.throws_ = true;
987+
}
988+
}
976989
};
977990

978991
public:

src/ir/module-utils.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ struct CodeScanner
341341
counts.include(get->type);
342342
} else if (auto* set = curr->dynCast<ArraySet>()) {
343343
counts.note(set->ref->type);
344+
} else if (auto* resume = curr->dynCast<Resume>()) {
345+
counts.note(resume->contType);
344346
} else if (Properties::isControlFlowStructure(curr)) {
345347
counts.noteControlFlow(Signature(Type::none, curr->type));
346348
}

src/ir/possible-contents.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,11 @@ struct InfoCollector
11991199

12001200
void visitReturn(Return* curr) { addResult(curr->value); }
12011201

1202+
void visitResume(Resume* curr) {
1203+
// TODO: optimize when possible
1204+
addRoot(curr);
1205+
}
1206+
12021207
void visitFunction(Function* func) {
12031208
// Functions with a result can flow a value out from their body.
12041209
addResult(func->body);

src/ir/subtype-exprs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
333333
void visitStringIterMove(StringIterMove* curr) {}
334334
void visitStringSliceWTF(StringSliceWTF* curr) {}
335335
void visitStringSliceIter(StringSliceIter* curr) {}
336+
337+
void visitResume(Resume* curr) { WASM_UNREACHABLE("not implemented"); }
336338
};
337339

338340
} // namespace wasm

0 commit comments

Comments
 (0)