Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 710adf3

Browse files
committed
Fix Issue 19072 - Object.toHash and typeid(void*).getHash(&ptr) should be more varied in their low bits
The low bits of Object.toHash are insufficiently varied. Depending on the platform the bottom 4, 3, or 2 bits of the result will always be zero. This is bad because the low bits of a hash code are typically the most significant for hashtable implementations. D's builtin AA deals with this and other potential defects by rehashing the hash codes it receives. Some 3rd party hashtable implementations do the same, but others assume that keys with a defined toHash have reasonable hashcodes that can be used without need for further mixing. Fixing this is not hard and not computationally expensive. This PR also does a similar thing for raw pointers. Although it will not always be necessary for them the cost is low and it will frequently be a benefit.
1 parent f2f1a0a commit 710adf3

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

src/object.d

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,15 @@ class Object
871871
size_t toHash() @trusted nothrow
872872
{
873873
// BUG: this prevents a compacting GC from working, needs to be fixed
874-
return cast(size_t)cast(void*)this;
874+
size_t addr = cast(size_t) cast(void*) this;
875+
// The bottom log2((void*).alignof) bits of the address will always
876+
// be 0. Moreover it is likely that each Object is allocated with a
877+
// separate call to malloc. The alignment of malloc differs from
878+
// platform to platform, but rather than having special cases for
879+
// each platform it is safe to use a shift of 4. To minimize
880+
// collisions in the low bits it is more important for the shift to
881+
// not be too small than for the shift to not be too big.
882+
return addr ^ (addr >>> 4);
875883
}
876884

877885
/**
@@ -1183,7 +1191,12 @@ class TypeInfo_Pointer : TypeInfo
11831191

11841192
override size_t getHash(scope const void* p) @trusted const
11851193
{
1186-
return cast(size_t)*cast(void**)p;
1194+
// If the target of `p` is n-byte aligned then the
1195+
// bottom log2(n) bits of `p` will always be 0.
1196+
// Performing a constant magnitude xor-shift is
1197+
// inexpensive and will generally pay off.
1198+
size_t addr = cast(size_t) *cast(const void**) p;
1199+
return addr ^ (addr >>> 4);
11871200
}
11881201

11891202
override bool equals(in void* p1, in void* p2) const

0 commit comments

Comments
 (0)