Skip to content

Commit a52c2bd

Browse files
committed
Optimize constant pool hash for short strings
1 parent 2a1dc79 commit a52c2bd

1 file changed

Lines changed: 37 additions & 26 deletions

File tree

src/util/pm_constant_pool.c

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -84,37 +84,48 @@ pm_constant_pool_hash(const uint8_t *start, size_t length) {
8484
static const uint64_t secret = 0x517cc1b727220a95ULL;
8585
uint64_t hash = (uint64_t) length;
8686

87-
const uint8_t *ptr = start;
88-
size_t remaining = length;
89-
90-
while (remaining >= 8) {
87+
if (length <= 8) {
88+
// Short strings: read first and last 4 bytes (overlapping for len < 8).
89+
// This covers the majority of Ruby identifiers with a single multiply.
90+
if (length >= 4) {
91+
uint32_t a, b;
92+
memcpy(&a, start, 4);
93+
memcpy(&b, start + length - 4, 4);
94+
hash ^= (uint64_t) a | ((uint64_t) b << 32);
95+
} else if (length > 0) {
96+
hash ^= (uint64_t) start[0] | ((uint64_t) start[length >> 1] << 8) | ((uint64_t) start[length - 1] << 16);
97+
}
98+
hash *= secret;
99+
} else if (length <= 16) {
100+
// Medium strings: read first and last 8 bytes (overlapping).
101+
// Two multiplies instead of the three the loop-based approach needs.
91102
uint64_t word;
92-
memcpy(&word, ptr, 8);
103+
memcpy(&word, start, 8);
93104
hash ^= word;
94105
hash *= secret;
95-
ptr += 8;
96-
remaining -= 8;
97-
}
98-
99-
if (remaining >= 4) {
100-
uint32_t word;
101-
memcpy(&word, ptr, 4);
102-
hash ^= (uint64_t) word;
103-
hash *= secret;
104-
ptr += 4;
105-
remaining -= 4;
106-
}
107-
108-
if (remaining >= 2) {
109-
hash ^= (uint64_t) ptr[0] | ((uint64_t) ptr[1] << 8);
106+
memcpy(&word, start + length - 8, 8);
107+
hash ^= word;
110108
hash *= secret;
111-
ptr += 2;
112-
remaining -= 2;
113-
}
109+
} else {
110+
const uint8_t *ptr = start;
111+
size_t remaining = length;
112+
113+
while (remaining >= 8) {
114+
uint64_t word;
115+
memcpy(&word, ptr, 8);
116+
hash ^= word;
117+
hash *= secret;
118+
ptr += 8;
119+
remaining -= 8;
120+
}
114121

115-
if (remaining >= 1) {
116-
hash ^= (uint64_t) ptr[0];
117-
hash *= secret;
122+
if (remaining > 0) {
123+
// Read the last 8 bytes (overlapping with already-processed data).
124+
uint64_t word;
125+
memcpy(&word, start + length - 8, 8);
126+
hash ^= word;
127+
hash *= secret;
128+
}
118129
}
119130

120131
hash ^= hash >> 32;

0 commit comments

Comments
 (0)