@@ -491,6 +491,7 @@ void TranslateToFuzzReader::setupHeapTypes() {
491491 auto eq = HeapTypes::eq.getBasic (share);
492492 auto any = HeapTypes::any.getBasic (share);
493493 auto func = HeapTypes::func.getBasic (share);
494+ auto cont = HeapTypes::cont.getBasic (share);
494495 switch (type.getKind ()) {
495496 case HeapTypeKind::Func:
496497 interestingHeapSubTypes[func].push_back (type);
@@ -517,7 +518,8 @@ void TranslateToFuzzReader::setupHeapTypes() {
517518 }
518519 break ;
519520 case HeapTypeKind::Cont:
520- WASM_UNREACHABLE (" TODO: cont" );
521+ interestingHeapSubTypes[cont].push_back (type);
522+ break ;
521523 case HeapTypeKind::Basic:
522524 WASM_UNREACHABLE (" unexpected kind" );
523525 }
@@ -672,6 +674,7 @@ void TranslateToFuzzReader::setupGlobals() {
672674 // Create new random globals.
673675 for (size_t index = upTo (fuzzParams->MAX_GLOBALS ); index > 0 ; --index) {
674676 auto type = getConcreteType ();
677+
675678 // Prefer immutable ones as they can be used in global.gets in other
676679 // globals, for more interesting patterns.
677680 auto mutability = oneIn (3 ) ? Builder::Mutable : Builder::Immutable;
@@ -680,12 +683,16 @@ void TranslateToFuzzReader::setupGlobals() {
680683 // initializer.
681684 auto * init = makeTrivial (type);
682685
683- if (!FindAll<RefAs>(init).list .empty ()) {
686+ if (!FindAll<RefAs>(init).list .empty () ||
687+ !FindAll<ContNew>(init).list .empty ()) {
684688 // When creating this initial value we ended up emitting a RefAs, which
685689 // means we had to stop in the middle of an overly-nested struct or array,
686690 // which we can break out of using ref.as_non_null of a nullable ref. That
687691 // traps in normal code, which is bad enough, but it does not even
688692 // validate in a global. Switch to something safe instead.
693+ //
694+ // Likewise, if we see cont.new, we must switch as well. That can happen
695+ // if a nested struct we create has a continuation field, for example.
689696 type = getMVPType ();
690697 init = makeConst (type);
691698 } else if (type.isTuple () && !init->is <TupleMake>()) {
@@ -708,6 +715,9 @@ void TranslateToFuzzReader::setupTags() {
708715 if (tag->imported () && !preserveImportsAndExports) {
709716 tag->module = tag->base = Name ();
710717 }
718+ if (tag->results () == Type::none) {
719+ exceptionTags.push_back (tag.get ());
720+ }
711721 }
712722
713723 // Add some random tags.
@@ -736,7 +746,8 @@ void TranslateToFuzzReader::setupTags() {
736746void TranslateToFuzzReader::addTag () {
737747 auto tag = builder.makeTag (Names::getValidTagName (wasm, " tag$" ),
738748 Signature (getControlFlowType (), Type::none));
739- wasm.addTag (std::move (tag));
749+ auto * tagg = wasm.addTag (std::move (tag));
750+ exceptionTags.push_back (tagg);
740751}
741752
742753void TranslateToFuzzReader::finalizeMemory () {
@@ -2432,10 +2443,10 @@ Expression* TranslateToFuzzReader::makeTry(Type type) {
24322443 auto numTags = upTo (fuzzParams->MAX_TRY_CATCHES );
24332444 std::unordered_set<Tag*> usedTags;
24342445 for (Index i = 0 ; i < numTags; i++) {
2435- if (wasm. tags .empty ()) {
2446+ if (exceptionTags .empty ()) {
24362447 addTag ();
24372448 }
2438- auto * tag = pick (wasm. tags ). get ( );
2449+ auto * tag = pick (exceptionTags );
24392450 if (usedTags.count (tag)) {
24402451 continue ;
24412452 }
@@ -2482,7 +2493,7 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) {
24822493 return builder.makeTryTable (body, {}, {}, {});
24832494 }
24842495
2485- if (wasm. tags .empty ()) {
2496+ if (exceptionTags .empty ()) {
24862497 addTag ();
24872498 }
24882499
@@ -2497,7 +2508,7 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) {
24972508 Type tagType;
24982509 if (i < numCatches) {
24992510 // Look for a specific tag.
2500- auto & tag = pick (wasm. tags );
2511+ auto * tag = pick (exceptionTags );
25012512 tagName = tag->name ;
25022513 tagType = tag->params ();
25032514 } else {
@@ -3449,7 +3460,15 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) {
34493460 return makeRefFuncConst (type);
34503461 }
34513462 case HeapType::cont: {
3452- WASM_UNREACHABLE (" not implemented" );
3463+ // Most of the time, avoid null continuations, as they will trap.
3464+ if (type.isNullable () && oneIn (4 )) {
3465+ return builder.makeRefNull (HeapTypes::cont.getBasic (share));
3466+ }
3467+ // Emit the simplest possible continuation.
3468+ auto funcSig = Signature (Type::none, Type::none);
3469+ auto funcType = Type (funcSig, NonNullable);
3470+ auto contType = Continuation (funcSig);
3471+ return builder.makeContNew (contType, makeRefFuncConst (funcType));
34533472 }
34543473 case HeapType::any: {
34553474 // Choose a subtype we can materialize a constant for. We cannot
@@ -3673,8 +3692,10 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) {
36733692 builder.makeConst (int32_t (upTo (fuzzParams->MAX_ARRAY_SIZE )));
36743693 return builder.makeArrayNew (type.getHeapType (), count, init);
36753694 }
3676- case HeapTypeKind::Cont:
3677- WASM_UNREACHABLE (" TODO: cont" );
3695+ case HeapTypeKind::Cont: {
3696+ auto funcType = heapType.getContinuation ().type ;
3697+ return builder.makeContNew (heapType, makeTrappingRefUse (funcType));
3698+ }
36783699 case HeapTypeKind::Basic:
36793700 break ;
36803701 }
@@ -5222,10 +5243,10 @@ Expression* TranslateToFuzzReader::makeThrow(Type type) {
52225243 }
52235244 } else {
52245245 // Get a random tag, adding a random one if necessary.
5225- if (wasm. tags .empty ()) {
5246+ if (exceptionTags .empty ()) {
52265247 addTag ();
52275248 }
5228- tag = pick (wasm. tags ). get ( );
5249+ tag = pick (exceptionTags );
52295250 }
52305251 auto tagType = tag->params ();
52315252 std::vector<Expression*> operands;
0 commit comments