@@ -352,9 +352,24 @@ static int fstring_cmp(VALUE a, VALUE b);
352352
353353static VALUE register_fstring (VALUE str , bool copy , bool precompute_hash );
354354
355+ #if SIZEOF_LONG == SIZEOF_VOIDP
356+ static st_index_t
357+ fstring_hash (VALUE str )
358+ {
359+ if (FL_TEST_RAW (str , STR_FAKESTR )) {
360+ // register_fstring precomputes the hash and stores it in capa for fake strings
361+ return (st_index_t )RSTRING (str )-> as .heap .aux .capa ;
362+ }
363+ else {
364+ return rb_str_hash (str );
365+ }
366+ }
367+ #else
368+ #define fstring_hash rb_str_hash
369+ #endif
355370const struct st_hash_type rb_fstring_hash_type = {
356371 fstring_cmp ,
357- rb_str_hash ,
372+ fstring_hash ,
358373};
359374
360375#define BARE_STRING_P (str ) (!FL_ANY_RAW(str, FL_EXIVAR) && RBASIC_CLASS(str) == rb_cString)
@@ -371,7 +386,7 @@ str_do_hash(VALUE str)
371386}
372387
373388static VALUE
374- str_precompute_hash (VALUE str )
389+ str_store_precomputed_hash (VALUE str , st_index_t hash )
375390{
376391 RUBY_ASSERT (!FL_TEST_RAW (str , STR_PRECOMPUTED_HASH ));
377392 RUBY_ASSERT (STR_EMBED_P (str ));
@@ -382,7 +397,6 @@ str_precompute_hash(VALUE str)
382397 RUBY_ASSERT (free_bytes >= sizeof (st_index_t ));
383398#endif
384399
385- st_index_t hash = str_do_hash (str );
386400 memcpy (RSTRING_END (str ) + TERM_LEN (str ), & hash , sizeof (hash ));
387401
388402 FL_SET (str , STR_PRECOMPUTED_HASH );
@@ -399,7 +413,6 @@ struct fstr_update_arg {
399413static int
400414fstr_update_callback (st_data_t * key , st_data_t * value , st_data_t data , int existing )
401415{
402-
403416 struct fstr_update_arg * arg = (struct fstr_update_arg * )data ;
404417 VALUE str = (VALUE )* key ;
405418
@@ -429,7 +442,7 @@ fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int exist
429442 STR_SET_LEN (new_str , RSTRING_LEN (str ));
430443 TERM_FILL (RSTRING_END (new_str ), TERM_LEN (str ));
431444 rb_enc_copy (new_str , str );
432- str_precompute_hash (new_str );
445+ str_store_precomputed_hash (new_str , fstring_hash ( str ) );
433446 }
434447 else {
435448 new_str = str_new (rb_cString , RSTRING (str )-> as .heap .ptr , RSTRING (str )-> len );
@@ -509,6 +522,14 @@ register_fstring(VALUE str, bool copy, bool precompute_hash)
509522 .precompute_hash = precompute_hash
510523 };
511524
525+ #if SIZEOF_VOIDP == SIZEOF_LONG
526+ if (FL_TEST_RAW (str , STR_FAKESTR )) {
527+ // if the string hasn't been interned, we'll need the hash twice, so we
528+ // compute it once and store it in capa
529+ RSTRING (str )-> as .heap .aux .capa = (long )str_do_hash (str );
530+ }
531+ #endif
532+
512533 RB_VM_LOCK_ENTER ();
513534 {
514535 st_table * frozen_strings = rb_vm_fstring_table ();
@@ -531,7 +552,6 @@ static VALUE
531552setup_fake_str (struct RString * fake_str , const char * name , long len , int encidx )
532553{
533554 fake_str -> basic .flags = T_STRING |RSTRING_NOEMBED |STR_NOFREE |STR_FAKESTR ;
534- /* SHARED to be allocated by the callback */
535555
536556 if (!name ) {
537557 RUBY_ASSERT_ALWAYS (len == 0 );
0 commit comments