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

ruby-changes:53229

From: ko1 <ko1@a...>
Date: Wed, 31 Oct 2018 05:46:32 +0900 (JST)
Subject: [ruby-changes:53229] ko1:r65444 (trunk): introduce TransientHeap. [Bug #14858]

ko1	2018-10-31 05:46:24 +0900 (Wed, 31 Oct 2018)

  New Revision: 65444

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=65444

  Log:
    introduce TransientHeap. [Bug #14858]
    
    * transient_heap.c, transient_heap.h: implement TransientHeap (theap).
      theap is designed for Ruby's object system. theap is like Eden heap
      on generational GC terminology. theap allocation is very fast because
      it only needs to bump up pointer and deallocation is also fast because
      we don't do anything. However we need to evacuate (Copy GC terminology)
      if theap memory is long-lived. Evacuation logic is needed for each type.
    
      See [Bug #14858] for details.
    
    * array.c: Now, theap for T_ARRAY is supported.
    
      ary_heap_alloc() tries to allocate memory area from theap. If this trial
      sccesses, this array has theap ptr and RARRAY_TRANSIENT_FLAG is turned on.
      We don't need to free theap ptr.
    
    * ruby.h: RARRAY_CONST_PTR() returns malloc'ed memory area. It menas that
      if ary is allocated at theap, force evacuation to malloc'ed memory.
      It makes programs slow, but very compatible with current code because
      theap memory can be evacuated (theap memory will be recycled).
    
      If you want to get transient heap ptr, use RARRAY_CONST_PTR_TRANSIENT()
      instead of RARRAY_CONST_PTR(). If you can't understand when evacuation
      will occur, use RARRAY_CONST_PTR().

  Modified files:
    trunk/array.c
    trunk/common.mk
    trunk/compile.c
    trunk/debug_counter.h
    trunk/enum.c
    trunk/gc.c
    trunk/include/ruby/ruby.h
    trunk/inits.c
    trunk/insns.def
    trunk/internal.h
    trunk/string.c
    trunk/test/ruby/test_enum.rb
    trunk/vm_args.c
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
Index: internal.h
===================================================================
--- internal.h	(revision 65443)
+++ internal.h	(revision 65444)
@@ -1073,6 +1073,26 @@ VALUE rb_gvar_set(struct rb_global_entry https://github.com/ruby/ruby/blob/trunk/internal.h#L1073
 VALUE rb_gvar_defined(struct rb_global_entry *);
 
 /* array.c */
+
+#ifndef ARRAY_DEBUG
+#define ARRAY_DEBUG 0
+#endif
+
+#ifdef ARRAY_DEBUG
+#define RARRAY_PTR_IN_USE_FLAG FL_USER14
+#define ARY_PTR_USING_P(ary) FL_TEST_RAW((ary), RARRAY_PTR_IN_USE_FLAG)
+
+#else
+
+/* disable debug function */
+#undef  RARRAY_PTR_USE_START
+#undef  RARRAY_PTR_USE_END
+#define RARRAY_PTR_USE_START(a) ((VALUE *)RARRAY_CONST_PTR_TRANSIENT(a))
+#define RARRAY_PTR_USE_END(a)
+#define ARY_PTR_USING_P(ary) 0
+
+#endif
+
 VALUE rb_ary_last(int, const VALUE *, VALUE);
 void rb_ary_set_len(VALUE, long);
 void rb_ary_delete_same(VALUE, VALUE);
@@ -1100,7 +1120,7 @@ static inline VALUE https://github.com/ruby/ruby/blob/trunk/internal.h#L1120
 rb_ary_entry_internal(VALUE ary, long offset)
 {
     long len = RARRAY_LEN(ary);
-    const VALUE *ptr = RARRAY_CONST_PTR(ary);
+    const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
     if (len == 0) return Qnil;
     if (offset < 0) {
         offset += len;
@@ -1337,6 +1357,9 @@ RUBY_SYMBOL_EXPORT_END https://github.com/ruby/ruby/blob/trunk/internal.h#L1357
 			rb_wb_unprotected_newobj_of(klass, flags))
 #define NEWOBJ_OF(obj,type,klass,flags) RB_NEWOBJ_OF(obj,type,klass,flags)
 
+void *rb_aligned_malloc(size_t, size_t);
+void rb_aligned_free(void *);
+
 /* hash.c */
 struct st_table *rb_hash_tbl_raw(VALUE hash);
 VALUE rb_hash_new_with_size(st_index_t size);
Index: enum.c
===================================================================
--- enum.c	(revision 65443)
+++ enum.c	(revision 65444)
@@ -14,6 +14,7 @@ https://github.com/ruby/ruby/blob/trunk/enum.c#L14
 #include "ruby/util.h"
 #include "id.h"
 #include "symbol.h"
+#include "transient_heap.h"
 
 #include <assert.h>
 
@@ -1171,9 +1172,10 @@ enum_sort_by(VALUE obj) https://github.com/ruby/ruby/blob/trunk/enum.c#L1172
 	rb_ary_concat(ary, buf);
     }
     if (RARRAY_LEN(ary) > 2) {
-	RARRAY_PTR_USE(ary, ptr,
-		      ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
-				 sort_by_cmp, (void *)ary));
+        rb_ary_transient_heap_evacuate(ary, TRUE); /* should be malloc heap */
+        RARRAY_PTR_USE(ary, ptr,
+                       ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
+                                  sort_by_cmp, (void *)ary));
     }
     if (RBASIC(ary)->klass) {
 	rb_raise(rb_eRuntimeError, "sort_by reentered");
Index: insns.def
===================================================================
--- insns.def	(revision 65443)
+++ insns.def	(revision 65444)
@@ -524,7 +524,7 @@ newhashfromarray https://github.com/ruby/ruby/blob/trunk/insns.def#L524
 {
     VM_ASSERT(num * 2 == (rb_num_t)RARRAY_LEN(ary));
     hash = rb_hash_new_with_size(num);
-    rb_hash_bulk_insert(num * 2, RARRAY_CONST_PTR(ary), hash);
+    rb_hash_bulk_insert(num * 2, RARRAY_CONST_PTR_TRANSIENT(ary), hash);
 }
 
 /* put new Range object.(Range.new(low, high, flag)) */
Index: array.c
===================================================================
--- array.c	(revision 65443)
+++ array.c	(revision 65444)
@@ -14,12 +14,14 @@ https://github.com/ruby/ruby/blob/trunk/array.c#L14
 #include "ruby/encoding.h"
 #include "ruby/util.h"
 #include "ruby/st.h"
-#include "internal.h"
 #include "probes.h"
 #include "id.h"
 #include "debug_counter.h"
+#include "gc.h"
+#include "transient_heap.h"
+#include "internal.h"
 
-#ifndef ARRAY_DEBUG
+#if !ARRAY_DEBUG
 # define NDEBUG
 #endif
 #include "ruby_assert.h"
@@ -42,17 +44,21 @@ VALUE rb_cArray; https://github.com/ruby/ruby/blob/trunk/array.c#L44
 
 #define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
 #define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
+#define ARY_HEAP_CAPA(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.aux.capa)
+
 #define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
 #define ARY_EMBED_LEN(a) \
     (assert(ARY_EMBED_P(a)), \
      (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
 	 (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
-#define ARY_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), RARRAY(a)->as.heap.aux.capa * sizeof(VALUE))
+#define ARY_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), ARY_HEAP_CAPA(a) * sizeof(VALUE))
 
 #define ARY_OWNS_HEAP_P(a) (!FL_TEST((a), ELTS_SHARED|RARRAY_EMBED_FLAG))
 #define FL_SET_EMBED(a) do { \
     assert(!ARY_SHARED_P(a)); \
     FL_SET((a), RARRAY_EMBED_FLAG); \
+    FL_UNSET_RAW((a), RARRAY_TRANSIENT_FLAG); \
+    ary_verify(a); \
 } while (0)
 #define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
 #define FL_SET_SHARED(ary) do { \
@@ -102,7 +108,7 @@ VALUE rb_cArray; https://github.com/ruby/ruby/blob/trunk/array.c#L108
 } while (0)
 
 #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \
-		       ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : RARRAY(ary)->as.heap.aux.capa)
+		       ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary))
 #define ARY_SET_CAPA(ary, n) do { \
     assert(!ARY_EMBED_P(ary)); \
     assert(!ARY_SHARED_P(ary)); \
@@ -130,11 +136,82 @@ VALUE rb_cArray; https://github.com/ruby/ruby/blob/trunk/array.c#L136
 } while (0)
 #define FL_SET_SHARED_ROOT(ary) do { \
     assert(!ARY_EMBED_P(ary)); \
