summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2019-12-17 15:49:41 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2019-12-18 12:52:28 +0900
commitf054f11a38f66af17a0aed8e0d2d46731eaab27d (patch)
treed85000f9e73f282d6e79056415e33c99eb6d86a0
parent77e3078ede833e86a1ee0e2ce745b15e892bdbf6 (diff)
per-method serial number
Methods and their definitions can be allocated/deallocated on-the-fly. One pathological situation is when a method is deallocated then another one is allocated immediately after that. Address of those old/new method entries/definitions can be the same then, depending on underlying malloc/free implementation. So pointer comparison is insufficient. We have to check the contents. To do so we introduce def->method_serial, which is an integer unique to that specific method definition. PS: Note that method_serial being uintptr_t rather than rb_serial_t is intentional. This is because rb_serial_t can be bigger than a pointer on a 32bit system (rb_serial_t is at least 64bit). In order to preserve old packing of struct rb_call_cache, rb_serial_t is inappropriate.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2759
-rw-r--r--internal.h4
-rw-r--r--method.h1
-rw-r--r--vm_eval.c2
-rw-r--r--vm_insnhelper.c4
-rw-r--r--vm_insnhelper.h2
-rw-r--r--vm_method.c2
6 files changed, 9 insertions, 6 deletions
diff --git a/internal.h b/internal.h
index fe2b028f47..c35e3bdb6f 100644
--- a/internal.h
+++ b/internal.h
@@ -2350,7 +2350,7 @@ struct rb_call_cache {
(CACHELINE
- sizeof(rb_serial_t) /* method_state */
- sizeof(struct rb_callable_method_entry_struct *) /* me */
- - sizeof(struct rb_callable_method_definition_struct *) /* def */
+ - sizeof(uintptr_t) /* method_serial */
- sizeof(enum method_missing_reason) /* aux */
- sizeof(VALUE (*)( /* call */
struct rb_execution_context_struct *e,
@@ -2362,7 +2362,7 @@ struct rb_call_cache {
/* inline cache: values */
const struct rb_callable_method_entry_struct *me;
- const struct rb_method_definition_struct *def;
+ uintptr_t method_serial; /* me->def->method_serial */
VALUE (*call)(struct rb_execution_context_struct *ec,
struct rb_control_frame_struct *cfp,
diff --git a/method.h b/method.h
index 14ffecc398..b26caaa92d 100644
--- a/method.h
+++ b/method.h
@@ -177,6 +177,7 @@ struct rb_method_definition_struct {
} body;
ID original_id;
+ uintptr_t method_serial;
};
typedef struct rb_method_definition_struct rb_method_definition_t;
diff --git a/vm_eval.c b/vm_eval.c
index cec1ea41f6..54a4036ae7 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -47,7 +47,7 @@ rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE
{
struct rb_calling_info calling = { Qundef, recv, argc, kw_splat, };
struct rb_call_info ci = { id, (kw_splat ? VM_CALL_KW_SPLAT : 0), argc, };
- struct rb_call_cache cc = { 0, { 0, }, me, me->def, vm_call_general, { 0, }, };
+ struct rb_call_cache cc = { 0, { 0, }, me, me->def->method_serial, vm_call_general, { 0, }, };
struct rb_call_data cd = { cc, ci, };
return vm_call0_body(ec, &calling, &cd, argv);
}
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index efd297d506..e35000e758 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1443,7 +1443,7 @@ calccall(const struct rb_call_data *cd, const rb_callable_method_entry_t *me)
RB_DEBUG_COUNTER_INC(mc_miss_by_distinct);
return vm_call_general; /* normal cases */
}
- else if (UNLIKELY(cc->def != me->def)) {
+ else if (UNLIKELY(cc->method_serial != me->def->method_serial)) {
RB_DEBUG_COUNTER_INC(mc_miss_by_refine);
return vm_call_general; /* cc->me was refined elsewhere */
}
@@ -1475,7 +1475,7 @@ rb_vm_search_method_slowpath(struct rb_call_data *cd, VALUE klass)
GET_GLOBAL_METHOD_STATE(),
{ RCLASS_SERIAL(klass) },
me,
- me ? me->def : NULL,
+ me ? me->def->method_serial : 0,
call,
};
if (call != vm_call_general) {
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 1a3dbc0326..18a670bf14 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -132,7 +132,7 @@ static inline void
CC_SET_ME(CALL_CACHE cc, const rb_callable_method_entry_t *me)
{
cc->me = me;
- cc->def = me ? me->def : NULL;
+ cc->method_serial = me ? me->def->method_serial : 0;
}
#define GET_BLOCK_HANDLER() (GET_LEP()[VM_ENV_DATA_INDEX_SPECVAL])
diff --git a/vm_method.c b/vm_method.c
index d2bd677e6a..4504468789 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -351,6 +351,8 @@ rb_method_definition_create(rb_method_type_t type, ID mid)
def = ZALLOC(rb_method_definition_t);
def->type = type;
def->original_id = mid;
+ static uintptr_t method_serial = 1;
+ def->method_serial = method_serial++;
return def;
}