newhash insn reuses existing keys

This gives the newhash VM instruction the same string reuse
capabilities as rb_hash_aset.

* st.c (str_key): new wrapper function to call rb_fstring_existing
  (rb_hash_bulk_insert): use str_key
* test/ruby/test_optimization.rb (test_hash_reuse_fstring):
  ensure key reuse for newhash instructions

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59355 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2017-07-18 04:30:08 +00:00
Родитель d04c085b3c
Коммит 4f473905e1
2 изменённых файлов: 25 добавлений и 2 удалений

20
st.c
Просмотреть файл

@ -2092,6 +2092,23 @@ st_rehash(st_table *tab)
}
#ifdef RUBY
static VALUE
str_key(VALUE key)
{
VALUE k;
if (RB_OBJ_FROZEN(key)) {
return key;
}
if ((k = rb_fstring_existing(key)) != Qnil) {
return k;
}
else {
return rb_str_new_frozen(key);
}
}
/* Mimics ruby's { foo => bar } syntax. This function is placed here
because it touches table internals and write barriers at once. */
void
@ -2114,8 +2131,7 @@ rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
for (i = 0; i < argc; /* */) {
VALUE key = argv[i++];
VALUE val = argv[i++];
st_data_t k = (rb_obj_class(key) == rb_cString) ?
rb_str_new_frozen(key) : key;
st_data_t k = (rb_obj_class(key) == rb_cString) ? str_key(key) : key;
st_table_entry e;
e.hash = do_hash(k, tab);
e.key = k;

Просмотреть файл

@ -196,6 +196,9 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_predicate h.keys[0], :frozen?
assert_same exp, h.keys[0]
h = { key => 1 }
assert_same exp, h.keys[0], 'newhash insn should reuse strings, too'
h1 = {}
h2 = {}
key.taint
@ -206,6 +209,10 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_same k1, k2
assert_predicate k1, :tainted?
h = { key => 1 }
assert_not_predicate key, :frozen?
assert_same k1, h.keys[0], 'newhash insn should reuse tainted strings'
assert_equal GC::INTERNAL_CONSTANTS[:RVALUE_SIZE],
ObjectSpace.memsize_of(k1),
'tainted string should share with untainted fstring'