diff options
author | Alon Zakai <azakai@google.com> | 2023-10-17 10:12:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-17 17:12:02 +0000 |
commit | 2bf3caae764689c606ae38353b1bad5fe28bf5bb (patch) | |
tree | 7112801575e46132fdccad7bf120f5cafb9471da | |
parent | b816ac563de6b1c53087796335fce593a96f569a (diff) | |
download | binaryen-2bf3caae764689c606ae38353b1bad5fe28bf5bb.tar.gz binaryen-2bf3caae764689c606ae38353b1bad5fe28bf5bb.tar.bz2 binaryen-2bf3caae764689c606ae38353b1bad5fe28bf5bb.zip |
Add getGeneralSuperType() that includes basic supers, and use in fuzzer (#6005)
With this, the fuzzer can replace e.g. an eq expression with a specific struct type,
because now it is away that struct types have eq as their ancestor.
-rw-r--r-- | src/ir/subtypes.h | 1 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 7 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 3 | ||||
-rw-r--r-- | src/wasm-type.h | 5 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 41 | ||||
-rw-r--r-- | test/gtest/possible-contents.cpp | 7 | ||||
-rw-r--r-- | test/gtest/type-builder.cpp | 73 | ||||
-rw-r--r-- | test/passes/translate-to-fuzz_all-features_metrics_noprint.txt | 81 |
8 files changed, 166 insertions, 52 deletions
diff --git a/src/ir/subtypes.h b/src/ir/subtypes.h index 7cc633a75..488bb8310 100644 --- a/src/ir/subtypes.h +++ b/src/ir/subtypes.h @@ -122,7 +122,6 @@ struct SubTypes { } // Add the max depths of basic types. - // TODO: update when we get structtype for (auto type : types) { HeapType basic; if (type.isStruct()) { diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index e29a6ddaf..a40a76106 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -25,8 +25,6 @@ high chance for set at start of loop high chance of a tee in that case => loop var */ -// TODO Generate exception handling instructions - #include "ir/branch-utils.h" #include "ir/memory-utils.h" #include "ir/struct-utils.h" @@ -399,8 +397,3 @@ private: }; } // namespace wasm - -// XXX Switch class has a condition?! is it real? should the node type be the -// value type if it exists?! - -// TODO copy an existing function and replace just one node in it diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 2e4d460f7..bdaf71e83 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -765,8 +765,7 @@ void TranslateToFuzzReader::recombine(Function* func) { while (1) { ret.push_back(Type(heapType, nullability)); - // TODO: handle basic supertypes too - auto super = heapType.getDeclaredSuperType(); + auto super = heapType.getSuperType(); if (!super) { break; } diff --git a/src/wasm-type.h b/src/wasm-type.h index bc6b25b34..23ceb9143 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -372,6 +372,11 @@ public: // module) nominal supertype, return it, else an empty optional. std::optional<HeapType> getDeclaredSuperType() const; + // As |getDeclaredSuperType|, but also handles basic types, that is, if the + // super is a basic type, then we return it here. Declared types are returned + // as well, just like |getDeclaredSuperType|. + std::optional<HeapType> getSuperType() const; + // Return the depth of this heap type in the nominal type hierarchy, i.e. the // number of supertypes in its supertype chain. size_t getDepth() const; diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 1b8d7d0f1..68d7f732b 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -1219,6 +1219,47 @@ std::optional<HeapType> HeapType::getDeclaredSuperType() const { return {}; } +std::optional<HeapType> HeapType::getSuperType() const { + auto ret = getDeclaredSuperType(); + if (ret) { + return ret; + } + + // There may be a basic supertype. + if (isBasic()) { + switch (getBasic()) { + case ext: + case noext: + case func: + case nofunc: + case any: + case none: + case string: + case stringview_wtf8: + case stringview_wtf16: + case stringview_iter: + return {}; + case eq: + return any; + case i31: + case struct_: + case array: + return eq; + } + } + + auto* info = getHeapTypeInfo(*this); + switch (info->kind) { + case HeapTypeInfo::SignatureKind: + return func; + case HeapTypeInfo::StructKind: + return struct_; + case HeapTypeInfo::ArrayKind: + return array; + } + WASM_UNREACHABLE("unexpected kind"); +} + size_t HeapType::getDepth() const { size_t depth = 0; std::optional<HeapType> super; diff --git a/test/gtest/possible-contents.cpp b/test/gtest/possible-contents.cpp index 8e07ef8c3..ce5a1ae18 100644 --- a/test/gtest/possible-contents.cpp +++ b/test/gtest/possible-contents.cpp @@ -552,9 +552,10 @@ TEST_F(PossibleContentsTest, TestStructCones) { auto C = types[2]; auto D = types[3]; auto E = types[4]; - ASSERT_TRUE(B.getDeclaredSuperType() == A); - ASSERT_TRUE(C.getDeclaredSuperType() == A); - ASSERT_TRUE(D.getDeclaredSuperType() == C); + ASSERT_FALSE(A.getDeclaredSuperType()); + ASSERT_EQ(B.getDeclaredSuperType(), A); + ASSERT_EQ(C.getDeclaredSuperType(), A); + ASSERT_EQ(D.getDeclaredSuperType(), C); auto nullA = Type(A, Nullable); auto nullB = Type(B, Nullable); diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp index 0184eb074..43e470a02 100644 --- a/test/gtest/type-builder.cpp +++ b/test/gtest/type-builder.cpp @@ -1080,3 +1080,76 @@ TEST_F(TypeTest, TestIterSubTypes) { EXPECT_EQ(getSubTypes(C, 1), TypeDepths({{C, 0}, {D, 1}})); EXPECT_EQ(getSubTypes(C, 2), TypeDepths({{C, 0}, {D, 1}})); } + +// Test supertypes +TEST_F(TypeTest, TestSupertypes) { + // Basic types: getDeclaredSuperType always returns nothing. + ASSERT_FALSE(HeapType(HeapType::ext).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::func).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::any).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::eq).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::i31).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::struct_).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::array).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::string).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::stringview_wtf8).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::stringview_wtf16).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::stringview_iter).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::none).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::noext).getDeclaredSuperType()); + ASSERT_FALSE(HeapType(HeapType::nofunc).getDeclaredSuperType()); + + // Basic types: getSuperType does return a super, when there is one. + ASSERT_FALSE(HeapType(HeapType::ext).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::func).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::any).getSuperType()); + ASSERT_EQ(HeapType(HeapType::eq).getSuperType(), HeapType::any); + ASSERT_EQ(HeapType(HeapType::i31).getSuperType(), HeapType::eq); + ASSERT_EQ(HeapType(HeapType::struct_).getSuperType(), HeapType::eq); + ASSERT_EQ(HeapType(HeapType::array).getSuperType(), HeapType::eq); + ASSERT_FALSE(HeapType(HeapType::string).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::stringview_wtf8).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::stringview_wtf16).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::stringview_iter).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::none).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::noext).getSuperType()); + ASSERT_FALSE(HeapType(HeapType::nofunc).getSuperType()); + + // Non-basic types. + HeapType struct1, struct2, array1, array2, sig1, sig2; + { + TypeBuilder builder(6); + builder[0].setOpen() = Struct(); + builder[1].setOpen().subTypeOf(builder[0]) = Struct(); + auto array = Array(Field(Type::i32, Immutable)); + builder[2].setOpen() = array; + builder[3].setOpen().subTypeOf(builder[2]) = array; + auto sig = Signature(Type::none, Type::none); + builder[4].setOpen() = sig; + builder[5].setOpen().subTypeOf(builder[4]) = sig; + auto result = builder.build(); + ASSERT_TRUE(result); + auto built = *result; + struct1 = built[0]; + struct2 = built[1]; + array1 = built[2]; + array2 = built[3]; + sig1 = built[4]; + sig2 = built[5]; + } + + ASSERT_EQ(struct1.getSuperType(), HeapType::struct_); + ASSERT_EQ(struct2.getSuperType(), struct1); + ASSERT_EQ(array1.getSuperType(), HeapType::array); + ASSERT_EQ(array2.getSuperType(), array1); + ASSERT_EQ(sig1.getSuperType(), HeapType::func); + ASSERT_EQ(sig2.getSuperType(), sig1); + + // With getDeclaredSuperType we don't get basic supers, only declared ones. + ASSERT_FALSE(struct1.getDeclaredSuperType()); + ASSERT_EQ(struct2.getDeclaredSuperType(), struct1); + ASSERT_FALSE(array1.getDeclaredSuperType()); + ASSERT_EQ(array2.getDeclaredSuperType(), array1); + ASSERT_FALSE(sig1.getDeclaredSuperType()); + ASSERT_EQ(sig2.getDeclaredSuperType(), sig1); +} 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 8d88600ed..3cd4228e9 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,53 +1,56 @@ total - [exports] : 4 - [funcs] : 6 + [exports] : 5 + [funcs] : 8 [globals] : 1 [imports] : 5 [memories] : 1 [memory-data] : 20 - [table-data] : 0 + [table-data] : 6 [tables] : 1 [tags] : 2 - [total] : 630 - [vars] : 23 - ArrayGet : 1 - ArrayLen : 2 - ArrayNew : 8 + [total] : 807 + [vars] : 27 + ArrayLen : 1 + ArrayNew : 7 ArrayNewFixed : 3 ArraySet : 1 - AtomicNotify : 1 - Binary : 81 - Block : 66 - Break : 12 - Call : 22 + AtomicCmpxchg : 1 + AtomicFence : 1 + Binary : 89 + Block : 102 + Break : 18 + Call : 21 CallRef : 1 - Const : 132 - Drop : 6 - GlobalGet : 20 - GlobalSet : 20 - I31Get : 1 - If : 23 - Load : 23 - LocalGet : 70 - LocalSet : 41 - Loop : 5 - Nop : 12 - RefAs : 4 - RefCast : 1 + Const : 154 + Drop : 5 + GlobalGet : 38 + GlobalSet : 38 + I31Get : 2 + If : 27 + Load : 19 + LocalGet : 62 + LocalSet : 48 + Loop : 12 + MemoryFill : 1 + Nop : 10 + Pop : 5 + RefAs : 19 + RefCast : 3 RefEq : 2 - RefFunc : 1 - RefI31 : 3 - RefNull : 6 - Return : 7 + RefFunc : 7 + RefI31 : 4 + RefIsNull : 2 + RefNull : 14 + RefTest : 2 + Return : 2 SIMDExtract : 1 - SIMDTernary : 1 - Select : 4 - Store : 3 - StructGet : 1 + Select : 5 + Store : 4 + StructGet : 6 StructNew : 9 - StructSet : 2 - Try : 2 - TupleExtract : 1 + StructSet : 1 + Try : 5 + TupleExtract : 2 TupleMake : 2 - Unary : 19 - Unreachable : 10 + Unary : 32 + Unreachable : 19 |