summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--st.c20
-rw-r--r--test/ruby/test_optimization.rb7
2 files changed, 25 insertions, 2 deletions
diff --git a/st.c b/st.c
index c2848b69b6..c983c0291b 100644
--- a/st.c
+++ b/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;
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 0d14c9c932..6cf6c63d1b 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -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'