[前][次][番号順一覧][スレッド一覧]

ruby-changes:59319

From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Wed, 18 Dec 2019 12:52:48 +0900 (JST)
Subject: [ruby-changes:59319] f054f11a38 (master): per-method serial number

https://git.ruby-lang.org/ruby.git/commit/?id=f054f11a38

From f054f11a38f66af17a0aed8e0d2d46731eaab27d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?=
 <shyouhei@r...>
Date: Tue, 17 Dec 2019 15:49:41 +0900
Subject: 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.

diff --git a/internal.h b/internal.h
index fe2b028..c35e3bd 100644
--- a/internal.h
+++ b/internal.h
@@ -2350,7 +2350,7 @@ struct rb_call_cache { https://github.com/ruby/ruby/blob/trunk/internal.h#L2350
         (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 { https://github.com/ruby/ruby/blob/trunk/internal.h#L2362
 
     /* 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 14ffecc..b26caaa 100644
--- a/method.h
+++ b/method.h
@@ -177,6 +177,7 @@ struct rb_method_definition_struct { https://github.com/ruby/ruby/blob/trunk/method.h#L177
     } 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 cec1ea4..54a4036 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 https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L47
 {
     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 efd297d..e35000e 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) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1443
         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) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1475
         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 1a3dbc0..18a670b 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -132,7 +132,7 @@ static inline void https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.h#L132
 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 d2bd677..4504468 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -351,6 +351,8 @@ rb_method_definition_create(rb_method_type_t type, ID mid) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L351
     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;
 }
 
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]