@@ -560,12 +560,20 @@ void TranslateToFuzzReader::setupHeapTypes() {
560560 interestingHeapSubTypes[struct_].push_back (type);
561561 interestingHeapSubTypes[eq].push_back (type);
562562 interestingHeapSubTypes[any].push_back (type);
563- // Note the mutable fields.
563+ // Note the mutable fields and fields that can be waited on .
564564 auto & fields = type.getStruct ().fields ;
565565 for (Index i = 0 ; i < fields.size (); i++) {
566566 if (fields[i].mutable_ ) {
567567 mutableStructFields.push_back (StructField{type, i});
568568 }
569+ if (!fields[i].isPacked ()) {
570+ auto fieldType = fields[i].type ;
571+ if (fieldType == Type::i32 || fieldType == Type::i64 ||
572+ Type::isSubType (
573+ fieldType, Type (HeapTypes::eq.getBasic (Shared), Nullable))) {
574+ structWaitFields.push_back (StructField{type, i});
575+ }
576+ }
569577 }
570578 break ;
571579 }
@@ -1709,6 +1717,18 @@ void TranslateToFuzzReader::processFunctions() {
17091717 }
17101718 }
17111719
1720+ if (!ATOMIC_WAITS ) {
1721+ for (auto & func : wasm.functions ) {
1722+ if (!func->imported ()) {
1723+ for (auto * wait : FindAll<StructWait>(func->body ).list ) {
1724+ if (wait->timeout ->type == Type::i64 ) {
1725+ wait->timeout = builder.makeConst (int64_t (0 ));
1726+ }
1727+ }
1728+ }
1729+ }
1730+ }
1731+
17121732 // Also fix up closed world, if we need to. We must do this at the end, so
17131733 // nothing can break the closed world assumptions after.
17141734 if (worldMode == WorldMode::Closed) {
@@ -1858,6 +1878,13 @@ void TranslateToFuzzReader::addHangLimitChecks(Function* func) {
18581878 AndInt32, arrayNew->size , builder.makeConst (int32_t (1024 - 1 )));
18591879 }
18601880 }
1881+ if (!ATOMIC_WAITS ) {
1882+ for (auto * wait : FindAll<StructWait>(func->body ).list ) {
1883+ if (wait->timeout ->type == Type::i64 ) {
1884+ wait->timeout = builder.makeConst (int64_t (0 ));
1885+ }
1886+ }
1887+ }
18611888}
18621889
18631890void TranslateToFuzzReader::recombine (Function* func) {
@@ -2393,6 +2420,14 @@ void TranslateToFuzzReader::fixAfterChanges(Function* func) {
23932420 } fixer (wasm, *this );
23942421 fixer.walk (func->body );
23952422
2423+ if (!ATOMIC_WAITS ) {
2424+ for (auto * wait : FindAll<StructWait>(func->body ).list ) {
2425+ if (wait->timeout ->type == Type::i64 ) {
2426+ wait->timeout = builder.makeConst (int64_t (0 ));
2427+ }
2428+ }
2429+ }
2430+
23962431 // Refinalize at the end, after labels are all fixed up.
23972432 ReFinalize ().walkFunctionInModule (func, &wasm);
23982433}
@@ -2838,6 +2873,11 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
28382873 &Self::makeStringEq,
28392874 &Self::makeStringMeasure,
28402875 &Self::makeStringGet);
2876+ options.add (FeatureSet::ReferenceTypes | FeatureSet::SharedEverything,
2877+ &Self::makeWaitqueueNotify);
2878+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
2879+ FeatureSet::SharedEverything,
2880+ &Self::makeStructWait);
28412881 }
28422882 if (type.isTuple ()) {
28432883 if (type == Types::getI64Pair () && oneIn (2 )) {
@@ -4349,17 +4389,20 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) {
43494389 case HeapType::noext:
43504390 case HeapType::nofunc:
43514391 case HeapType::nocont:
4352- case HeapType::noexn: {
4392+ case HeapType::noexn:
4393+ case HeapType::nowaitqueue: {
43534394 auto null = builder.makeRefNull (heapType.getBasic (share));
43544395 if (!type.isNullable ()) {
43554396 return builder.makeRefAs (RefAsNonNull, null);
43564397 }
43574398 return null;
43584399 }
43594400
4360- case HeapType::waitqueue:
4361- case HeapType::nowaitqueue: {
4362- WASM_UNREACHABLE (" waitqueue is unimplemented in the fuzzer" );
4401+ case HeapType::waitqueue: {
4402+ if (type.isNullable () && oneIn (2 )) {
4403+ return builder.makeRefNull (HeapTypes::sharedWaitqueue.getBasic (share));
4404+ }
4405+ return builder.makeWaitqueueNew ();
43634406 }
43644407 }
43654408 WASM_UNREACHABLE (" invalid basic ref type" );
@@ -6002,8 +6045,11 @@ Expression* TranslateToFuzzReader::makeStructSet(Type type) {
60026045 return makeTrivial (type);
60036046 }
60046047 auto [structType, fieldIndex] = pick (mutableStructFields);
6005- auto fieldType = structType.getStruct ().fields [fieldIndex].type ;
60066048 auto * ref = makeTrappingRefUse (structType);
6049+ auto fieldType = structType.getStruct ().fields [fieldIndex].type ;
6050+ if (ref->type .isStruct ()) {
6051+ fieldType = ref->type .getHeapType ().getStruct ().fields [fieldIndex].type ;
6052+ }
60076053 auto * value = make (fieldType);
60086054 auto order = MemoryOrder::Unordered;
60096055 if (wasm.features .hasAtomics () && wasm.features .hasSharedEverything () &&
@@ -6013,6 +6059,35 @@ Expression* TranslateToFuzzReader::makeStructSet(Type type) {
60136059 return builder.makeStructSet (fieldIndex, ref, value, order);
60146060}
60156061
6062+ Expression* TranslateToFuzzReader::makeStructWait (Type type) {
6063+ assert (type == Type::i32 );
6064+ if (structWaitFields.empty ()) {
6065+ return makeTrivial (type);
6066+ }
6067+ auto [structType, fieldIndex] = pick (structWaitFields);
6068+ auto * ref = makeTrappingRefUse (structType);
6069+ auto * waitqueue = make (Type (HeapTypes::sharedWaitqueue, Nullable));
6070+ auto fieldType = structType.getStruct ().fields [fieldIndex].type ;
6071+ if (ref->type .isStruct ()) {
6072+ fieldType = ref->type .getHeapType ().getStruct ().fields [fieldIndex].type ;
6073+ }
6074+ auto * expected = make (fieldType);
6075+ Expression* timeout = nullptr ;
6076+ if (ATOMIC_WAITS && oneIn (2 )) {
6077+ timeout = make (Type::i64 );
6078+ } else {
6079+ timeout = builder.makeConst (int64_t (0 ));
6080+ }
6081+ return builder.makeStructWait (fieldIndex, ref, waitqueue, expected, timeout);
6082+ }
6083+
6084+ Expression* TranslateToFuzzReader::makeWaitqueueNotify (Type type) {
6085+ assert (type == Type::i32 );
6086+ auto * waitqueue = make (Type (HeapTypes::sharedWaitqueue, Nullable));
6087+ auto * count = make (Type::i32 );
6088+ return builder.makeWaitqueueNotify (waitqueue, count);
6089+ }
6090+
60166091// Make a bounds check for an array operation, given a ref + index. An optional
60176092// additional length parameter can be provided, which is added to the index if
60186093// so (that is useful for something like array.fill, which operations on not a
@@ -6647,11 +6722,11 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) {
66476722 case HeapType::nofunc:
66486723 case HeapType::nocont:
66496724 case HeapType::noexn:
6725+ case HeapType::nowaitqueue:
66506726 break ;
66516727 case HeapType::waitqueue:
6652- case HeapType::nowaitqueue: {
6653- WASM_UNREACHABLE (" waitqueue is unimplemented in the fuzzer" );
6654- }
6728+ return pick (HeapTypes::sharedWaitqueue, HeapTypes::sharedNowaitqueue)
6729+ .getBasic (share);
66556730 }
66566731 }
66576732 // Look for an interesting subtype.
0 commit comments