diff options
author | Frank Emrich <git@emrich.io> | 2024-03-04 18:04:20 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-04 10:04:20 -0800 |
commit | 88108efb180d6059417c26af6ff6123cde26eba3 (patch) | |
tree | ce253c8954d054d269f415bd5b2537efc588c1c1 /src | |
parent | 2ca9638354e4a5f260ced04d186808fc8b498986 (diff) | |
download | binaryen-88108efb180d6059417c26af6ff6123cde26eba3.tar.gz binaryen-88108efb180d6059417c26af6ff6123cde26eba3.tar.bz2 binaryen-88108efb180d6059417c26af6ff6123cde26eba3.zip |
Typed continuations: cont.bind instructions (#6365)
This PR is part of a series that adds basic support for the [typed
continuations/wasmfx proposal](https://github.com/wasmfx/specfx).
This particular PR adds support for the `cont.bind` instruction for partially
applying continuations, documented
[here](https://github.com/wasmfx/specfx/blob/main/proposals/continuations/Overview.md#instructions).
In short, these instructions are of the form `(cont.bind $ct_before $ct_after)`
where `$ct_before` and `$ct_after` are related continuation types. They must
only differ in the number of arguments, where `$ct_before` has _n_ additional
parameters as compared to `$ct_after`, for some _n_ ≥ 0. The idea is that
`(cont.bind $ct_before $ct_after)` then takes a reference to a continuation of
type `$ct_before` as well as _n_ operands and returns a (reference to a)
continuation of type `$ct_after`. Thus, the folded textual representation looks
like `(cont.bind $ct_before $ct_after arg1 ... argn c)`.
Support for the instruction is implemented in both the old and the new wat
parser.
Note that this PR does not implement validation of the new instruction.
Diffstat (limited to 'src')
-rw-r--r-- | src/gen-s-parser.inc | 35 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/cost.h | 10 | ||||
-rw-r--r-- | src/ir/effects.h | 4 | ||||
-rw-r--r-- | src/ir/module-utils.cpp | 3 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 4 | ||||
-rw-r--r-- | src/ir/subtype-exprs.h | 1 | ||||
-rw-r--r-- | src/parser/contexts.h | 12 | ||||
-rw-r--r-- | src/parser/parsers.h | 15 | ||||
-rw-r--r-- | src/passes/Print.cpp | 7 | ||||
-rw-r--r-- | src/passes/TypeGeneralizing.cpp | 1 | ||||
-rw-r--r-- | src/wasm-binary.h | 2 | ||||
-rw-r--r-- | src/wasm-builder.h | 12 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 9 | ||||
-rw-r--r-- | src/wasm-delegations.def | 1 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 2 | ||||
-rw-r--r-- | src/wasm-ir-builder.h | 3 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm.h | 13 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 41 | ||||
-rw-r--r-- | src/wasm/wasm-ir-builder.cpp | 42 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 23 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 6 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 19 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 2 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
26 files changed, 264 insertions, 9 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 01f138cc0..8f13750d4 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -169,9 +169,17 @@ switch (buf[0]) { default: goto parse_error; } } - case 'o': - if (op == "cont.new"sv) { return makeContNew(s); } - goto parse_error; + case 'o': { + switch (buf[5]) { + case 'b': + if (op == "cont.bind"sv) { return makeContBind(s); } + goto parse_error; + case 'n': + if (op == "cont.new"sv) { return makeContNew(s); } + goto parse_error; + default: goto parse_error; + } + } default: goto parse_error; } } @@ -3853,12 +3861,23 @@ switch (buf[0]) { default: goto parse_error; } } - case 'o': - if (op == "cont.new"sv) { - CHECK_ERR(makeContNew(ctx, pos, annotations)); - return Ok{}; + case 'o': { + switch (buf[5]) { + case 'b': + if (op == "cont.bind"sv) { + CHECK_ERR(makeContBind(ctx, pos, annotations)); + return Ok{}; + } + goto parse_error; + case 'n': + if (op == "cont.new"sv) { + CHECK_ERR(makeContNew(ctx, pos, annotations)); + return Ok{}; + } + goto parse_error; + default: goto parse_error; } - goto parse_error; + } default: goto parse_error; } } diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 7c81b0d0d..6d872056a 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -183,6 +183,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::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); } diff --git a/src/ir/cost.h b/src/ir/cost.h index 7a8776c00..d66c97282 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -726,6 +726,16 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { return 8 + visit(curr->ref) + visit(curr->num); } + CostType visitContBind(ContBind* curr) { + // Inspired by struct.new: The only cost of cont.bind is that it may need to + // allocate a buffer to hold the arguments. + CostType ret = 4; + ret += visit(curr->cont); + for (auto* arg : curr->operands) { + ret += visit(arg); + } + return ret; + } CostType visitContNew(ContNew* curr) { // Some arbitrary "high" value, reflecting that this may allocate a stack return 14 + visit(curr->func); diff --git a/src/ir/effects.h b/src/ir/effects.h index d0af932bd..0b3d2a4af 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -974,6 +974,10 @@ private: parent.implicitTrap = true; } + void visitContBind(ContBind* curr) { + // traps when curr->cont is null ref. + parent.implicitTrap = true; + } void visitContNew(ContNew* curr) { // traps when curr->func is null ref. parent.implicitTrap = true; diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index b61fddd8b..c2f48eec8 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -341,6 +341,9 @@ struct CodeScanner counts.include(get->type); } else if (auto* set = curr->dynCast<ArraySet>()) { counts.note(set->ref->type); + } else if (auto* contBind = curr->dynCast<ContBind>()) { + counts.note(contBind->contTypeBefore); + counts.note(contBind->contTypeAfter); } else if (auto* contNew = curr->dynCast<ContNew>()) { counts.note(contNew->contType); } else if (auto* resume = curr->dynCast<Resume>()) { diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index d0b0ea3ae..44015c113 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -1200,6 +1200,10 @@ struct InfoCollector void visitReturn(Return* curr) { addResult(curr->value); } + void visitContBind(ContBind* curr) { + // TODO: optimize when possible + addRoot(curr); + } void visitContNew(ContNew* curr) { // TODO: optimize when possible addRoot(curr); diff --git a/src/ir/subtype-exprs.h b/src/ir/subtype-exprs.h index ab0ace53d..553c1497b 100644 --- a/src/ir/subtype-exprs.h +++ b/src/ir/subtype-exprs.h @@ -391,6 +391,7 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> { void visitStringSliceWTF(StringSliceWTF* curr) {} void visitStringSliceIter(StringSliceIter* curr) {} + void visitContBind(ContBind* curr) { WASM_UNREACHABLE("not implemented"); } void visitContNew(ContNew* curr) { WASM_UNREACHABLE("not implemented"); } void visitResume(Resume* curr) { WASM_UNREACHABLE("not implemented"); } }; diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 4c15c0308..08cebe33b 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -808,6 +808,11 @@ struct NullInstrParserCtx { return Ok{}; } template<typename HeapTypeT> + Result<> + makeContBind(Index, const std::vector<Annotation>&, HeapTypeT, HeapTypeT) { + return Ok{}; + } + template<typename HeapTypeT> Result<> makeContNew(Index, const std::vector<Annotation>&, HeapTypeT) { return Ok{}; } @@ -2547,6 +2552,13 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return withLoc(pos, irBuilder.makeStringSliceIter()); } + Result<> makeContBind(Index pos, + const std::vector<Annotation>& annotations, + HeapType contTypeBefore, + HeapType contTypeAfter) { + return withLoc(pos, irBuilder.makeContBind(contTypeBefore, contTypeAfter)); + } + Result<> makeContNew(Index pos, const std::vector<Annotation>& annotations, HeapType type) { diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 4a2b99d84..0dde4b765 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -304,6 +304,8 @@ Result<> makeStringSliceWTF(Ctx&, template<typename Ctx> Result<> makeStringSliceIter(Ctx&, Index, const std::vector<Annotation>&); template<typename Ctx> +Result<> makeContBind(Ctx&, Index, const std::vector<Annotation>&); +template<typename Ctx> Result<> makeContNew(Ctx*, Index, const std::vector<Annotation>&); template<typename Ctx> Result<> makeResume(Ctx&, Index, const std::vector<Annotation>&); @@ -2459,6 +2461,19 @@ Result<> makeStringSliceIter(Ctx& ctx, return ctx.makeStringSliceIter(pos, annotations); } +// contbind ::= 'cont.bind' typeidx typeidx +template<typename Ctx> +Result<> +makeContBind(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) { + auto typeBefore = typeidx(ctx); + CHECK_ERR(typeBefore); + + auto typeAfter = typeidx(ctx); + CHECK_ERR(typeAfter); + + return ctx.makeContBind(pos, annotations, *typeBefore, *typeAfter); +} + template<typename Ctx> Result<> makeContNew(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) { diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index abe68f13d..3f0cfbabb 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2378,7 +2378,12 @@ struct PrintExpressionContents void visitStringSliceIter(StringSliceIter* curr) { printMedium(o, "stringview_iter.slice"); } - + void visitContBind(ContBind* curr) { + printMedium(o, "cont.bind "); + printHeapType(curr->contTypeBefore); + o << ' '; + printHeapType(curr->contTypeAfter); + } void visitContNew(ContNew* curr) { printMedium(o, "cont.new "); printHeapType(curr->contType); diff --git a/src/passes/TypeGeneralizing.cpp b/src/passes/TypeGeneralizing.cpp index c19766ae3..10dfe8737 100644 --- a/src/passes/TypeGeneralizing.cpp +++ b/src/passes/TypeGeneralizing.cpp @@ -875,6 +875,7 @@ struct TransferFn : OverriddenVisitor<TransferFn> { void visitStringSliceWTF(StringSliceWTF* curr) { WASM_UNREACHABLE("TODO"); } void visitStringSliceIter(StringSliceIter* curr) { WASM_UNREACHABLE("TODO"); } + void visitContBind(ContBind* curr) { WASM_UNREACHABLE("TODO"); } void visitContNew(ContNew* curr) { WASM_UNREACHABLE("TODO"); } void visitResume(Resume* curr) { WASM_UNREACHABLE("TODO"); } }; diff --git a/src/wasm-binary.h b/src/wasm-binary.h index c1d79ec2a..082b711d7 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1299,6 +1299,7 @@ enum ASTNodes { // typed continuation opcodes ContNew = 0xe0, + ContBind = 0xe1, Resume = 0xe3, }; @@ -1928,6 +1929,7 @@ public: void visitRefAsCast(RefCast* curr, uint32_t code); void visitRefAs(RefAs* curr, uint8_t code); void visitContNew(ContNew* curr); + void visitContBind(ContBind* curr); void visitResume(Resume* curr); [[noreturn]] void throwError(std::string text); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 03fddb178..eb1874c3b 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -1198,6 +1198,18 @@ public: return ret; } + ContBind* makeContBind(HeapType contTypeBefore, + HeapType contTypeAfter, + const std::vector<Expression*>& operands, + Expression* cont) { + auto* ret = wasm.allocator.alloc<ContBind>(); + ret->contTypeBefore = contTypeBefore; + ret->contTypeAfter = contTypeAfter; + ret->operands.set(operands); + ret->cont = cont; + ret->finalize(); + return ret; + } ContNew* makeContNew(HeapType contType, Expression* func) { auto* ret = wasm.allocator.alloc<ContNew>(); ret->contType = contType; diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index c895c31dd..ac0256cf2 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -946,6 +946,15 @@ switch (DELEGATE_ID) { break; } + case Expression::Id::ContBindId: { + DELEGATE_START(ContBind); + DELEGATE_FIELD_CHILD(ContBind, cont); + DELEGATE_FIELD_CHILD_VECTOR(ContBind, operands); + DELEGATE_FIELD_HEAPTYPE(ContBind, contTypeAfter); + DELEGATE_FIELD_HEAPTYPE(ContBind, contTypeBefore); + DELEGATE_END(ContBind); + break; + } case Expression::Id::ContNewId: { DELEGATE_START(ContNew); DELEGATE_FIELD_CHILD(ContNew, func); diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index 5a57e399b..c07a78f8b 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -105,6 +105,7 @@ DELEGATE(StringIterNext); DELEGATE(StringIterMove); DELEGATE(StringSliceWTF); DELEGATE(StringSliceIter); +DELEGATE(ContBind); DELEGATE(ContNew); DELEGATE(Resume); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index f1b081e51..47b8d5eb5 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2401,6 +2401,7 @@ public: } return ExpressionRunner<SubType>::visitRefAs(curr); } + Flow visitContBind(ContBind* curr) { WASM_UNREACHABLE("unimplemented"); } Flow visitContNew(ContNew* curr) { WASM_UNREACHABLE("unimplemented"); } Flow visitResume(Resume* curr) { WASM_UNREACHABLE("unimplemented"); } @@ -3976,6 +3977,7 @@ public: multiValues.pop_back(); return ret; } + Flow visitContBind(ContBind* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitContNew(ContNew* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitResume(Resume* curr) { return Flow(NONCONSTANT_FLOW); } diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index d31a532a7..917080fc4 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -210,6 +210,8 @@ public: [[nodiscard]] Result<> makeStringIterMove(StringIterMoveOp op); [[nodiscard]] Result<> makeStringSliceWTF(StringSliceWTFOp op); [[nodiscard]] Result<> makeStringSliceIter(); + [[nodiscard]] Result<> makeContBind(HeapType contTypeBefore, + HeapType contTypeAfter); [[nodiscard]] Result<> makeContNew(HeapType ct); [[nodiscard]] Result<> makeResume(HeapType ct, const std::vector<Name>& tags, @@ -252,6 +254,7 @@ public: [[nodiscard]] Result<> visitThrow(Throw*); [[nodiscard]] Result<> visitStringNew(StringNew*); [[nodiscard]] Result<> visitStringEncode(StringEncode*); + [[nodiscard]] Result<> visitContBind(ContBind*); [[nodiscard]] Result<> visitResume(Resume*); [[nodiscard]] Result<> visitTupleMake(TupleMake*); [[nodiscard]] Result<> diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 953599a1e..e1d9dab47 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -328,6 +328,7 @@ private: Expression* makeStringIterMove(Element& s, StringIterMoveOp op); Expression* makeStringSliceWTF(Element& s, StringSliceWTFOp op); Expression* makeStringSliceIter(Element& s); + Expression* makeContBind(Element& s); Expression* makeContNew(Element& s); Expression* makeResume(Element& s); diff --git a/src/wasm.h b/src/wasm.h index 3da245547..ad7ccb3ad 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -743,6 +743,7 @@ public: StringIterMoveId, StringSliceWTFId, StringSliceIterId, + ContBindId, ContNewId, ResumeId, NumExpressionIds @@ -1998,6 +1999,18 @@ public: void finalize(); }; +class ContBind : public SpecificExpression<Expression::ContBindId> { +public: + ContBind(MixedArena& allocator) : operands(allocator) {} + + HeapType contTypeBefore; + HeapType contTypeAfter; + ExpressionList operands; + Expression* cont; + + void finalize(); +}; + class ContNew : public SpecificExpression<Expression::ContNewId> { public: ContNew() = default; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 6f41c3c87..efb65bb50 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -4046,6 +4046,10 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { visitCallRef(call); break; } + case BinaryConsts::ContBind: { + visitContBind((curr = allocator.alloc<ContBind>())->cast<ContBind>()); + break; + } case BinaryConsts::ContNew: { auto contNew = allocator.alloc<ContNew>(); curr = contNew; @@ -7768,6 +7772,43 @@ void WasmBinaryReader::visitRefAs(RefAs* curr, uint8_t code) { curr->finalize(); } +void WasmBinaryReader::visitContBind(ContBind* curr) { + BYN_TRACE("zz node: ContBind\n"); + + auto contTypeBeforeIndex = getU32LEB(); + curr->contTypeBefore = getTypeByIndex(contTypeBeforeIndex); + + auto contTypeAfterIndex = getU32LEB(); + curr->contTypeAfter = getTypeByIndex(contTypeAfterIndex); + + for (auto& ct : {curr->contTypeBefore, curr->contTypeAfter}) { + if (!ct.isContinuation()) { + throwError("non-continuation type in cont.bind instruction " + + ct.toString()); + } + } + + curr->cont = popNonVoidExpression(); + + size_t paramsBefore = + curr->contTypeBefore.getContinuation().type.getSignature().params.size(); + size_t paramsAfter = + curr->contTypeAfter.getContinuation().type.getSignature().params.size(); + if (paramsBefore < paramsAfter) { + throwError("incompatible continuation types in cont.bind: source type " + + curr->contTypeBefore.toString() + + " has fewer parameters than destination " + + curr->contTypeAfter.toString()); + } + size_t numArgs = paramsBefore - paramsAfter; + curr->operands.resize(numArgs); + for (size_t i = 0; i < numArgs; i++) { + curr->operands[numArgs - i - 1] = popNonVoidExpression(); + } + + curr->finalize(); +} + void WasmBinaryReader::visitContNew(ContNew* curr) { BYN_TRACE("zz node: ContNew\n"); diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 8d87d0f33..628a257c7 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -619,6 +619,32 @@ Result<> IRBuilder::visitStringEncode(StringEncode* curr) { WASM_UNREACHABLE("unexpected op"); } +Result<> IRBuilder::visitContBind(ContBind* curr) { + auto cont = pop(); + CHECK_ERR(cont); + curr->cont = *cont; + + size_t paramsBefore = + curr->contTypeBefore.getContinuation().type.getSignature().params.size(); + size_t paramsAfter = + curr->contTypeAfter.getContinuation().type.getSignature().params.size(); + if (paramsBefore < paramsAfter) { + return Err{"incompatible continuation types in cont.bind: source type " + + curr->contTypeBefore.toString() + + " has fewer parameters than destination " + + curr->contTypeAfter.toString()}; + } + size_t numArgs = paramsBefore - paramsAfter; + + curr->operands.resize(numArgs); + for (size_t i = 0; i < numArgs; ++i) { + auto val = pop(); + CHECK_ERR(val); + curr->operands[numArgs - i - 1] = *val; + } + return Ok{}; +} + Result<> IRBuilder::visitResume(Resume* curr) { auto cont = pop(); CHECK_ERR(cont); @@ -1833,6 +1859,22 @@ Result<> IRBuilder::makeStringSliceIter() { return Ok{}; } +Result<> IRBuilder::makeContBind(HeapType contTypeBefore, + HeapType contTypeAfter) { + if (!contTypeBefore.isContinuation() || !contTypeAfter.isContinuation()) { + return Err{"expected continuation types"}; + } + ContBind curr(wasm.allocator); + curr.contTypeBefore = contTypeBefore; + curr.contTypeAfter = contTypeAfter; + CHECK_ERR(visitContBind(&curr)); + + std::vector<Expression*> operands(curr.operands.begin(), curr.operands.end()); + push( + builder.makeContBind(contTypeBefore, contTypeAfter, operands, curr.cont)); + return Ok{}; +} + Result<> IRBuilder::makeContNew(HeapType ct) { if (!ct.isContinuation()) { return Err{"expected continuation type"}; diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index b7113d2b2..44ba84351 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2990,6 +2990,29 @@ Expression* SExpressionWasmBuilder::makeCallRef(Element& s, bool isReturn) { target, operands, sigType.getSignature().results, isReturn); } +Expression* SExpressionWasmBuilder::makeContBind(Element& s) { + auto ret = allocator.alloc<ContBind>(); + + ret->contTypeBefore = parseHeapType(*s[1]); + if (!ret->contTypeBefore.isContinuation()) { + throw ParseException("expected continuation type", s[1]->line, s[1]->col); + } + ret->contTypeAfter = parseHeapType(*s[2]); + if (!ret->contTypeAfter.isContinuation()) { + throw ParseException("expected continuation type", s[2]->line, s[2]->col); + } + + Index i = 3; + while (i < s.size() - 1) { + ret->operands.push_back(parseExpression(s[i++])); + } + + ret->cont = parseExpression(s[i]); + + ret->finalize(); + return ret; +} + Expression* SExpressionWasmBuilder::makeContNew(Element& s) { auto ret = allocator.alloc<ContNew>(); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 0857e9a0d..90d5a3768 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2489,6 +2489,12 @@ void BinaryInstWriter::visitStringSliceIter(StringSliceIter* curr) { << U32LEB(BinaryConsts::StringViewIterSlice); } +void BinaryInstWriter::visitContBind(ContBind* curr) { + o << int8_t(BinaryConsts::ContBind); + parent.writeIndexedHeapType(curr->contTypeBefore); + parent.writeIndexedHeapType(curr->contTypeAfter); +} + void BinaryInstWriter::visitContNew(ContNew* curr) { o << int8_t(BinaryConsts::ContNew); parent.writeIndexedHeapType(curr->contType); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index d745585e5..4bb556160 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -487,6 +487,7 @@ public: void visitStringIterMove(StringIterMove* curr); void visitStringSliceWTF(StringSliceWTF* curr); void visitStringSliceIter(StringSliceIter* curr); + void visitContBind(ContBind* curr); void visitContNew(ContNew* curr); void visitResume(Resume* curr); @@ -3295,6 +3296,24 @@ void FunctionValidator::visitStringSliceIter(StringSliceIter* curr) { "string operations require reference-types [--enable-strings]"); } +void FunctionValidator::visitContBind(ContBind* curr) { + // TODO implement actual type-checking + shouldBeTrue( + !getModule() || getModule()->features.hasTypedContinuations(), + curr, + "cont.bind requires typed-continuatons [--enable-typed-continuations]"); + + shouldBeTrue((curr->contTypeBefore.isContinuation() && + curr->contTypeBefore.getContinuation().type.isSignature()), + curr, + "invalid first type in ContBind expression"); + + shouldBeTrue((curr->contTypeAfter.isContinuation() && + curr->contTypeAfter.getContinuation().type.isSignature()), + curr, + "invalid second type in ContBind expression"); +} + void FunctionValidator::visitContNew(ContNew* curr) { // TODO implement actual type-checking shouldBeTrue( diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index ce5fd7006..374a97e19 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1352,6 +1352,8 @@ void StringSliceIter::finalize() { } } +void ContBind::finalize() { type = Type(contTypeAfter, NonNullable); } + void ContNew::finalize() { type = Type(contType, NonNullable); } static void populateResumeSentTypes(Resume* curr, Module* wasm) { diff --git a/src/wasm2js.h b/src/wasm2js.h index 92ba397be..5f0305877 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2428,6 +2428,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, WASM_UNREACHABLE("unimp"); } + Ref visitContBind(ContBind* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } Ref visitContNew(ContNew* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); |