@@ -491,6 +491,7 @@ void TranslateToFuzzReader::setupHeapTypes() {
491
491
auto eq = HeapTypes::eq.getBasic (share);
492
492
auto any = HeapTypes::any.getBasic (share);
493
493
auto func = HeapTypes::func.getBasic (share);
494
+ auto cont = HeapTypes::cont.getBasic (share);
494
495
switch (type.getKind ()) {
495
496
case HeapTypeKind::Func:
496
497
interestingHeapSubTypes[func].push_back (type);
@@ -517,7 +518,8 @@ void TranslateToFuzzReader::setupHeapTypes() {
517
518
}
518
519
break ;
519
520
case HeapTypeKind::Cont:
520
- WASM_UNREACHABLE (" TODO: cont" );
521
+ interestingHeapSubTypes[cont].push_back (type);
522
+ break ;
521
523
case HeapTypeKind::Basic:
522
524
WASM_UNREACHABLE (" unexpected kind" );
523
525
}
@@ -672,6 +674,7 @@ void TranslateToFuzzReader::setupGlobals() {
672
674
// Create new random globals.
673
675
for (size_t index = upTo (fuzzParams->MAX_GLOBALS ); index > 0 ; --index) {
674
676
auto type = getConcreteType ();
677
+
675
678
// Prefer immutable ones as they can be used in global.gets in other
676
679
// globals, for more interesting patterns.
677
680
auto mutability = oneIn (3 ) ? Builder::Mutable : Builder::Immutable;
@@ -680,12 +683,16 @@ void TranslateToFuzzReader::setupGlobals() {
680
683
// initializer.
681
684
auto * init = makeTrivial (type);
682
685
683
- if (!FindAll<RefAs>(init).list .empty ()) {
686
+ if (!FindAll<RefAs>(init).list .empty () ||
687
+ !FindAll<ContNew>(init).list .empty ()) {
684
688
// When creating this initial value we ended up emitting a RefAs, which
685
689
// means we had to stop in the middle of an overly-nested struct or array,
686
690
// which we can break out of using ref.as_non_null of a nullable ref. That
687
691
// traps in normal code, which is bad enough, but it does not even
688
692
// 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.
689
696
type = getMVPType ();
690
697
init = makeConst (type);
691
698
} else if (type.isTuple () && !init->is <TupleMake>()) {
@@ -708,6 +715,9 @@ void TranslateToFuzzReader::setupTags() {
708
715
if (tag->imported () && !preserveImportsAndExports) {
709
716
tag->module = tag->base = Name ();
710
717
}
718
+ if (tag->results () == Type::none) {
719
+ exceptionTags.push_back (tag.get ());
720
+ }
711
721
}
712
722
713
723
// Add some random tags.
@@ -736,7 +746,8 @@ void TranslateToFuzzReader::setupTags() {
736
746
void TranslateToFuzzReader::addTag () {
737
747
auto tag = builder.makeTag (Names::getValidTagName (wasm, " tag$" ),
738
748
Signature (getControlFlowType (), Type::none));
739
- wasm.addTag (std::move (tag));
749
+ auto * tagg = wasm.addTag (std::move (tag));
750
+ exceptionTags.push_back (tagg);
740
751
}
741
752
742
753
void TranslateToFuzzReader::finalizeMemory () {
@@ -2432,10 +2443,10 @@ Expression* TranslateToFuzzReader::makeTry(Type type) {
2432
2443
auto numTags = upTo (fuzzParams->MAX_TRY_CATCHES );
2433
2444
std::unordered_set<Tag*> usedTags;
2434
2445
for (Index i = 0 ; i < numTags; i++) {
2435
- if (wasm. tags .empty ()) {
2446
+ if (exceptionTags .empty ()) {
2436
2447
addTag ();
2437
2448
}
2438
- auto * tag = pick (wasm. tags ). get ( );
2449
+ auto * tag = pick (exceptionTags );
2439
2450
if (usedTags.count (tag)) {
2440
2451
continue ;
2441
2452
}
@@ -2482,7 +2493,7 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) {
2482
2493
return builder.makeTryTable (body, {}, {}, {});
2483
2494
}
2484
2495
2485
- if (wasm. tags .empty ()) {
2496
+ if (exceptionTags .empty ()) {
2486
2497
addTag ();
2487
2498
}
2488
2499
@@ -2497,7 +2508,7 @@ Expression* TranslateToFuzzReader::makeTryTable(Type type) {
2497
2508
Type tagType;
2498
2509
if (i < numCatches) {
2499
2510
// Look for a specific tag.
2500
- auto & tag = pick (wasm. tags );
2511
+ auto * tag = pick (exceptionTags );
2501
2512
tagName = tag->name ;
2502
2513
tagType = tag->params ();
2503
2514
} else {
@@ -3449,7 +3460,15 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) {
3449
3460
return makeRefFuncConst (type);
3450
3461
}
3451
3462
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));
3453
3472
}
3454
3473
case HeapType::any: {
3455
3474
// Choose a subtype we can materialize a constant for. We cannot
@@ -3673,8 +3692,10 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) {
3673
3692
builder.makeConst (int32_t (upTo (fuzzParams->MAX_ARRAY_SIZE )));
3674
3693
return builder.makeArrayNew (type.getHeapType (), count, init);
3675
3694
}
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
+ }
3678
3699
case HeapTypeKind::Basic:
3679
3700
break ;
3680
3701
}
@@ -5222,10 +5243,10 @@ Expression* TranslateToFuzzReader::makeThrow(Type type) {
5222
5243
}
5223
5244
} else {
5224
5245
// Get a random tag, adding a random one if necessary.
5225
- if (wasm. tags .empty ()) {
5246
+ if (exceptionTags .empty ()) {
5226
5247
addTag ();
5227
5248
}
5228
- tag = pick (wasm. tags ). get ( );
5249
+ tag = pick (exceptionTags );
5229
5250
}
5230
5251
auto tagType = tag->params ();
5231
5252
std::vector<Expression*> operands;
0 commit comments