summaryrefslogtreecommitdiff
path: root/array.c
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2022-07-27 11:26:31 -0400
committerPeter Zhu <peter@peterzhu.ca>2022-07-28 10:02:12 -0400
commit1c16645216b6db04ccb1144e6f7e085e1e0a6132 (patch)
tree79f835bb18ecbabf593bbbc52eee85efd8e7c86c /array.c
parent2375afb8d6fd218cd9083749d87a7a59946d8938 (diff)
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.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6192
Diffstat (limited to 'array.c')
-rw-r--r--array.c39
1 files changed, 29 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)
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)
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)
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);