summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/fuzzing.h4
-rw-r--r--src/tools/fuzzing/fuzzing.cpp74
-rw-r--r--src/tools/fuzzing/parameters.h4
-rw-r--r--test/passes/translate-to-fuzz_all-features_metrics_noprint.txt74
4 files changed, 119 insertions, 37 deletions
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index 5a9ebdf22..e29a6ddaf 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -207,6 +207,7 @@ private:
void setupTables();
void setupGlobals();
void setupTags();
+ void addTag();
void finalizeMemory();
void finalizeTable();
void prepareHangLimitSupport();
@@ -283,6 +284,7 @@ private:
Expression* makeMaybeBlock(Type type);
Expression* buildIf(const struct ThreeArgs& args, Type type);
Expression* makeIf(Type type);
+ Expression* makeTry(Type type);
Expression* makeBreak(Type type);
Expression* makeCall(Type type);
Expression* makeCallIndirect(Type type);
@@ -358,6 +360,8 @@ private:
// get/set).
Expression* makeArrayBulkMemoryOp(Type type);
Expression* makeI31Get(Type type);
+ Expression* makeThrow(Type type);
+
Expression* makeMemoryInit();
Expression* makeDataDrop();
Expression* makeMemoryCopy();
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 54ff3533b..3fb8c1ea5 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -404,12 +404,16 @@ void TranslateToFuzzReader::setupGlobals() {
void TranslateToFuzzReader::setupTags() {
Index num = upTo(3);
for (size_t i = 0; i < num; i++) {
- auto tag = builder.makeTag(Names::getValidTagName(wasm, "tag$"),
- Signature(getControlFlowType(), Type::none));
- wasm.addTag(std::move(tag));
+ addTag();
}
}
+void TranslateToFuzzReader::addTag() {
+ auto tag = builder.makeTag(Names::getValidTagName(wasm, "tag$"),
+ Signature(getControlFlowType(), Type::none));
+ wasm.addTag(std::move(tag));
+}
+
void TranslateToFuzzReader::finalizeMemory() {
auto& memory = wasm.memories[0];
for (auto& segment : wasm.dataSegments) {
@@ -1123,6 +1127,7 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
WeightedOption{&Self::makeBreak, Important},
&Self::makeCall,
&Self::makeCallIndirect)
+ .add(FeatureSet::ExceptionHandling, &Self::makeTry)
.add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef);
}
if (type.isSingle()) {
@@ -1232,6 +1237,7 @@ Expression* TranslateToFuzzReader::_makeunreachable() {
&Self::makeSwitch,
&Self::makeDrop,
&Self::makeReturn)
+ .add(FeatureSet::ExceptionHandling, &Self::makeThrow)
.add(FeatureSet::GC | FeatureSet::ReferenceTypes, &Self::makeCallRef);
return (this->*pick(options))(Type::unreachable);
}
@@ -1363,6 +1369,54 @@ Expression* TranslateToFuzzReader::makeIf(Type type) {
return ret;
}
+Expression* TranslateToFuzzReader::makeTry(Type type) {
+ auto* body = make(type);
+ std::vector<Name> catchTags;
+ std::vector<Expression*> catchBodies;
+ auto numTags = upTo(MAX_TRY_CATCHES);
+ std::unordered_set<Tag*> usedTags;
+ for (Index i = 0; i < numTags; i++) {
+ if (wasm.tags.empty()) {
+ addTag();
+ }
+ auto* tag = pick(wasm.tags).get();
+ if (usedTags.count(tag)) {
+ continue;
+ }
+ usedTags.insert(tag);
+ catchTags.push_back(tag->name);
+ }
+ // The number of tags in practice may be fewer than we planned.
+ numTags = catchTags.size();
+ auto numCatches = numTags;
+ if (numTags == 0 || oneIn(2)) {
+ // Add a catch-all.
+ numCatches++;
+ }
+ for (Index i = 0; i < numCatches; i++) {
+ // Catch bodies (aside from a catch-all) begin with a pop.
+ Expression* prefix = nullptr;
+ if (i < numTags) {
+ auto tagType = wasm.getTag(catchTags[i])->sig.params;
+ if (tagType != Type::none) {
+ auto* pop = builder.makePop(tagType);
+ // Capture the pop in a local, so that it can be used later.
+ // TODO: add a good chance for using this particular local in this catch
+ // TODO: reuse an existing var if there is one
+ auto index = builder.addVar(funcContext->func, tagType);
+ prefix = builder.makeLocalSet(index, pop);
+ }
+ }
+ auto* catchBody = make(type);
+ if (prefix) {
+ catchBody = builder.makeSequence(prefix, catchBody);
+ }
+ catchBodies.push_back(catchBody);
+ }
+ // TODO: delegate stuff
+ return builder.makeTry(body, catchTags, catchBodies);
+}
+
Expression* TranslateToFuzzReader::makeBreak(Type type) {
if (funcContext->breakableStack.empty()) {
return makeTrivial(type);
@@ -3499,6 +3553,20 @@ Expression* TranslateToFuzzReader::makeI31Get(Type type) {
return builder.makeI31Get(i31, bool(oneIn(2)));
}
+Expression* TranslateToFuzzReader::makeThrow(Type type) {
+ assert(type == Type::unreachable);
+ if (wasm.tags.empty()) {
+ addTag();
+ }
+ auto* tag = pick(wasm.tags).get();
+ auto tagType = tag->sig.params;
+ std::vector<Expression*> operands;
+ for (auto t : tagType) {
+ operands.push_back(make(t));
+ }
+ return builder.makeThrow(tag, operands);
+}
+
Expression* TranslateToFuzzReader::makeMemoryInit() {
if (!allowMemory) {
return makeTrivial(Type::none);
diff --git a/src/tools/fuzzing/parameters.h b/src/tools/fuzzing/parameters.h
index dd5c8d82c..51531681b 100644
--- a/src/tools/fuzzing/parameters.h
+++ b/src/tools/fuzzing/parameters.h
@@ -67,6 +67,10 @@ constexpr int HANG_LIMIT = 100;
// the maximum amount of new GC types (structs, etc.) to create
constexpr int MAX_NEW_GC_TYPES = 25;
+// the maximum amount of catches in each try (not including a catch-all, if
+// present).
+constexpr int MAX_TRY_CATCHES = 4;
+
//
constexpr size_t VeryImportant = 4;
constexpr size_t Important = 2;
diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
index 8609159bc..b5efc4c85 100644
--- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -1,44 +1,50 @@
total
- [exports] : 3
- [funcs] : 11
+ [exports] : 9
+ [funcs] : 16
[globals] : 16
[imports] : 5
[memories] : 1
[memory-data] : 20
[table-data] : 2
[tables] : 1
- [tags] : 0
- [total] : 549
- [vars] : 49
- ArrayCopy : 1
+ [tags] : 1
+ [total] : 666
+ [vars] : 32
ArrayFill : 1
ArrayLen : 1
- ArrayNew : 14
- ArrayNewFixed : 2
- Binary : 75
- Block : 51
- Break : 6
- Call : 5
- Const : 136
- Drop : 2
- GlobalGet : 24
- GlobalSet : 24
- I31New : 4
- If : 16
- Load : 18
- LocalGet : 54
- LocalSet : 31
- Loop : 2
- Nop : 8
- RefAs : 3
- RefFunc : 4
- RefNull : 10
- Return : 1
- SIMDExtract : 1
+ ArrayNew : 7
+ ArrayNewFixed : 3
+ AtomicCmpxchg : 1
+ AtomicFence : 2
+ AtomicNotify : 1
+ Binary : 81
+ Block : 84
+ Break : 8
+ Call : 23
+ Const : 152
+ Drop : 6
+ GlobalGet : 40
+ GlobalSet : 38
+ I31Get : 1
+ I31New : 3
+ If : 29
+ Load : 19
+ LocalGet : 39
+ LocalSet : 20
+ Loop : 5
+ Nop : 9
+ RefAs : 5
+ RefEq : 2
+ RefFunc : 6
+ RefIsNull : 2
+ RefNull : 9
+ Return : 4
Select : 1
- StructGet : 2
- StructNew : 16
- TupleExtract : 3
- TupleMake : 4
- Unary : 17
- Unreachable : 12
+ Store : 4
+ StructGet : 1
+ StructNew : 10
+ Try : 2
+ TupleExtract : 1
+ TupleMake : 3
+ Unary : 23
+ Unreachable : 20