[ruby/prism] Use a simpler and faster hash function for locals

https://github.com/ruby/prism/commit/5f56bf4464
This commit is contained in:
Kevin Newton 2024-04-05 14:53:37 -04:00 committed by git
parent a801889c58
commit 1953ead74e

View File

@ -805,17 +805,15 @@ pm_locals_free(pm_locals_t *locals) {
} }
/** /**
* Use the mid-square method to hash the given constant id. * Use as simple and fast a hash function as we can that still properly mixes
* the bits.
*/ */
static uint32_t static uint32_t
pm_locals_hash(pm_constant_id_t name) { pm_locals_hash(pm_constant_id_t name) {
uint64_t square = (uint64_t) name * (uint64_t) name; name = ((name >> 16) ^ name) * 0x45d9f3b;
name = ((name >> 16) ^ name) * 0x45d9f3b;
uint32_t num_digits = (uint32_t) floor(log10((double) square) + 1); name = (name >> 16) ^ name;
uint32_t start = num_digits / 2; return name;
uint32_t end = start + 1;
return (uint32_t) (((uint64_t) ((square / ((uint64_t) pow(10, (double) start)))) % (uint64_t) pow(10, (double) end)));
} }
/** /**
@ -837,15 +835,16 @@ pm_locals_resize(pm_locals_t *locals) {
} else { } else {
// If we just switched from a list to a hash, then we need to fill in // If we just switched from a list to a hash, then we need to fill in
// the hash values of all of the locals. // the hash values of all of the locals.
bool hash_needed = locals->locals[0].hash == 0; bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
uint32_t mask = next_capacity - 1; uint32_t mask = next_capacity - 1;
for (uint32_t index = 0; index < locals->capacity; index++) { for (uint32_t index = 0; index < locals->capacity; index++) {
pm_local_t *local = &locals->locals[index]; pm_local_t *local = &locals->locals[index];
if (local->name != PM_CONSTANT_ID_UNSET) { if (local->name != PM_CONSTANT_ID_UNSET) {
uint32_t hash = hash_needed ? pm_locals_hash(local->name) : local->hash; if (hash_needed) local->hash = pm_locals_hash(local->name);
uint32_t hash = local->hash;
while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++; while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
next_locals[hash & mask] = *local; next_locals[hash & mask] = *local;
} }
@ -908,7 +907,7 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
.name = name, .name = name,
.index = locals->size++, .index = locals->size++,
.reads = reads, .reads = reads,
.hash = hash .hash = initial_hash
}; };
return true; return true;
} else if (local->name == name) { } else if (local->name == name) {
@ -920,6 +919,7 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
} }
assert(false && "unreachable"); assert(false && "unreachable");
return true;
} }
/** /**