@@ -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