+    assert(!RARRAY_TRANSIENT_P(ary)); \
     FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
 } while (0)
 
 #define ARY_SET(a, i, v) RARRAY_ASET((assert(!ARY_SHARED_P(a)), (a)), (i), (v))
 
+
+#if ARRAY_DEBUG
+#define ary_verify(ary) ary_verify_(ary, __FILE__, __LINE__)
+
+static VALUE
+ary_verify_(VALUE ary, const char *file, int line)
+{
+    assert(RB_TYPE_P(ary, T_ARRAY));
+
+    if (FL_TEST(ary, ELTS_SHARED)) {
+        VALUE root = RARRAY(ary)->as.heap.aux.shared;
+        const VALUE *ptr = ARY_HEAP_PTR(ary);
+        const VALUE *root_ptr = RARRAY_CONST_PTR_TRANSIENT(root);
+        long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root);
+        assert(FL_TEST(root, RARRAY_SHARED_ROOT_FLAG));
+        assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
+        ary_verify(root);
+    }
+    else if (ARY_EMBED_P(ary)) {
+        assert(!RARRAY_TRANSIENT_P(ary));
+        assert(!ARY_SHARED_P(ary));
+        assert(RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX);
+    }
+    else {
+#if 1
+        const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
+        long i, len = RARRAY_LEN(ary);
+        volatile VALUE v;
+        if (len > 1) len = 1; /* check only HEAD */
+        for (i=0; i<len; i++) {
+            v = ptr[i]; /* access check */
+        }
+        v = v;
+#endif
+    }
+
+    if (RARRAY_TRANSIENT_P(ary)) {
+        assert(rb_transient_heap_managed_ptr_p(RARRAY_CONST_PTR_TRANSIENT(ary)));
+    }
+
+    rb_transient_heap_verify();
+
+    return ary;
+}
+
+void
+rb_ary_verify(VALUE ary){
+    ary_verify(ary);
+}
+#else
+#define ary_verify(ary) ((void)0)
+#endif
+
+VALUE *
+rb_ary_ptr_use_start(VALUE ary)
+{
+#if ARRAY_DEBUG
+    FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
+#endif
+    return (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary);
+}
+
+void
+rb_ary_ptr_use_end(VALUE ary)
+{
+#if ARRAY_DEBUG
+    FL_UNSET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
+#endif
+}
+
 void
 rb_mem_clear(register VALUE *mem, register long size)
 {
@@ -195,49 +272,167 @@ ary_memcpy(VALUE ary, long beg, long arg https://github.com/ruby/ruby/blob/trunk/array.c#L272
     ary_memcpy0(ary, beg, argc, argv, ary);
 }
 
+static VALUE *
+ary_heap_alloc(VALUE ary, size_t capa)
+{
+    VALUE *ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * capa);
+
+    if (ptr != NULL) {
+        FL_SET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+    }
+    else {
+        FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+        ptr = ALLOC_N(VALUE, capa);
+    }
+
+    return ptr;
+}
+
+static void
+ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
+{
+    if (RARRAY_TRANSIENT_P(ary)) {
+        /* ignore it */
+    }
+    else {
+        ruby_sized_xfree((void *)ptr, size);
+    }
+}
+
+static void
+ary_heap_free(VALUE ary)
+{
+    if (RARRAY_TRANSIENT_P(ary)) {
+        FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+    }
+    else {
+        ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
+    }
+}
+
+static void
+ary_heap_realloc(VALUE ary, size_t new_capa)
+{
+    size_t old_capa = ARY_HEAP_CAPA(ary);
+
+    if (RARRAY_TRANSIENT_P(ary)) {
+        if (new_capa <= old_capa) {
+            /* do nothing */
+        }
+        else {
+            VALUE *new_ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * new_capa);
+
+            if (new_ptr == NULL) {
+                new_ptr = ALLOC_N(VALUE, new_capa);
+                FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+            }
+
+            MEMCPY(new_ptr, ARY_HEAP_PTR(ary), VALUE, old_capa);
+            ARY_SET_PTR(ary, new_ptr);
+        }
+    }
+    else {
+        SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, old_capa);
+    }
+    ary_verify(ary);
+}
+
+static inline void
+rb_ary_transient_heap_evacuate_(VALUE ary, int transient, int promote)
+{
+    if (transient) {
+        VALUE *new_ptr;
+        const VALUE *old_ptr = ARY_HEAP_PTR(ary);
+        long capa = ARY_HEAP_CAPA(ary);
+        long len  = ARY_HEAP_LEN(ary);
+
+        if (ARY_SHARED_ROOT_P(ary)) {
+            capa = len;
+        }
+
+        assert(ARY_OWNS_HEAP_P(ary));
+        assert(RARRAY_TRANSIENT_P(ary));
+        assert(!ARY_PTR_USING_P(ary));
+
+        if (promote) {
+            new_ptr = ALLOC_N(VALUE, capa);
+            FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+        }
+        else {
+            new_ptr = ary_heap_alloc(ary, capa);
+        }
+
+        MEMCPY(new_ptr, old_ptr, VALUE, capa);
+        /* do not use ARY_SET_PTR() because they assert !frozen */
+        RARRAY(ary)->as.heap.ptr = new_ptr;
+    }
+
+    ary_verify(ary);
+}
+
+void
+rb_ary_transient_heap_evacuate(VALUE ary, int promote)
+{
+    rb_ary_transient_heap_evacuate_(ary, RARRAY_TRANSIENT_P(ary), promote);
+}
+
+void
+rb_ary_detransient(VALUE ary)
+{
+    assert(RARRAY_TRANSIENT_P(ary));
+    rb_ary_transient_heap_evacuate_(ary, TRUE, TRUE);
+}
+
 static void
 ary_resize_capa(VALUE ary, long capacity)
 {
     assert(RARRAY_LEN(ary) <= capacity);
     assert(!OBJ_FROZEN(ary));
     assert(!ARY_SHARED_P(ary));
+
     if (capacity > RARRAY_EMBED_LEN_MAX) {
         if (ARY_EMBED_P(ary)) {
             long len = ARY_EMBED_LEN(ary);
-            VALUE *ptr = ALLOC_N(VALUE, (capacity));
+            VALUE *ptr = ary_heap_alloc(ary, capacity);
+
             MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
             FL_UNSET_EMBED(ary);
             ARY_SET_PTR(ary, ptr);
             ARY_SET_HEAP_LEN(ary, len);
         }
         else {
-	    SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, capacity, RARRAY(ary)->as.heap.aux.capa);
+            ary_heap_realloc(ary, capacity);
         }
-        ARY_SET_CAPA(ary, (capacity));
+        ARY_SET_CAPA(ary, capacity);
     }
     else {
         if (!ARY_EMBED_P(ary)) {
-            long len = RARRAY_LEN(ary);
-	    const VALUE *ptr = RARRAY_CONST_PTR(ary);
+            long len = ARY_HEAP_LEN(ary);
+            long old_capa = ARY_HEAP_CAPA(ary);
+	    const VALUE *ptr = ARY_HEAP_PTR(ary);
 
-	    if (len > capacity) len = capacity;
+            if (len > capacity) len = capacity;
             MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len);
+            ary_heap_free_ptr(ary, ptr, old_capa);
+
             FL_SET_EMBED(ary);
             ARY_SET_LEN(ary, len);
-            ruby_sized_xfree((VALUE *)ptr, RARRAY(ary)->as.heap.aux.capa);
         }
     }
