diff options
-rw-r--r-- | src/ir/possible-contents.h | 21 | ||||
-rw-r--r-- | src/support/hash.h | 2 | ||||
-rw-r--r-- | test/gtest/possible-contents.cpp | 22 |
3 files changed, 33 insertions, 12 deletions
diff --git a/src/ir/possible-contents.h b/src/ir/possible-contents.h index f7c39e1f9..863a0dbab 100644 --- a/src/ir/possible-contents.h +++ b/src/ir/possible-contents.h @@ -21,6 +21,7 @@ #include "ir/possible-constant.h" #include "ir/subtypes.h" +#include "support/hash.h" #include "support/small_vector.h" #include "wasm-builder.h" #include "wasm.h" @@ -213,23 +214,21 @@ public: } size_t hash() const { - // Encode this using three bits for the variant type, then the rest of the - // contents. - if (isNone()) { - return 0; + // First hash the index of the variant, then add the internals for each. + size_t ret = std::hash<size_t>()(value.index()); + if (isNone() || isMany()) { + // Nothing to add. } else if (isLiteral()) { - return size_t(1) | (std::hash<Literal>()(getLiteral()) << 3); + rehash(ret, getLiteral()); } else if (isGlobal()) { - return size_t(2) | (std::hash<Name>()(getGlobal()) << 3); + rehash(ret, getGlobal()); } else if (auto* coneType = std::get_if<ConeType>(&value)) { - return size_t(3) | ((std::hash<std::pair<Type, Index>>{}( - {coneType->type, coneType->depth})) - << 3); - } else if (isMany()) { - return 4; + rehash(ret, coneType->type); + rehash(ret, coneType->depth); } else { WASM_UNREACHABLE("bad variant"); } + return ret; } void dump(std::ostream& o, Module* wasm = nullptr) const { diff --git a/src/support/hash.h b/src/support/hash.h index d3a858698..fb0e710a5 100644 --- a/src/support/hash.h +++ b/src/support/hash.h @@ -29,7 +29,7 @@ template<typename T> inline std::size_t hash(const T& value) { // Combines two digests into the first digest. Use instead of `rehash` if // `otherDigest` is another digest and not a `size_t` value. -static inline void hash_combine(std::size_t& digest, std::size_t otherDigest) { +inline void hash_combine(std::size_t& digest, const std::size_t otherDigest) { // see: boost/container_hash/hash.hpp // The constant is the N-bits reciprocal of the golden ratio: // phi = (1 + sqrt(5)) / 2 diff --git a/test/gtest/possible-contents.cpp b/test/gtest/possible-contents.cpp index 933e220bb..0bb1ecafa 100644 --- a/test/gtest/possible-contents.cpp +++ b/test/gtest/possible-contents.cpp @@ -146,6 +146,28 @@ TEST_F(PossibleContentsTest, TestComparisons) { assertNotEqualSymmetric(exactNonNullAnyref, exactAnyref); } +TEST_F(PossibleContentsTest, TestHash) { + // Hashes should be deterministic. + EXPECT_EQ(none.hash(), none.hash()); + EXPECT_EQ(many.hash(), many.hash()); + + // Hashes should be different. (In theory hash collisions could appear here, + // but if such simple things collide and the test fails then we should really + // rethink our hash functions!) + EXPECT_NE(none.hash(), many.hash()); + EXPECT_NE(none.hash(), i32Zero.hash()); + EXPECT_NE(none.hash(), i32One.hash()); + EXPECT_NE(none.hash(), anyGlobal.hash()); + EXPECT_NE(none.hash(), funcGlobal.hash()); + EXPECT_NE(none.hash(), exactAnyref.hash()); + EXPECT_NE(none.hash(), exactFuncSignatureType.hash()); + // TODO: cones + + EXPECT_NE(i32Zero.hash(), i32One.hash()); + EXPECT_NE(anyGlobal.hash(), funcGlobal.hash()); + EXPECT_NE(exactAnyref.hash(), exactFuncSignatureType.hash()); +} + TEST_F(PossibleContentsTest, TestCombinations) { // None with anything else becomes the other thing. assertCombination(none, none, none); |