aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--benchmark/vm2_poly_same_method.yml25
-rw-r--r--insns.def2
-rw-r--r--internal.h2
-rw-r--r--vm_insnhelper.c37
4 files changed, 59 insertions, 7 deletions
diff --git a/benchmark/vm2_poly_same_method.yml b/benchmark/vm2_poly_same_method.yml
new file mode 100644
index 0000000000..867c433cf8
--- /dev/null
+++ b/benchmark/vm2_poly_same_method.yml
@@ -0,0 +1,25 @@
+prelude: |
+ module AR; end
+ class AR::Base
+ def create_or_update
+ nil
+ end
+ def save
+ create_or_update
+ end
+ end
+ class Foo < AR::Base; end
+ class Bar < AR::Base; end
+ o1 = Foo.new
+ o2 = Bar.new
+benchmark:
+ vm2_poly_same_method: |
+ o1.save; o2.save;
+ o1.save; o2.save;
+ o1.save; o2.save;
+ o1.save; o2.save;
+ o1.save; o2.save;
+ o1.save; o2.save;
+ o1.save; o2.save;
+ o1.save; o2.save;
+loop_count: 6000000
diff --git a/insns.def b/insns.def
index e3edc5e29f..f365106e2c 100644
--- a/insns.def
+++ b/insns.def
@@ -911,7 +911,7 @@ invokeblock
// attr rb_snum_t sp_inc = sp_inc_of_invokeblock(ci);
{
static struct rb_call_cache cc = {
- 0, 0, NULL, vm_invokeblock_i,
+ 0, 0, NULL, NULL, vm_invokeblock_i,
};
VALUE bh = VM_BLOCK_HANDLER_NONE;
diff --git a/internal.h b/internal.h
index 3dbe9ad38e..2e8d23b085 100644
--- a/internal.h
+++ b/internal.h
@@ -2328,6 +2328,7 @@ enum method_missing_reason {
MISSING_NONE = 0x40
};
struct rb_callable_method_entry_struct;
+struct rb_method_definition_struct;
struct rb_execution_context_struct;
struct rb_control_frame_struct;
struct rb_calling_info;
@@ -2339,6 +2340,7 @@ struct rb_call_cache {
/* inline cache: values */
const struct rb_callable_method_entry_struct *me;
+ const struct rb_method_definition_struct *def;
VALUE (*call)(struct rb_execution_context_struct *ec,
struct rb_control_frame_struct *cfp,
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 352d38fe45..66c50cdf59 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1374,16 +1374,41 @@ vm_expandarray(VALUE *sp, VALUE ary, rb_num_t num, int flag)
static VALUE vm_call_general(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
+#ifdef __has_attribute
+#if __has_attribute(artificial)
+__attribute__((__artificial__))
+#endif
+#endif
+static inline vm_call_handler
+calccall(const struct rb_call_cache *cc, const rb_callable_method_entry_t *me)
+{
+ if (UNLIKELY(!me)) {
+ return vm_call_general; /* vm_call_method_nome() situation */
+ }
+ else if (LIKELY(cc->me != me)) {
+ return vm_call_general; /* normal cases */
+ }
+ else if (UNLIKELY(cc->def != me->def)) {
+ return vm_call_general; /* cc->me was refined elsewhere */
+ }
+ else {
+ return cc->call;
+ }
+}
+
MJIT_FUNC_EXPORTED void
rb_vm_search_method_slowpath(const struct rb_call_info *ci, struct rb_call_cache *cc, VALUE klass)
{
- cc->me = rb_callable_method_entry(klass, ci->mid);
+ const rb_callable_method_entry_t *me =
+ rb_callable_method_entry(klass, ci->mid);
+ *cc = (struct rb_call_cache) {
+ GET_GLOBAL_METHOD_STATE(),
+ RCLASS_SERIAL(klass),
+ me,
+ me ? me->def : NULL,
+ calccall(cc, me),
+ };
VM_ASSERT(callable_method_entry_p(cc->me));
- cc->call = vm_call_general;
-#if OPT_INLINE_METHOD_CACHE
- cc->method_state = GET_GLOBAL_METHOD_STATE();
- cc->class_serial = RCLASS_SERIAL(klass);
-#endif
}
static void