diff options
-rw-r--r-- | src/tools/fuzzing.h | 4 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 74 | ||||
-rw-r--r-- | src/tools/fuzzing/parameters.h | 4 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 74 |
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 |