@@ -2608,6 +2608,12 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
26082608 if (typeArrays.find (type) != typeArrays.end ()) {
26092609 options.add (FeatureSet::ReferenceTypes | FeatureSet::GC,
26102610 &Self::makeArrayGet);
2611+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
2612+ FeatureSet::Atomics | FeatureSet::SharedEverything,
2613+ &Self::makeArrayRMW);
2614+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
2615+ FeatureSet::Atomics | FeatureSet::SharedEverything,
2616+ &Self::makeArrayCmpxchg);
26112617 }
26122618 }
26132619 return (this ->*pick (options))(type);
@@ -5726,19 +5732,23 @@ Expression* TranslateToFuzzReader::makeArrayGet(Type type) {
57265732 auto * ref = makeTrappingRefUse (arrayType);
57275733 auto * index = make (Type::i32 );
57285734 auto signed_ = maybeSignedGet (arrayType.getArray ().element );
5735+ auto order = MemoryOrder::Unordered;
5736+ if (wasm.features .hasAtomics () && wasm.features .hasSharedEverything () &&
5737+ oneIn (2 )) {
5738+ order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5739+ }
57295740 // Only rarely emit a plain get which might trap. See related logic in
57305741 // ::makePointer().
57315742 if (allowOOB && oneIn (10 )) {
5732- return builder.makeArrayGet (
5733- ref, index, MemoryOrder::Unordered, type, signed_);
5743+ return builder.makeArrayGet (ref, index, order, type, signed_);
57345744 }
57355745 // To avoid a trap, check the length dynamically using this pattern:
57365746 //
57375747 // index < array.len ? array[index] : ..some fallback value..
57385748 //
57395749 auto check = makeArrayBoundsCheck (ref, index, funcContext->func , builder);
5740- auto * get = builder. makeArrayGet (
5741- check.getRef , check.getIndex , MemoryOrder::Unordered , type, signed_);
5750+ auto * get =
5751+ builder. makeArrayGet ( check.getRef , check.getIndex , order , type, signed_);
57425752 auto * fallback = makeTrivial (type);
57435753 return builder.makeIf (check.condition , get, fallback);
57445754}
@@ -5753,21 +5763,96 @@ Expression* TranslateToFuzzReader::makeArraySet(Type type) {
57535763 auto * index = make (Type::i32 );
57545764 auto * ref = makeTrappingRefUse (arrayType);
57555765 auto * value = make (elementType);
5766+ auto order = MemoryOrder::Unordered;
5767+ if (wasm.features .hasAtomics () && wasm.features .hasSharedEverything () &&
5768+ oneIn (2 )) {
5769+ order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5770+ }
57565771 // Only rarely emit a plain get which might trap. See related logic in
57575772 // ::makePointer().
57585773 if (allowOOB && oneIn (10 )) {
5759- return builder.makeArraySet (ref, index, value, MemoryOrder::Unordered );
5774+ return builder.makeArraySet (ref, index, value, order );
57605775 }
5761- // To avoid a trap, check the length dynamically using this pattern:
5762- //
5763- // if (index < array.len) array[index] = value;
5764- //
5776+ // To avoid a trap, check the length dynamically.
57655777 auto check = makeArrayBoundsCheck (ref, index, funcContext->func , builder);
5766- auto * set = builder.makeArraySet (
5767- check.getRef , check.getIndex , value, MemoryOrder::Unordered);
5778+ auto * set = builder.makeArraySet (check.getRef , check.getIndex , value, order);
57685779 return builder.makeIf (check.condition , set);
57695780}
57705781
5782+ Expression* TranslateToFuzzReader::makeArrayRMW (Type type) {
5783+ bool isAny =
5784+ type.isRef () &&
5785+ HeapType (type.getHeapType ().getTop ()).isMaybeShared (HeapType::any);
5786+ if (type != Type::i32 && type != Type::i64 && !isAny) {
5787+ // Not a valid element type for an RMW operation.
5788+ return makeArrayGet (type);
5789+ }
5790+ auto & arrays = typeArrays[type];
5791+ assert (!arrays.empty ());
5792+ auto arrayType = pick (arrays);
5793+ const auto & element = arrayType.getArray ().element ;
5794+ if (element.isPacked () || element.mutable_ == Immutable) {
5795+ // Cannot RMW a packed or immutable field.
5796+ return makeArrayGet (type);
5797+ }
5798+ AtomicRMWOp op = RMWXchg;
5799+ if (type == Type::i32 || type == Type::i64 ) {
5800+ op = pick (RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg);
5801+ }
5802+ auto * ref = makeTrappingRefUse (arrayType);
5803+ auto * index = make (Type::i32 );
5804+ auto * value = make (type);
5805+ auto order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5806+ // Only rarely emit a plain operation which might trap. See related logic in
5807+ // ::makePointer().
5808+ if (allowOOB && oneIn (10 )) {
5809+ return builder.makeArrayRMW (op, ref, index, value, order);
5810+ }
5811+ // To avoid a trap, check the length dynamically.
5812+ auto check = makeArrayBoundsCheck (ref, index, funcContext->func , builder);
5813+ auto * rmw =
5814+ builder.makeArrayRMW (op, check.getRef , check.getIndex , value, order);
5815+ auto * fallback = makeTrivial (type);
5816+ return builder.makeIf (check.condition , rmw, fallback);
5817+ }
5818+
5819+ Expression* TranslateToFuzzReader::makeArrayCmpxchg (Type type) {
5820+ bool isShared = type.isRef () && type.getHeapType ().isShared ();
5821+ Type eq (HeapTypes::eq.getBasic (isShared ? Shared : Unshared), Nullable);
5822+ bool isEq = Type::isSubType (type, eq);
5823+ if (type != Type::i32 && type != Type::i64 && !isEq) {
5824+ // Not a valid element type for a cmpxchg operation.
5825+ return makeArrayGet (type);
5826+ }
5827+ auto & arrays = typeArrays[type];
5828+ assert (!arrays.empty ());
5829+ auto arrayType = pick (arrays);
5830+ const auto & element = arrayType.getArray ().element ;
5831+ if (element.isPacked () || element.mutable_ == Immutable) {
5832+ // Cannot RMW a packed or immutable field.
5833+ return makeArrayGet (type);
5834+ }
5835+ auto * ref = makeTrappingRefUse (arrayType);
5836+ auto * index = make (Type::i32 );
5837+ // For reference fields, expected can be a subtype of eq. Only use the extra
5838+ // flexibility occasionally because it makes the expected value less likely to
5839+ // be equal to the actual value.
5840+ auto * expected = make (isEq && oneIn (4 ) ? eq : type);
5841+ auto * replacement = make (type);
5842+ auto order = oneIn (2 ) ? MemoryOrder::SeqCst : MemoryOrder::AcqRel;
5843+ // Only rarely emit a plain operation which might trap. See related logic in
5844+ // ::makePointer().
5845+ if (allowOOB && oneIn (10 )) {
5846+ return builder.makeArrayCmpxchg (ref, index, expected, replacement, order);
5847+ }
5848+ // To avoid a trap, check the length dynamically.
5849+ auto check = makeArrayBoundsCheck (ref, index, funcContext->func , builder);
5850+ auto * cmpxchg = builder.makeArrayCmpxchg (
5851+ check.getRef , check.getIndex , expected, replacement, order);
5852+ auto * fallback = makeTrivial (type);
5853+ return builder.makeIf (check.condition , cmpxchg, fallback);
5854+ }
5855+
57715856Expression* TranslateToFuzzReader::makeArrayBulkMemoryOp (Type type) {
57725857 assert (type == Type::none);
57735858 if (mutableArrays.empty ()) {
0 commit comments