summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Barrié <[email protected]>2024-11-04 11:41:04 +0100
committerJean Boussier <[email protected]>2024-11-04 14:37:14 +0100
commit1e037108a13bc876af9adf09d133dcc3274aa277 (patch)
tree3d574480a81e77f9eced2b164f80d9f1ca24744b
parent09874e90bf4e7850c00552cfee2beb103902a4ad (diff)
Precompute hash only once when interning string literals
When a fake string is interned, use the capa field to store the string hash. This lets us compute it once for hash lookup and embedding the hash in the interned string. Co-authored-by: Jean Boussier <[email protected]>
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/11989
-rw-r--r--string.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/string.c b/string.c
index 11a2ec1b71..83c3cd7aba 100644
--- a/string.c
+++ b/string.c
@@ -352,9 +352,24 @@ static int fstring_cmp(VALUE a, VALUE b);
static VALUE register_fstring(VALUE str, bool copy, bool precompute_hash);
+#if SIZEOF_LONG == SIZEOF_VOIDP
+static st_index_t
+fstring_hash(VALUE str)
+{
+ if (FL_TEST_RAW(str, STR_FAKESTR)) {
+ // register_fstring precomputes the hash and stores it in capa for fake strings
+ return (st_index_t)RSTRING(str)->as.heap.aux.capa;
+ }
+ else {
+ return rb_str_hash(str);
+ }
+}
+#else
+#define fstring_hash rb_str_hash
+#endif
const struct st_hash_type rb_fstring_hash_type = {
fstring_cmp,
- rb_str_hash,
+ fstring_hash,
};
#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)
}
static VALUE
-str_precompute_hash(VALUE str)
+str_store_precomputed_hash(VALUE str, st_index_t hash)
{
RUBY_ASSERT(!FL_TEST_RAW(str, STR_PRECOMPUTED_HASH));
RUBY_ASSERT(STR_EMBED_P(str));
@@ -382,7 +397,6 @@ str_precompute_hash(VALUE str)
RUBY_ASSERT(free_bytes >= sizeof(st_index_t));
#endif
- st_index_t hash = str_do_hash(str);
memcpy(RSTRING_END(str) + TERM_LEN(str), &hash, sizeof(hash));
FL_SET(str, STR_PRECOMPUTED_HASH);
@@ -399,7 +413,6 @@ struct fstr_update_arg {
static int
fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int existing)
{
-
struct fstr_update_arg *arg = (struct fstr_update_arg *)data;
VALUE str = (VALUE)*key;
@@ -429,7 +442,7 @@ fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int exist
STR_SET_LEN(new_str, RSTRING_LEN(str));
TERM_FILL(RSTRING_END(new_str), TERM_LEN(str));
rb_enc_copy(new_str, str);
- str_precompute_hash(new_str);
+ str_store_precomputed_hash(new_str, fstring_hash(str));
}
else {
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)
.precompute_hash = precompute_hash
};
+#if SIZEOF_VOIDP == SIZEOF_LONG
+ if (FL_TEST_RAW(str, STR_FAKESTR)) {
+ // if the string hasn't been interned, we'll need the hash twice, so we
+ // compute it once and store it in capa
+ RSTRING(str)->as.heap.aux.capa = (long)str_do_hash(str);
+ }
+#endif
+
RB_VM_LOCK_ENTER();
{
st_table *frozen_strings = rb_vm_fstring_table();
@@ -531,7 +552,6 @@ static VALUE
setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx)
{
fake_str->basic.flags = T_STRING|RSTRING_NOEMBED|STR_NOFREE|STR_FAKESTR;
- /* SHARED to be allocated by the callback */
if (!name) {
RUBY_ASSERT_ALWAYS(len == 0);