summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2021-09-30 13:18:14 -0900
committerGitHub <noreply@github.com>2021-09-30 15:18:14 -0700
commit1f5f8a187adb746b01cc95c3f29a0a355f513374 (patch)
tree9d907b527d60b89f4c9d6402b1bdabb8aec7abf0
parenta55a5fc68426ed701dace6bc166d18de06d8dcb2 (diff)
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]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4911 Merged-By: jeremyevans <code@jeremyevans.net>
-rw-r--r--insns.def4
-rw-r--r--test/ruby/test_optimization.rb12
-rw-r--r--test/ruby/test_refinement.rb19
-rw-r--r--vm_insnhelper.c22
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
// 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
// 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
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
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)
#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)
}
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)
}
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);
+ }
}
}