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/