aboutsummaryrefslogtreecommitdiffstats
path: root/vm_callinfo.h
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2023-07-31 16:17:55 +0900
committerKoichi Sasada <ko1@atdot.net>2023-07-31 17:13:43 +0900
commitcfd7729ce7a31c8b6ec5dd0e99c67b2932de4732 (patch)
tree3b489657b66d4a67e179afddb2dd950f8892bcd0 /vm_callinfo.h
parent280419d0e0ba3e96e19551c70cba789fbedd80e1 (diff)
downloadruby-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.h17
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 | \