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

ruby-changes:72561

From: Peter <ko1@a...>
Date: Fri, 15 Jul 2022 22:21:19 +0900 (JST)
Subject: [ruby-changes:72561] 7424ea184f (master): Implement Objects on VWA

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

From 7424ea184f9d67c1c7f3ee97494ed3bd1aa60833 Mon Sep 17 00:00:00 2001
From: Peter Zhu <peter@p...>
Date: Mon, 11 Jul 2022 10:09:39 -0400
Subject: Implement Objects on VWA

This commit implements Objects on Variable Width Allocation. This allows
Objects with more ivars to be embedded (i.e. contents directly follow the
object header) which improves performance through better cache locality.
---
 debug.c                                   |   2 +
 gc.c                                      | 120 +++++++++++++++++++++++-------
 include/ruby/internal/abi.h               |   2 +-
 include/ruby/internal/core/robject.h      |  45 ++++++++++-
 mjit_compile.c                            |   4 +
 object.c                                  |  33 ++------
 test/ruby/test_gc_compact.rb              |  24 ++++++
 test/ruby/test_mjit.rb                    |   5 +-
 tool/ruby_vm/views/_mjit_compile_ivar.erb |   9 +++
 variable.c                                |   8 +-
 yjit/bindgen/src/main.rs                  |   6 +-
 yjit/src/codegen.rs                       |  21 ++++--
 yjit/src/cruby.rs                         |   4 -
 yjit/src/cruby_bindings.inc.rs            |   7 +-
 14 files changed, 216 insertions(+), 74 deletions(-)

diff --git a/debug.c b/debug.c
index 6b5684efb2..d927f72231 100644
--- a/debug.c
+++ b/debug.c
@@ -53,7 +53,9 @@ const union { https://github.com/ruby/ruby/blob/trunk/debug.c#L53
     rb_econv_result_t           econv_result;
     enum ruby_preserved_encindex encoding_index;
     enum ruby_robject_flags     robject_flags;
+#if !USE_RVARGC
     enum ruby_robject_consts    robject_consts;
+#endif
     enum ruby_rmodule_flags     rmodule_flags;
     enum ruby_rstring_flags     rstring_flags;
 #if !USE_RVARGC
diff --git a/gc.c b/gc.c
index 39d82a6a77..e92a576c29 100644
--- a/gc.c
+++ b/gc.c
@@ -2865,18 +2865,65 @@ rb_newobj(void) https://github.com/ruby/ruby/blob/trunk/gc.c#L2865
     return newobj_of(0, T_NONE, 0, 0, 0, FALSE, sizeof(RVALUE));
 }
 