+
+    ary_verify(ary);
 }
 
 static inline void
 ary_shrink_capa(VALUE ary)
 {
     long capacity = ARY_HEAP_LEN(ary);
-    long old_capa = RARRAY(ary)->as.heap.aux.capa;
+    long old_capa = ARY_HEAP_CAPA(ary);
     assert(!ARY_SHARED_P(ary));
     assert(old_capa >= capacity);
-    if (old_capa > capacity)
-        SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, capacity, old_capa);
+    if (old_capa > capacity) ary_heap_realloc(ary, capacity);
+
+    ary_verify(ary);
 }
 
 static void
@@ -253,6 +448,8 @@ ary_double_capa(VALUE ary, long min) https://github.com/ruby/ruby/blob/trunk/array.c#L448
     }
     new_capa += min;
     ary_resize_capa(ary, new_capa);
+
+    ary_verify(ary);
 }
 
 static void
@@ -308,6 +505,7 @@ static inline void https://github.com/ruby/ruby/blob/trunk/array.c#L505
 rb_ary_modify_check(VALUE ary)
 {
     rb_check_frozen(ary);
+    ary_verify(ary);
 }
 
 void
@@ -317,6 +515,9 @@ rb_ary_modify(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L515
     if (ARY_SHARED_P(ary)) {
 	long shared_len, len = RARRAY_LEN(ary);
 	VALUE shared = ARY_SHARED(ary);
+
+        ary_verify(shared);
+
         if (len <= RARRAY_EMBED_LEN_MAX) {
 	    const VALUE *ptr = ARY_HEAP_PTR(ary);
             FL_UNSET_SHARED(ary);
@@ -326,9 +527,9 @@ rb_ary_modify(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L527
             ARY_SET_EMBED_LEN(ary, len);
         }
 	else if (ARY_SHARED_OCCUPIED(shared) && len > ((shared_len = RARRAY_LEN(shared))>>1)) {
-	    long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared);
+            long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared);
 	    FL_UNSET_SHARED(ary);
-	    ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared));
+	    ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared));
 	    ARY_SET_CAPA(ary, shared_len);
 	    RARRAY_PTR_USE(ary, ptr, {
 		MEMMOVE(ptr, ptr+shift, VALUE, len);
@@ -337,8 +538,8 @@ rb_ary_modify(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L538
 	    rb_ary_decrement_share(shared);
 	}
         else {
-            VALUE *ptr = ALLOC_N(VALUE, len);
-            MEMCPY(ptr, RARRAY_CONST_PTR(ary), VALUE, len);
+            VALUE *ptr = ary_heap_alloc(ary, len);
+            MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
             rb_ary_unshare(ary);
             ARY_SET_CAPA(ary, len);
             ARY_SET_PTR(ary, ptr);
@@ -346,6 +547,7 @@ rb_ary_modify(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L547
 
 	rb_gc_writebarrier_remember(ary);
     }
+    ary_verify(ary);
 }
 
 static VALUE
@@ -362,9 +564,12 @@ ary_ensure_room_for_push(VALUE ary, long https://github.com/ruby/ruby/blob/trunk/array.c#L564
 	if (new_len > RARRAY_EMBED_LEN_MAX) {
 	    VALUE shared = ARY_SHARED(ary);
 	    if (ARY_SHARED_OCCUPIED(shared)) {
-		if (RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared) + new_len <= RARRAY_LEN(shared)) {
+		if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR_TRANSIENT(shared) + new_len <= RARRAY_LEN(shared)) {
 		    rb_ary_modify_check(ary);
-		    return shared;
+
+                    ary_verify(ary);
+                    ary_verify(shared);
+                    return shared;
 		}
 		else {
 		    /* if array is shared, then it is likely it participate in push/shift pattern */
@@ -373,11 +578,13 @@ ary_ensure_room_for_push(VALUE ary, long https://github.com/ruby/ruby/blob/trunk/array.c#L578
 		    if (new_len > capa - (capa >> 6)) {
 			ary_double_capa(ary, new_len);
 		    }
+                    ary_verify(ary);
 		    return ary;
 		}
 	    }
 	}
-	rb_ary_modify(ary);
+        ary_verify(ary);
+        rb_ary_modify(ary);
     }
     else {
 	rb_ary_modify_check(ary);
@@ -387,6 +594,7 @@ ary_ensure_room_for_push(VALUE ary, long https://github.com/ruby/ruby/blob/trunk/array.c#L594
 	ary_double_capa(ary, new_len);
     }
 
+    ary_verify(ary);
     return ary;
 }
 
@@ -459,7 +667,7 @@ ary_new(VALUE klass, long capa) https://github.com/ruby/ruby/blob/trunk/array.c#L667
 
     ary = ary_alloc(klass);
     if (capa > RARRAY_EMBED_LEN_MAX) {
-	ptr = ALLOC_N(VALUE, capa);
+        ptr = ary_heap_alloc(ary, capa);
         FL_UNSET_EMBED(ary);
         ARY_SET_PTR(ary, ptr);
         ARY_SET_CAPA(ary, capa);
@@ -523,7 +731,9 @@ rb_ary_new_from_values(long n, const VAL https://github.com/ruby/ruby/blob/trunk/array.c#L731
 VALUE
 rb_ary_tmp_new(long capa)
 {
-    return ary_new(0, capa);
+    VALUE ary = ary_new(0, capa);
+    rb_ary_transient_heap_evacuate(ary, TRUE);
+    return ary;
 }
 
 VALUE
@@ -532,6 +742,7 @@ rb_ary_tmp_new_fill(long capa) https://github.com/ruby/ruby/blob/trunk/array.c#L742
     VALUE ary = ary_new(0, capa);
     ary_memfill(ary, 0, capa, Qnil);
     ARY_SET_LEN(ary, capa);
+    rb_ary_transient_heap_evacuate(ary, TRUE);
     return ary;
 }
 
@@ -539,8 +750,13 @@ void https://github.com/ruby/ruby/blob/trunk/array.c#L750
 rb_ary_free(VALUE ary)
 {
     if (ARY_OWNS_HEAP_P(ary)) {
-	RB_DEBUG_COUNTER_INC(obj_ary_ptr);
-	ruby_sized_xfree((void *)ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
+        if (RARRAY_TRANSIENT_P(ary)) {
+            RB_DEBUG_COUNTER_INC(obj_ary_transient);
+        }
+        else {
+            RB_DEBUG_COUNTER_INC(obj_ary_ptr);
+            ary_heap_free(ary);
+        }
     }
     else {
 	RB_DEBUG_COUNTER_INC(obj_ary_embed);
@@ -563,13 +779,15 @@ ary_discard(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L779
 {
     rb_ary_free(ary);
     RBASIC(ary)->flags |= RARRAY_EMBED_FLAG;
-    RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK;
+    RBASIC(ary)->flags &= ~(RARRAY_EMBED_LEN_MASK | RARRAY_TRANSIENT_FLAG);
 }
 
 static VALUE
 ary_make_shared(VALUE ary)
 {
     assert(!ARY_EMBED_P(ary));
+    ary_verify(ary);
+
     if (ARY_SHARED_P(ary)) {
 	return ARY_SHARED(ary);
     }
@@ -577,6 +795,7 @@ ary_make_shared(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L795
 	return ary;
     }
     else if (OBJ_FROZEN(ary)) {
+        rb_ary_transient_heap_evacuate(ary, TRUE);
 	ary_shrink_capa(ary);
 	FL_SET_SHARED_ROOT(ary);
 	ARY_SET_SHARED_NUM(ary, 1);
@@ -584,18 +803,25 @@ ary_make_shared(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L803
     }
     else {
 	long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary);
+        const VALUE *ptr;
 	NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0));
-        FL_UNSET_EMBED(shared);
 
+        rb_ary_transient_heap_evacuate(ary, TRUE);
+        ptr = ARY_HEAP_PTR(ary);
+
+        FL_UNSET_EMBED(shared);
 	ARY_SET_LEN((VALUE)shared, capa);
-	ARY_SET_PTR((VALUE)shared, RARRAY_CONST_PTR(ary));
-	ary_mem_clear((VALUE)shared, len, capa - len);
+	ARY_SET_PTR((VALUE)shared, ptr);
+        ary_mem_clear((VALUE)shared, len, capa - len);
 	FL_SET_SHARED_ROOT(shared);
 	ARY_SET_SHARED_NUM((VALUE)shared, 1);
 	FL_SET_SHARED(ary);
 	ARY_SET_SHARED(ary, (VALUE)shared);
 	OBJ_FREEZE(shared);
-	return (VALUE)shared;
+
+        ary_verify((VALUE)shared);
+        ary_verify(ary);
+        return (VALUE)shared;
     }
 }
 
@@ -606,7 +832,7 @@ ary_make_substitution(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L832
 
     if (len <= RARRAY_EMBED_LEN_MAX) {
 	VALUE subst = rb_ary_new2(len);
-	ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary));
+	ary_memcpy(subst, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
         ARY_SET_EMBED_LEN(subst, len);
         return subst;
     }
@@ -729,8 +955,8 @@ rb_ary_initialize(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/array.c#L955
 
     rb_ary_modify(ary);
     if (argc == 0) {
-	if (ARY_OWNS_HEAP_P(ary) && RARRAY_CONST_PTR(ary) != 0) {
-	    ruby_sized_xfree((void *)RARRAY_CONST_PTR(ary), ARY_HEAP_SIZE(ary));
+        if (ARY_OWNS_HEAP_P(ary) && ARY_HEAP_PTR(ary) != NULL) {
+            ary_heap_free(ary);
 	}
         rb_ary_unshare_safe(ary);
         FL_SET_EMBED(ary);
@@ -837,7 +1063,7 @@ ary_make_partial(VALUE ary, VALUE klass, https://github.com/ruby/ruby/blob/trunk/array.c#L1063
 
     if (len <= RARRAY_EMBED_LEN_MAX) {
         VALUE result = ary_alloc(klass);
-	ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset);
+	ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(a (... truncated)

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

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