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

ruby-changes:68850

From: Alan <ko1@a...>
Date: Thu, 21 Oct 2021 08:14:24 +0900 (JST)
Subject: [ruby-changes:68850] ec1cbbb07d (master): Get rid of dependency on rb_call_cache

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

From ec1cbbb07d00828e6265074ca4977a8dae6b8b29 Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Wed, 17 Mar 2021 19:07:20 -0400
Subject: Get rid of dependency on rb_call_cache

---
 common.mk      |   1 +
 vm_method.c    |   8 +-
 yjit.h         |   4 +-
 yjit_codegen.c |   4 +-
 yjit_core.c    |   4 +-
 yjit_core.h    |   9 +-
 yjit_iface.c   | 291 +++++++++++++++++++++++++++++++++++++++++----------------
 yjit_iface.h   |   2 +-
 8 files changed, 232 insertions(+), 91 deletions(-)

diff --git a/common.mk b/common.mk
index d78351bb28..0b2ba1953c 100644
--- a/common.mk
+++ b/common.mk
@@ -17319,6 +17319,7 @@ yjit_iface.$(OBJEXT): {$(VPATH)}config.h https://github.com/ruby/ruby/blob/trunk/common.mk#L17319
 yjit_iface.$(OBJEXT): {$(VPATH)}darray.h
 yjit_iface.$(OBJEXT): {$(VPATH)}debug_counter.h
 yjit_iface.$(OBJEXT): {$(VPATH)}defines.h
+yjit_iface.$(OBJEXT): {$(VPATH)}gc.h
 yjit_iface.$(OBJEXT): {$(VPATH)}id.h
 yjit_iface.$(OBJEXT): {$(VPATH)}id_table.h
 yjit_iface.$(OBJEXT): {$(VPATH)}insns.def
diff --git a/vm_method.c b/vm_method.c
index 5fd8f6a8bc..5260f2d05c 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -123,7 +123,6 @@ rb_vm_cc_invalidate(const struct rb_callcache *cc) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L123
     VM_ASSERT(cc->klass != 0); // should be enable
 
     *(VALUE *)&cc->klass = 0;
-    rb_yjit_method_lookup_change((VALUE)cc);
     RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
 }
 
@@ -135,7 +134,8 @@ vm_cme_invalidate(rb_callable_method_entry_t *cme) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L134
     VM_ASSERT(callable_method_entry_p(cme));
     METHOD_ENTRY_INVALIDATED_SET(cme);
     RB_DEBUG_COUNTER_INC(cc_cme_invalidate);
-    rb_yjit_method_lookup_change((VALUE)cme);
+
+    rb_yjit_cme_invalidate((VALUE)cme);
 }
 
 void
@@ -238,6 +238,8 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L238
             invalidate_negative_cache(mid);
         }
     }
+
+    rb_yjit_method_lookup_change(klass, mid);
 }
 
 static void
@@ -305,6 +307,8 @@ void https://github.com/ruby/ruby/blob/trunk/vm_method.c#L307
 rb_clear_method_cache_all(void)
 {
     rb_objspace_each_objects(invalidate_all_cc, NULL);
+
+    rb_yjit_invalidate_all_method_lookup_assumptions();
 }
 
 void
diff --git a/yjit.h b/yjit.h
index f2dfb31142..b72de1a16e 100644
--- a/yjit.h
+++ b/yjit.h
@@ -47,8 +47,10 @@ bool rb_yjit_enabled_p(void); https://github.com/ruby/ruby/blob/trunk/yjit.h#L47
 unsigned rb_yjit_call_threshold(void);
 RUBY_SYMBOL_EXPORT_END
 
+void rb_yjit_invalidate_all_method_lookup_assumptions(void);
+void rb_yjit_method_lookup_change(VALUE klass, ID mid);
+void rb_yjit_cme_invalidate(VALUE cme);
 void rb_yjit_collect_vm_usage_insn(int insn);
