summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2021-05-13 03:10:18 +0900
committerKoichi Sasada <ko1@atdot.net>2021-07-29 00:56:48 +0900
commitfb4cf204a662a8cd9dafef6f31f2bd0db9129abe (patch)
treeb66769f1420ab372f81ea5e5ae53d232cfe60a98
parent7af750af8e718acf962578af988883ead55135b3 (diff)
use me->def instead of me for opt_table
`vm_opt_method_table` is me=>bop table to manage the optimized methods (by specialized instruction). However, `me` can be invalidated to invalidate the method cache entry. [Bug #17725] To solve the issue, use `me-def` instead of `me` which simply copied at invalidation timing. A test by @jeremyevans https://github.com/ruby/ruby/pull/4376
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4493
-rw-r--r--test/ruby/test_method.rb15
-rw-r--r--vm.c11
2 files changed, 20 insertions, 6 deletions
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index 240821c9e2..0bd5dc63dd 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -1303,6 +1303,21 @@ class TestMethod < Test::Unit::TestCase
end;
end
+ def test_override_optimized_method_on_class_using_prepend
+ assert_separately(%w(--disable-gems), <<-'end;', timeout: 30)
+ # Bug #17725 [ruby-core:102884]
+ $VERBOSE = nil
+ String.prepend(Module.new)
+ class String
+ def + other
+ 'blah blah'
+ end
+ end
+
+ assert_equal('blah blah', 'a' + 'b')
+ end;
+ end
+
def test_eqq
assert_operator(0.method(:<), :===, 5)
assert_not_operator(0.method(:<), :===, -5)
diff --git a/vm.c b/vm.c
index accd12644e..8a044efa1f 100644
--- a/vm.c
+++ b/vm.c
@@ -1798,7 +1798,7 @@ rb_iter_break_value(VALUE val)
/* optimization: redefine management */
-static st_table *vm_opt_method_table = 0;
+static st_table *vm_opt_method_def_table = 0;
static st_table *vm_opt_mid_table = 0;
static int
@@ -1852,9 +1852,8 @@ rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
klass = RBASIC_CLASS(klass);
}
if (vm_redefinition_check_method_type(me->def)) {
- if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
- int flag = vm_redefinition_check_flag(klass);
-
+ if (st_lookup(vm_opt_method_def_table, (st_data_t)me->def, &bop)) {
+ int flag = vm_redefinition_check_flag(klass);
ruby_vm_redefined_flag[bop] |= flag;
}
}
@@ -1885,7 +1884,7 @@ add_opt_method(VALUE klass, ID mid, VALUE bop)
const rb_method_entry_t *me = rb_method_entry_at(klass, mid);
if (me && vm_redefinition_check_method_type(me->def)) {
- st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
+ st_insert(vm_opt_method_def_table, (st_data_t)me->def, (st_data_t)bop);
st_insert(vm_opt_mid_table, (st_data_t)mid, (st_data_t)Qtrue);
}
else {
@@ -1899,7 +1898,7 @@ vm_init_redefined_flag(void)
ID mid;
VALUE bop;
- vm_opt_method_table = st_init_numtable();
+ vm_opt_method_def_table = st_init_numtable();
vm_opt_mid_table = st_init_numtable();
#define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0)