-VALUE
-rb_newobj_of(VALUE klass, VALUE flags)
+static size_t
+rb_obj_embedded_size(uint32_t numiv)
 {
-    if ((flags & RUBY_T_MASK) == T_OBJECT) {
-        st_table *index_tbl = RCLASS_IV_INDEX_TBL(klass);
+    return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
+}
+
+static VALUE
+rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected)
+{
+    GC_ASSERT((flags & RUBY_T_MASK) == T_OBJECT);
+    GC_ASSERT(flags & ROBJECT_EMBED);
+
+    st_table *index_tbl = RCLASS_IV_INDEX_TBL(klass);
+    uint32_t index_tbl_num_entries = index_tbl == NULL ? 0 : (uint32_t)index_tbl->num_entries;
+
+    size_t size;
+    bool embed = true;
+#if USE_RVARGC
+    size = rb_obj_embedded_size(index_tbl_num_entries);
+    if (!rb_gc_size_allocatable_p(size)) {
+        size = sizeof(struct RObject);
+        embed = false;
+    }
+#else
+    size = sizeof(struct RObject);
+    if (index_tbl_num_entries > ROBJECT_EMBED_LEN_MAX) {
+        embed = false;
+    }
+#endif
+
+#if USE_RVARGC
+    VALUE obj = newobj_of(klass, flags, 0, 0, 0, wb_protected, size);
+#else
+    VALUE obj = newobj_of(klass, flags, Qundef, Qundef, Qundef, wb_protected, size);
+#endif
 
-        VALUE obj = newobj_of(klass, (flags | ROBJECT_EMBED) & ~FL_WB_PROTECTED , Qundef, Qundef, Qundef, flags & FL_WB_PROTECTED, sizeof(RVALUE));
+    if (embed) {
+#if USE_RVARGC
+        uint32_t capa = (uint32_t)((rb_gc_obj_slot_size(obj) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
+        GC_ASSERT(capa >= index_tbl_num_entries);
 
-        if (index_tbl && index_tbl->num_entries > ROBJECT_EMBED_LEN_MAX) {
-            rb_init_iv_list(obj);
+        ROBJECT(obj)->numiv = capa;
+        for (size_t i = 0; i < capa; i++) {
+            ROBJECT(obj)->as.ary[i] = Qundef;
         }
-        return obj;
+#endif
+    }
+    else {
+        rb_init_iv_list(obj);
+    }
+
+    return obj;
+}
+
+VALUE
+rb_newobj_of(VALUE klass, VALUE flags)
+{
+    if ((flags & RUBY_T_MASK) == T_OBJECT) {
+        return rb_class_instance_allocate_internal(klass, (flags | ROBJECT_EMBED) & ~FL_WB_PROTECTED, flags & FL_WB_PROTECTED);
     }
     else {
         return newobj_of(klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED, sizeof(RVALUE));
@@ -2989,17 +3036,7 @@ rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, https://github.com/ruby/ruby/blob/trunk/gc.c#L3036
 VALUE
 rb_class_allocate_instance(VALUE klass)
 {
-    st_table *index_tbl = RCLASS_IV_INDEX_TBL(klass);
-
-    VALUE flags = T_OBJECT | ROBJECT_EMBED;
-
-    VALUE obj = newobj_of(klass, flags, Qundef, Qundef, Qundef, RGENGC_WB_PROTECTED_OBJECT, sizeof(RVALUE));
-
-    if (index_tbl && index_tbl->num_entries > ROBJECT_EMBED_LEN_MAX) {
-        rb_init_iv_list(obj);
-    }
-
-    return obj;
+    return rb_class_instance_allocate_internal(klass, T_OBJECT | ROBJECT_EMBED, RGENGC_WB_PROTECTED_OBJECT);
 }
 
 static inline void
@@ -8322,17 +8359,23 @@ gc_compact_destination_pool(rb_objspace_t *objspace, rb_size_pool_t *src_pool, V https://github.com/ruby/ruby/blob/trunk/gc.c#L8359
     size_t obj_size;
 
     switch (BUILTIN_TYPE(src)) {
-        case T_STRING:
-            obj_size = rb_str_size_as_embedded(src);
-            break;
         case T_ARRAY:
             obj_size = rb_ary_size_as_embedded(src);
             break;
+
+        case T_OBJECT:
+            obj_size = rb_obj_embedded_size(ROBJECT_NUMIV(src));
+            break;
+
+        case T_STRING:
+            obj_size = rb_str_size_as_embedded(src);
+            break;
+
         default:
             return src_pool;
     }
 
-    if (rb_gc_size_allocatable_p(obj_size)) {
+    if (rb_gc_size_allocatable_p(obj_size)){
         return &size_pools[size_pool_idx_for_size(obj_size)];
     }
     else {
@@ -9896,12 +9939,37 @@ gc_ref_update_array(rb_objspace_t * objspace, VALUE v) https://github.com/ruby/ruby/blob/trunk/gc.c#L9939
 }
 
 static void
-gc_ref_update_object(rb_objspace_t * objspace, VALUE v)
+gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
 {
     VALUE *ptr = ROBJECT_IVPTR(v);
+    uint32_t numiv = ROBJECT_NUMIV(v);
+
+#if USE_RVARGC
+    size_t slot_size = rb_gc_obj_slot_size(v);
+    size_t embed_size = rb_obj_embedded_size(numiv);
+    if (slot_size >= embed_size && !RB_FL_TEST_RAW(v, ROBJECT_EMBED)) {
+        // Object can be re-embedded
+        memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * numiv);
+        RB_FL_SET_RAW(v, ROBJECT_EMBED);
+        if (ROBJ_TRANSIENT_P(v)) {
+            ROBJ_TRANSIENT_UNSET(v);
+        }
+        else {
+            xfree(ptr);
+        }
+        ptr = ROBJECT(v)->as.ary;
+
+        uint32_t capa = (uint32_t)((slot_size - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
+        ROBJECT(v)->numiv = capa;
+
+        // Fill end with Qundef
+        for (uint32_t i = numiv; i < capa; i++) {
+            ptr[i] = Qundef;
+        }
+    }
+#endif
 
-    uint32_t i, len = ROBJECT_NUMIV(v);
-    for (i = 0; i < len; i++) {
+    for (uint32_t i = 0; i < numiv; i++) {
         UPDATE_IF_MOVED(objspace, ptr[i]);
     }
 }
diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h
index ed779f3558..e42a1777ff 100644
--- a/include/ruby/internal/abi.h
+++ b/include/ruby/internal/abi.h
@@ -22,7 +22,7 @@ https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/abi.h#L22
  * In released versions of Ruby, this number should not be changed since teeny
  * versions of Ruby should guarantee ABI compatibility.
  */
-#define RUBY_ABI_VERSION 1
+#define RUBY_ABI_VERSION 2
 
 /* Windows does not support weak symbols so ruby_abi_version will not exist
  * in the shared library. */
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index f2028063a6..7823061d8f 100644
--- a/include/ruby/internal/core/robject.h
+++ b/include/ruby/internal/core/robject.h
@@ -75,6 +75,7 @@ enum ruby_robject_flags { https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/robject.h#L75
     ROBJECT_EMBED = RUBY_FL_USER1
 };
 
+#if !USE_RVARGC
 /**
  * This is an enum because GDB wants it (rather than a macro).  People need not
  * bother.
@@ -83,6 +84,7 @@ enum ruby_robject_consts { https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/robject.h#L84
     /** Max possible number of instance variables that can be embedded. */
     ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
 };
+#endif
 
 struct st_table;
 
@@ -95,6 +97,14 @@ struct RObject { https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/robject.h#L97
     /** Basic part, including flags and class. */
     struct RBasic basic;
 
+#if USE_RVARGC
+    /**
+    * Number of instance variables.  This is per object; objects might
+    * differ in this field even if they have the identical classes.
+    */
+    uint32_t numiv;
+#endif
+
     /** Object's specific fields. */
     union {
 
@@ -103,12 +113,13 @@ struct RObject { https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/robject.h#L113
          * this pattern.
          */
         struct {
-
+#if !USE_RVARGC
             /**
              * Number of instance variables.  This is per object; objects might
              * differ in this field even if they have the identical classes.
              */
             uint32_t numiv;
+#endif
 
             /** Pointer to a C array that holds instance variables. */
             VALUE *ivptr;
@@ -124,14 +135,38 @@ struct RObject { https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/robject.h#L135
             struct st_table *iv_index_tbl;
         } heap;
 
-        /**
-         * Embedded instance  variables.  When  an object  is small  enough, it
+#if USE_RVARGC
+        /* Embedded instance variables. When an object is small enough, it
          * uses this area to store the instance variables.
+         *
+         * This is a length 1 array because:
+         *   1. GCC has a bug that does not optimize C flexible array memb (... truncated)

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

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