diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index bc12bdbe08b..75e0b749585 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -327,6 +327,7 @@ def is_git_repo(): 'typed_continuations.wast', 'typed_continuations_resume.wast', 'typed_continuations_contnew.wast', + 'typed_continuations_contbind.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 2e3c0a8f1c3..b2cac2b89c0 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -568,6 +568,7 @@ ("return_call_ref", "makeCallRef(s, /*isReturn=*/true)"), # Typed continuations instructions ("cont.new", "makeContNew(s)"), + ("cont.bind", "makeContBind(s)"), ("resume", "makeResume(s)"), # GC ("i31.new", "makeRefI31(s)"), # deprecated diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 01f138cc0c0..8f13750d441 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 7c81b0d0d37..6d872056adb 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 7a8776c0076..d66c97282f1 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -726,6 +726,16 @@ struct CostAnalyzer : public OverriddenVisitor { 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 d0af932bd1e..0b3d2a4afd2 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -974,6 +974,10 @@ class EffectAnalyzer { 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 b61fddd8b82..c2f48eec852 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()) { counts.note(set->ref->type); + } else if (auto* contBind = curr->dynCast()) { + counts.note(contBind->contTypeBefore); + counts.note(contBind->contTypeAfter); } else if (auto* contNew = curr->dynCast()) { counts.note(contNew->contType); } else if (auto* resume = curr->dynCast()) { diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index d0b0ea3aee0..44015c113bc 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 1c922521f75..a191cf428f5 100644 --- a/src/ir/subtype-exprs.h +++ b/src/ir/subtype-exprs.h @@ -384,6 +384,7 @@ struct SubtypingDiscoverer : public OverriddenVisitor { 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 6505d11a448..3f38e8fbfa5 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -808,6 +808,11 @@ struct NullInstrParserCtx { return Ok{}; } template + Result<> + makeContBind(Index, const std::vector&, HeapTypeT, HeapTypeT) { + return Ok{}; + } + template Result<> makeContNew(Index, const std::vector&, HeapTypeT) { return Ok{}; } @@ -2523,6 +2528,13 @@ struct ParseDefsCtx : TypeParserCtx { return withLoc(pos, irBuilder.makeStringSliceIter()); } + Result<> makeContBind(Index pos, + const std::vector& annotations, + HeapType contTypeBefore, + HeapType contTypeAfter) { + return withLoc(pos, irBuilder.makeContBind(contTypeBefore, contTypeAfter)); + } + Result<> makeContNew(Index pos, const std::vector& annotations, HeapType type) { diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 987f0f5aa6d..58a70411be5 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -302,6 +302,8 @@ Result<> makeStringSliceWTF(Ctx&, template Result<> makeStringSliceIter(Ctx&, Index, const std::vector&); template +Result<> makeContBind(Ctx&, Index, const std::vector&); +template Result<> makeContNew(Ctx*, Index, const std::vector&); template Result<> makeResume(Ctx&, Index, const std::vector&); @@ -2431,6 +2433,19 @@ Result<> makeStringSliceIter(Ctx& ctx, return ctx.makeStringSliceIter(pos, annotations); } +// contbind ::= 'cont.bind' typeidx typeidx +template +Result<> +makeContBind(Ctx& ctx, Index pos, const std::vector& annotations) { + auto typeBefore = typeidx(ctx); + CHECK_ERR(typeBefore); + + auto typeAfter = typeidx(ctx); + CHECK_ERR(typeAfter); + + return ctx.makeContBind(pos, annotations, *typeBefore, *typeAfter); +} + template Result<> makeContNew(Ctx& ctx, Index pos, const std::vector& annotations) { diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 2288b691419..77b4e553b83 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 c19766ae3ea..10dfe873711 100644 --- a/src/passes/TypeGeneralizing.cpp +++ b/src/passes/TypeGeneralizing.cpp @@ -875,6 +875,7 @@ struct TransferFn : OverriddenVisitor { 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 c1d79ec2a6c..082b711d794 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 @@ class WasmBinaryReader { 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 03fddb17860..eb1874c3b81 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -1198,6 +1198,18 @@ class Builder { return ret; } + ContBind* makeContBind(HeapType contTypeBefore, + HeapType contTypeAfter, + const std::vector& operands, + Expression* cont) { + auto* ret = wasm.allocator.alloc(); + 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(); ret->contType = contType; diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index c895c31ddcc..ac0256cf244 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 5a57e399b3f..c07a78f8b6f 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 f1b081e5103..47b8d5eb5b8 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2401,6 +2401,7 @@ class ConstantExpressionRunner : public ExpressionRunner { } return ExpressionRunner::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 @@ class ModuleRunnerBase : public ExpressionRunner { 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 d31a532a74c..917080fc4bb 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -210,6 +210,8 @@ class IRBuilder : public UnifiedExpressionVisitor> { [[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& tags, @@ -252,6 +254,7 @@ class IRBuilder : public UnifiedExpressionVisitor> { [[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 953599a1e85..e1d9dab47ee 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -328,6 +328,7 @@ class SExpressionWasmBuilder { 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 3da245547cb..ad7ccb3adaa 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -743,6 +743,7 @@ class Expression { StringIterMoveId, StringSliceWTFId, StringSliceIterId, + ContBindId, ContNewId, ResumeId, NumExpressionIds @@ -1998,6 +1999,18 @@ class StringSliceIter void finalize(); }; +class ContBind : public SpecificExpression { +public: + ContBind(MixedArena& allocator) : operands(allocator) {} + + HeapType contTypeBefore; + HeapType contTypeAfter; + ExpressionList operands; + Expression* cont; + + void finalize(); +}; + class ContNew : public SpecificExpression { public: ContNew() = default; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 6f41c3c8769..efb65bb5095 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())->cast()); + break; + } case BinaryConsts::ContNew: { auto contNew = allocator.alloc(); 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 8d87d0f3335..628a257c708 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 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 b7113d2b243..44ba8435113 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(); + + 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(); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 0857e9a0d6b..90d5a3768b8 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 d745585e529..4bb5561604a 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -487,6 +487,7 @@ struct FunctionValidator : public WalkerPass> { 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 ce5fd700659..374a97e1902 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 92ba397be72..5f030587706 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"); diff --git a/test/lit/basic/typed_continuations_contbind.wast b/test/lit/basic/typed_continuations_contbind.wast new file mode 100644 index 00000000000..065d4a7962f --- /dev/null +++ b/test/lit/basic/typed_continuations_contbind.wast @@ -0,0 +1,98 @@ +;; 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 $ft1 (func (param i32 i64 i32) (result i32))) + ;; CHECK-BIN: (type $ft1 (func (param i32 i64 i32) (result i32))) + (type $ft1 (func (param i32 i64 i32) (result i32))) + ;; CHECK-TEXT: (type $ct1 (cont $ft1)) + + ;; CHECK-TEXT: (type $ft2 (func (param i32) (result i32))) + ;; CHECK-BIN: (type $ct1 (cont $ft1)) + + ;; CHECK-BIN: (type $ft2 (func (param i32) (result i32))) + (type $ft2 (func (param i32) (result i32))) + (type $ct1 (cont $ft1)) + ;; CHECK-TEXT: (type $ct2 (cont $ft2)) + ;; CHECK-BIN: (type $ct2 (cont $ft2)) + (type $ct2 (cont $ft2)) + + ;; CHECK-TEXT: (type $4 (func (param (ref $ct1)) (result (ref $ct2)))) + + ;; CHECK-TEXT: (type $5 (func (param (ref $ct1)) (result (ref $ct1)))) + + ;; CHECK-TEXT: (func $f (type $4) (param $x (ref $ct1)) (result (ref $ct2)) + ;; CHECK-TEXT-NEXT: (cont.bind $ct1 $ct2 + ;; CHECK-TEXT-NEXT: (i32.const 123) + ;; CHECK-TEXT-NEXT: (i64.const 456) + ;; CHECK-TEXT-NEXT: (local.get $x) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-BIN: (type $4 (func (param (ref $ct1)) (result (ref $ct2)))) + + ;; CHECK-BIN: (type $5 (func (param (ref $ct1)) (result (ref $ct1)))) + + ;; CHECK-BIN: (func $f (type $4) (param $x (ref $ct1)) (result (ref $ct2)) + ;; CHECK-BIN-NEXT: (cont.bind $ct1 $ct2 + ;; CHECK-BIN-NEXT: (i32.const 123) + ;; CHECK-BIN-NEXT: (i64.const 456) + ;; CHECK-BIN-NEXT: (local.get $x) + ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: ) + (func $f (param $x (ref $ct1)) (result (ref $ct2)) + (cont.bind $ct1 $ct2 + (i32.const 123) + (i64.const 456) + (local.get $x) + ) + ) + + ;; CHECK-TEXT: (func $g (type $5) (param $x (ref $ct1)) (result (ref $ct1)) + ;; CHECK-TEXT-NEXT: (cont.bind $ct1 $ct1 + ;; CHECK-TEXT-NEXT: (local.get $x) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-BIN: (func $g (type $5) (param $x (ref $ct1)) (result (ref $ct1)) + ;; CHECK-BIN-NEXT: (cont.bind $ct1 $ct1 + ;; CHECK-BIN-NEXT: (local.get $x) + ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: ) + (func $g (param $x (ref $ct1)) (result (ref $ct1)) + (cont.bind $ct1 $ct1 + (local.get $x) + ) + ) +) +;; CHECK-BIN-NODEBUG: (type $0 (func (param i32 i64 i32) (result i32))) + +;; CHECK-BIN-NODEBUG: (type $1 (cont $0)) + +;; CHECK-BIN-NODEBUG: (type $2 (func (param i32) (result i32))) + +;; CHECK-BIN-NODEBUG: (type $3 (cont $2)) + +;; CHECK-BIN-NODEBUG: (type $4 (func (param (ref $1)) (result (ref $3)))) + +;; CHECK-BIN-NODEBUG: (type $5 (func (param (ref $1)) (result (ref $1)))) + +;; CHECK-BIN-NODEBUG: (func $0 (type $4) (param $0 (ref $1)) (result (ref $3)) +;; CHECK-BIN-NODEBUG-NEXT: (cont.bind $1 $3 +;; CHECK-BIN-NODEBUG-NEXT: (i32.const 123) +;; CHECK-BIN-NODEBUG-NEXT: (i64.const 456) +;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) +;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: ) + +;; CHECK-BIN-NODEBUG: (func $1 (type $5) (param $0 (ref $1)) (result (ref $1)) +;; CHECK-BIN-NODEBUG-NEXT: (cont.bind $1 $1 +;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) +;; 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 ab81fa4c764..65b22a77aad 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -25,12 +25,12 @@ ;; CHECK: (type $8 (func (param anyref))) - ;; CHECK: (type $9 (func (param i32 i64 v128))) - ;; CHECK: (type $simple (func (param i32 i64) (result f32))) ;; CHECK: (type $simple-cont (cont $simple)) + ;; CHECK: (type $11 (func (param i32 i64 v128))) + ;; CHECK: (rec ;; CHECK-NEXT: (type $s0 (struct )) (type $s0 (struct)) @@ -74,123 +74,129 @@ ;; CHECK: (type $30 (func (param i64 v128))) - ;; CHECK: (type $31 (func (result i32 i64 (ref null $simple-cont)))) + ;; CHECK: (type $cont-bind-before-func (func (param i32 i64 i32 i64) (result f32))) + + ;; CHECK: (type $cont-bind-before (cont $cont-bind-before-func)) - ;; CHECK: (type $32 (func (param i32 i32))) + ;; CHECK: (type $33 (func (result i32 i64 (ref null $simple-cont)))) - ;; CHECK: (type $33 (func (param exnref))) + ;; CHECK: (type $34 (func (param i32 i32))) - ;; CHECK: (type $34 (func (param i32 i32 f64 f64))) + ;; CHECK: (type $35 (func (param exnref))) - ;; CHECK: (type $35 (func (param i64))) + ;; CHECK: (type $36 (func (param i32 i32 f64 f64))) - ;; CHECK: (type $36 (func (param v128) (result i32))) + ;; CHECK: (type $37 (func (param i64))) - ;; CHECK: (type $37 (func (param v128 v128) (result v128))) + ;; CHECK: (type $38 (func (param v128) (result i32))) - ;; CHECK: (type $38 (func (param v128 v128 v128) (result v128))) + ;; CHECK: (type $39 (func (param v128 v128) (result v128))) - ;; CHECK: (type $39 (func (param i32 i32 i64 i64))) + ;; CHECK: (type $40 (func (param v128 v128 v128) (result v128))) - ;; CHECK: (type $40 (func (param i32) (result i32))) + ;; CHECK: (type $41 (func (param i32 i32 i64 i64))) - ;; CHECK: (type $41 (func (param i64) (result i32 i64))) + ;; CHECK: (type $42 (func (param i32) (result i32))) - ;; CHECK: (type $42 (func (param i32) (result i32 i64))) + ;; CHECK: (type $43 (func (param i64) (result i32 i64))) - ;; CHECK: (type $43 (func (param anyref) (result i32))) + ;; CHECK: (type $44 (func (param i32) (result i32 i64))) - ;; CHECK: (type $44 (func (param eqref eqref) (result i32))) + ;; CHECK: (type $45 (func (param anyref) (result i32))) - ;; CHECK: (type $45 (func (param i32) (result i31ref))) + ;; CHECK: (type $46 (func (param eqref eqref) (result i32))) - ;; CHECK: (type $46 (func (param i31ref))) + ;; CHECK: (type $47 (func (param i32) (result i31ref))) - ;; CHECK: (type $47 (func (param i32 i64) (result (ref $pair)))) + ;; CHECK: (type $48 (func (param i31ref))) - ;; CHECK: (type $48 (func (result (ref $pair)))) + ;; CHECK: (type $49 (func (param i32 i64) (result (ref $pair)))) - ;; CHECK: (type $49 (func (param (ref $pair)) (result i32))) + ;; CHECK: (type $50 (func (result (ref $pair)))) - ;; CHECK: (type $50 (func (param (ref $pair)) (result i64))) + ;; CHECK: (type $51 (func (param (ref $pair)) (result i32))) - ;; CHECK: (type $51 (func (param (ref null $pair)) (result i32))) + ;; CHECK: (type $52 (func (param (ref $pair)) (result i64))) - ;; CHECK: (type $52 (func (param (ref $pair) i32))) + ;; CHECK: (type $53 (func (param (ref null $pair)) (result i32))) - ;; CHECK: (type $53 (func (param (ref $pair) i64))) + ;; CHECK: (type $54 (func (param (ref $pair) i32))) - ;; CHECK: (type $54 (func (param (ref null $pair) i64))) + ;; CHECK: (type $55 (func (param (ref $pair) i64))) - ;; CHECK: (type $55 (func (param i64 i32) (result (ref $a1)))) + ;; CHECK: (type $56 (func (param (ref null $pair) i64))) - ;; CHECK: (type $56 (func (param i32) (result (ref $a1)))) + ;; CHECK: (type $57 (func (param i64 i32) (result (ref $a1)))) - ;; CHECK: (type $57 (func (param i32 i32) (result (ref $a1)))) + ;; CHECK: (type $58 (func (param i32) (result (ref $a1)))) - ;; CHECK: (type $58 (func (param (ref $a1) i32) (result i64))) + ;; CHECK: (type $59 (func (param i32 i32) (result (ref $a1)))) - ;; CHECK: (type $59 (func (param (ref $packed-i8) i32) (result i32))) + ;; CHECK: (type $60 (func (param (ref $a1) i32) (result i64))) - ;; CHECK: (type $60 (func (param (ref $packed-i16) i32) (result i32))) + ;; CHECK: (type $61 (func (param (ref $packed-i8) i32) (result i32))) - ;; CHECK: (type $61 (func (param (ref $a2) i32 f32))) + ;; CHECK: (type $62 (func (param (ref $packed-i16) i32) (result i32))) - ;; CHECK: (type $62 (func (param arrayref) (result i32))) + ;; CHECK: (type $63 (func (param (ref $a2) i32 f32))) - ;; CHECK: (type $63 (func (param (ref $a2) i32 (ref $a2) i32 i32))) + ;; CHECK: (type $64 (func (param arrayref) (result i32))) - ;; CHECK: (type $64 (func (param (ref $a2) i32 f32 i32))) + ;; CHECK: (type $65 (func (param (ref $a2) i32 (ref $a2) i32 i32))) - ;; CHECK: (type $65 (func (param (ref $a2) i32 i32 i32))) + ;; CHECK: (type $66 (func (param (ref $a2) i32 f32 i32))) - ;; CHECK: (type $66 (func (param (ref $any-array) i32 i32 i32))) + ;; CHECK: (type $67 (func (param (ref $a2) i32 i32 i32))) - ;; CHECK: (type $67 (func (param externref))) + ;; CHECK: (type $68 (func (param (ref $any-array) i32 i32 i32))) - ;; CHECK: (type $68 (func (param i32 i32) (result stringref))) + ;; CHECK: (type $69 (func (param externref))) - ;; CHECK: (type $69 (func (param (ref $packed-i8) i32 i32) (result stringref))) + ;; CHECK: (type $70 (func (param i32 i32) (result stringref))) - ;; CHECK: (type $70 (func (param i32) (result stringref))) + ;; CHECK: (type $71 (func (param (ref $packed-i8) i32 i32) (result stringref))) - ;; CHECK: (type $71 (func (result (ref string)))) + ;; CHECK: (type $72 (func (param i32) (result stringref))) - ;; CHECK: (type $72 (func (param stringref) (result i32))) + ;; CHECK: (type $73 (func (result (ref string)))) - ;; CHECK: (type $73 (func (param stringview_wtf16) (result i32))) + ;; CHECK: (type $74 (func (param stringref) (result i32))) - ;; CHECK: (type $74 (func (param stringref (ref $packed-i8) i32) (result i32))) + ;; CHECK: (type $75 (func (param stringview_wtf16) (result i32))) - ;; CHECK: (type $75 (func (param stringref stringref) (result (ref string)))) + ;; CHECK: (type $76 (func (param stringref (ref $packed-i8) i32) (result i32))) - ;; CHECK: (type $76 (func (param stringref) (result stringview_wtf8))) + ;; CHECK: (type $77 (func (param stringref stringref) (result (ref string)))) - ;; CHECK: (type $77 (func (param stringref) (result (ref stringview_wtf16)))) + ;; CHECK: (type $78 (func (param stringref) (result stringview_wtf8))) - ;; CHECK: (type $78 (func (param stringref) (result stringview_iter))) + ;; CHECK: (type $79 (func (param stringref) (result (ref stringview_wtf16)))) - ;; CHECK: (type $79 (func (param (ref stringview_wtf8) i32 i32) (result i32))) + ;; CHECK: (type $80 (func (param stringref) (result stringview_iter))) - ;; CHECK: (type $80 (func (param stringview_wtf16 i32) (result i32))) + ;; CHECK: (type $81 (func (param (ref stringview_wtf8) i32 i32) (result i32))) - ;; CHECK: (type $81 (func (param stringview_iter) (result i32))) + ;; CHECK: (type $82 (func (param stringview_wtf16 i32) (result i32))) - ;; CHECK: (type $82 (func (param stringview_iter i32) (result i32))) + ;; CHECK: (type $83 (func (param stringview_iter) (result i32))) - ;; CHECK: (type $83 (func (param (ref stringview_iter) i32) (result i32))) + ;; CHECK: (type $84 (func (param stringview_iter i32) (result i32))) - ;; CHECK: (type $84 (func (param stringview_wtf8 stringview_wtf16 i32 i32))) + ;; CHECK: (type $85 (func (param (ref stringview_iter) i32) (result i32))) - ;; CHECK: (type $85 (func (param stringview_iter i32) (result (ref string)))) + ;; CHECK: (type $86 (func (param stringview_wtf8 stringview_wtf16 i32 i32))) - ;; CHECK: (type $86 (func (param (ref $simple-cont)))) + ;; CHECK: (type $87 (func (param stringview_iter i32) (result (ref string)))) + + ;; CHECK: (type $88 (func (param (ref $simple-cont)))) ;; CHECK: (type $to-f32 (func (result f32))) ;; CHECK: (type $to-f32-cont (cont $to-f32)) - ;; CHECK: (type $89 (func (param (ref $simple)) (result (ref $simple-cont)))) + ;; CHECK: (type $91 (func (param (ref $simple)) (result (ref $simple-cont)))) + + ;; CHECK: (type $92 (func (param (ref $cont-bind-before)) (result (ref $simple-cont)))) ;; CHECK: (type $s2 (struct (field i32))) (type $s2 (struct i32)) @@ -240,6 +246,10 @@ (type $simple-cont (cont $simple)) (type $to-f32-cont (cont $to-f32)) + + (type $cont-bind-before-func (func (param i32) (param i64) (param i32) (param i64) (result f32))) + (type $cont-bind-before (cont $cont-bind-before-func)) + ;; CHECK: (type $all-types (struct (field externref) (field (ref extern)) (field funcref) (field (ref func)) (field anyref) (field (ref any)) (field eqref) (field (ref eq)) (field i31ref) (field (ref i31)) (field structref) (field (ref struct)) (field arrayref) (field (ref array)) (field exnref) (field (ref exn)) (field stringref) (field (ref string)) (field stringview_wtf8) (field (ref stringview_wtf8)) (field stringview_wtf16) (field (ref stringview_wtf16)) (field stringview_iter) (field (ref stringview_iter)) (field nullref) (field (ref none)) (field nullexternref) (field (ref noextern)) (field nullfuncref) (field (ref nofunc)) (field nullexnref) (field (ref noexn)))) (type $all-types (struct externref (ref extern) funcref (ref func) @@ -260,7 +270,7 @@ ;; imported memories (memory (export "mem") (export "mem2") (import "" "mem") 0) - ;; CHECK: (type $101 (func (param (ref $s0) (ref $s1) (ref $s2) (ref $s3) (ref $s4) (ref $s5) (ref $s6) (ref $s7) (ref $s8) (ref $a0) (ref $a1) (ref $a2) (ref $a3) (ref $subvoid) (ref $submany) (ref $all-types)))) + ;; CHECK: (type $104 (func (param (ref $s0) (ref $s1) (ref $s2) (ref $s3) (ref $s4) (ref $s5) (ref $s6) (ref $s7) (ref $s8) (ref $a0) (ref $a1) (ref $a2) (ref $a3) (ref $subvoid) (ref $submany) (ref $all-types)))) ;; CHECK: (import "" "mem" (memory $mimport$0 0)) @@ -927,7 +937,7 @@ drop ) - ;; CHECK: (func $locals (type $32) (param $0 i32) (param $x i32) + ;; CHECK: (func $locals (type $34) (param $0 i32) (param $x i32) ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (local $y i32) ;; CHECK-NEXT: (drop @@ -2580,7 +2590,7 @@ ) ) - ;; CHECK: (func $try-table-throw-ref (type $33) (param $0 exnref) + ;; CHECK: (func $try-table-throw-ref (type $35) (param $0 exnref) ;; CHECK-NEXT: (throw_ref ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -2998,7 +3008,7 @@ end ) - ;; CHECK: (func $binary (type $34) (param $0 i32) (param $1 i32) (param $2 f64) (param $3 f64) + ;; CHECK: (func $binary (type $36) (param $0 i32) (param $1 i32) (param $2 f64) (param $3 f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) @@ -3023,7 +3033,7 @@ drop ) - ;; CHECK: (func $unary (type $35) (param $0 i64) + ;; CHECK: (func $unary (type $37) (param $0 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i64.eqz ;; CHECK-NEXT: (local.get $0) @@ -3372,7 +3382,7 @@ drop ) - ;; CHECK: (func $simd-extract (type $36) (param $0 v128) (result i32) + ;; CHECK: (func $simd-extract (type $38) (param $0 v128) (result i32) ;; CHECK-NEXT: (i32x4.extract_lane 3 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -3394,7 +3404,7 @@ i32x4.replace_lane 2 ) - ;; CHECK: (func $simd-shuffle (type $37) (param $0 v128) (param $1 v128) (result v128) + ;; CHECK: (func $simd-shuffle (type $39) (param $0 v128) (param $1 v128) (result v128) ;; CHECK-NEXT: (i8x16.shuffle 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -3406,7 +3416,7 @@ i8x16.shuffle 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23 ) - ;; CHECK: (func $simd-ternary (type $38) (param $0 v128) (param $1 v128) (param $2 v128) (result v128) + ;; CHECK: (func $simd-ternary (type $40) (param $0 v128) (param $1 v128) (param $2 v128) (result v128) ;; CHECK-NEXT: (v128.bitselect ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -3453,7 +3463,7 @@ drop ) - ;; CHECK: (func $simd-load-store-lane (type $9) (param $0 i32) (param $1 i64) (param $2 v128) + ;; CHECK: (func $simd-load-store-lane (type $11) (param $0 i32) (param $1 i64) (param $2 v128) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (v128.load16_lane $mimport$0 7 ;; CHECK-NEXT: (local.get $0) @@ -3516,7 +3526,7 @@ data.drop $passive ) - ;; CHECK: (func $memory-copy (type $39) (param $0 i32) (param $1 i32) (param $2 i64) (param $3 i64) + ;; CHECK: (func $memory-copy (type $41) (param $0 i32) (param $1 i32) (param $2 i64) (param $3 i64) ;; CHECK-NEXT: (memory.copy $mimport$0 $mimport$0 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -3587,7 +3597,7 @@ return ) - ;; CHECK: (func $return-one (type $40) (param $0 i32) (result i32) + ;; CHECK: (func $return-one (type $42) (param $0 i32) (result i32) ;; CHECK-NEXT: (return ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -3611,7 +3621,7 @@ return ) - ;; CHECK: (func $return-two-first-unreachable (type $41) (param $0 i64) (result i32 i64) + ;; CHECK: (func $return-two-first-unreachable (type $43) (param $0 i64) (result i32 i64) ;; CHECK-NEXT: (return ;; CHECK-NEXT: (tuple.make 2 ;; CHECK-NEXT: (unreachable) @@ -3625,7 +3635,7 @@ return ) - ;; CHECK: (func $return-two-second-unreachable (type $42) (param $0 i32) (result i32 i64) + ;; CHECK: (func $return-two-second-unreachable (type $44) (param $0 i32) (result i32 i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -3642,7 +3652,7 @@ return ) - ;; CHECK: (func $ref-is-null (type $43) (param $0 anyref) (result i32) + ;; CHECK: (func $ref-is-null (type $45) (param $0 anyref) (result i32) ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -3686,7 +3696,7 @@ throw $tag-pair ) - ;; CHECK: (func $ref-eq (type $44) (param $0 eqref) (param $1 eqref) (result i32) + ;; CHECK: (func $ref-eq (type $46) (param $0 eqref) (param $1 eqref) (result i32) ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -3863,7 +3873,7 @@ table.copy 2 $funcs ) - ;; CHECK: (func $i31-new (type $45) (param $0 i32) (result i31ref) + ;; CHECK: (func $i31-new (type $47) (param $0 i32) (result i31ref) ;; CHECK-NEXT: (ref.i31 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -3873,7 +3883,7 @@ ref.i31 ) - ;; CHECK: (func $i31-get (type $46) (param $0 i31ref) + ;; CHECK: (func $i31-get (type $48) (param $0 i31ref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i31.get_s ;; CHECK-NEXT: (local.get $0) @@ -4092,7 +4102,7 @@ drop ) - ;; CHECK: (func $struct-new (type $47) (param $0 i32) (param $1 i64) (result (ref $pair)) + ;; CHECK: (func $struct-new (type $49) (param $0 i32) (param $1 i64) (result (ref $pair)) ;; CHECK-NEXT: (struct.new $pair ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4104,14 +4114,14 @@ struct.new $pair ) - ;; CHECK: (func $struct-new-default (type $48) (result (ref $pair)) + ;; CHECK: (func $struct-new-default (type $50) (result (ref $pair)) ;; CHECK-NEXT: (struct.new_default $pair) ;; CHECK-NEXT: ) (func $struct-new-default (result (ref $pair)) struct.new_default 14 ) - ;; CHECK: (func $struct-get-0 (type $49) (param $0 (ref $pair)) (result i32) + ;; CHECK: (func $struct-get-0 (type $51) (param $0 (ref $pair)) (result i32) ;; CHECK-NEXT: (struct.get $pair $first ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4121,7 +4131,7 @@ struct.get 14 0 ) - ;; CHECK: (func $struct-get-1 (type $50) (param $0 (ref $pair)) (result i64) + ;; CHECK: (func $struct-get-1 (type $52) (param $0 (ref $pair)) (result i64) ;; CHECK-NEXT: (struct.get $pair $second ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4131,7 +4141,7 @@ struct.get $pair 1 ) - ;; CHECK: (func $struct-get-named (type $51) (param $0 (ref null $pair)) (result i32) + ;; CHECK: (func $struct-get-named (type $53) (param $0 (ref null $pair)) (result i32) ;; CHECK-NEXT: (struct.get $pair $first ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4141,7 +4151,7 @@ struct.get $pair $first ) - ;; CHECK: (func $struct-set-0 (type $52) (param $0 (ref $pair)) (param $1 i32) + ;; CHECK: (func $struct-set-0 (type $54) (param $0 (ref $pair)) (param $1 i32) ;; CHECK-NEXT: (struct.set $pair $first ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4153,7 +4163,7 @@ struct.set $pair 0 ) - ;; CHECK: (func $struct-set-1 (type $53) (param $0 (ref $pair)) (param $1 i64) + ;; CHECK: (func $struct-set-1 (type $55) (param $0 (ref $pair)) (param $1 i64) ;; CHECK-NEXT: (struct.set $pair $second ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4165,7 +4175,7 @@ struct.set 14 1 ) - ;; CHECK: (func $struct-set-named (type $54) (param $0 (ref null $pair)) (param $1 i64) + ;; CHECK: (func $struct-set-named (type $56) (param $0 (ref null $pair)) (param $1 i64) ;; CHECK-NEXT: (struct.set $pair $second ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4177,7 +4187,7 @@ struct.set 14 $second ) - ;; CHECK: (func $array-new (type $55) (param $0 i64) (param $1 i32) (result (ref $a1)) + ;; CHECK: (func $array-new (type $57) (param $0 i64) (param $1 i32) (result (ref $a1)) ;; CHECK-NEXT: (array.new $a1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4189,7 +4199,7 @@ array.new $a1 ) - ;; CHECK: (func $array-new-default (type $56) (param $0 i32) (result (ref $a1)) + ;; CHECK: (func $array-new-default (type $58) (param $0 i32) (result (ref $a1)) ;; CHECK-NEXT: (array.new_default $a1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4199,7 +4209,7 @@ array.new_default 11 ) - ;; CHECK: (func $array-new-data (type $57) (param $0 i32) (param $1 i32) (result (ref $a1)) + ;; CHECK: (func $array-new-data (type $59) (param $0 i32) (param $1 i32) (result (ref $a1)) ;; CHECK-NEXT: (array.new_data $a1 $implicit-data ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4233,7 +4243,7 @@ drop ) - ;; CHECK: (func $array-get (type $58) (param $0 (ref $a1)) (param $1 i32) (result i64) + ;; CHECK: (func $array-get (type $60) (param $0 (ref $a1)) (param $1 i32) (result i64) ;; CHECK-NEXT: (array.get $a1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4245,7 +4255,7 @@ array.get $a1 ) - ;; CHECK: (func $array-get-s (type $59) (param $0 (ref $packed-i8)) (param $1 i32) (result i32) + ;; CHECK: (func $array-get-s (type $61) (param $0 (ref $packed-i8)) (param $1 i32) (result i32) ;; CHECK-NEXT: (array.get_s $packed-i8 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4257,7 +4267,7 @@ array.get_s 15 ) - ;; CHECK: (func $array-get-u (type $60) (param $0 (ref $packed-i16)) (param $1 i32) (result i32) + ;; CHECK: (func $array-get-u (type $62) (param $0 (ref $packed-i16)) (param $1 i32) (result i32) ;; CHECK-NEXT: (array.get_u $packed-i16 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4269,7 +4279,7 @@ array.get_u $packed-i16 ) - ;; CHECK: (func $array-set (type $61) (param $0 (ref $a2)) (param $1 i32) (param $2 f32) + ;; CHECK: (func $array-set (type $63) (param $0 (ref $a2)) (param $1 i32) (param $2 f32) ;; CHECK-NEXT: (array.set $a2 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4283,7 +4293,7 @@ array.set $a2 ) - ;; CHECK: (func $array-len (type $62) (param $0 arrayref) (result i32) + ;; CHECK: (func $array-len (type $64) (param $0 arrayref) (result i32) ;; CHECK-NEXT: (array.len ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4293,7 +4303,7 @@ array.len ) - ;; CHECK: (func $array-copy (type $63) (param $0 (ref $a2)) (param $1 i32) (param $2 (ref $a2)) (param $3 i32) (param $4 i32) + ;; CHECK: (func $array-copy (type $65) (param $0 (ref $a2)) (param $1 i32) (param $2 (ref $a2)) (param $3 i32) (param $4 i32) ;; CHECK-NEXT: (array.copy $a2 $a2 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4311,7 +4321,7 @@ array.copy $a2 $a2 ) - ;; CHECK: (func $array-fill (type $64) (param $0 (ref $a2)) (param $1 i32) (param $2 f32) (param $3 i32) + ;; CHECK: (func $array-fill (type $66) (param $0 (ref $a2)) (param $1 i32) (param $2 f32) (param $3 i32) ;; CHECK-NEXT: (array.fill $a2 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4327,7 +4337,7 @@ array.fill $a2 ) - ;; CHECK: (func $array-init-data (type $65) (param $0 (ref $a2)) (param $1 i32) (param $2 i32) (param $3 i32) + ;; CHECK: (func $array-init-data (type $67) (param $0 (ref $a2)) (param $1 i32) (param $2 i32) (param $3 i32) ;; CHECK-NEXT: (array.init_data $a2 $implicit-data ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4343,7 +4353,7 @@ array.init_data $a2 0 ) - ;; CHECK: (func $array-init-elem (type $66) (param $0 (ref $any-array)) (param $1 i32) (param $2 i32) (param $3 i32) + ;; CHECK: (func $array-init-elem (type $68) (param $0 (ref $any-array)) (param $1 i32) (param $2 i32) (param $3 i32) ;; CHECK-NEXT: (array.init_elem $any-array $passive-2 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4372,7 +4382,7 @@ drop ) - ;; CHECK: (func $any-convert-extern (type $67) (param $0 externref) + ;; CHECK: (func $any-convert-extern (type $69) (param $0 externref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (extern.internalize ;; CHECK-NEXT: (local.get $0) @@ -4398,7 +4408,7 @@ drop ) - ;; CHECK: (func $string-new (type $68) (param $0 i32) (param $1 i32) (result stringref) + ;; CHECK: (func $string-new (type $70) (param $0 i32) (param $1 i32) (result stringref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (string.new_utf8_try ;; CHECK-NEXT: (local.get $0) @@ -4440,7 +4450,7 @@ string.new_wtf16 ) - ;; CHECK: (func $string-new-gc (type $69) (param $0 (ref $packed-i8)) (param $1 i32) (param $2 i32) (result stringref) + ;; CHECK: (func $string-new-gc (type $71) (param $0 (ref $packed-i8)) (param $1 i32) (param $2 i32) (result stringref) ;; CHECK-NEXT: (string.new_utf8_array ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4454,7 +4464,7 @@ string.new_utf8_array ) - ;; CHECK: (func $string-new-code-point (type $70) (param $0 i32) (result stringref) + ;; CHECK: (func $string-new-code-point (type $72) (param $0 i32) (result stringref) ;; CHECK-NEXT: (string.from_code_point ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4464,7 +4474,7 @@ string.from_code_point ) - ;; CHECK: (func $string-const (type $71) (result (ref string)) + ;; CHECK: (func $string-const (type $73) (result (ref string)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (string.const "foobar") ;; CHECK-NEXT: ) @@ -4513,7 +4523,7 @@ drop ) - ;; CHECK: (func $string-hash (type $72) (param $0 stringref) (result i32) + ;; CHECK: (func $string-hash (type $74) (param $0 stringref) (result i32) ;; CHECK-NEXT: (string.hash ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4523,7 +4533,7 @@ string.hash ) - ;; CHECK: (func $stringview-length (type $73) (param $0 stringview_wtf16) (result i32) + ;; CHECK: (func $stringview-length (type $75) (param $0 stringview_wtf16) (result i32) ;; CHECK-NEXT: (stringview_wtf16.length ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4578,7 +4588,7 @@ drop ) - ;; CHECK: (func $string-encode-gc (type $74) (param $0 stringref) (param $1 (ref $packed-i8)) (param $2 i32) (result i32) + ;; CHECK: (func $string-encode-gc (type $76) (param $0 stringref) (param $1 (ref $packed-i8)) (param $2 i32) (result i32) ;; CHECK-NEXT: (string.encode_wtf8_array ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4592,7 +4602,7 @@ string.encode_wtf8_array ) - ;; CHECK: (func $string-concat (type $75) (param $0 stringref) (param $1 stringref) (result (ref string)) + ;; CHECK: (func $string-concat (type $77) (param $0 stringref) (param $1 stringref) (result (ref string)) ;; CHECK-NEXT: (string.concat ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4628,7 +4638,7 @@ string.compare ) - ;; CHECK: (func $string-as-wtf8 (type $76) (param $0 stringref) (result stringview_wtf8) + ;; CHECK: (func $string-as-wtf8 (type $78) (param $0 stringref) (result stringview_wtf8) ;; CHECK-NEXT: (string.as_wtf8 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4638,7 +4648,7 @@ string.as_wtf8 ) - ;; CHECK: (func $string-as-wtf16 (type $77) (param $0 stringref) (result (ref stringview_wtf16)) + ;; CHECK: (func $string-as-wtf16 (type $79) (param $0 stringref) (result (ref stringview_wtf16)) ;; CHECK-NEXT: (string.as_wtf16 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4648,7 +4658,7 @@ string.as_wtf16 ) - ;; CHECK: (func $string-as-iter (type $78) (param $0 stringref) (result stringview_iter) + ;; CHECK: (func $string-as-iter (type $80) (param $0 stringref) (result stringview_iter) ;; CHECK-NEXT: (string.as_iter ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4658,7 +4668,7 @@ string.as_iter ) - ;; CHECK: (func $string-advance (type $79) (param $0 (ref stringview_wtf8)) (param $1 i32) (param $2 i32) (result i32) + ;; CHECK: (func $string-advance (type $81) (param $0 (ref stringview_wtf8)) (param $1 i32) (param $2 i32) (result i32) ;; CHECK-NEXT: (stringview_wtf8.advance ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4672,7 +4682,7 @@ stringview_wtf8.advance ) - ;; CHECK: (func $string-get (type $80) (param $0 stringview_wtf16) (param $1 i32) (result i32) + ;; CHECK: (func $string-get (type $82) (param $0 stringview_wtf16) (param $1 i32) (result i32) ;; CHECK-NEXT: (stringview_wtf16.get_codeunit ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4684,7 +4694,7 @@ stringview_wtf16.get_codeunit ) - ;; CHECK: (func $string-iter-next (type $81) (param $0 stringview_iter) (result i32) + ;; CHECK: (func $string-iter-next (type $83) (param $0 stringview_iter) (result i32) ;; CHECK-NEXT: (stringview_iter.next ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4694,7 +4704,7 @@ stringview_iter.next ) - ;; CHECK: (func $string-iter-advance (type $82) (param $0 stringview_iter) (param $1 i32) (result i32) + ;; CHECK: (func $string-iter-advance (type $84) (param $0 stringview_iter) (param $1 i32) (result i32) ;; CHECK-NEXT: (stringview_iter.advance ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4706,7 +4716,7 @@ stringview_iter.advance ) - ;; CHECK: (func $string-iter-rewind (type $83) (param $0 (ref stringview_iter)) (param $1 i32) (result i32) + ;; CHECK: (func $string-iter-rewind (type $85) (param $0 (ref stringview_iter)) (param $1 i32) (result i32) ;; CHECK-NEXT: (stringview_iter.rewind ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4718,7 +4728,7 @@ stringview_iter.rewind ) - ;; CHECK: (func $string-slice (type $84) (param $0 stringview_wtf8) (param $1 stringview_wtf16) (param $2 i32) (param $3 i32) + ;; CHECK: (func $string-slice (type $86) (param $0 stringview_wtf8) (param $1 stringview_wtf16) (param $2 i32) (param $3 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (stringview_wtf8.slice ;; CHECK-NEXT: (local.get $0) @@ -4747,7 +4757,7 @@ drop ) - ;; CHECK: (func $string-iter-slice (type $85) (param $0 stringview_iter) (param $1 i32) (result (ref string)) + ;; CHECK: (func $string-iter-slice (type $87) (param $0 stringview_iter) (param $1 i32) (result (ref string)) ;; CHECK-NEXT: (stringview_iter.slice ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -4783,7 +4793,7 @@ return_call $return_call ) - ;; CHECK: (func $call-indirect (type $9) (param $0 i32) (param $1 i64) (param $2 v128) + ;; CHECK: (func $call-indirect (type $11) (param $0 i32) (param $1 i64) (param $2 v128) ;; CHECK-NEXT: (call_indirect $timport$0 (type $void) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4845,7 +4855,7 @@ drop ) - ;; CHECK: (func $call-indirect-folded (type $9) (param $0 i32) (param $1 i64) (param $2 v128) + ;; CHECK: (func $call-indirect-folded (type $11) (param $0 i32) (param $1 i64) (param $2 v128) ;; CHECK-NEXT: (call_indirect $timport$0 (type $void) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4918,7 +4928,7 @@ ) ) - ;; CHECK: (func $return-call-indirect (type $9) (param $0 i32) (param $1 i64) (param $2 v128) + ;; CHECK: (func $return-call-indirect (type $11) (param $0 i32) (param $1 i64) (param $2 v128) ;; CHECK-NEXT: (return_call_indirect $timport$0 (type $void) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -4977,7 +4987,7 @@ return_call_indirect (param i64 v128) ) - ;; CHECK: (func $return-call-indirect-folded (type $9) (param $0 i32) (param $1 i64) (param $2 v128) + ;; CHECK: (func $return-call-indirect-folded (type $11) (param $0 i32) (param $1 i64) (param $2 v128) ;; CHECK-NEXT: (return_call_indirect $timport$0 (type $void) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -5046,14 +5056,14 @@ ) ) - ;; CHECK: (func $resume (type $86) (param $ct (ref $simple-cont)) + ;; CHECK: (func $resume (type $88) (param $ct (ref $simple-cont)) ;; CHECK-NEXT: (local $f f32) ;; CHECK-NEXT: (block $label_1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $label (result (ref $to-f32-cont)) ;; CHECK-NEXT: (tuple.drop 3 - ;; CHECK-NEXT: (block $label_0 (type $31) (result i32 i64 (ref null $simple-cont)) + ;; CHECK-NEXT: (block $label_0 (type $33) (result i32 i64 (ref null $simple-cont)) ;; CHECK-NEXT: (local.set $f ;; CHECK-NEXT: (resume $simple-cont (tag $empty $label) (tag $tag-pair-to-pair $label_0) ;; CHECK-NEXT: (i32.const 0) @@ -5087,7 +5097,7 @@ br 0 ) - ;; CHECK: (func $contnew (type $89) (param $f (ref $simple)) (result (ref $simple-cont)) + ;; CHECK: (func $contnew (type $91) (param $f (ref $simple)) (result (ref $simple-cont)) ;; CHECK-NEXT: (cont.new $simple-cont ;; CHECK-NEXT: (local.get $f) ;; CHECK-NEXT: ) @@ -5097,6 +5107,20 @@ cont.new $simple-cont ) + ;; CHECK: (func $contbind (type $92) (param $c (ref $cont-bind-before)) (result (ref $simple-cont)) + ;; CHECK-NEXT: (cont.bind $cont-bind-before $simple-cont + ;; CHECK-NEXT: (i32.const 123) + ;; CHECK-NEXT: (i64.const 123) + ;; CHECK-NEXT: (local.get $c) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $contbind (param $c (ref $cont-bind-before)) (result (ref $simple-cont)) + i32.const 123 + i64.const 123 + local.get $c + cont.bind $cont-bind-before $simple-cont + ) + ;; CHECK: (func $source-maps (type $void) ;; CHECK-NEXT: ;;@ src.cpp:40:1 ;; CHECK-NEXT: (drop @@ -5158,7 +5182,7 @@ end ) - ;; CHECK: (func $use-types (type $101) (param $0 (ref $s0)) (param $1 (ref $s1)) (param $2 (ref $s2)) (param $3 (ref $s3)) (param $4 (ref $s4)) (param $5 (ref $s5)) (param $6 (ref $s6)) (param $7 (ref $s7)) (param $8 (ref $s8)) (param $9 (ref $a0)) (param $10 (ref $a1)) (param $11 (ref $a2)) (param $12 (ref $a3)) (param $13 (ref $subvoid)) (param $14 (ref $submany)) (param $15 (ref $all-types)) + ;; CHECK: (func $use-types (type $104) (param $0 (ref $s0)) (param $1 (ref $s1)) (param $2 (ref $s2)) (param $3 (ref $s3)) (param $4 (ref $s4)) (param $5 (ref $s5)) (param $6 (ref $s6)) (param $7 (ref $s7)) (param $8 (ref $s8)) (param $9 (ref $a0)) (param $10 (ref $a1)) (param $11 (ref $a2)) (param $12 (ref $a3)) (param $13 (ref $subvoid)) (param $14 (ref $submany)) (param $15 (ref $all-types)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $use-types