dumping ground for random patches and texts
 help / color / mirror / Atom feed
From: Eric Wong <e@80x24.org>
To: spew@80x24.org
Subject: [PATCH 1/2] compile.c: hide "literal" optimizations behind peephole optimize
Date: Sat, 15 Nov 2014 22:16:11 +0000	[thread overview]
Message-ID: <opt_str_lit-v8-prepare@0> (raw)

This allows us to disable/enable optimizations at runtime.
---
 compile.c                      | 47 ++++++++++++++++++++++++++----------------
 test/-ext-/symbol/test_type.rb |  1 +
 test/lib/envutil.rb            | 10 +++++++++
 test/objspace/test_objspace.rb |  1 +
 test/ruby/test_hash.rb         |  2 ++
 test/ruby/test_iseq.rb         |  1 +
 test/ruby/test_optimization.rb | 11 +++++++++-
 7 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/compile.c b/compile.c
index 4e4101f..9936647 100644
--- a/compile.c
+++ b/compile.c
@@ -1913,6 +1913,33 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
 	    }
 	}
     }
+
+    /* string literal optimizations */
+    if (iobj->insn_id == BIN(putstring)) {
+	INSN *niobj = (INSN *)get_next_insn((INSN *)list);
+
+	if (niobj && niobj->insn_id == BIN(send)) {
+	    rb_call_info_t *ci = (rb_call_info_t *)niobj->operands[0];
+
+	    if (!ci->blockiseq && !(ci->flag & ~VM_CALL_ARGS_SIMPLE)) {
+		/* obj["literal"] -> opt_aref_with(obj, "literal") */
+		if (ci->mid == idAREF && ci->orig_argc == 1) {
+		    VALUE *old_operands = iobj->operands;
+
+		    iobj->insn_id = BIN(opt_aref_with);
+		    iobj->operand_size = insn_len(iobj->insn_id) - 1;
+
+		    iobj->operands = (VALUE *)compile_data_alloc(iseq,
+					iobj->operand_size * sizeof(VALUE));
+		    iobj->operands[0] = (VALUE)ci;
+		    iobj->operands[1] = old_operands[0];
+
+		    REMOVE_ELEM((LINK_ELEMENT *)niobj);
+		}
+	    }
+	}
+    }
+
     return COMPILE_OK;
 }
 
@@ -4376,7 +4403,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	/* optimization shortcut
 	 *   "literal".freeze -> opt_str_freeze("literal")
 	 */
-	if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
+	if (iseq->compile_data->option->peephole_optimization &&
+	    node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
 	    node->nd_mid == idFreeze && node->nd_args == NULL)
 	{
 	    VALUE str = rb_fstring(node->nd_recv->nd_lit);
@@ -4387,23 +4415,6 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	    }
 	    break;
 	}
-	/* optimization shortcut
-	 *   obj["literal"] -> opt_aref_with(obj, "literal")
-	 */
-	if (node->nd_mid == idAREF && !private_recv_p(node) && 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_with,
-		      new_callinfo(iseq, idAREF, 1, 0, 0, NULL), str);
-	    if (poped) {
-		ADD_INSN(ret, line, pop);
-	    }
-	    break;
-	}
       case NODE_FCALL:
       case NODE_VCALL:{		/* VCALL: variable or call */
 	/*
diff --git a/test/-ext-/symbol/test_type.rb b/test/-ext-/symbol/test_type.rb
index f1749f5..5bd79b8 100644
--- a/test/-ext-/symbol/test_type.rb
+++ b/test/-ext-/symbol/test_type.rb
@@ -4,6 +4,7 @@ require "-test-/symbol"
 module Test_Symbol
   class TestType < Test::Unit::TestCase
     def test_id2str_fstring_bug9171
+      require_compile_option(:peephole_optimization)
       fstr = eval("# encoding: us-ascii
         'foobar'.freeze")
       assert_same fstr, Bug::Symbol.id2str(:foobar)
diff --git a/test/lib/envutil.rb b/test/lib/envutil.rb
index 001753a..852cfe1 100644
--- a/test/lib/envutil.rb
+++ b/test/lib/envutil.rb
@@ -551,6 +551,16 @@ eom
         values
       end
 
+      def require_compile_option(opt)
+        case RubyVM::InstructionSequence.compile_option[opt]
+        when true
+        when false
+          skip(":#{opt} disabled")
+        else
+          raise ArgumentError, "unrecognized compile option: #{opt.inspect}"
+        end
+      end
+
       class << (AssertFile = Struct.new(:failure_message).new)
         include Assertions
         def assert_file_predicate(predicate, *args)
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index f507562..cfdb908 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -194,6 +194,7 @@ class TestObjSpace < Test::Unit::TestCase
   end
 
   def test_dump_flags
+    require_compile_option(:peephole_optimization)
     info = ObjectSpace.dump("foo".freeze)
     assert_match /"wb_protected":true, "old":true, "long_lived":true, "marked":true/, info
     assert_match /"fstring":true/, info
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index da07df9..370e8be 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -215,6 +215,7 @@ class TestHash < Test::Unit::TestCase
   end
 
   def test_AREF_fstring_key
+    require_compile_option(:peephole_optimization)
     h = {"abc" => 1}
     before = GC.stat(:total_allocated_objects)
     5.times{ h["abc"] }
@@ -229,6 +230,7 @@ class TestHash < Test::Unit::TestCase
   end
 
   def test_NEWHASH_fstring_key
+    require_compile_option(:peephole_optimization)
     a = {"ABC" => :t}
     b = {"ABC" => :t}
     assert_same a.keys[0], b.keys[0]
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 79c41bb..e3a28fa 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -117,6 +117,7 @@ class TestISeq < Test::Unit::TestCase
   end
 
   def test_label_fstring
+    require_compile_option(:peephole_optimization)
     c = Class.new{ def foobar() end }
 
     a, b = eval("# encoding: us-ascii\n'foobar'.freeze"),
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 129f62a..79cfa1c 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -28,6 +28,13 @@ class TestRubyOptimization < Test::Unit::TestCase
     end;
   end
 
+  def assert_no_allocation(mesg = "", adjust = 0)
+    before = GC.stat(:total_allocated_objects)
+    yield
+    after = GC.stat(:total_allocated_objects)
+    assert_equal before, after - adjust, mesg
+  end
+
   def test_fixnum_plus
     a, b = 1, 2
     assert_equal 3, a + b
@@ -117,8 +124,10 @@ class TestRubyOptimization < Test::Unit::TestCase
   end
 
   def test_string_freeze
-    assert_equal "foo", "foo".freeze
     assert_redefine_method('String', 'freeze', 'assert_nil "foo".freeze')
+    require_compile_option(:peephole_optimization)
+    assert_no_allocation { 5.times { "".freeze } }
+    assert_equal "foo", "foo".freeze
   end
 
   def test_string_eq_neq
-- 
EW


             reply	other threads:[~2014-11-15 22:16 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-15 22:16 Eric Wong [this message]
2014-11-15 22:16 ` [PATCH 2/2] opt_str_lit-v8 Eric Wong
2014-11-16  9:21   ` [PATCH 2/2 v2] opt_str_lit-v9 Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=opt_str_lit-v8-prepare@0 \
    --to=e@80x24.org \
    --cc=spew@80x24.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).