summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/fuzz_opt.py1
-rwxr-xr-xscripts/gen-s-parser.py1
-rw-r--r--src/gen-s-parser.inc9
-rw-r--r--src/ir/ReFinalize.cpp1
-rw-r--r--src/ir/cost.h13
-rw-r--r--src/ir/effects.h8
-rw-r--r--src/ir/possible-contents.cpp4
-rw-r--r--src/ir/subtype-exprs.h1
-rw-r--r--src/parser/contexts.h8
-rw-r--r--src/parser/parsers.h11
-rw-r--r--src/passes/Print.cpp5
-rw-r--r--src/passes/TypeGeneralizing.cpp1
-rw-r--r--src/wasm-binary.h2
-rw-r--r--src/wasm-builder.h7
-rw-r--r--src/wasm-delegations-fields.def7
-rw-r--r--src/wasm-delegations.def1
-rw-r--r--src/wasm-interpreter.h2
-rw-r--r--src/wasm-ir-builder.h2
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm.h14
-rw-r--r--src/wasm/wasm-binary.cpp24
-rw-r--r--src/wasm/wasm-ir-builder.cpp23
-rw-r--r--src/wasm/wasm-s-parser.cpp14
-rw-r--r--src/wasm/wasm-stack.cpp4
-rw-r--r--src/wasm/wasm-validator.cpp9
-rw-r--r--src/wasm/wasm.cpp33
-rw-r--r--src/wasm2js.h4
-rw-r--r--test/lit/basic/typed_continuations_suspend.wast49
-rw-r--r--test/lit/wat-kitchen-sink.wast44
29 files changed, 281 insertions, 22 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index 8bef4e98c..3cf711e7b 100755
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -328,6 +328,7 @@ INITIAL_CONTENTS_IGNORE = [
'typed_continuations_resume.wast',
'typed_continuations_contnew.wast',
'typed_continuations_contbind.wast',
+ 'typed_continuations_suspend.wast',
# New EH implementation is in progress
'exception-handling.wast',
'translate-eh-old-to-new.wast',
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py
index b2cac2b89..3f632c004 100755
--- a/scripts/gen-s-parser.py
+++ b/scripts/gen-s-parser.py
@@ -570,6 +570,7 @@ instructions = [
("cont.new", "makeContNew(s)"),
("cont.bind", "makeContBind(s)"),
("resume", "makeResume(s)"),
+ ("suspend", "makeSuspend(s)"),
# GC
("i31.new", "makeRefI31(s)"), # deprecated
("ref.i31", "makeRefI31(s)"),
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index 8f13750d4..939031020 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -3369,6 +3369,9 @@ switch (buf[0]) {
default: goto parse_error;
}
}
+ case 'u':
+ if (op == "suspend"sv) { return makeSuspend(s); }
+ goto parse_error;
default: goto parse_error;
}
}
@@ -8653,6 +8656,12 @@ switch (buf[0]) {
default: goto parse_error;
}
}
+ case 'u':
+ if (op == "suspend"sv) {
+ CHECK_ERR(makeSuspend(ctx, pos, annotations));
+ return Ok{};
+ }
+ goto parse_error;
default: goto parse_error;
}
}
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index 6d872056a..c8f83f1ba 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -185,6 +185,7 @@ void ReFinalize::visitStringSliceIter(StringSliceIter* curr) {
void ReFinalize::visitContNew(ContNew* curr) { curr->finalize(); }
void ReFinalize::visitContBind(ContBind* curr) { curr->finalize(); }
void ReFinalize::visitResume(Resume* curr) { curr->finalize(); }
+void ReFinalize::visitSuspend(Suspend* curr) { curr->finalize(getModule()); }
void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
diff --git a/src/ir/cost.h b/src/ir/cost.h
index d66c97282..edb39546d 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -742,7 +742,18 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
}
CostType visitResume(Resume* curr) {
// Inspired by indirect calls, but twice the cost.
- return 12 + visit(curr->cont);
+ CostType ret = 12 + visit(curr->cont);
+ for (auto* arg : curr->operands) {
+ ret += visit(arg);
+ }
+ return ret;
+ }
+ CostType visitSuspend(Suspend* curr) {
+ CostType ret = 12;
+ for (auto* arg : curr->operands) {
+ ret += visit(arg);
+ }
+ return ret;
}
private:
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 0b3d2a4af..6901f99de 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -994,6 +994,14 @@ private:
parent.throws_ = true;
}
}
+ void visitSuspend(Suspend* curr) {
+ // Similar to resume/call: Suspending means that we execute arbitrary
+ // other code before we may resume here.
+ parent.calls = true;
+ if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) {
+ parent.throws_ = true;
+ }
+ }
};
public:
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index 44015c113..c80ada95c 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -1212,6 +1212,10 @@ struct InfoCollector
// TODO: optimize when possible
addRoot(curr);
}
+ void visitSuspend(Suspend* curr) {
+ // TODO: optimize when possible
+ addRoot(curr);
+ }
void visitFunction(Function* func) {
// Functions with a result can flow a value out from their body.
diff --git a/src/ir/subtype-exprs.h b/src/ir/subtype-exprs.h
index 553c1497b..1457e1ef5 100644
--- a/src/ir/subtype-exprs.h
+++ b/src/ir/subtype-exprs.h
@@ -394,6 +394,7 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
void visitContBind(ContBind* curr) { WASM_UNREACHABLE("not implemented"); }
void visitContNew(ContNew* curr) { WASM_UNREACHABLE("not implemented"); }
void visitResume(Resume* curr) { WASM_UNREACHABLE("not implemented"); }
+ void visitSuspend(Suspend* curr) { WASM_UNREACHABLE("not implemented"); }
};
} // namespace wasm
diff --git a/src/parser/contexts.h b/src/parser/contexts.h
index e79330871..8b59ab40b 100644
--- a/src/parser/contexts.h
+++ b/src/parser/contexts.h
@@ -824,6 +824,9 @@ struct NullInstrParserCtx {
const TagLabelListT&) {
return Ok{};
}
+ Result<> makeSuspend(Index, const std::vector<Annotation>&, TagIdxT) {
+ return Ok{};
+ }
};
struct NullCtx : NullTypeParserCtx, NullInstrParserCtx {
@@ -2594,6 +2597,11 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
}
return withLoc(pos, irBuilder.makeResume(type, tags, labels));
}
+
+ Result<>
+ makeSuspend(Index pos, const std::vector<Annotation>& annotations, Name tag) {
+ return withLoc(pos, irBuilder.makeSuspend(tag));
+ }
};
} // namespace wasm::WATParser
diff --git a/src/parser/parsers.h b/src/parser/parsers.h
index 0150af811..51b5d8f9e 100644
--- a/src/parser/parsers.h
+++ b/src/parser/parsers.h
@@ -309,6 +309,8 @@ template<typename Ctx>
Result<> makeContNew(Ctx*, Index, const std::vector<Annotation>&);
template<typename Ctx>
Result<> makeResume(Ctx&, Index, const std::vector<Annotation>&);
+template<typename Ctx>
+Result<> makeSuspend(Ctx&, Index, const std::vector<Annotation>&);
// Modules
template<typename Ctx> MaybeResult<Index> maybeTypeidx(Ctx& ctx);
@@ -2498,6 +2500,15 @@ makeResume(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
return ctx.makeResume(pos, annotations, *type, tagLabels);
}
+template<typename Ctx>
+Result<>
+makeSuspend(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {
+ auto tag = tagidx(ctx);
+ CHECK_ERR(tag);
+
+ return ctx.makeSuspend(pos, annotations, *tag);
+}
+
// =======
// Modules
// =======
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index a9354defa..643f1cc3f 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2382,6 +2382,11 @@ struct PrintExpressionContents
o << ')';
}
}
+
+ void visitSuspend(Suspend* curr) {
+ printMedium(o, "suspend ");
+ curr->tag.print(o);
+ }
};
void PrintSExpression::setModule(Module* module) {
diff --git a/src/passes/TypeGeneralizing.cpp b/src/passes/TypeGeneralizing.cpp
index 10dfe8737..26a0f1eab 100644
--- a/src/passes/TypeGeneralizing.cpp
+++ b/src/passes/TypeGeneralizing.cpp
@@ -878,6 +878,7 @@ struct TransferFn : OverriddenVisitor<TransferFn> {
void visitContBind(ContBind* curr) { WASM_UNREACHABLE("TODO"); }
void visitContNew(ContNew* curr) { WASM_UNREACHABLE("TODO"); }
void visitResume(Resume* curr) { WASM_UNREACHABLE("TODO"); }
+ void visitSuspend(Suspend* curr) { WASM_UNREACHABLE("TODO"); }
};
struct TypeGeneralizing : WalkerPass<PostWalker<TypeGeneralizing>> {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 16e7945c5..f8463f3b1 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1179,6 +1179,7 @@ enum ASTNodes {
// typed continuation opcodes
ContNew = 0xe0,
ContBind = 0xe1,
+ Suspend = 0xe2,
Resume = 0xe3,
};
@@ -1810,6 +1811,7 @@ public:
void visitContNew(ContNew* curr);
void visitContBind(ContBind* curr);
void visitResume(Resume* curr);
+ void visitSuspend(Suspend* curr);
[[noreturn]] void throwError(std::string text);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index eb1874c3b..7d4991d9a 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -1231,6 +1231,13 @@ public:
ret->finalize(&wasm);
return ret;
}
+ Suspend* makeSuspend(Name tag, const std::vector<Expression*>& args) {
+ auto* ret = wasm.allocator.alloc<Suspend>();
+ ret->tag = tag;
+ ret->operands.set(args);
+ ret->finalize(&wasm);
+ return ret;
+ }
// Additional helpers
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index ac0256cf2..02674e8b2 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -973,6 +973,13 @@ switch (DELEGATE_ID) {
DELEGATE_END(Resume);
break;
}
+ case Expression::Id::SuspendId: {
+ DELEGATE_START(Suspend);
+ DELEGATE_FIELD_CHILD_VECTOR(Suspend, operands);
+ DELEGATE_FIELD_NAME_KIND(Suspend, tag, ModuleItemKind::Tag);
+ DELEGATE_END(Suspend);
+ break;
+ }
}
#undef DELEGATE_ID
diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def
index c07a78f8b..ca07356b9 100644
--- a/src/wasm-delegations.def
+++ b/src/wasm-delegations.def
@@ -108,5 +108,6 @@ DELEGATE(StringSliceIter);
DELEGATE(ContBind);
DELEGATE(ContNew);
DELEGATE(Resume);
+DELEGATE(Suspend);
#undef DELEGATE
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 5179d6ad0..b9b12bc35 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -2488,6 +2488,7 @@ public:
Flow visitContBind(ContBind* curr) { WASM_UNREACHABLE("unimplemented"); }
Flow visitContNew(ContNew* curr) { WASM_UNREACHABLE("unimplemented"); }
Flow visitResume(Resume* curr) { WASM_UNREACHABLE("unimplemented"); }
+ Flow visitSuspend(Suspend* curr) { WASM_UNREACHABLE("unimplemented"); }
void trap(const char* why) override { throw NonconstantException(); }
@@ -4064,6 +4065,7 @@ public:
Flow visitContBind(ContBind* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitContNew(ContNew* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitResume(Resume* curr) { return Flow(NONCONSTANT_FLOW); }
+ Flow visitSuspend(Suspend* curr) { return Flow(NONCONSTANT_FLOW); }
void trap(const char* why) override { externalInterface->trap(why); }
diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h
index 917080fc4..7c4c4a36d 100644
--- a/src/wasm-ir-builder.h
+++ b/src/wasm-ir-builder.h
@@ -216,6 +216,7 @@ public:
[[nodiscard]] Result<> makeResume(HeapType ct,
const std::vector<Name>& tags,
const std::vector<Index>& labels);
+ [[nodiscard]] Result<> makeSuspend(Name tag);
// Private functions that must be public for technical reasons.
[[nodiscard]] Result<> visitExpression(Expression*);
@@ -256,6 +257,7 @@ public:
[[nodiscard]] Result<> visitStringEncode(StringEncode*);
[[nodiscard]] Result<> visitContBind(ContBind*);
[[nodiscard]] Result<> visitResume(Resume*);
+ [[nodiscard]] Result<> visitSuspend(Suspend*);
[[nodiscard]] Result<> visitTupleMake(TupleMake*);
[[nodiscard]] Result<>
visitTupleExtract(TupleExtract*,
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index e1d9dab47..7b8faa16b 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -331,6 +331,7 @@ private:
Expression* makeContBind(Element& s);
Expression* makeContNew(Element& s);
Expression* makeResume(Element& s);
+ Expression* makeSuspend(Element& s);
// Helper functions
Type parseBlockType(Element& s, Index& i);
diff --git a/src/wasm.h b/src/wasm.h
index ad7ccb3ad..d852950e8 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -746,6 +746,7 @@ public:
ContBindId,
ContNewId,
ResumeId,
+ SuspendId,
NumExpressionIds
};
Id _id;
@@ -2048,6 +2049,19 @@ public:
ArenaVector<Type> sentTypes;
};
+class Suspend : public SpecificExpression<Expression::SuspendId> {
+public:
+ Suspend(MixedArena& allocator) : operands(allocator) {}
+
+ Name tag;
+ ExpressionList operands;
+
+ // We need access to the module to obtain the signature of the tag,
+ // which determines this node's type.
+ // If no module is given, then the type must have been set already.
+ void finalize(Module* wasm = nullptr);
+};
+
// Globals
struct Named {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index efb65bb50..55cdd726c 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -4060,6 +4060,10 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) {
visitResume((curr = allocator.alloc<Resume>())->cast<Resume>());
break;
}
+ case BinaryConsts::Suspend: {
+ visitSuspend((curr = allocator.alloc<Suspend>())->cast<Suspend>());
+ break;
+ }
case BinaryConsts::AtomicPrefix: {
code = static_cast<uint8_t>(getU32LEB());
if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) {
@@ -7869,6 +7873,26 @@ void WasmBinaryReader::visitResume(Resume* curr) {
curr->finalize(&wasm);
}
+void WasmBinaryReader::visitSuspend(Suspend* curr) {
+ BYN_TRACE("zz node: Suspend\n");
+
+ auto tagIndex = getU32LEB();
+ if (tagIndex >= wasm.tags.size()) {
+ throwError("bad tag index");
+ }
+ auto* tag = wasm.tags[tagIndex].get();
+ curr->tag = tag->name;
+ tagRefs[tagIndex].push_back(&curr->tag);
+
+ auto numArgs = tag->sig.params.size();
+ curr->operands.resize(numArgs);
+ for (size_t i = 0; i < numArgs; i++) {
+ curr->operands[numArgs - i - 1] = popNonVoidExpression();
+ }
+
+ curr->finalize(&wasm);
+}
+
void WasmBinaryReader::throwError(std::string text) {
throw ParseException(text, 0, pos);
}
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index 4bc80d25c..99462e9a8 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -658,6 +658,19 @@ Result<> IRBuilder::visitResume(Resume* curr) {
return Ok{};
}
+Result<> IRBuilder::visitSuspend(Suspend* curr) {
+ auto tag = wasm.getTag(curr->tag);
+ auto sig = tag->sig;
+ auto size = sig.params.size();
+ curr->operands.resize(size);
+ for (size_t i = 0; i < size; ++i) {
+ auto val = pop();
+ CHECK_ERR(val);
+ curr->operands[size - i - 1] = *val;
+ }
+ return Ok{};
+}
+
Result<> IRBuilder::visitTupleMake(TupleMake* curr) {
assert(curr->operands.size() >= 2);
for (size_t i = 0, size = curr->operands.size(); i < size; ++i) {
@@ -1930,4 +1943,14 @@ Result<> IRBuilder::makeResume(HeapType ct,
return Ok{};
}
+Result<> IRBuilder::makeSuspend(Name tag) {
+ Suspend curr(wasm.allocator);
+ curr.tag = tag;
+ CHECK_ERR(visitSuspend(&curr));
+
+ std::vector<Expression*> operands(curr.operands.begin(), curr.operands.end());
+ push(builder.makeSuspend(tag, operands));
+ return Ok{};
+}
+
} // namespace wasm
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 44ba84351..2d4f3fffe 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -3059,6 +3059,20 @@ Expression* SExpressionWasmBuilder::makeResume(Element& s) {
return ret;
}
+Expression* SExpressionWasmBuilder::makeSuspend(Element& s) {
+ auto ret = allocator.alloc<Suspend>();
+
+ ret->tag = getTagName(*s[1]);
+
+ Index i = 2;
+ while (i < s.size()) {
+ ret->operands.push_back(parseExpression(s[i++]));
+ }
+
+ ret->finalize(&wasm);
+ return ret;
+}
+
Expression* SExpressionWasmBuilder::makeRefI31(Element& s) {
auto ret = allocator.alloc<RefI31>();
ret->value = parseExpression(s[1]);
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 90d5a3768..31742681d 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2512,6 +2512,10 @@ void BinaryInstWriter::visitResume(Resume* curr) {
}
}
+void BinaryInstWriter::visitSuspend(Suspend* curr) {
+ o << int8_t(BinaryConsts::Suspend) << U32LEB(parent.getTagIndex(curr->tag));
+}
+
void BinaryInstWriter::emitScopeEnd(Expression* curr) {
assert(!breakStack.empty());
breakStack.pop_back();
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 4bb556160..0b60aed5c 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -490,6 +490,7 @@ public:
void visitContBind(ContBind* curr);
void visitContNew(ContNew* curr);
void visitResume(Resume* curr);
+ void visitSuspend(Suspend* curr);
void visitFunction(Function* curr);
@@ -3345,6 +3346,14 @@ void FunctionValidator::visitResume(Resume* curr) {
"invalid type in Resume expression");
}
+void FunctionValidator::visitSuspend(Suspend* curr) {
+ // TODO implement actual type-checking
+ shouldBeTrue(
+ !getModule() || getModule()->features.hasTypedContinuations(),
+ curr,
+ "suspend requires typed-continuations [--enable-typed-continuations]");
+}
+
void FunctionValidator::visitFunction(Function* curr) {
FeatureSet features;
// Check for things like having a rec group with GC enabled. The type we're
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 7147f2c3d..bc707890c 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1360,9 +1360,21 @@ void StringSliceIter::finalize() {
}
}
-void ContBind::finalize() { type = Type(contTypeAfter, NonNullable); }
+void ContBind::finalize() {
+ if (cont->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else if (!handleUnreachableOperands(this)) {
+ type = Type(contTypeAfter, NonNullable);
+ }
+}
-void ContNew::finalize() { type = Type(contType, NonNullable); }
+void ContNew::finalize() {
+ if (func->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type(contType, NonNullable);
+ }
+}
static void populateResumeSentTypes(Resume* curr, Module* wasm) {
if (!wasm) {
@@ -1406,13 +1418,24 @@ static void populateResumeSentTypes(Resume* curr, Module* wasm) {
}
void Resume::finalize(Module* wasm) {
- const Signature& contSig =
- this->contType.getContinuation().type.getSignature();
- type = contSig.results;
+ if (cont->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else if (!handleUnreachableOperands(this)) {
+ const Signature& contSig =
+ this->contType.getContinuation().type.getSignature();
+ type = contSig.results;
+ }
populateResumeSentTypes(this, wasm);
}
+void Suspend::finalize(Module* wasm) {
+ if (!handleUnreachableOperands(this) && wasm) {
+ auto tag = wasm->getTag(this->tag);
+ type = tag->sig.results;
+ }
+}
+
size_t Function::getNumParams() { return getParams().size(); }
size_t Function::getNumVars() { return vars.size(); }
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 5f0305877..3ac4d2b4d 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -2440,6 +2440,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
+ Ref visitSuspend(Suspend* curr) {
+ unimplemented(curr);
+ WASM_UNREACHABLE("unimp");
+ }
private:
Ref makePointer(Expression* ptr, Address offset) {
diff --git a/test/lit/basic/typed_continuations_suspend.wast b/test/lit/basic/typed_continuations_suspend.wast
new file mode 100644
index 000000000..62a09c213
--- /dev/null
+++ b/test/lit/basic/typed_continuations_suspend.wast
@@ -0,0 +1,49 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+
+;; RUN: wasm-opt %s -all -o %t.text.wast -g -S
+;; RUN: wasm-as %s -all -g -o %t.wasm
+;; RUN: wasm-dis %t.wasm -all -o %t.bin.wast
+;; RUN: wasm-as %s -all -o %t.nodebug.wasm
+;; RUN: wasm-dis %t.nodebug.wasm -all -o %t.bin.nodebug.wast
+;; RUN: cat %t.text.wast | filecheck %s --check-prefix=CHECK-TEXT
+;; RUN: cat %t.bin.wast | filecheck %s --check-prefix=CHECK-BIN
+;; RUN: cat %t.bin.nodebug.wast | filecheck %s --check-prefix=CHECK-BIN-NODEBUG
+
+(module
+ ;; CHECK-TEXT: (type $0 (func (param i32) (result i64)))
+
+ ;; CHECK-TEXT: (type $1 (func (result i64)))
+
+ ;; CHECK-TEXT: (tag $t (param i32) (result i64))
+ ;; CHECK-BIN: (type $0 (func (param i32) (result i64)))
+
+ ;; CHECK-BIN: (type $1 (func (result i64)))
+
+ ;; CHECK-BIN: (tag $t (param i32) (result i64))
+ (tag $t (param i32) (result i64))
+
+ ;; CHECK-TEXT: (func $f (type $1) (result i64)
+ ;; CHECK-TEXT-NEXT: (suspend $t
+ ;; CHECK-TEXT-NEXT: (i32.const 123)
+ ;; CHECK-TEXT-NEXT: )
+ ;; CHECK-TEXT-NEXT: )
+ ;; CHECK-BIN: (func $f (type $1) (result i64)
+ ;; CHECK-BIN-NEXT: (suspend $t
+ ;; CHECK-BIN-NEXT: (i32.const 123)
+ ;; CHECK-BIN-NEXT: )
+ ;; CHECK-BIN-NEXT: )
+ (func $f (result i64)
+ (suspend $t (i32.const 123))
+ )
+)
+;; CHECK-BIN-NODEBUG: (type $0 (func (param i32) (result i64)))
+
+;; CHECK-BIN-NODEBUG: (type $1 (func (result i64)))
+
+;; CHECK-BIN-NODEBUG: (tag $tag$0 (param i32) (result i64))
+
+;; CHECK-BIN-NODEBUG: (func $0 (type $1) (result i64)
+;; CHECK-BIN-NODEBUG-NEXT: (suspend $tag$0
+;; CHECK-BIN-NODEBUG-NEXT: (i32.const 123)
+;; CHECK-BIN-NODEBUG-NEXT: )
+;; CHECK-BIN-NODEBUG-NEXT: )
diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast
index af9ce7ff0..c56523af1 100644
--- a/test/lit/wat-kitchen-sink.wast
+++ b/test/lit/wat-kitchen-sink.wast
@@ -13,9 +13,9 @@
(type $ret2 (func (result i32 i32)))
(rec
- ;; CHECK: (type $pair (struct (field $first (mut i32)) (field $second (mut i64))))
+ ;; CHECK: (type $3 (func (result i32 i64)))
- ;; CHECK: (type $4 (func (result i32 i64)))
+ ;; CHECK: (type $pair (struct (field $first (mut i32)) (field $second (mut i64))))
;; CHECK: (type $5 (func (param i32 i64)))
@@ -315,7 +315,7 @@
;; CHECK: (import "mod" "f5" (func $fimport$0 (type $void)))
- ;; CHECK: (import "mod" "imported-f" (func $fimport$1 (type $4) (result i32 i64)))
+ ;; CHECK: (import "mod" "imported-f" (func $fimport$1 (type $3) (result i32 i64)))
;; CHECK: (import "mod" "t0" (tag $imported (param i32 i64)))
@@ -1874,8 +1874,8 @@
end
)
- ;; CHECK: (func $try-catch-params (type $4) (result i32 i64)
- ;; CHECK-NEXT: (try (type $4) (result i32 i64)
+ ;; CHECK: (func $try-catch-params (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (try (type $3) (result i32 i64)
;; CHECK-NEXT: (do
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
@@ -1895,8 +1895,8 @@
end
)
- ;; CHECK: (func $try-catch-pop (type $4) (result i32 i64)
- ;; CHECK-NEXT: (try (type $4) (result i32 i64)
+ ;; CHECK: (func $try-catch-pop (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (try (type $3) (result i32 i64)
;; CHECK-NEXT: (do
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
@@ -2754,8 +2754,8 @@
br 0
)
- ;; CHECK: (func $br-multivalue (type $4) (result i32 i64)
- ;; CHECK-NEXT: (block $label (type $4) (result i32 i64)
+ ;; CHECK: (func $br-multivalue (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (block $label (type $3) (result i32 i64)
;; CHECK-NEXT: (br $label
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
@@ -2770,9 +2770,9 @@
br 0
)
- ;; CHECK: (func $br-multivalue-drop (type $4) (result i32 i64)
- ;; CHECK-NEXT: (block $label (type $4) (result i32 i64)
- ;; CHECK-NEXT: (block (type $4) (result i32 i64)
+ ;; CHECK: (func $br-multivalue-drop (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (block $label (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (block (type $3) (result i32 i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (f32.const 0)
;; CHECK-NEXT: )
@@ -2972,9 +2972,9 @@
end
)
- ;; CHECK: (func $br-table-multivalue (type $4) (result i32 i64)
- ;; CHECK-NEXT: (block $a (type $4) (result i32 i64)
- ;; CHECK-NEXT: (block $b (type $4) (result i32 i64)
+ ;; CHECK: (func $br-table-multivalue (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (block $a (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (block $b (type $3) (result i32 i64)
;; CHECK-NEXT: (br_table $a $b
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 42)
@@ -3662,7 +3662,7 @@
return
)
- ;; CHECK: (func $return-multivalue (type $4) (result i32 i64)
+ ;; CHECK: (func $return-multivalue (type $3) (result i32 i64)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (call $return-multivalue)
;; CHECK-NEXT: )
@@ -5141,6 +5141,18 @@
cont.bind $cont-bind-before $simple-cont
)
+ ;; CHECK: (func $suspend (type $3) (result i32 i64)
+ ;; CHECK-NEXT: (suspend $tag-pair-to-pair
+ ;; CHECK-NEXT: (i32.const 123)
+ ;; CHECK-NEXT: (i64.const 456)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $suspend (result i32 i64)
+ i32.const 123
+ i64.const 456
+ suspend $tag-pair-to-pair
+ )
+
;; CHECK: (func $source-maps (type $void)
;; CHECK-NEXT: ;;@ src.cpp:40:1
;; CHECK-NEXT: (drop