Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/tools/fuzzing.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ class TranslateToFuzzReader {
Expression* makeStringNewArray();
Expression* makeStringNewCodePoint();
Expression* makeStringConcat();
Expression* makeStringEncode(Type type);

// Similar to makeBasic/CompoundRef, but indicates that this value will be
// used in a place that will trap on null. For example, the reference of a
Expand Down Expand Up @@ -391,13 +392,13 @@ class TranslateToFuzzReader {
Type getLoggableType();
bool isLoggableType(Type type);
Nullability getNullability();
Mutability getMutability();
Nullability getSubType(Nullability nullability);
HeapType getSubType(HeapType type);
Type getSubType(Type type);
Nullability getSuperType(Nullability nullability);
HeapType getSuperType(HeapType type);
Type getSuperType(Type type);
Type getArrayTypeForString();

// Utilities
Name getTargetName(Expression* target);
Expand Down
64 changes: 50 additions & 14 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,9 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
&Self::makeRefEq,
&Self::makeRefTest,
&Self::makeI31Get);
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC |
FeatureSet::Strings,
&Self::makeStringEncode);
}
if (type.isTuple()) {
options.add(FeatureSet::Multivalue, &Self::makeTupleMake);
Expand Down Expand Up @@ -2752,12 +2755,7 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) {
}

Expression* TranslateToFuzzReader::makeStringNewArray() {
auto mutability = getMutability();
auto arrayHeapType =
HeapType(Array(Field(Field::PackedType::i16, mutability)));
auto nullability = getNullability();
auto arrayType = Type(arrayHeapType, nullability);
auto array = make(arrayType);
auto* array = make(getArrayTypeForString());
auto* start = make(Type::i32);
auto* end = make(Type::i32);
return builder.makeStringNew(StringNewWTF16Array, array, start, end, false);
Expand Down Expand Up @@ -2814,8 +2812,8 @@ Expression* TranslateToFuzzReader::makeStringConst() {
}

Expression* TranslateToFuzzReader::makeStringConcat() {
auto left = make(Type(HeapType::string, getNullability()));
auto right = make(Type(HeapType::string, getNullability()));
auto* left = make(Type(HeapType::string, getNullability()));
auto* right = make(Type(HeapType::string, getNullability()));
return builder.makeStringConcat(left, right);
}

Expand Down Expand Up @@ -3806,9 +3804,9 @@ static auto makeArrayBoundsCheck(Expression* ref,
// An additional use of the reference (we stored the reference in a local,
// so this reads from that local).
Expression* getRef;
// An addition use of the index (as with the ref, it reads from a local).
// An additional use of the index (as with the ref, it reads from a local).
Expression* getIndex;
// An addition use of the length, if it was provided.
// An additional use of the length, if it was provided.
Expression* getLength = nullptr;
} result = {builder.makeBinary(LtUInt32, effectiveIndex, getSize),
builder.makeLocalGet(tempRef, ref->type),
Expand Down Expand Up @@ -3919,6 +3917,40 @@ Expression* TranslateToFuzzReader::makeArrayBulkMemoryOp(Type type) {
}
}

Expression* TranslateToFuzzReader::makeStringEncode(Type type) {
assert(type == Type::i32);

auto* ref = make(Type(HeapType::string, getNullability()));
auto* array = make(getArrayTypeForString());
auto* start = make(Type::i32);

// Only rarely emit without a bounds check, which might trap. See related
// logic in other array operations.
if (allowOOB || oneIn(10)) {
return builder.makeStringEncode(StringEncodeWTF16Array, ref, array, start);
}

// Stash the string reference while computing its length for a bounds check.
auto refLocal = builder.addVar(funcContext->func, ref->type);
auto* setRef = builder.makeLocalSet(refLocal, ref);
auto* strLen = builder.makeStringMeasure(
StringMeasureWTF16, builder.makeLocalGet(refLocal, ref->type));

// Do a bounds check on the array.
auto check =
makeArrayBoundsCheck(array, start, funcContext->func, builder, strLen);
array = check.getRef;
start = check.getIndex;
auto* getRef = builder.makeLocalGet(refLocal, ref->type);
auto* encode =
builder.makeStringEncode(StringEncodeWTF16Array, getRef, array, start);

// Emit the set of the string reference and then an if that picks which code
// path to visit, depending on the outcome of the bounds check.
auto* iff = builder.makeIf(check.condition, encode, make(Type::i32));
return builder.makeSequence(setRef, iff);
}

Expression* TranslateToFuzzReader::makeI31Get(Type type) {
assert(type == Type::i32);
assert(wasm.features.hasReferenceTypes() && wasm.features.hasGC());
Expand Down Expand Up @@ -4136,10 +4168,6 @@ Nullability TranslateToFuzzReader::getNullability() {
return Nullable;
}

Mutability TranslateToFuzzReader::getMutability() {
return oneIn(2) ? Mutable : Immutable;
}

Nullability TranslateToFuzzReader::getSubType(Nullability nullability) {
if (nullability == NonNullable) {
return NonNullable;
Expand Down Expand Up @@ -4279,6 +4307,14 @@ Type TranslateToFuzzReader::getSuperType(Type type) {
return superType;
}

Type TranslateToFuzzReader::getArrayTypeForString() {
// Emit an array that can be used with JS-style strings, containing 16-bit
// elements. For now, this must be a mutable type as that is all V8 accepts.
auto arrayHeapType = HeapType(Array(Field(Field::PackedType::i16, Mutable)));
auto nullability = getNullability();
return Type(arrayHeapType, nullability);
}

Name TranslateToFuzzReader::getTargetName(Expression* target) {
if (auto* block = target->dynCast<Block>()) {
return block->name;
Expand Down
61 changes: 30 additions & 31 deletions test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
total
[exports] : 3
[funcs] : 5
[exports] : 7
[funcs] : 12
[globals] : 14
[imports] : 5
[memories] : 1
[memory-data] : 20
[table-data] : 1
[table-data] : 6
[tables] : 1
[tags] : 1
[total] : 387
[vars] : 23
[total] : 493
[vars] : 31
ArrayNew : 1
ArrayNewFixed : 3
AtomicCmpxchg : 1
AtomicNotify : 1
Binary : 57
Block : 33
ArrayNewFixed : 1
Binary : 61
Block : 59
Break : 2
Call : 4
Const : 95
Drop : 2
GlobalGet : 15
GlobalSet : 15
If : 9
Call : 29
CallRef : 1
Const : 101
Drop : 10
GlobalGet : 28
GlobalSet : 26
I31Get : 1
If : 17
Load : 16
LocalGet : 41
LocalSet : 20
Loop : 3
Nop : 2
Pop : 1
RefAs : 3
RefFunc : 2
LocalGet : 36
LocalSet : 29
Loop : 2
Nop : 5
RefAs : 1
RefCast : 2
RefFunc : 8
RefI31 : 4
RefNull : 5
RefNull : 4
Return : 3
Store : 1
SIMDExtract : 1
StringConst : 1
StructNew : 11
Try : 1
TupleExtract : 7
TupleMake : 11
Unary : 9
Unreachable : 8
StructNew : 5
TupleExtract : 1
TupleMake : 7
Unary : 16
Unreachable : 15