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

ruby-changes:72724

From: Peter <ko1@a...>
Date: Thu, 28 Jul 2022 23:02:29 +0900 (JST)
Subject: [ruby-changes:72724] 1c16645216 (master): Make array slices views rather than copies

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

From 1c16645216b6db04ccb1144e6f7e085e1e0a6132 Mon Sep 17 00:00:00 2001
From: Peter Zhu <peter@p...>
Date: Wed, 27 Jul 2022 11:26:31 -0400
Subject: Make array slices views rather than copies

Before this commit, if the slice fits in VWA, it would make a copy
rather than a view. This is slower as it requires a memcpy of the
contents.
---
 array.c | 39 +++++++++++++++++++++++++++++----------
 gc.c    | 14 ++++++++++++++
 2 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/array.c b/array.c
index 8c7fa583e9..b2ebf3c0e9 100644
--- a/array.c
+++ b/array.c
@@ -1027,7 +1027,7 @@ rb_ary_memsize(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L1027
 static VALUE
 ary_make_shared(VALUE ary)
 {
-    assert(!ARY_EMBED_P(ary));
+    assert(USE_RVARGC || !ARY_EMBED_P(ary));
     ary_verify(ary);
 
     if (ARY_SHARED_P(ary)) {
@@ -1037,21 +1037,38 @@ ary_make_shared(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L1037
         return ary;
     }
     else if (OBJ_FROZEN(ary)) {
-        rb_ary_transient_heap_evacuate(ary, TRUE);
-        ary_shrink_capa(ary);
+        if (!ARY_EMBED_P(ary)) {
+            rb_ary_transient_heap_evacuate(ary, TRUE);
+            ary_shrink_capa(ary);
+        }
         return ary;
     }
     else {
-        long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary);
-        const VALUE *ptr;
+        rb_ary_transient_heap_evacuate(ary, TRUE);
+
+        long capa = ARY_CAPA(ary);
+        long len = RARRAY_LEN(ary);
+
+        /* Shared roots cannot be embedded because the reference count
+         * (refcnt) is stored in as.heap.aux.capa. */
         VALUE shared = ary_alloc_heap(0);
 
-        rb_ary_transient_heap_evacuate(ary, TRUE);
-        ptr = ARY_HEAP_PTR(ary);
+        if (ARY_EMBED_P(ary)) {
+            /* Cannot use ary_heap_alloc because we don't want to allocate
+             * on the transient heap. */
+            VALUE *ptr = ALLOC_N(VALUE, capa);
+            ARY_SET_PTR(shared, ptr);
+            ary_memcpy(shared, 0, len, RARRAY_PTR(ary));
+
+            FL_UNSET_EMBED(ary);
+            ARY_SET_HEAP_LEN(ary, len);
+            ARY_SET_PTR(ary, ptr);
+        }
+        else {
+            ARY_SET_PTR(shared, RARRAY_PTR(ary));
+        }
 
-        FL_UNSET_EMBED(shared);
         ARY_SET_LEN(shared, capa);
-        ARY_SET_PTR(shared, ptr);
         ary_mem_clear(shared, len, capa - len);
         FL_SET_SHARED_ROOT(shared);
         ARY_SET_SHARED_ROOT_REFCNT(shared, 1);
@@ -1318,7 +1335,9 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len) https://github.com/ruby/ruby/blob/trunk/array.c#L1335
     assert(len >= 0);
     assert(offset+len <= RARRAY_LEN(ary));
 
-    if (ary_embeddable_p(len)) {
+    const size_t rarray_embed_capa_max = (sizeof(struct RArray) - offsetof(struct RArray, as.ary)) / sizeof(VALUE);
+
+    if ((size_t)len <= rarray_embed_capa_max && ary_embeddable_p(len)) {
         VALUE result = ary_alloc_embed(klass, len);
         ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset);
         ARY_SET_EMBED_LEN(result, len);
diff --git a/gc.c b/gc.c
index 84f9aa30f6..cd48c47a94 100644
--- a/gc.c
+++ b/gc.c
@@ -9958,7 +9958,21 @@ static void https://github.com/ruby/ruby/blob/trunk/gc.c#L9958
 gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
 {
     if (ARY_SHARED_P(v)) {
+#if USE_RVARGC
+        VALUE old_root = RARRAY(v)->as.heap.aux.shared_root;
+#endif
+
         UPDATE_IF_MOVED(objspace, RARRAY(v)->as.heap.aux.shared_root);
+
+#if USE_RVARGC
+        VALUE new_root = RARRAY(v)->as.heap.aux.shared_root;
+        // If the root is embedded and its location has changed
+        if (ARY_EMBED_P(new_root) && new_root != old_root) {
+            size_t offset = (size_t)(RARRAY(v)->as.heap.ptr - RARRAY(old_root)->as.ary);
+            GC_ASSERT(RARRAY(v)->as.heap.ptr >= RARRAY(old_root)->as.ary);
+            RARRAY(v)->as.heap.ptr = RARRAY(new_root)->as.ary + offset;
+        }
+#endif
     }
     else {
         long len = RARRAY_LEN(v);
-- 
cgit v1.2.1


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

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