From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS8100 96.47.226.0/23 X-Spam-Status: No, score=-1.5 required=3.0 tests=BAYES_00,RCVD_IN_XBL shortcircuit=no autolearn=no version=3.3.2 X-Original-To: spew@80x24.org Received: from 80x24.org (bolobolo1.torservers.net [96.47.226.20]) by dcvr.yhbt.net (Postfix) with ESMTP id 0265C1F72F for ; Thu, 9 Oct 2014 04:03:35 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH] compile.c: optimize << and == using putstring_for Date: Thu, 9 Oct 2014 04:03:33 +0000 Message-Id: <1412827413-14385-1-git-send-email-e@80x24.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1412819460-29287-2-git-send-email-e@80x24.org> References: <1412819460-29287-2-git-send-email-e@80x24.org> List-Id: This optimizes `obj << "literal"' and `obj == "literal"' calls. Note: `"literal" == obj' is not optimized, yet. We may have the same problem as opt_aset_with in the peephole optimizer. --- benchmark/bm_vm2_strcat.rb | 7 ++++++ benchmark/bm_vm2_streq1.rb | 6 +++++ compile.c | 14 +++++++++++- test/ruby/test_string.rb | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 benchmark/bm_vm2_strcat.rb create mode 100644 benchmark/bm_vm2_streq1.rb diff --git a/benchmark/bm_vm2_strcat.rb b/benchmark/bm_vm2_strcat.rb new file mode 100644 index 0000000..b25ac6e --- /dev/null +++ b/benchmark/bm_vm2_strcat.rb @@ -0,0 +1,7 @@ +i = 0 +str = "" +while i<6_000_000 # benchmark loop 2 + i += 1 + str << "const" + str.clear +end diff --git a/benchmark/bm_vm2_streq1.rb b/benchmark/bm_vm2_streq1.rb new file mode 100644 index 0000000..2a4b0f8 --- /dev/null +++ b/benchmark/bm_vm2_streq1.rb @@ -0,0 +1,6 @@ +i = 0 +foo = "literal" +while i<6_000_000 # benchmark loop 2 + i += 1 + foo == "literal" +end diff --git a/compile.c b/compile.c index 10db05d..6e83c3c 100644 --- a/compile.c +++ b/compile.c @@ -1865,7 +1865,19 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal /* obj["literal"] -> putstring_for("literal", Hash, 0) */ else if (ci->mid == idAREF && ci->orig_argc == 1) { swap_putstring_for_arg(iseq, iobj, BOP_AREF, - STRING_REDEFINED_OP_FLAG, rb_cHash, 0); + HASH_REDEFINED_OP_FLAG, rb_cHash, 0); + } + + /* optimize allocation: obj == "lit" */ + else if (ci->mid == idEq && ci->orig_argc == 1) { + swap_putstring_for_arg(iseq, iobj, BOP_EQ, + STRING_REDEFINED_OP_FLAG, rb_cString, 0); + } + + /* optimize allocation: obj << "lit" */ + else if (ci->mid == idLTLT && ci->orig_argc == 1) { + swap_putstring_for_arg(iseq, iobj, BOP_LTLT, + STRING_REDEFINED_OP_FLAG, rb_cString, 0); } } } diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 4dc790f..4165e97 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -2279,6 +2279,33 @@ class TestString < Test::Unit::TestCase end; end if [0].pack("l!").bytesize < [nil].pack("p").bytesize # enable only when string size range is smaller than memory space + + def test_opt_strcat_with + assert_separately([], <<-RUBY) + class String + undef << + def <<(str) + "overridden" + end + end + assert_equal("overridden", "" << "foo") + foo = "foo" + assert_equal("overridden", foo << "bar") + RUBY + + if @cls == String + nr = 10 + recv = "" + before = GC.stat(:total_allocated_objects) + nr.times { recv << "constant" } + assert_equal before, GC.stat(:total_allocated_objects) + assert_equal "constant" * nr, recv + + before = GC.stat(:total_allocated_objects) + nr.times { "recv" << "constant" } + assert_equal before + nr, GC.stat(:total_allocated_objects) + end + end end class TestString2 < TestString @@ -2286,4 +2313,33 @@ class TestString2 < TestString super @cls = S2 end + + def test_opt_streq1 + assert_separately([], <<-RUBY) + class String + undef == + def ==(str) + :TROO + end + end + assert_equal(:TROO, ("foo" == "foo")) + RUBY + + if @cls == String + nr = 10 + + recv = "something" + res = [] + before = GC.stat(:total_allocated_objects) + nr.times { res << (recv == "constant") } + assert_equal before, GC.stat(:total_allocated_objects) + assert_equal [ false ], res.uniq! + + res.clear + before = GC.stat(:total_allocated_objects) + nr.times { res << (recv == "something") } + assert_equal before, GC.stat(:total_allocated_objects) + assert_equal [ true ], res.uniq! + end + end end -- EW