[ruby-core:85359] [PATCH] compile.c: avoid String#+@ call with FSL

From: Eric Wong <normalperson@...>
Date: 2018-02-03 07:39:56 UTC
List: ruby-core #85359
Eric Wong wrote:
> Considering String#+@ and String#-@ look like syntax elements
> and are relatively new; can get rid of redefinition check in
> opt_str_uminus?

Maybe we can do this (still running tests, will take a while):

----8<---
Subject: [PATCH] compile.c: avoid String#+@ call with FSL

When using "frozen_string_literal: true", String#+@ is often
used to create mutable strings.  Treat it like an immutable
syntax to allow for optimization.

Followup to r62039 and r62041.
---
 compile.c                      | 22 ++++++++++++++++++++++
 test/ruby/test_optimization.rb | 10 ++++++++++
 2 files changed, 32 insertions(+)

diff --git a/compile.c b/compile.c
index 315e2dc92e..12f1c481e9 100644
--- a/compile.c
+++ b/compile.c
@@ -2850,6 +2850,28 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
 	}
     }
 
+    if (IS_INSN_ID(iobj, putobject) &&
+        RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING) &&
+        IS_NEXT_INSN_ID(&iobj->link, send)) {
+        INSN *niobj = (INSN *)iobj->link.next;
+        struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
+
+        /*
+	 *  (with frozen_string_literal: true)
+         *  putobject "literal"
+         *  send <:+@, 0, ARG_SIMPLE>
+         * =>
+         *  putstring "literal"
+         */
+        if (ci->mid == idUPlus &&
+            (ci->flag & VM_CALL_ARGS_SIMPLE) &&
+            ci->orig_argc == 0) {
+            ELEM_REMOVE(iobj->link.next);
+            iobj->insn_id = BIN(putstring);
+            return COMPILE_OK;
+        }
+    }
+
     if (do_tailcallopt &&
 	(IS_INSN_ID(iobj, send) ||
 	 IS_INSN_ID(iobj, opt_aref_with) ||
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index e8b4f92d92..5d7118d045 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -718,4 +718,14 @@ def obj.a(&block)
     end
     assert_equal(:ok, obj.a())
   end
+
+  def test_uplus_removal
+    code = '+"unfrozen"'
+    opt = { frozen_string_literal: true }
+    iseq = RubyVM::InstructionSequence.compile(code, nil, nil, opt)
+    insn = iseq.disasm.inspect
+    assert_match %r{\bputstring\b}, insn
+    assert_no_match %r{\bputobject\b}, insn
+    assert_no_match %r{\bmid:\+@\b}, insn
+  end
 end

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread