diff options
author | Koichi Sasada <[email protected]> | 2023-07-31 16:17:55 +0900 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2023-07-31 17:13:43 +0900 |
commit | cfd7729ce7a31c8b6ec5dd0e99c67b2932de4732 (patch) | |
tree | 3b489657b66d4a67e179afddb2dd950f8892bcd0 /vm_method.c | |
parent | 280419d0e0ba3e96e19551c70cba789fbedd80e1 (diff) |
use inline cache for refinements
From Ruby 3.0, refined method invocations are slow because
resolved methods are not cached by inline cache because of
conservertive strategy. However, `using` clears all caches
so that it seems safe to cache resolved method entries.
This patch caches resolved method entries in inline cache
and clear all of inline method caches when `using` is called.
fix [Bug #18572]
```ruby
# without refinements
class C
def foo = :C
end
N = 1_000_000
obj = C.new
require 'benchmark'
Benchmark.bm{|x|
x.report{N.times{
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
}}
}
_END__
user system total real
master 0.362859 0.002544 0.365403 ( 0.365424)
modified 0.357251 0.000000 0.357251 ( 0.357258)
```
```ruby
# with refinment but without using
class C
def foo = :C
end
module R
refine C do
def foo = :R
end
end
N = 1_000_000
obj = C.new
require 'benchmark'
Benchmark.bm{|x|
x.report{N.times{
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
}}
}
__END__
user system total real
master 0.957182 0.000000 0.957182 ( 0.957212)
modified 0.359228 0.000000 0.359228 ( 0.359238)
```
```ruby
# with using
class C
def foo = :C
end
module R
refine C do
def foo = :R
end
end
N = 1_000_000
using R
obj = C.new
require 'benchmark'
Benchmark.bm{|x|
x.report{N.times{
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
}}
}
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/8129
Diffstat (limited to 'vm_method.c')
-rw-r--r-- | vm_method.c | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/vm_method.c b/vm_method.c index 221f184267..a65c676cfc 100644 --- a/vm_method.c +++ b/vm_method.c @@ -307,19 +307,19 @@ rb_clear_method_cache(VALUE klass_or_module, ID mid) void rb_cc_table_free(VALUE klass); static int -invalidate_all_cc(void *vstart, void *vend, size_t stride, void *data) +invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data) { VALUE v = (VALUE)vstart; for (; v != (VALUE)vend; v += stride) { void *ptr = asan_poisoned_object_p(v); asan_unpoison_object(v, false); + if (RBASIC(v)->flags) { // liveness check - if (RB_TYPE_P(v, T_CLASS) || - RB_TYPE_P(v, T_ICLASS)) { - if (RCLASS_CC_TBL(v)) { - rb_cc_table_free(v); + if (imemo_type_p(v, imemo_callcache)) { + const struct rb_callcache *cc = (const struct rb_callcache *)v; + if (vm_cc_refinement_p(cc) && cc->klass) { + vm_cc_invalidate(cc); } - RCLASS_CC_TBL(v) = NULL; } } @@ -331,10 +331,9 @@ invalidate_all_cc(void *vstart, void *vend, size_t stride, void *data) } void -rb_clear_method_cache_all(void) +rb_clear_all_refinement_method_cache(void) { - rb_objspace_each_objects(invalidate_all_cc, NULL); - + rb_objspace_each_objects(invalidate_all_refinement_cc, NULL); rb_yjit_invalidate_all_method_lookup_assumptions(); } |