Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fuzzer: Generate TryTables #6987

Merged
merged 11 commits into from
Oct 7, 2024
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
1 change: 1 addition & 0 deletions src/tools/fuzzing.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ class TranslateToFuzzReader {
Expression* buildIf(const struct ThreeArgs& args, Type type);
Expression* makeIf(Type type);
Expression* makeTry(Type type);
Expression* makeTryTable(Type type);
Expression* makeBreak(Type type);
Expression* makeCall(Type type);
Expression* makeCallIndirect(Type type);
Expand Down
68 changes: 68 additions & 0 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,7 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
&Self::makeCall,
&Self::makeCallIndirect)
.add(FeatureSet::ExceptionHandling, &Self::makeTry)
.add(FeatureSet::ExceptionHandling, &Self::makeTryTable)
.add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef);
}
if (type.isSingle()) {
Expand Down Expand Up @@ -1451,6 +1452,8 @@ Expression* TranslateToFuzzReader::_makenone() {
&Self::makeGlobalSet)
.add(FeatureSet::BulkMemory, &Self::makeBulkMemory)
.add(FeatureSet::Atomics, &Self::makeAtomic)
.add(FeatureSet::ExceptionHandling, &Self::makeTry)
.add(FeatureSet::ExceptionHandling, &Self::makeTryTable)
.add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef)
.add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeStructSet)
.add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeArraySet)
Expand Down Expand Up @@ -1688,6 +1691,71 @@ Expression* TranslateToFuzzReader::makeTry(Type type) {
return builder.makeTry(body, catchTags, catchBodies);
}

Expression* TranslateToFuzzReader::makeTryTable(Type type) {
auto* body = make(type);

if (funcContext->breakableStack.empty()) {
// Nothing to break to, emit a trivial TryTable.
// TODO: Perhaps generate a block wrapping us?
return builder.makeTryTable(body, {}, {}, {});
}

if (wasm.tags.empty()) {
addTag();
}

// Add catches of specific tags, and possibly a catch_all at the end. We use
// the last iteration of the loop for that.
std::vector<Name> catchTags;
std::vector<Name> catchDests;
std::vector<bool> catchRefs;
auto numCatches = upTo(MAX_TRY_CATCHES);
for (Index i = 0; i <= numCatches; i++) {
Name tagName;
Type tagType;
if (i < numCatches) {
// Look for a specific tag.
auto& tag = pick(wasm.tags);
tagName = tag->name;
tagType = tag->sig.params;
} else {
// Add a catch_all at the end, some of the time (but all of the time if we
// have nothing else).
if (!catchTags.empty() && oneIn(2)) {
break;
}
tagType = Type::none;
}

// We need to find a proper target to break to, which means a target that
// has the type of the tag, or the tag + an exnref at the end.
std::vector<Type> vec(tagType.begin(), tagType.end());
// Use a non-nullable exnref here, and then the subtyping check below will
// also accept a target that is nullable.
vec.push_back(Type(HeapType::exn, NonNullable));
auto tagTypeWithExn = Type(vec);
int tries = TRIES;
while (tries-- > 0) {
auto* target = pick(funcContext->breakableStack);
auto dest = getTargetName(target);
auto valueType = getTargetType(target);
auto subOfTagType = Type::isSubType(tagType, valueType);
auto subOfTagTypeWithExn = Type::isSubType(tagTypeWithExn, valueType);
if (subOfTagType || subOfTagTypeWithExn) {
catchTags.push_back(tagName);
catchDests.push_back(dest);
catchRefs.push_back(subOfTagTypeWithExn);
break;
}
}
// TODO: Perhaps generate a block wrapping us, if we fail to find a target?
// TODO: It takes a bit of luck to find a target with an exnref - perhaps
// generate those?
}

return builder.makeTryTable(body, catchTags, catchDests, catchRefs);
}

Expression* TranslateToFuzzReader::makeBreak(Type type) {
if (funcContext->breakableStack.empty()) {
return makeTrivial(type);
Expand Down
82 changes: 41 additions & 41 deletions test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
Metrics
total
[exports] : 5
[funcs] : 9
[exports] : 3
[funcs] : 5
[globals] : 26
[imports] : 5
[memories] : 1
[memory-data] : 20
[table-data] : 3
[table-data] : 0
[tables] : 1
[tags] : 2
[total] : 669
[vars] : 27
ArrayNew : 16
ArrayNewFixed : 3
[total] : 499
[vars] : 20
ArrayNew : 14
ArrayNewFixed : 2
AtomicCmpxchg : 1
AtomicFence : 1
Binary : 75
Block : 70
Break : 7
Call : 26
CallRef : 1
Const : 143
Drop : 3
GlobalGet : 37
GlobalSet : 27
AtomicNotify : 1
AtomicRMW : 1
Binary : 69
Block : 42
Break : 8
Call : 6
Const : 126
Drop : 2
GlobalGet : 27
GlobalSet : 16
I31Get : 1
If : 20
Load : 21
LocalGet : 55
LocalSet : 40
Loop : 6
Nop : 5
Pop : 5
If : 10
Load : 18
LocalGet : 43
LocalSet : 22
Loop : 5
Nop : 3
Pop : 3
RefAs : 2
RefEq : 2
RefFunc : 5
RefI31 : 2
RefNull : 11
RefTest : 2
Return : 6
Select : 2
StringConst : 6
StringEq : 1
StringMeasure : 1
StringWTF16Get : 1
StructNew : 17
RefFunc : 2
RefI31 : 1
RefNull : 8
RefTest : 1
Return : 1
Select : 1
Store : 3
StringConst : 9
StringEncode : 1
StringEq : 3
StructNew : 12
StructSet : 1
Try : 4
TupleExtract : 3
TupleMake : 5
Unary : 20
Unreachable : 15
Try : 3
TryTable : 2
TupleExtract : 1
TupleMake : 4
Unary : 13
Unreachable : 11
Loading