@@ -603,11 +603,19 @@ void TranslateToFuzzReader::setupHeapTypes() {
603603 interestingHeapSubTypes[struct_].push_back (type);
604604 interestingHeapSubTypes[eq].push_back (type);
605605 interestingHeapSubTypes[any].push_back (type);
606- // Note the mutable fields.
607- auto & fields = type.getStruct ().fields ;
606+ // Note the mutable fields and fields that can be waited on .
607+ const auto & fields = type.getStruct ().fields ;
608608 for (Index i = 0 ; i < fields.size (); i++) {
609609 if (fields[i].mutable_ ) {
610- mutableStructFields.push_back (StructField{type, i});
610+ mutableStructFields.emplace_back (type, i);
611+ }
612+ if (!fields[i].isPacked ()) {
613+ auto fieldType = fields[i].type ;
614+ if (fieldType == Type::i32 || fieldType == Type::i64 ||
615+ Type::isSubType (
616+ fieldType, Type (HeapTypes::eq.getBasic (Shared), Nullable))) {
617+ structWaitFields.emplace_back (type, i);
618+ }
611619 }
612620 }
613621 break ;
@@ -1752,6 +1760,18 @@ void TranslateToFuzzReader::processFunctions() {
17521760 }
17531761 }
17541762
1763+ // if (!ATOMIC_WAITS) {
1764+ // for (auto& func : wasm.functions) {
1765+ // if (!func->imported()) {
1766+ // for (auto* wait : FindAll<StructWait>(func->body).list) {
1767+ // if (wait->timeout->type == Type::i64) {
1768+ // wait->timeout = builder.makeConst(int64_t(0));
1769+ // }
1770+ // }
1771+ // }
1772+ // }
1773+ // }
1774+
17551775 // Also fix up closed world, if we need to. We must do this at the end, so
17561776 // nothing can break the closed world assumptions after.
17571777 if (worldMode == WorldMode::Closed) {
@@ -1901,6 +1921,13 @@ void TranslateToFuzzReader::addHangLimitChecks(Function* func) {
19011921 AndInt32, arrayNew->size , builder.makeConst (int32_t (1024 - 1 )));
19021922 }
19031923 }
1924+ if (!ATOMIC_WAITS ) {
1925+ for (auto * wait : FindAll<StructWait>(func->body ).list ) {
1926+ if (wait->timeout ->type == Type::i64 ) {
1927+ wait->timeout = builder.makeConst (int64_t (0 ));
1928+ }
1929+ }
1930+ }
19041931}
19051932
19061933void TranslateToFuzzReader::recombine (Function* func) {
@@ -2436,6 +2463,14 @@ void TranslateToFuzzReader::fixAfterChanges(Function* func) {
24362463 } fixer (wasm, *this );
24372464 fixer.walk (func->body );
24382465
2466+ // if (!ATOMIC_WAITS) {
2467+ // for (auto* wait : FindAll<StructWait>(func->body).list) {
2468+ // if (wait->timeout->type == Type::i64) {
2469+ // wait->timeout = builder.makeConst(int64_t(0));
2470+ // }
2471+ // }
2472+ // }
2473+
24392474 // Refinalize at the end, after labels are all fixed up.
24402475 ReFinalize ().walkFunctionInModule (func, &wasm);
24412476}
@@ -2881,6 +2916,13 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
28812916 &Self::makeStringEq,
28822917 &Self::makeStringMeasure,
28832918 &Self::makeStringGet);
2919+ options.add (FeatureSet::ReferenceTypes | FeatureSet::SharedEverything,
2920+ &Self::makeWaitqueueNotify);
2921+ if (!structWaitFields.empty ()) {
2922+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
2923+ FeatureSet::SharedEverything,
2924+ &Self::makeStructWait);
2925+ }
28842926 }
28852927 if (type == Type::i64 ) {
28862928 options.add (FeatureSet::WideArithmetic | FeatureSet::Multivalue,
@@ -4407,17 +4449,20 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) {
44074449 case HeapType::noext:
44084450 case HeapType::nofunc:
44094451 case HeapType::nocont:
4410- case HeapType::noexn: {
4452+ case HeapType::noexn:
4453+ case HeapType::nowaitqueue: {
44114454 auto null = builder.makeRefNull (heapType.getBasic (share));
44124455 if (!type.isNullable ()) {
44134456 return builder.makeRefAs (RefAsNonNull, null);
44144457 }
44154458 return null;
44164459 }
44174460
4418- case HeapType::waitqueue:
4419- case HeapType::nowaitqueue: {
4420- WASM_UNREACHABLE (" waitqueue is unimplemented in the fuzzer" );
4461+ case HeapType::waitqueue: {
4462+ if (type.isNullable () && oneIn (2 )) {
4463+ return builder.makeRefNull (HeapTypes::sharedWaitqueue.getBasic (share));
4464+ }
4465+ return builder.makeWaitqueueNew ();
44214466 }
44224467 }
44234468 WASM_UNREACHABLE (" invalid basic ref type" );
@@ -6060,8 +6105,8 @@ Expression* TranslateToFuzzReader::makeStructSet(Type type) {
60606105 return makeTrivial (type);
60616106 }
60626107 auto [structType, fieldIndex] = pick (mutableStructFields);
6063- auto fieldType = structType.getStruct ().fields [fieldIndex].type ;
60646108 auto * ref = makeTrappingRefUse (structType);
6109+ auto fieldType = structType.getStruct ().fields [fieldIndex].type ;
60656110 auto * value = make (fieldType);
60666111 auto order = MemoryOrder::Unordered;
60676112 if (wasm.features .hasAtomics () && wasm.features .hasSharedEverything () &&
@@ -6071,6 +6116,35 @@ Expression* TranslateToFuzzReader::makeStructSet(Type type) {
60716116 return builder.makeStructSet (fieldIndex, ref, value, order);
60726117}
60736118
6119+ Expression* TranslateToFuzzReader::makeStructWait (Type type) {
6120+ assert (type == Type::i32 );
6121+ assert (!structWaitFields.empty ());
6122+ auto [structType, fieldIndex] = pick (structWaitFields);
6123+ auto * ref = makeTrappingRefUse (structType);
6124+ auto * waitqueue =
6125+ makeTrappingRefUse (Type (HeapTypes::sharedWaitqueue, Nullable));
6126+ auto expectedType = structType.getStruct ().fields [fieldIndex].type ;
6127+ if (expectedType.isRef ()) {
6128+ expectedType = Type (HeapTypes::eq.getBasic (Shared), Nullable);
6129+ }
6130+ auto * expected = make (expectedType);
6131+ Expression* timeout = nullptr ;
6132+ if (ATOMIC_WAITS && oneIn (2 )) {
6133+ timeout = make (Type::i64 );
6134+ } else {
6135+ timeout = builder.makeConst (int64_t {0 });
6136+ }
6137+ return builder.makeStructWait (fieldIndex, ref, waitqueue, expected, timeout);
6138+ }
6139+
6140+ Expression* TranslateToFuzzReader::makeWaitqueueNotify (Type type) {
6141+ assert (type == Type::i32 );
6142+ auto * waitqueue =
6143+ makeTrappingRefUse (Type (HeapTypes::sharedWaitqueue, Nullable));
6144+ auto * count = make (Type::i32 );
6145+ return builder.makeWaitqueueNotify (waitqueue, count);
6146+ }
6147+
60746148// Make a bounds check for an array operation, given a ref + index. An optional
60756149// additional length parameter can be provided, which is added to the index if
60766150// so (that is useful for something like array.fill, which operations on not a
@@ -6705,11 +6779,11 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) {
67056779 case HeapType::nofunc:
67066780 case HeapType::nocont:
67076781 case HeapType::noexn:
6782+ case HeapType::nowaitqueue:
67086783 break ;
67096784 case HeapType::waitqueue:
6710- case HeapType::nowaitqueue: {
6711- WASM_UNREACHABLE (" waitqueue is unimplemented in the fuzzer" );
6712- }
6785+ return pick (HeapTypes::sharedWaitqueue, HeapTypes::sharedNowaitqueue)
6786+ .getBasic (share);
67136787 }
67146788 }
67156789 // Look for an interesting subtype.
0 commit comments