aboutsummaryrefslogtreecommitdiffstats
path: root/hash.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-07-09 23:04:43 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-07-09 23:04:43 +0000
commit6ef7a8ae3b1b1ff8bb3e504703df7dbf7c6494a0 (patch)
tree80934b43c4bb9de45f66103c42dd9cbcef35b7be /hash.c
parentf934951357eee3bafac6b13533252477b69ca3aa (diff)
downloadruby-6ef7a8ae3b1b1ff8bb3e504703df7dbf7c6494a0.tar.gz
Hash#[]= deduplicates string keys if (and only if) fstring exists
In typical applications, hash entries are read after being written to. Blindly writing to hashes which are never read makes little sense. So, for any hash which is read from, an fstring entry for the key should already exist for the key. We no longer blindly create fstrings if the code is blindly setting random hash keys, preventing the performance regression in the reverted r43870. Regarding <https://bugs.ruby-lang.org/issues/9188>, this has a minimum impact on the bm_so_k_nucleotide where hash keys are set and not reused, performance is within 1-2% of existing cases. * hash.c: #include gc.h for rb_objspace_garbage_object_p (hash_aset_str): do read-only check of fstring table and reuse fstring if it exists and is still alive (not garbage) [ruby-core:81942] [Feature #13725] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/hash.c b/hash.c
index 3176bc7a24..0514c852a9 100644
--- a/hash.c
+++ b/hash.c
@@ -18,6 +18,7 @@
#include "probes.h"
#include "id.h"
#include "symbol.h"
+#include "gc.h"
#ifdef __APPLE__
# ifdef HAVE_CRT_EXTERNS_H
@@ -1518,8 +1519,21 @@ hash_aset(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
static int
hash_aset_str(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
{
- if (!existing) {
- *key = rb_str_new_frozen(*key);
+ if (!existing && !RB_OBJ_FROZEN(*key)) {
+ VALUE fstr;
+ st_table *tbl = rb_vm_fstring_table();
+
+ if (st_lookup(tbl, *key, (st_data_t *)&fstr)) {
+ if (rb_objspace_garbage_object_p(fstr)) {
+ *key = rb_fstring(*key);
+ }
+ else {
+ *key = fstr;
+ }
+ }
+ else {
+ *key = rb_str_new_frozen(*key);
+ }
}
return hash_aset(key, val, arg, existing);
}