aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_db_hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_db_hash.c')
-rw-r--r--erts/emulator/beam/erl_db_hash.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 06dac8f161..063808eb79 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -171,10 +171,53 @@ static ERTS_INLINE void add_fixed_deletion(DbTableHash* tb, int ix)
#define MAX_HASH 0xEFFFFFFFUL
#define INVALID_HASH 0xFFFFFFFFUL
-/* optimised version of make_hash (normal case? atomic key) */
-#define MAKE_HASH(term) \
- ((is_atom(term) ? (atom_tab(atom_val(term))->slot.bucket.hvalue) : \
- make_hash2(term)) % MAX_HASH)
+static ERTS_INLINE HashValue
+MAKE_HASH(Eterm term)
+{
+ if (is_atom(term)) {
+ /*
+ * optimised version of make_hash, although poor hashvalue
+ * (normal case? atomic key)
+ */
+ return atom_tab(atom_val(term))->slot.bucket.hvalue;
+ }
+ if (is_ref(term)) {
+ /*
+ * make_hash2() produce poor hash values
+ * for refs.
+ */
+ int no;
+ Uint32 *ref;
+ HashValue hval;
+ if (is_internal_ref(term)) {
+ no = (int) internal_ref_no_of_numbers(term);
+ ref = internal_ref_numbers(term);
+ }
+ else {
+ no = (int) external_ref_no_of_numbers(term);
+ ref = external_ref_numbers(term);
+ }
+ switch (no) {
+ case 3:
+ ref_limit:
+ if (!ref[2])
+ no = 2;
+ case 2:
+ if (!ref[1])
+ no = 1;
+ case 1:
+ break;
+ default:
+ no = 3;
+ goto ref_limit;
+ }
+ hval = (HashValue) block_hash((byte *) ref,
+ no * sizeof(Uint32),
+ 0x08d12e65);
+ return hval % MAX_HASH;
+ }
+ return make_hash2(term) % MAX_HASH;
+}
#ifdef ERTS_SMP
# define DB_HASH_LOCK_MASK (DB_HASH_LOCK_CNT-1)