mirror of
https://github.com/ruby/ruby.git
synced 2025-08-16 05:59:00 +02:00
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.
This commit is contained in:
parent
2375afb8d6
commit
1c16645216
Notes:
git
2022-07-28 23:02:33 +09:00
2 changed files with 43 additions and 10 deletions
39
array.c
39
array.c
|
@ -1027,7 +1027,7 @@ rb_ary_memsize(VALUE ary)
|
||||||
static VALUE
|
static VALUE
|
||||||
ary_make_shared(VALUE ary)
|
ary_make_shared(VALUE ary)
|
||||||
{
|
{
|
||||||
assert(!ARY_EMBED_P(ary));
|
assert(USE_RVARGC || !ARY_EMBED_P(ary));
|
||||||
ary_verify(ary);
|
ary_verify(ary);
|
||||||
|
|
||||||
if (ARY_SHARED_P(ary)) {
|
if (ARY_SHARED_P(ary)) {
|
||||||
|
@ -1037,21 +1037,38 @@ ary_make_shared(VALUE ary)
|
||||||
return ary;
|
return ary;
|
||||||
}
|
}
|
||||||
else if (OBJ_FROZEN(ary)) {
|
else if (OBJ_FROZEN(ary)) {
|
||||||
rb_ary_transient_heap_evacuate(ary, TRUE);
|
if (!ARY_EMBED_P(ary)) {
|
||||||
ary_shrink_capa(ary);
|
rb_ary_transient_heap_evacuate(ary, TRUE);
|
||||||
|
ary_shrink_capa(ary);
|
||||||
|
}
|
||||||
return ary;
|
return ary;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary);
|
rb_ary_transient_heap_evacuate(ary, TRUE);
|
||||||
const VALUE *ptr;
|
|
||||||
|
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);
|
VALUE shared = ary_alloc_heap(0);
|
||||||
|
|
||||||
rb_ary_transient_heap_evacuate(ary, TRUE);
|
if (ARY_EMBED_P(ary)) {
|
||||||
ptr = ARY_HEAP_PTR(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_LEN(shared, capa);
|
||||||
ARY_SET_PTR(shared, ptr);
|
|
||||||
ary_mem_clear(shared, len, capa - len);
|
ary_mem_clear(shared, len, capa - len);
|
||||||
FL_SET_SHARED_ROOT(shared);
|
FL_SET_SHARED_ROOT(shared);
|
||||||
ARY_SET_SHARED_ROOT_REFCNT(shared, 1);
|
ARY_SET_SHARED_ROOT_REFCNT(shared, 1);
|
||||||
|
@ -1318,7 +1335,9 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
assert(offset+len <= RARRAY_LEN(ary));
|
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);
|
VALUE result = ary_alloc_embed(klass, len);
|
||||||
ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset);
|
ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset);
|
||||||
ARY_SET_EMBED_LEN(result, len);
|
ARY_SET_EMBED_LEN(result, len);
|
||||||
|
|
14
gc.c
14
gc.c
|
@ -9958,7 +9958,21 @@ static void
|
||||||
gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
|
gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
|
||||||
{
|
{
|
||||||
if (ARY_SHARED_P(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);
|
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 {
|
else {
|
||||||
long len = RARRAY_LEN(v);
|
long len = RARRAY_LEN(v);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue