[前][次][番号順一覧][スレッド一覧]

ruby-changes:68181

From: Jeremy <ko1@a...>
Date: Fri, 1 Oct 2021 07:18:30 +0900 (JST)
Subject: [ruby-changes:68181] 1f5f8a187a (master): Make Array#min/max optimization respect refined methods

https://git.ruby-lang.org/ruby.git/commit/?id=1f5f8a187a

From 1f5f8a187adb746b01cc95c3f29a0a355f513374 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Thu, 30 Sep 2021 13:18:14 -0900
Subject: Make Array#min/max optimization respect refined methods

Pass in ec to vm_opt_newarray_{max,min}. Avoids having to
call GET_EC inside the functions, for better performance.

While here, add a test for Array#min/max being redefined to
test_optimization.rb.

Fixes [Bug #18180]
---
 insns.def                      |  4 ++--
 test/ruby/test_optimization.rb | 12 ++++++++++++
 test/ruby/test_refinement.rb   | 19 +++++++++++++++++++
 vm_insnhelper.c                | 22 ++++++++++++++++++----
 4 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/insns.def b/insns.def
index cf09809ba1..43690be52e 100644
--- a/insns.def
+++ b/insns.def
@@ -834,7 +834,7 @@ opt_newarray_max https://github.com/ruby/ruby/blob/trunk/insns.def#L834
 // attr bool leaf = false; /* has rb_funcall() */
 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
 {
-    val = vm_opt_newarray_max(num, STACK_ADDR_FROM_TOP(num));
+    val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
 }
 
 DEFINE_INSN
@@ -846,7 +846,7 @@ opt_newarray_min https://github.com/ruby/ruby/blob/trunk/insns.def#L846
 // attr bool leaf = false; /* has rb_funcall() */
 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
 {
-    val = vm_opt_newarray_min(num, STACK_ADDR_FROM_TOP(num));
+    val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
 }
 
 /* super(args) # args.size => num */
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 2075bf3513..cbae6d5e8c 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -150,6 +150,18 @@ class TestRubyOptimization < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_optimization.rb#L150
     assert_redefine_method('String', '-@', 'assert_nil(-"foo")')
   end
 
+  def test_array_min
+    assert_equal 1, [1, 2, 4].min
+    assert_redefine_method('Array', 'min', 'assert_nil([1, 2, 4].min)')
+    assert_redefine_method('Array', 'min', 'assert_nil([1 + 0, 2, 4].min)')
+  end
+
+  def test_array_max
+    assert_equal 4, [1, 2, 4].max
+    assert_redefine_method('Array', 'max', 'assert_nil([1, 2, 4].max)')
+    assert_redefine_method('Array', 'max', 'assert_nil([1 + 0, 2, 4].max)')
+  end
+
   def test_trace_optimized_methods
     bug14870 = "[ruby-core:87638]"
     expected = [:-@, :max, :min, :+, :-, :*, :/, :%, :==, :<, :<=, :>, :>=, :<<,
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index a623432cf1..96baab03ee 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -2537,6 +2537,25 @@ class TestRefinement < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L2537
     assert_equal(:second, klass.new.foo)
   end
 
+  class Bug18180
+    module M
+      refine Array do
+        def min; :min; end
+        def max; :max; end
+      end
+    end
+
+    using M
+
+    def t
+      [[1+0, 2, 4].min, [1, 2, 4].min, [1+0, 2, 4].max, [1, 2, 4].max]
+    end
+  end
+
+  def test_refine_array_min_max
+    assert_equal([:min, :min, :max, :max], Bug18180.new.t)
+  end
+
   class Bug17822
     module Ext
       refine(Bug17822) do
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index bbb62d8397..d4740ecc4e 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -4655,7 +4655,7 @@ vm_opt_str_freeze(VALUE str, int bop, ID id) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L4655
 #define id_cmp idCmp
 
 static VALUE
-vm_opt_newarray_max(rb_num_t num, const VALUE *ptr)
+vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
 {
     if (BASIC_OP_UNREDEFINED_P(BOP_MAX, ARRAY_REDEFINED_OP_FLAG)) {
 	if (num == 0) {
@@ -4676,12 +4676,19 @@ vm_opt_newarray_max(rb_num_t num, const VALUE *ptr) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L4676
     }
     else {
 	VALUE ary = rb_ary_new4(num, ptr);
-	return rb_funcall(ary, idMax, 0);
+        const rb_callable_method_entry_t *me =
+            rb_callable_method_entry_with_refinements(rb_cArray, idMax, NULL);
+        if (me) {
+            return rb_vm_call0(ec, ary, idMax, 0, NULL, me, RB_NO_KEYWORDS);
+        }
+        else {
+            return rb_funcall(ary, idMax, 0);
+        }
     }
 }
 
 static VALUE
-vm_opt_newarray_min(rb_num_t num, const VALUE *ptr)
+vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
 {
     if (BASIC_OP_UNREDEFINED_P(BOP_MIN, ARRAY_REDEFINED_OP_FLAG)) {
 	if (num == 0) {
@@ -4702,7 +4709,14 @@ vm_opt_newarray_min(rb_num_t num, const VALUE *ptr) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L4709
     }
     else {
 	VALUE ary = rb_ary_new4(num, ptr);
-	return rb_funcall(ary, idMin, 0);
+        const rb_callable_method_entry_t *me =
+            rb_callable_method_entry_with_refinements(rb_cArray, idMin, NULL);
+        if (me) {
+            return rb_vm_call0(ec, ary, idMin, 0, NULL, me, RB_NO_KEYWORDS);
+        }
+        else {
+            return rb_funcall(ary, idMin, 0);
+        }
     }
 }
 
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]