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

ruby-changes:66032

From: Aaron <ko1@a...>
Date: Tue, 4 May 2021 06:12:05 +0900 (JST)
Subject: [ruby-changes:66032] 9a6226c61e (master): Eagerly allocate instance variable tables along with object

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

From 9a6226c61ea8a8ae7b3516b693a0d6e73526a99f Mon Sep 17 00:00:00 2001
From: Aaron Patterson <tenderlove@r...>
Date: Mon, 22 Feb 2021 16:18:10 -0800
Subject: Eagerly allocate instance variable tables along with object

This allows us to allocate the right size for the object in advance,
meaning that we don't have to pay the cost of ivar table extension
later.  The idea is that if an object type ever became "extended" at
some point, then it is very likely it will become extended again.  So we
may as well allocate the ivar table up front.
---
 benchmark/ivar_extend.yml | 23 +++++++++++++++++++++++
 gc.c                      | 20 ++++++++++++++++++--
 object.c                  | 35 ++++++++++++++++++++++-------------
 3 files changed, 63 insertions(+), 15 deletions(-)
 create mode 100644 benchmark/ivar_extend.yml

diff --git a/benchmark/ivar_extend.yml b/benchmark/ivar_extend.yml
new file mode 100644
index 0000000..eb9ee92
--- /dev/null
+++ b/benchmark/ivar_extend.yml
@@ -0,0 +1,23 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/ivar_extend.yml#L1
+prelude: |
+  class Embedded
+    def initialize
+      @a = 1
+      @b = 1
+      @c = 1
+    end
+  end
+
+  class Extended
+    def initialize
+      @a = 1
+      @b = 1
+      @c = 1
+      @d = 1
+      @e = 1
+      @f = 1
+    end
+  end
+benchmark:
+  embedded: Embedded.new
+  extended: Extended.new
+loop_count: 20_000_000
diff --git a/gc.c b/gc.c
index 4d78b85..1507be6 100644
--- a/gc.c
+++ b/gc.c
@@ -2390,7 +2390,14 @@ VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L2390
 rb_newobj_of(VALUE klass, VALUE flags)
 {
     if ((flags & RUBY_T_MASK) == T_OBJECT) {
-        return newobj_of(klass, (flags | ROBJECT_EMBED) & ~FL_WB_PROTECTED , Qundef, Qundef, Qundef, flags & FL_WB_PROTECTED);
+        st_table *index_tbl = RCLASS_IV_INDEX_TBL(klass);
+
+        VALUE obj = newobj_of(klass, (flags | ROBJECT_EMBED) & ~FL_WB_PROTECTED , Qundef, Qundef, Qundef, flags & FL_WB_PROTECTED);
+
+        if (index_tbl && index_tbl->num_entries > ROBJECT_EMBED_LEN_MAX) {
+            rb_init_iv_list(obj);
+        }
+        return obj;
     }
     else {
         return newobj_of(klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED);
@@ -2501,8 +2508,17 @@ 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#L2508
 VALUE
 rb_class_allocate_instance(VALUE klass)
 {
+    st_table *index_tbl = RCLASS_IV_INDEX_TBL(klass);
+
     VALUE flags = T_OBJECT | ROBJECT_EMBED;
-    return newobj_of(klass, flags, Qundef, Qundef, Qundef, RGENGC_WB_PROTECTED_OBJECT);
+
+    VALUE obj = newobj_of(klass, flags, Qundef, Qundef, Qundef, RGENGC_WB_PROTECTED_OBJECT);
+
+    if (index_tbl && index_tbl->num_entries > ROBJECT_EMBED_LEN_MAX) {
+        rb_init_iv_list(obj);
+    }
+
+    return obj;
 }
 
 VALUE
diff --git a/object.c b/object.c
index c1e75d3..d1e8ad7 100644
--- a/object.c
+++ b/object.c
@@ -324,24 +324,33 @@ rb_obj_singleton_class(VALUE obj) https://github.com/ruby/ruby/blob/trunk/object.c#L324
 MJIT_FUNC_EXPORTED void
 rb_obj_copy_ivar(VALUE dest, VALUE obj)
 {
-    RUBY_ASSERT(RBASIC(dest)->flags & ROBJECT_EMBED);
+    VALUE *dst_buf = 0;
+    VALUE *src_buf = 0;
+    uint32_t len = ROBJECT_EMBED_LEN_MAX;
 
     if (RBASIC(obj)->flags & ROBJECT_EMBED) {
-	MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX);
-	RBASIC(dest)->flags |= ROBJECT_EMBED;
+        src_buf = ROBJECT(obj)->as.ary;
+
+        // embedded -> embedded
+        if (RBASIC(dest)->flags & ROBJECT_EMBED) {
+            dst_buf = ROBJECT(dest)->as.ary;
+        }
+        // embedded -> extended
+        else {
+            dst_buf = ROBJECT(dest)->as.heap.ivptr;
+        }
     }
+    // extended -> extended
     else {
-	uint32_t len = ROBJECT(obj)->as.heap.numiv;
-	VALUE *ptr = 0;
-	if (len > 0) {
-	    ptr = ALLOC_N(VALUE, len);
-	    MEMCPY(ptr, ROBJECT(obj)->as.heap.ivptr, VALUE, len);
-	}
-	ROBJECT(dest)->as.heap.ivptr = ptr;
-	ROBJECT(dest)->as.heap.numiv = len;
-	ROBJECT(dest)->as.heap.iv_index_tbl = ROBJECT(obj)->as.heap.iv_index_tbl;
-	RBASIC(dest)->flags &= ~ROBJECT_EMBED;
+        uint32_t src_len = ROBJECT(obj)->as.heap.numiv;
+        uint32_t dst_len = ROBJECT(dest)->as.heap.numiv;
+
+        len = src_len < dst_len ? src_len : dst_len;
+        dst_buf = ROBJECT(dest)->as.heap.ivptr;
+        src_buf = ROBJECT(obj)->as.heap.ivptr;
     }
+
+    MEMCPY(dst_buf, src_buf, VALUE, len);
 }
 
 static void
-- 
cgit v1.1


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

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