summaryrefslogtreecommitdiff
path: root/array.c
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2022-07-19 11:15:05 -0400
committerPeter Zhu <peter@peterzhu.ca>2022-07-20 13:13:56 -0400
commit5871ecf956711fcacad7c03f2aef95115ed25bc4 (patch)
treeef8db409dd1acd1d2184279d8a8d3893f6b965f6 /array.c
parentb25ee69e3873162689c46bc3ffdd1686151184b2 (diff)
Add RARRAY_LITERAL_FLAG for array literals
Array created as literals during iseq compilation don't need a reference count since they can never be modified. The previous implementation would mutate the hidden array's reference count, causing copy-on-write invalidation. This commit adds a RARRAY_LITERAL_FLAG for arrays created through rb_ary_literal_new. Arrays created with this flag do not have reference count stored and just assume they have infinite number of references. Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6151
Diffstat (limited to 'array.c')
-rw-r--r--array.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/array.c b/array.c
index 7f8c25ac08..deea0834d7 100644
--- a/array.c
+++ b/array.c
@@ -153,15 +153,17 @@ should_not_be_shared_and_embedded(VALUE ary)
const VALUE _value_ = (value); \
assert(!ARY_EMBED_P(_ary_)); \
assert(ARY_SHARED_P(_ary_)); \
- assert(ARY_SHARED_ROOT_P(_value_)); \
+ assert(!ARY_LITERAL_P(_ary_)); \
+ assert(ARY_SHARED_ROOT_P(_value_) || ARY_LITERAL_P(_value_)); \
RB_OBJ_WRITE(_ary_, &RARRAY(_ary_)->as.heap.aux.shared_root, _value_); \
} while (0)
+
#define RARRAY_SHARED_ROOT_FLAG FL_USER12
#define ARY_SHARED_ROOT_P(ary) (assert(should_be_T_ARRAY((VALUE)(ary))), \
FL_TEST_RAW((ary), RARRAY_SHARED_ROOT_FLAG))
#define ARY_SHARED_ROOT_REFCNT(ary) \
(assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa)
-#define ARY_SHARED_ROOT_OCCUPIED(ary) (ARY_SHARED_ROOT_REFCNT(ary) == 1)
+#define ARY_SHARED_ROOT_OCCUPIED(ary) (!ARY_LITERAL_P(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1)
#define ARY_SET_SHARED_ROOT_REFCNT(ary, value) do { \
assert(ARY_SHARED_ROOT_P(ary)); \
assert((value) >= 0); \
@@ -173,6 +175,11 @@ should_not_be_shared_and_embedded(VALUE ary)
FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
} while (0)
+#define RARRAY_LITERAL_FLAG FL_USER15
+#define ARY_LITERAL_P(ary) \
+ (assert(should_be_T_ARRAY((VALUE)(ary))), \
+ FL_TEST_RAW((ary), RARRAY_LITERAL_FLAG))
+
static inline void
ARY_SET(VALUE a, long i, VALUE v)
{
@@ -249,7 +256,7 @@ ary_verify_(VALUE ary, const char *file, int line)
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(ARY_SHARED_ROOT_P(root) || ARY_LITERAL_P(root));
assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
ary_verify(root);
}
@@ -581,8 +588,10 @@ ary_double_capa(VALUE ary, long min)
static void
rb_ary_decrement_share(VALUE shared_root)
{
- long num = ARY_SHARED_ROOT_REFCNT(shared_root);
- ARY_SET_SHARED_ROOT_REFCNT(shared_root, num - 1);
+ if (!ARY_LITERAL_P(shared_root)) {
+ long num = ARY_SHARED_ROOT_REFCNT(shared_root);
+ ARY_SET_SHARED_ROOT_REFCNT(shared_root, num - 1);
+ }
}
static void
@@ -610,9 +619,11 @@ rb_ary_reset(VALUE ary)
static VALUE
rb_ary_increment_share(VALUE shared_root)
{
- long num = ARY_SHARED_ROOT_REFCNT(shared_root);
- assert(num >= 0);
- ARY_SET_SHARED_ROOT_REFCNT(shared_root, num + 1);
+ if (!ARY_LITERAL_P(shared_root)) {
+ long num = ARY_SHARED_ROOT_REFCNT(shared_root);
+ assert(num >= 0);
+ ARY_SET_SHARED_ROOT_REFCNT(shared_root, num + 1);
+ }
return shared_root;
}
@@ -971,6 +982,15 @@ rb_ary_tmp_new_fill(long capa)
return ary;
}
+VALUE
+rb_ary_literal_new(long capa)
+{
+ VALUE ary = ary_new(0, capa);
+ rb_ary_transient_heap_evacuate(ary, TRUE);
+ FL_SET(ary, RARRAY_LITERAL_FLAG);
+ return ary;
+}
+
void
rb_ary_free(VALUE ary)
{
@@ -1024,6 +1044,7 @@ static VALUE
ary_make_shared(VALUE ary)
{
assert(!ARY_EMBED_P(ary));
+ assert(!ARY_LITERAL_P(ary));
ary_verify(ary);
if (ARY_SHARED_P(ary)) {
@@ -1034,8 +1055,8 @@ ary_make_shared(VALUE ary)
}
else if (OBJ_FROZEN(ary)) {
rb_ary_transient_heap_evacuate(ary, TRUE);
- ary_shrink_capa(ary);
- FL_SET_SHARED_ROOT(ary);
+ ary_shrink_capa(ary);
+ FL_SET_SHARED_ROOT(ary);
ARY_SET_SHARED_ROOT_REFCNT(ary, 1);
return ary;
}
@@ -1324,10 +1345,11 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
return result;
}
else {
- VALUE shared, result = ary_alloc_heap(klass);
+ VALUE result = ary_alloc_heap(klass);
assert(!ARY_EMBED_P(result));
- shared = ary_make_shared(ary);
+ VALUE shared = ARY_LITERAL_P(ary) ? ary : ary_make_shared(ary);
+
ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(result, RARRAY_LEN(ary));
rb_ary_set_shared(result, shared);