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: 3 additions & 0 deletions src/tools/fuzzing.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class TranslateToFuzzReader {
Name HANG_LIMIT_GLOBAL;

Name funcrefTableName;
Name exnrefTableName;

std::unordered_map<Type, Name> logImportNames;
Name throwImportName;
Expand Down Expand Up @@ -465,6 +466,8 @@ class TranslateToFuzzReader {
Expression* makeSIMDShift();
Expression* makeSIMDLoad();
Expression* makeBulkMemory(Type type);
Expression* makeTableGet(Type type);
Expression* makeTableSet(Type type);
// TODO: support other RefIs variants, and rename this
Expression* makeRefIsNull(Type type);
Expression* makeRefEq(Type type);
Expand Down
84 changes: 82 additions & 2 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,22 @@ void TranslateToFuzzReader::setupTables() {
segment->setName(Names::getValidElementSegmentName(wasm, "elem$"), false);
wasm.addElementSegment(std::move(segment));
}

// When EH is enabled, set up an exnref table.
if (wasm.features.hasExceptionHandling()) {
Type exnref = Type(HeapType::exn, Nullable);
Address initial = upTo(10);
Address max = oneIn(2) ? initial + upTo(4) : Memory::kUnlimitedSize;
auto tablePtr =
builder.makeTable(Names::getValidTableName(wasm, "exnref_table"),
exnref,
initial,
max,
Type::i32); // TODO: wasm64
tablePtr->hasExplicitName = true;
table = wasm.addTable(std::move(tablePtr));
exnrefTableName = table->name;
}
}

void TranslateToFuzzReader::setupGlobals() {
Expand Down Expand Up @@ -1953,6 +1969,14 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
if (heapType.isBasic()) {
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
&Self::makeBasicRef);
if (type.isNullable() && funcContext) {
if (heapType == HeapType::func) {
options.add(FeatureSet::ReferenceTypes, &Self::makeTableGet);
}
if (heapType == HeapType::exn) {
options.add(FeatureSet::ExceptionHandling, &Self::makeTableGet);
}
}
} else {
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
&Self::makeCompoundRef);
Expand Down Expand Up @@ -2000,6 +2024,7 @@ Expression* TranslateToFuzzReader::_makenone() {
&Self::makeGlobalSet)
.add(FeatureSet::BulkMemory, &Self::makeBulkMemory)
.add(FeatureSet::Atomics, &Self::makeAtomic)
.add(FeatureSet::ReferenceTypes, &Self::makeTableSet)
.add(FeatureSet::ExceptionHandling, &Self::makeTry)
.add(FeatureSet::ExceptionHandling, &Self::makeTryTable)
.add(FeatureSet::ExceptionHandling, &Self::makeImportThrowing)
Expand Down Expand Up @@ -4418,6 +4443,58 @@ Expression* TranslateToFuzzReader::makeBulkMemory(Type type) {
WASM_UNREACHABLE("invalid value");
}

Expression* TranslateToFuzzReader::makeTableGet(Type type) {
// Emit a get from the funcref table (which always exists) or the exnref one
// (which might not, if EH is disabled).
auto makeTableGet = [&](Name tableName) {
auto* table = wasm.getTable(tableName);
// Usually emit in-bounds gets, to avoid trapping, but rarely allow
// anything.
Expression* index;
if (allowOOB && oneIn(10)) {
index = make(table->addressType);
} else {
index = builder.makeConst(
Literal::makeFromInt32(upTo(table->initial), table->addressType));
}
return builder.makeTableGet(tableName, index, table->type);
};
if (type.getHeapType() == HeapType::exn) {
return makeTableGet(exnrefTableName);
} else if (type.getHeapType() == HeapType::func) {
return makeTableGet(funcrefTableName);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it always HeapType::func here? Can we assert? (The same for makeTableSet)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I added asserts.

} else {
WASM_UNREACHABLE("bad TableGet type");
}
}

Expression* TranslateToFuzzReader::makeTableSet(Type type) {
assert(type == Type::none);

// Emit a set to either the funcref table (which always exists) or the exnref
// one (which might not, if EH is disabled).
auto makeTableSet = [&](Name tableName) {
auto* table = wasm.getTable(tableName);
// Usually emit in-bounds sets, to avoid trapping, but rarely allow
// anything.
Expression* index;
if (allowOOB && oneIn(10)) {
index = make(table->addressType);
} else {
index = builder.makeConst(
Literal::makeFromInt32(upTo(table->initial), table->addressType));
}
auto* value = make(table->type);
return builder.makeTableSet(tableName, index, value);
};
if (exnrefTableName && oneIn(2)) {
return makeTableSet(exnrefTableName);
} else {
assert(funcrefTableName);
return makeTableSet(funcrefTableName);
}
}

Expression* TranslateToFuzzReader::makeRefIsNull(Type type) {
assert(type == Type::i32);
assert(wasm.features.hasReferenceTypes());
Expand Down Expand Up @@ -4922,8 +4999,8 @@ Type TranslateToFuzzReader::getSingleConcreteType() {
auto nullability = getNullability();
return Type(heapType, nullability);
}
// Skip (ref func), (ref extern), and (ref i31) for now
// because there is no way to create them in globals. TODO.
// Skip (ref func|extern|i31|exn) because there is no way to create them in
// globals. TODO
using WeightedOption = FeatureOptions<Type>::WeightedOption;
return pick(FeatureOptions<Type>()
.add(FeatureSet::MVP,
Expand All @@ -4935,6 +5012,9 @@ Type TranslateToFuzzReader::getSingleConcreteType() {
.add(FeatureSet::ReferenceTypes,
Type(HeapType::func, Nullable),
Type(HeapType::ext, Nullable))
.add(FeatureSet::ExceptionHandling,
// Type(HeapType::exn, NonNullable),
Type(HeapType::exn, Nullable))
.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
// Type(HeapType::func, NonNullable),
// Type(HeapType::ext, NonNullable),
Expand Down
93 changes: 54 additions & 39 deletions test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
Original file line number Diff line number Diff line change
@@ -1,46 +1,61 @@
Metrics
total
[exports] : 13
[funcs] : 14
[globals] : 4
[imports] : 12
[exports] : 9
[funcs] : 8
[globals] : 1
[imports] : 11
[memories] : 1
[memory-data] : 112
[table-data] : 2
[tables] : 1
[table-data] : 0
[tables] : 2
[tags] : 0
[total] : 654
[vars] : 15
ArrayGet : 1
ArrayLen : 1
ArrayNew : 6
ArrayNewFixed : 11
Binary : 74
Block : 64
Call : 43
CallIndirect : 1
Const : 170
Drop : 7
GlobalGet : 38
GlobalSet : 32
If : 18
Load : 17
LocalGet : 42
LocalSet : 23
Loop : 3
Nop : 3
RefAs : 2
RefFunc : 7
[total] : 738
[vars] : 40
ArrayCopy : 1
ArrayFill : 1
ArrayLen : 3
ArrayNew : 5
ArrayNewFixed : 1
AtomicFence : 2
AtomicNotify : 2
AtomicRMW : 1
Binary : 82
Block : 80
BrOn : 4
Break : 13
Call : 29
CallRef : 1
Const : 134
Drop : 15
GlobalGet : 26
GlobalSet : 26
I31Get : 3
If : 26
Load : 16
LocalGet : 85
LocalSet : 51
Loop : 6
MemoryFill : 2
Nop : 5
Pop : 4
RefAs : 10
RefEq : 1
RefFunc : 2
RefI31 : 12
RefIsNull : 1
RefNull : 7
Return : 3
Select : 1
RefTest : 2
Return : 4
SIMDExtract : 7
Select : 7
Store : 1
StringConst : 1
StringEncode : 1
StructNew : 37
StructSet : 1
Throw : 1
TryTable : 2
TupleMake : 3
Unary : 17
Unreachable : 16
StringConst : 3
StringEncode : 2
StringMeasure : 1
StructGet : 2
StructNew : 2
StructSet : 2
Try : 6
TryTable : 5
Unary : 24
Unreachable : 13