summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
25 files changed, 202 insertions, 6 deletions
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) {