@@ -1367,7 +1367,8 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
13671367 &Self::makeCallIndirect)
13681368 .add (FeatureSet::ExceptionHandling, &Self::makeTry)
13691369 .add (FeatureSet::ExceptionHandling, &Self::makeTryTable)
1370- .add (FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef);
1370+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeCallRef)
1371+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeBrOn);
13711372 }
13721373 if (type.isSingle ()) {
13731374 options
@@ -1454,10 +1455,11 @@ Expression* TranslateToFuzzReader::_makenone() {
14541455 .add (FeatureSet::Atomics, &Self::makeAtomic)
14551456 .add (FeatureSet::ExceptionHandling, &Self::makeTry)
14561457 .add (FeatureSet::ExceptionHandling, &Self::makeTryTable)
1457- .add (FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef)
1458- .add (FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeStructSet)
1459- .add (FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeArraySet)
1460- .add (FeatureSet::GC | FeatureSet::ReferenceTypes,
1458+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeCallRef)
1459+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeStructSet)
1460+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeArraySet)
1461+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeBrOn)
1462+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC,
14611463 &Self::makeArrayBulkMemoryOp);
14621464 return (this ->*pick (options))(Type::none);
14631465}
@@ -1484,7 +1486,7 @@ Expression* TranslateToFuzzReader::_makeunreachable() {
14841486 &Self::makeDrop,
14851487 &Self::makeReturn)
14861488 .add (FeatureSet::ExceptionHandling, &Self::makeThrow)
1487- .add (FeatureSet::GC | FeatureSet::ReferenceTypes , &Self::makeCallRef);
1489+ .add (FeatureSet::ReferenceTypes | FeatureSet::GC , &Self::makeCallRef);
14881490 return (this ->*pick (options))(Type::unreachable);
14891491}
14901492
@@ -3944,6 +3946,116 @@ Expression* TranslateToFuzzReader::makeRefCast(Type type) {
39443946 return builder.makeRefCast (make (refType), type);
39453947}
39463948
3949+ Expression* TranslateToFuzzReader::makeBrOn (Type type) {
3950+ if (funcContext->breakableStack .empty ()) {
3951+ return makeTrivial (type);
3952+ }
3953+ // We need to find a proper target to break to; try a few times. Finding the
3954+ // target is harder than flowing out the proper type, so focus on the target,
3955+ // and fix up the flowing type later. That is, once we find a target to break
3956+ // to, we can then either drop ourselves or wrap ourselves in a block +
3957+ // another value, so that we return the proper thing here (which is done below
3958+ // in fixFlowingType).
3959+ int tries = TRIES;
3960+ Name targetName;
3961+ Type targetType;
3962+ while (--tries >= 0 ) {
3963+ auto * target = pick (funcContext->breakableStack );
3964+ targetName = getTargetName (target);
3965+ targetType = getTargetType (target);
3966+ // We can send any reference type, or no value at all, but nothing else.
3967+ if (targetType.isRef () || targetType == Type::none) {
3968+ break ;
3969+ }
3970+ }
3971+ if (tries < 0 ) {
3972+ return makeTrivial (type);
3973+ }
3974+
3975+ auto fixFlowingType = [&](Expression* brOn) -> Expression* {
3976+ if (Type::isSubType (brOn->type , type)) {
3977+ // Already of the proper type.
3978+ return brOn;
3979+ }
3980+ if (type == Type::none) {
3981+ // We just need to drop whatever it is.
3982+ return builder.makeDrop (brOn);
3983+ }
3984+ // We need to replace the type with something else. Drop the BrOn if we need
3985+ // to, and append a value with the proper type.
3986+ if (brOn->type != Type::none) {
3987+ brOn = builder.makeDrop (brOn);
3988+ }
3989+ return builder.makeSequence (brOn, make (type));
3990+ };
3991+
3992+ // We found something to break to. Figure out which BrOn variants we can
3993+ // send.
3994+ if (targetType == Type::none) {
3995+ // BrOnNull is the only variant that sends no value.
3996+ return fixFlowingType (
3997+ builder.makeBrOn (BrOnNull, targetName, make (getReferenceType ())));
3998+ }
3999+
4000+ // We are sending a reference type to the target. All other BrOn variants can
4001+ // do that.
4002+ assert (targetType.isRef ());
4003+ auto op = pick (BrOnNonNull, BrOnCast, BrOnCastFail);
4004+ Type castType = Type::none;
4005+ Type refType;
4006+ switch (op) {
4007+ case BrOnNonNull: {
4008+ // The sent type is the non-nullable version of the reference, so any ref
4009+ // of that type is ok, nullable or not.
4010+ refType = Type (targetType.getHeapType (), getNullability ());
4011+ break ;
4012+ }
4013+ case BrOnCast: {
4014+ // The sent type is the heap type we cast to, with the input type's
4015+ // nullability, so the combination of the two must be a subtype of
4016+ // targetType.
4017+ castType = getSubType (targetType);
4018+ // The ref's type must be castable to castType, or we'd not validate. But
4019+ // it can also be a subtype, which will trivially also succeed (so do that
4020+ // more rarely). Pick subtypes rarely, as they make the cast trivial.
4021+ refType = oneIn (5 ) ? getSubType (castType) : getSuperType (castType);
4022+ if (targetType.isNonNullable ()) {
4023+ // And it must have the right nullability for the target, as mentioned
4024+ // above: if the target type is non-nullable then either the ref or the
4025+ // cast types must be.
4026+ if (!refType.isNonNullable () && !castType.isNonNullable ()) {
4027+ // Pick one to make non-nullable.
4028+ if (oneIn (2 )) {
4029+ refType = Type (refType.getHeapType (), NonNullable);
4030+ } else {
4031+ castType = Type (castType.getHeapType (), NonNullable);
4032+ }
4033+ }
4034+ }
4035+ break ;
4036+ }
4037+ case BrOnCastFail: {
4038+ // The sent type is the ref's type, with adjusted nullability (if the cast
4039+ // allows nulls then no null can fail the cast, and what is sent is non-
4040+ // nullable). First, pick a ref type that we can send to the target.
4041+ refType = getSubType (targetType);
4042+ // See above on BrOnCast, but flipped.
4043+ castType = oneIn (5 ) ? getSuperType (refType) : getSubType (refType);
4044+ // There is no nullability to adjust: if targetType is non-nullable then
4045+ // both refType and castType are as well, as subtypes of it. But we can
4046+ // also allow castType to be nullable (it is not sent to the target).
4047+ if (castType.isNonNullable () && oneIn (2 )) {
4048+ castType = Type (castType.getHeapType (), Nullable);
4049+ }
4050+ } break ;
4051+ default : {
4052+ WASM_UNREACHABLE (" bad br_on op" );
4053+ }
4054+ }
4055+ return fixFlowingType (
4056+ builder.makeBrOn (op, targetName, make (refType), castType));
4057+ }
4058+
39474059bool TranslateToFuzzReader::maybeSignedGet (const Field& field) {
39484060 if (field.isPacked ()) {
39494061 return oneIn (2 );
0 commit comments