-void rb_yjit_method_lookup_change(VALUE cme_or_cc);
 void rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec);
 void rb_yjit_init(struct rb_yjit_options *options);
 void rb_yjit_bop_redefined(VALUE klass, const rb_method_entry_t *me, enum ruby_basic_operators bop);
diff --git a/yjit_codegen.c b/yjit_codegen.c
index e1d27c5b45..bd3ab5543c 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -1399,7 +1399,7 @@ gen_oswb_cfunc(jitstate_t* jit, ctx_t* ctx, struct rb_call_data * cd, const rb_c https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1399
     x86opnd_t klass_opnd = mem_opnd(64, REG0, offsetof(struct RBasic, klass));
 
     // FIXME: This leaks when st_insert raises NoMemoryError
-    assume_method_lookup_stable(cd->cc, cme, jit->block);
+    assume_method_lookup_stable(cd->cc->klass, cme, jit->block);
 
     // Bail if receiver class is different from compile-time call cache class
     jit_mov_gc_ptr(jit, cb, REG1, (VALUE)cd->cc->klass);
@@ -1632,7 +1632,7 @@ gen_oswb_iseq(jitstate_t* jit, ctx_t* ctx, struct rb_call_data * cd, const rb_ca https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1632
     // Pointer to the klass field of the receiver &(recv->klass)
     x86opnd_t klass_opnd = mem_opnd(64, REG0, offsetof(struct RBasic, klass));
 
-    assume_method_lookup_stable(cd->cc, cme, jit->block);
+    assume_method_lookup_stable(cd->cc->klass, cme, jit->block);
 
     // Bail if receiver class is different from compile-time call cache class
     jit_mov_gc_ptr(jit, cb, REG1, (VALUE)cd->cc->klass);
diff --git a/yjit_core.c b/yjit_core.c
index bd1f6bdd59..cfd1abf901 100644
--- a/yjit_core.c
+++ b/yjit_core.c
@@ -209,8 +209,8 @@ add_block_version(blockid_t blockid, block_t* block) https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L209
     {
         // By writing the new block to the iseq, the iseq now
         // contains new references to Ruby objects. Run write barriers.
-        RB_OBJ_WRITTEN(iseq, Qundef, block->dependencies.cc);
-        RB_OBJ_WRITTEN(iseq, Qundef, block->dependencies.cme);
+        RB_OBJ_WRITTEN(iseq, Qundef, block->receiver_klass);
+        RB_OBJ_WRITTEN(iseq, Qundef, block->callee_cme);
 
         // Run write barriers for all objects in generated code.
         uint32_t *offset_element;
diff --git a/yjit_core.h b/yjit_core.h
index c9a2c5c888..1467395210 100644
--- a/yjit_core.h
+++ b/yjit_core.h
@@ -127,11 +127,10 @@ typedef struct yjit_block_version https://github.com/ruby/ruby/blob/trunk/yjit_core.h#L127
     // Offsets for GC managed objects in the mainline code block
     int32_array_t gc_object_offsets;
 
-    // GC managed objects that this block depend on
-    struct {
-        VALUE cc;
-        VALUE cme;
-    } dependencies;
+    // In case this block is invalidated, these two pieces of info
+    // help to remove all pointers to this block in the system.
+    VALUE receiver_klass;
+    VALUE callee_cme;
 
     // Index one past the last instruction in the iseq
     uint32_t end_idx;
diff --git a/yjit_iface.c b/yjit_iface.c
index 0229f8e1ba..e5789d3dbc 100644
--- a/yjit_iface.c
+++ b/yjit_iface.c
@@ -5,6 +5,7 @@ https://github.com/ruby/ruby/blob/trunk/yjit_iface.c#L5
 #include "vm_sync.h"
 #include "vm_callinfo.h"
 #include "builtin.h"
+#include "gc.h"
 #include "internal/compile.h"
 #include "internal/class.h"
 #include "insns_info.inc"
@@ -141,66 +142,112 @@ struct yjit_root_struct { https://github.com/ruby/ruby/blob/trunk/yjit_iface.c#L142
     int unused; // empty structs are not legal in C99
 };
 
-static void
-block_array_shuffle_remove(rb_yjit_block_array_t blocks, block_t *to_remove) {
-    block_t **elem;
-    rb_darray_foreach(blocks, i, elem) {
-        if (*elem == to_remove) {
-            // Remove the current element by moving the last element here then popping.
-            *elem = rb_darray_get(blocks, rb_darray_size(blocks) - 1);
-            rb_darray_pop_back(blocks);
-            break;
+// Hash table of BOP blocks
+static st_table *blocks_assuming_bops;
+
+bool
+assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop)
+{
+    if (BASIC_OP_UNREDEFINED_P(bop, redefined_flag)) {
+        if (blocks_assuming_bops) {
+            st_insert(blocks_assuming_bops, (st_data_t)block, 0);
         }
+        return true;
+    }
+    else {
+        return false;
     }
 }
 
-// Map cme_or_cc => [block]
+// Map klass => id_table[mid, set of blocks]
+// While a block `b` is in the table, b->callee_cme == rb_callable_method_entry(klass, mid).
+// See assume_method_lookup_stable()
 static st_table *method_lookup_dependency;
 
+// For adding to method_lookup_dependency data with st_update
+struct lookup_dependency_insertion {
+    block_t *block;
+    ID mid;
+};
+
+// Map cme => set of blocks
+// See assume_method_lookup_stable()
+static st_table *cme_validity_dependency;
+
 static int
-add_lookup_dependency_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
+add_cme_validity_dependency_i(st_data_t *key, st_data_t *value, st_data_t new_block, int existing)
 {
-    block_t *new_block = (block_t *)data;
-
-    rb_yjit_block_array_t blocks = NULL;
+    st_table *block_set;
     if (existing) {
-        blocks = (rb_yjit_block_array_t)*value;
+        block_set = (st_table *)*value;
     }
-    if (!rb_darray_append(&blocks, new_block)) {
-        rb_bug("yjit: failed to add method lookup dependency"); // TODO: we could bail out of compiling instead
+    else {
+        // Make the set and put it into cme_validity_dependency
+        block_set = st_init_numtable();
+        *value = (st_data_t)block_set;
     }
 
-    *value = (st_data_t)blocks;
+    // Put block into set
+    st_insert(block_set, new_block, 1);
+
     return ST_CONTINUE;
 }
 
-// Hash table of BOP blocks
-static st_table *blocks_assuming_bops;
-
-bool
-assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop)
+static int
+add_lookup_dependency_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
 {
-    if (BASIC_OP_UNREDEFINED_P(bop, redefined_flag)) {
-        if (blocks_assuming_bops) {
-            st_insert(blocks_assuming_bops, (st_data_t)block, 0);
-        }
-        return true;
+    struct lookup_dependency_insertion *info = (void *)data;
+
+    // Find or make an id table
+    struct rb_id_table *id2blocks;
+    if (existing) {
+        id2blocks = (void *)*value;
     }
     else {
-        return false;
+        // Make an id table and put it into the st_table
+        id2blocks = rb_id_table_create(1);
+        *value = (st_data_t)id2blocks;
+    }
+
+    // Find or make a block set
+    st_table *block_set;
+    {
+        VALUE blocks;
+        if (rb_id_table_lookup(id2blocks, info->mid, &blocks)) {
+            // Take existing set
+            block_set = (st_table *)blocks;
+        }
+        else {
+            // Make new block set and put it into the id table
+            block_set = st_init_numtable();
+            rb_id_table_insert(id2blocks, info->mid, (VALUE)block_set);
+        }
     }
+
+    st_insert(block_set, (st_data_t)info->block, 1);
+
+    return ST_CONTINUE;
 }
 
-// Remember that the currently (... truncated)

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

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