Skip to content

Commit 1f5f8a1

Browse files
authored
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]
1 parent a55a5fc commit 1f5f8a1

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

insns.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ opt_newarray_max
834834
// attr bool leaf = false; /* has rb_funcall() */
835835
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
836836
{
837-
val = vm_opt_newarray_max(num, STACK_ADDR_FROM_TOP(num));
837+
val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
838838
}
839839

840840
DEFINE_INSN
@@ -846,7 +846,7 @@ opt_newarray_min
846846
// attr bool leaf = false; /* has rb_funcall() */
847847
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
848848
{
849-
val = vm_opt_newarray_min(num, STACK_ADDR_FROM_TOP(num));
849+
val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
850850
}
851851

852852
/* super(args) # args.size => num */

test/ruby/test_optimization.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ def test_string_uminus
150150
assert_redefine_method('String', '-@', 'assert_nil(-"foo")')
151151
end
152152

153+
def test_array_min
154+
assert_equal 1, [1, 2, 4].min
155+
assert_redefine_method('Array', 'min', 'assert_nil([1, 2, 4].min)')
156+
assert_redefine_method('Array', 'min', 'assert_nil([1 + 0, 2, 4].min)')
157+
end
158+
159+
def test_array_max
160+
assert_equal 4, [1, 2, 4].max
161+
assert_redefine_method('Array', 'max', 'assert_nil([1, 2, 4].max)')
162+
assert_redefine_method('Array', 'max', 'assert_nil([1 + 0, 2, 4].max)')
163+
end
164+
153165
def test_trace_optimized_methods
154166
bug14870 = "[ruby-core:87638]"
155167
expected = [:-@, :max, :min, :+, :-, :*, :/, :%, :==, :<, :<=, :>, :>=, :<<,

test/ruby/test_refinement.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2537,6 +2537,25 @@ def test_redefining_refined_for_prepended_class
25372537
assert_equal(:second, klass.new.foo)
25382538
end
25392539

2540+
class Bug18180
2541+
module M
2542+
refine Array do
2543+
def min; :min; end
2544+
def max; :max; end
2545+
end
2546+
end
2547+
2548+
using M
2549+
2550+
def t
2551+
[[1+0, 2, 4].min, [1, 2, 4].min, [1+0, 2, 4].max, [1, 2, 4].max]
2552+
end
2553+
end
2554+
2555+
def test_refine_array_min_max
2556+
assert_equal([:min, :min, :max, :max], Bug18180.new.t)
2557+
end
2558+
25402559
class Bug17822
25412560
module Ext
25422561
refine(Bug17822) do

vm_insnhelper.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4655,7 +4655,7 @@ vm_opt_str_freeze(VALUE str, int bop, ID id)
46554655
#define id_cmp idCmp
46564656

46574657
static VALUE
4658-
vm_opt_newarray_max(rb_num_t num, const VALUE *ptr)
4658+
vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
46594659
{
46604660
if (BASIC_OP_UNREDEFINED_P(BOP_MAX, ARRAY_REDEFINED_OP_FLAG)) {
46614661
if (num == 0) {
@@ -4676,12 +4676,19 @@ vm_opt_newarray_max(rb_num_t num, const VALUE *ptr)
46764676
}
46774677
else {
46784678
VALUE ary = rb_ary_new4(num, ptr);
4679-
return rb_funcall(ary, idMax, 0);
4679+
const rb_callable_method_entry_t *me =
4680+
rb_callable_method_entry_with_refinements(rb_cArray, idMax, NULL);
4681+
if (me) {
4682+
return rb_vm_call0(ec, ary, idMax, 0, NULL, me, RB_NO_KEYWORDS);
4683+
}
4684+
else {
4685+
return rb_funcall(ary, idMax, 0);
4686+
}
46804687
}
46814688
}
46824689

46834690
static VALUE
4684-
vm_opt_newarray_min(rb_num_t num, const VALUE *ptr)
4691+
vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
46854692
{
46864693
if (BASIC_OP_UNREDEFINED_P(BOP_MIN, ARRAY_REDEFINED_OP_FLAG)) {
46874694
if (num == 0) {
@@ -4702,7 +4709,14 @@ vm_opt_newarray_min(rb_num_t num, const VALUE *ptr)
47024709
}
47034710
else {
47044711
VALUE ary = rb_ary_new4(num, ptr);
4705-
return rb_funcall(ary, idMin, 0);
4712+
const rb_callable_method_entry_t *me =
4713+
rb_callable_method_entry_with_refinements(rb_cArray, idMin, NULL);
4714+
if (me) {
4715+
return rb_vm_call0(ec, ary, idMin, 0, NULL, me, RB_NO_KEYWORDS);
4716+
}
4717+
else {
4718+
return rb_funcall(ary, idMin, 0);
4719+
}
47064720
}
47074721
}
47084722

0 commit comments

Comments
 (0)