summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/possible-contents.h21
-rw-r--r--src/support/hash.h2
-rw-r--r--test/gtest/possible-contents.cpp22
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);