@@ -1366,6 +1366,9 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
13661366 &Self::makeRefEq,
13671367 &Self::makeRefTest,
13681368 &Self::makeI31Get);
1369+ options.add (FeatureSet::ReferenceTypes | FeatureSet::GC |
1370+ FeatureSet::Strings,
1371+ &Self::makeStringEncode);
13691372 }
13701373 if (type.isTuple ()) {
13711374 options.add (FeatureSet::Multivalue, &Self::makeTupleMake);
@@ -2752,12 +2755,7 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) {
27522755}
27532756
27542757Expression* TranslateToFuzzReader::makeStringNewArray () {
2755- auto mutability = getMutability ();
2756- auto arrayHeapType =
2757- HeapType (Array (Field (Field::PackedType::i16 , mutability)));
2758- auto nullability = getNullability ();
2759- auto arrayType = Type (arrayHeapType, nullability);
2760- auto array = make (arrayType);
2758+ auto * array = make (getArrayTypeForString ());
27612759 auto * start = make (Type::i32 );
27622760 auto * end = make (Type::i32 );
27632761 return builder.makeStringNew (StringNewWTF16Array, array, start, end, false );
@@ -2814,8 +2812,8 @@ Expression* TranslateToFuzzReader::makeStringConst() {
28142812}
28152813
28162814Expression* TranslateToFuzzReader::makeStringConcat () {
2817- auto left = make (Type (HeapType::string, getNullability ()));
2818- auto right = make (Type (HeapType::string, getNullability ()));
2815+ auto * left = make (Type (HeapType::string, getNullability ()));
2816+ auto * right = make (Type (HeapType::string, getNullability ()));
28192817 return builder.makeStringConcat (left, right);
28202818}
28212819
@@ -3806,9 +3804,9 @@ static auto makeArrayBoundsCheck(Expression* ref,
38063804 // An additional use of the reference (we stored the reference in a local,
38073805 // so this reads from that local).
38083806 Expression* getRef;
3809- // An addition use of the index (as with the ref, it reads from a local).
3807+ // An additional use of the index (as with the ref, it reads from a local).
38103808 Expression* getIndex;
3811- // An addition use of the length, if it was provided.
3809+ // An additional use of the length, if it was provided.
38123810 Expression* getLength = nullptr ;
38133811 } result = {builder.makeBinary (LtUInt32, effectiveIndex, getSize),
38143812 builder.makeLocalGet (tempRef, ref->type ),
@@ -3919,6 +3917,40 @@ Expression* TranslateToFuzzReader::makeArrayBulkMemoryOp(Type type) {
39193917 }
39203918}
39213919
3920+ Expression* TranslateToFuzzReader::makeStringEncode (Type type) {
3921+ assert (type == Type::i32 );
3922+
3923+ auto * ref = make (Type (HeapType::string, getNullability ()));
3924+ auto * array = make (getArrayTypeForString ());
3925+ auto * start = make (Type::i32 );
3926+
3927+ // Only rarely emit without a bounds check, which might trap. See related
3928+ // logic in other array operations.
3929+ if (allowOOB || oneIn (10 )) {
3930+ return builder.makeStringEncode (StringEncodeWTF16Array, ref, array, start);
3931+ }
3932+
3933+ // Stash the string reference while computing its length for a bounds check.
3934+ auto refLocal = builder.addVar (funcContext->func , ref->type );
3935+ auto * setRef = builder.makeLocalSet (refLocal, ref);
3936+ auto * strLen = builder.makeStringMeasure (
3937+ StringMeasureWTF16, builder.makeLocalGet (refLocal, ref->type ));
3938+
3939+ // Do a bounds check on the array.
3940+ auto check =
3941+ makeArrayBoundsCheck (array, start, funcContext->func , builder, strLen);
3942+ array = check.getRef ;
3943+ start = check.getIndex ;
3944+ auto * getRef = builder.makeLocalGet (refLocal, ref->type );
3945+ auto * encode =
3946+ builder.makeStringEncode (StringEncodeWTF16Array, getRef, array, start);
3947+
3948+ // Emit the set of the string reference and then an if that picks which code
3949+ // path to visit, depending on the outcome of the bounds check.
3950+ auto * iff = builder.makeIf (check.condition , encode, make (Type::i32 ));
3951+ return builder.makeSequence (setRef, iff);
3952+ }
3953+
39223954Expression* TranslateToFuzzReader::makeI31Get (Type type) {
39233955 assert (type == Type::i32 );
39243956 assert (wasm.features .hasReferenceTypes () && wasm.features .hasGC ());
@@ -4136,10 +4168,6 @@ Nullability TranslateToFuzzReader::getNullability() {
41364168 return Nullable;
41374169}
41384170
4139- Mutability TranslateToFuzzReader::getMutability () {
4140- return oneIn (2 ) ? Mutable : Immutable;
4141- }
4142-
41434171Nullability TranslateToFuzzReader::getSubType (Nullability nullability) {
41444172 if (nullability == NonNullable) {
41454173 return NonNullable;
@@ -4279,6 +4307,14 @@ Type TranslateToFuzzReader::getSuperType(Type type) {
42794307 return superType;
42804308}
42814309
4310+ Type TranslateToFuzzReader::getArrayTypeForString () {
4311+ // Emit an array that can be used with JS-style strings, containing 16-bit
4312+ // elements. For now, this must be a mutable type as that is all V8 accepts.
4313+ auto arrayHeapType = HeapType (Array (Field (Field::PackedType::i16 , Mutable)));
4314+ auto nullability = getNullability ();
4315+ return Type (arrayHeapType, nullability);
4316+ }
4317+
42824318Name TranslateToFuzzReader::getTargetName (Expression* target) {
42834319 if (auto * block = target->dynCast <Block>()) {
42844320 return block->name ;
0 commit comments