From: Eric Wong Date: 2014-01-03T03:49:59+00:00 Subject: [ruby-core:59494] Re: [ruby-trunk - misc #9188] r43870 make benchmark/bm_so_k_nucleotide.rb slow Btw, I took some time to work on this further. Only _very_ lightly tested (make check passes) # GC::Profiler.report doesn't even show anything with this patch applied # because GC never happens. h = {} GC::Profiler.enable 10000000.times do h["HI"] = 0 h["HI"] end GC::Profiler.report ---------------------------8<------------------------------- Subject: [PATCH] prefreeze literal strings for hash aset/aref Based on a patch by Charlie Somerville and Aman Gupta: http://mid.gmane.org/redmine.journal-43505.20131208105635@ruby-lang.org --- The following changes since commit 12b09864056bfb961f06b0ef675b9fc2fabb9238: * properties. (2014-01-03 01:51:05 +0000) are available in the git repository at: git://80x24.org/ruby.git opt_aref_aset_str for you to fetch changes up to 2906ef4bf2aaa0873f198cc1a949c1cc7740be7f: prefreeze literal strings for hash aset/aref (2014-01-03 03:44:51 +0000) ---------------------------------------------------------------- Eric Wong (1): prefreeze literal strings for hash aset/aref compile.c | 36 ++++++++++++++++++++++++++++++++++++ hash.c | 2 +- insns.def | 41 +++++++++++++++++++++++++++++++++++++++++ test/ruby/test_hash.rb | 9 ++++++++- 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/compile.c b/compile.c index 5b28401..f12f40d 100644 --- a/compile.c +++ b/compile.c @@ -4330,6 +4330,23 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } break; } + if (node->nd_mid == idAREF && + node->nd_recv != (NODE *)1 && + node->nd_args && + nd_type(node->nd_args) == NODE_ARRAY && + node->nd_args->nd_alen == 1 && + nd_type(node->nd_args->nd_head) == NODE_STR) + { + VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit); + node->nd_args->nd_head->nd_lit = str; + COMPILE(ret, "recv", node->nd_recv); + ADD_INSN2(ret, line, opt_aref_str, + new_callinfo(iseq, idAREF, 1, 0, 0), str); + if (poped) { + ADD_INSN(ret, line, pop); + } + break; + } case NODE_FCALL: case NODE_VCALL:{ /* VCALL: variable or call */ /* @@ -5300,6 +5317,25 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) VALUE flag = 0; VALUE argc; + if (node->nd_mid == idASET && + node->nd_recv != (NODE *)1 && + node->nd_args && + nd_type(node->nd_args) == NODE_ARRAY && + node->nd_args->nd_alen == 2 && + nd_type(node->nd_args->nd_head) == NODE_STR) + { + VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit); + node->nd_args->nd_head->nd_lit = str; + COMPILE(ret, "recv", node->nd_recv); + COMPILE(ret, "value", node->nd_args->nd_next->nd_head); + ADD_INSN2(ret, line, opt_aset_str, + new_callinfo(iseq, idASET, 2, 0, 0), str); + if (poped) { + ADD_INSN(ret, line, pop); + } + break; + } + INIT_ANCHOR(recv); INIT_ANCHOR(args); argc = setup_args(iseq, args, node->nd_args, &flag); diff --git a/hash.c b/hash.c index 0eca4b9..3cf7d8d 100644 --- a/hash.c +++ b/hash.c @@ -2390,7 +2390,7 @@ static VALUE rb_hash_compare_by_id_p(VALUE hash); * h1["a"] #=> 100 * h1.compare_by_identity * h1.compare_by_identity? #=> true - * h1["a"] #=> nil # different objects. + * h1["a".dup] #=> nil # different objects. * h1[:c] #=> "c" # same symbols are all same. * */ diff --git a/insns.def b/insns.def index ad4bba6..616838d 100644 --- a/insns.def +++ b/insns.def @@ -1903,6 +1903,47 @@ opt_aset /** @c optimize + @e recv[str] = set + @j ������������������ recv[str] = set��� + */ +DEFINE_INSN +opt_aset_str +(CALL_INFO ci, VALUE key) +(VALUE recv, VALUE val) +(VALUE val) +{ + if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG)) { + rb_hash_aset(recv, key, val); + } else { + PUSH(recv); + PUSH(rb_str_resurrect(key)); + PUSH(val); + CALL_SIMPLE_METHOD(recv); + } +} + +/** + @c optimize + @e recv[str] + @j ������������������ recv[str]��� + */ +DEFINE_INSN +opt_aref_str +(CALL_INFO ci, VALUE key) +(VALUE recv) +(VALUE val) +{ + if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG)) { + val = rb_hash_aref(recv, key); + } else { + PUSH(recv); + PUSH(rb_str_resurrect(key)); + CALL_SIMPLE_METHOD(recv); + } +} + +/** + @c optimize @e optimized length @j ������������������ recv.length()��� */ diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 70c0442..f5af4dd 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -209,6 +209,13 @@ class TestHash < Test::Unit::TestCase assert_equal(256, h[z]) end + def test_ASET_fstring_key + a, b = {}, {} + a["abc"] = 1 + b["abc"] = 1 + assert_same a.keys[0], b.keys[0] + end + def test_NEWHASH_fstring_key a = {"ABC" => :t} b = {"ABC" => :t} @@ -946,7 +953,7 @@ class TestHash < Test::Unit::TestCase h = @cls[] h.compare_by_identity h["a"] = 1 - h["a"] = 2 + h["a".dup] = 2 assert_equal(["a",1], h.assoc("a")) end