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/