diff options
author | Koichi Sasada <ko1@atdot.net> | 2023-07-31 16:17:55 +0900 |
---|---|---|
committer | Koichi Sasada <ko1@atdot.net> | 2023-07-31 17:13:43 +0900 |
commit | cfd7729ce7a31c8b6ec5dd0e99c67b2932de4732 (patch) | |
tree | 3b489657b66d4a67e179afddb2dd950f8892bcd0 /vm_callinfo.h | |
parent | 280419d0e0ba3e96e19551c70cba789fbedd80e1 (diff) | |
download | ruby-cfd7729ce7a31c8b6ec5dd0e99c67b2932de4732.tar.gz |
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;
}}
}
Diffstat (limited to 'vm_callinfo.h')
-rw-r--r-- | vm_callinfo.h | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/vm_callinfo.h b/vm_callinfo.h index 914f1eafdf..91c92854d7 100644 --- a/vm_callinfo.h +++ b/vm_callinfo.h @@ -296,13 +296,15 @@ struct rb_callcache { #define VM_CALLCACHE_UNMARKABLE FL_FREEZE #define VM_CALLCACHE_ON_STACK FL_EXIVAR -#define VM_CALLCACHE_IVAR IMEMO_FL_USER0 -#define VM_CALLCACHE_BF IMEMO_FL_USER1 -#define VM_CALLCACHE_SUPER IMEMO_FL_USER2 +#define VM_CALLCACHE_IVAR IMEMO_FL_USER0 +#define VM_CALLCACHE_BF IMEMO_FL_USER1 +#define VM_CALLCACHE_SUPER IMEMO_FL_USER2 +#define VM_CALLCACHE_REFINEMENT IMEMO_FL_USER3 enum vm_cc_type { cc_type_normal, // chained from ccs cc_type_super, + cc_type_refinement, }; extern const struct rb_callcache *rb_vm_empty_cc(void); @@ -332,6 +334,9 @@ vm_cc_new(VALUE klass, case cc_type_super: *(VALUE *)&cc->flags |= VM_CALLCACHE_SUPER; break; + case cc_type_refinement: + *(VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT; + break; } vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); @@ -345,6 +350,12 @@ vm_cc_super_p(const struct rb_callcache *cc) return (cc->flags & VM_CALLCACHE_SUPER) != 0; } +static inline bool +vm_cc_refinement_p(const struct rb_callcache *cc) +{ + return (cc->flags & VM_CALLCACHE_REFINEMENT) != 0; +} + #define VM_CC_ON_STACK(clazz, call, aux, cme) \ (struct rb_callcache) { \ .flags = T_IMEMO | \ |