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

ruby-changes:53234

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

ko1	2018-10-31 06:53:56 +0900 (Wed, 31 Oct 2018)

  New Revision: 65449

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

  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().
    
    (re-commit of r65444)

  Added files:
    trunk/transient_heap.c
    trunk/transient_heap.h
  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: array.c
===================================================================
--- array.c	(revision 65448)
+++ array.c	(revision 65449)
@@ -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;
             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,8 +564,11 @@ 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);
+
+                    ary_verify(ary);
+                    ary_verify(shared);
                     return shared;
 		}
 		else {
@@ -373,10 +578,12 @@ 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;
 		}
 	    }
 	}
+        ary_verify(ary);
         rb_ary_modify(ary);
     }
     else {
@@ -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,17 +803,24 @@ 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_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);
+
+        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(ary) + offset);
         ARY_SET_EMBED_LEN(result, len);
         return result;
     }
@@ -846,12 +1072,15 @@ ary_make_partial(VALUE ary, VALUE klass, https://github.com/ruby/ruby/blob/trunk/array.c#L1072
         FL_UNSET_EMBED(result);
 
         shared = ary_make_shared(ary);
-        ARY_SET_PTR(result, RARRAY_CONST_PTR(ary));
+        ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary));
         ARY_SET_LEN(result, RARRAY_LEN(ary));
         rb_ary_set_shared(result, shared);
 
         ARY_INCREASE_PTR(result, offset);
         ARY_SET_LEN(result, len);
+
+        ary_verify(shared);
+        ary_verify(result);
         return result;
     }
 }
@@ -910,12 +1139,13 @@ ary_take_first_or_last(int argc, const V https://github.com/ruby/ruby/blob/trunk/array.c#L1139
 VALUE
 rb_ary_push(VALUE ary, VALUE item)
 {
-    long idx = RARRAY_LEN(ary);
+    long idx = RARRAY_LEN((ary_verify(ary), ary));
     VALUE target_ary = ary_ensure_room_for_push(ary, 1);
     RARRAY_PTR_USE(ary, ptr, {
 	RB_OBJ_WRITE(target_ary, &ptr[idx], item);
     });
     ARY_SET_LEN(ary, idx + 1);
+    ary_verify(ary);
     return ary;
 }
 
@@ -967,6 +1197,7 @@ rb_ary_pop(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L1197
     }
     --n;
     ARY_SET_LEN(ary, n);
+    ary_verify(ary);
     return RARRAY_AREF(ary, n);
 }
 
@@ -1000,6 +1231,7 @@ rb_ary_pop_m(int argc, VALUE *argv, VALU https://github.com/ruby/ruby/blob/trunk/array.c#L1231
     rb_ary_modify_check(ary);
     result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
     ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
+    ary_verify(ary);
     return result;
 }
 
@@ -1018,6 +1250,7 @@ rb_ary_shift(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L1250
 		MEMMOVE(ptr, ptr+1, VALUE, len-1);
 	    }); /* WB: no new reference */
             ARY_INCREASE_LEN(ary, -1);
+            ary_verify(ary);
 	    return top;
 	}
         assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */
@@ -1031,6 +1264,8 @@ rb_ary_shift(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L1264
     ARY_INCREASE_PTR(ary, 1);		/* shift ptr */
     ARY_INCREASE_LEN(ary, -1);
 
+    ary_verify(ary);
+
     return top;
 }
 
@@ -1101,6 +1336,7 @@ rb_ary_behead(VALUE ary, long n) https://github.com/ruby/ruby/blob/trunk/array.c#L1336
     }
     ARY_INCREASE_LEN(ary, -n);
 
+    ary_verify(ary);
     return ary;
 }
 
@@ -1120,8 +1356,8 @@ ary_ensure_room_for_unshift(VALUE ary, i https://github.com/ruby/ruby/blob/trunk/array.c#L1356
 	VALUE shared = ARY_SHARED(ary);
 	capa = RARRAY_LEN(shared);
 	if (ARY_SHARED_OCCUPIED(shared) && capa > new_len) {
-            head = RARRAY_CONST_PTR(ary);
-            sharedp = RARRAY_CONST_PTR(shared);
+	    head = RARRAY_CONST_PTR_TRANSIENT(ary);
+	    sharedp = RARRAY_CONST_PTR_TRANSIENT(shared);
 	    goto makeroom_if_need;
 	}
     }
@@ -1134,11 +1370,13 @@ ary_ensure_room_for_unshift(VALUE ary, i https://github.com/ruby/ruby/blob/trunk/array.c#L1370
 
     /* use shared array for big "queues" */
     if (new_len > ARY_DEFAULT_SIZE * 4) {
+        ary_verify(ary);
+
         /* make a room for unshifted items */
 	capa = ARY_CAPA(ary);
 	ary_make_shared(ary);
 
-        head = sharedp = RARRAY_CONST_PTR(ary);
+	head = sharedp = RARRAY_CONST_PTR_TRANSIENT(ary);
 	goto makeroom; (... truncated)

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

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