dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH 4/4] opt_str_lit_yoda: account for method redefinition in arg
@ 2014-11-05 23:18 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2014-11-05 23:18 UTC (permalink / raw)
  To: spew

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 5902 bytes --]

Strange arguments may redefine methods at run-time.  This commit
may not be necessary, as (hopefully) nobody writes such strange code.
[ruby-core:66097]
---
 compile.c                      | 63 ++++++++++++++++++++++++++++++++++++------
 insns.def                      | 27 ++++++++++++++++++
 test/ruby/test_optimization.rb | 28 +++++++++++++++++++
 3 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/compile.c b/compile.c
index 7498bca..cd1d43f 100644
--- a/compile.c
+++ b/compile.c
@@ -1812,6 +1812,18 @@ new_recvinfo_for_recv_(rb_iseq_t *iseq, VALUE str,
     return ri;
 }
 
+static VALUE
+new_recvinfo_for_yoda(rb_iseq_t *iseq, VALUE str,
+		    enum ruby_optimized_method om, int recv_off)
+{
+    VALUE ri = rb_ary_new_from_args(3, str, INT2FIX(om), INT2FIX(recv_off));
+
+    hide_obj(ri);
+    iseq_add_mark_object(iseq, ri);
+
+    return ri;
+}
+
 #define new_recvinfo_for_arg(iseq,str,mid,klass,off) \
     new_recvinfo_for_arg_((iseq),(str),(OM_##mid##__##klass),\
                           (OM_TMASK_##klass),(off))
@@ -4596,6 +4608,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	unsigned int flag = 0;
 	rb_call_info_kw_arg_t *keywords = NULL;
 	VALUE parent_block = iseq->compile_data->current_block;
+	INSN *yoda_insn = 0;
 	iseq->compile_data->current_block = Qfalse;
 
 	INIT_ANCHOR(recv);
@@ -4669,13 +4682,23 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	    enum ruby_optimized_method om;
 	    /*
 	     * optimize:
-	     *   "string literal".method(...)
-	     *   "yoda" == other -> opt_str_lit("yoda").send(:==, other)
-	     *   "yoda" != other -> opt_str_lit("yoda").send(:!=, other)
-	     *   "str" + other -> opt_str_lit("str").send(:+, other)
-	     *   "str" * other -> opt_str_lit("str").send(:*, other)
-	     *   "fmt" % args -> opt_str_lit("str").send(:%, other)
+	     *   "string literal".method(arg)
+	     *   "yoda" == other
+	     *   "yoda" != other
+	     *   "str" + other
+	     *   "str" * other
+	     *   "fmt" % args
 	     *   ...
+	     * result A:
+	     *   putobject str
+	     *   <setup_args>
+	     *   opt_str_lit_yoda([str, om, off])
+	     *   send mid ...
+	     *
+	     * result B:
+	     *   opt_str_lit_recv([str, om]) => str
+	     *   <setup_args (putobject|putstring|putspecial)>
+	     *   send mid ...
 	     */
 	    if (iseq->compile_data->option->peephole_optimization &&
 		((om = opt_str_lit_recv_om(mid)) != OM_LAST_) &&
@@ -4685,10 +4708,12 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 		node->nd_args->nd_alen == 1)
 	    {
 		VALUE yoda = rb_fstring(node->nd_recv->nd_lit);
-		VALUE recv_info = new_recvinfo_for_recv_(iseq, yoda, om);
+		int off = node->nd_args->nd_alen;
+		VALUE yoda_info = new_recvinfo_for_yoda(iseq, yoda, om, off);
 
 		node->nd_recv->nd_lit = yoda;
-		ADD_INSN1(recv, line, opt_str_lit_recv, recv_info);
+		ADD_INSN1(recv, line, putobject, yoda_info /* temporary */);
+		yoda_insn = (INSN *)recv->last;
 	    } else {
 		COMPILE(recv, "recv", node->nd_recv);
 	    }
@@ -4719,6 +4744,28 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 	    flag |= VM_CALL_FCALL;
 	}
 
+	if (yoda_insn) {
+	    INSN *last = (INSN *)ret->last;
+	    VALUE yoda_info = yoda_insn->operands[0];
+
+	    assert(yoda_insn->insn_id == BIN(putobject));
+	    switch (last->insn_id) {
+	    case BIN(putstring):
+	    case BIN(putobject):
+	    case BIN(getlocal):
+		/*
+		 * [putobject, yoda_info] => [opt_str_lit_recv, recv_info]
+		 * n.b.: opt_str_lit_recv ignores 3rd element of recv_info
+		 */
+		yoda_insn->insn_id = BIN(opt_str_lit_recv);
+		break;
+	    default:
+		/* [putobject, yoda_info] => [putobject, "str lit"] */
+		yoda_insn->operands[0] = RARRAY_AREF(yoda_info, 0); /* str */
+
+		ADD_INSN1(ret, line, opt_str_lit_yoda, yoda_info);
+	    }
+	}
 	ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
 
 	if (poped) {
diff --git a/insns.def b/insns.def
index ba86863..9728405 100644
--- a/insns.def
+++ b/insns.def
@@ -462,6 +462,33 @@ opt_str_lit_recv
 }
 
 /**
+  @c optimize
+  @e put string val. string may be dup-ed depending on recv_info conditions
+ */
+DEFINE_INSN
+opt_str_lit_yoda
+(VALUE recv_info)
+()
+()
+{
+    /*
+     * recv_info:
+     * 0 - str (only for assert)
+     * 1 - tmask (optimized receiver classes)
+     * 2 - stack offset (Fixint)
+     */
+    const VALUE *ri = RARRAY_CONST_PTR(recv_info);
+    enum ruby_optimized_method om = FIX2UINT(ri[1]);
+    int off = FIX2INT(ri[2]);
+    VALUE recv = TOPN(off);
+
+    assert(ri[0] == recv);
+    if (!rb_basic_op_unredefined_p(om)) {
+	TOPN(off) = rb_str_resurrect(recv);
+    }
+}
+
+/**
   @c put
   @e put concatenate strings
   @j スタックトップの文字列を n 個連結し,結果をスタックにプッシュする。
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 63ed22b..709b5cc 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -148,6 +148,34 @@ class TestRubyOptimization < Test::Unit::TestCase
     end
   end
 
+  def test_opt_str_lit_lazy
+    require_compile_option(:peephole_optimization)
+    assert_separately([], <<-"end;")#    do
+      def bar
+        String.class_eval %q{
+          def ==(other)
+            self.upcase! # modify operation
+            true
+          end
+        }
+        'bar'
+      end
+      assert('foo' == bar, "[ruby-core:66097]")
+
+      def break_gsub
+        String.class_eval %q{
+          def gsub(a, b)
+            self.dup.gsub!(a.upcase!, b.upcase)
+            true
+          end
+        }
+        'a'
+      end
+      str = 'A'
+      assert_equal('a', str.gsub(break_gsub, 'a'))
+    end;
+  end
+
   def test_string_ltlt
     assert_equal "", "" << ""
     assert_equal "x", "x" << ""
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2014-11-05 23:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-05 23:18 [PATCH 4/4] opt_str_lit_yoda: account for method redefinition in arg Eric Wong

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).