1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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>
This commit is contained in:
Peter Zhu 2022-07-19 11:15:05 -04:00
parent b25ee69e38
commit 5871ecf956
Notes: git 2022-07-21 02:14:17 +09:00
3 changed files with 37 additions and 14 deletions

46
array.c
View file

@ -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);

View file

@ -4369,7 +4369,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
/* The literal contains only optimizable elements, or the subarray is long enough */
VALUE ary = rb_ary_tmp_new(count);
VALUE ary = rb_ary_literal_new(count);
/* Create a hidden array */
for (; count; count--, node = node->nd_next)
@ -12349,7 +12349,7 @@ ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_heade
const long len = (long)ibf_load_small_value(load, &reading_pos);
VALUE ary = rb_ary_new_capa(len);
VALUE ary = header->internal ? rb_ary_literal_new(len) : rb_ary_new_capa(len);
int i;
for (i=0; i<len; i++) {

View file

@ -33,6 +33,7 @@ void rb_ary_cancel_sharing(VALUE ary);
size_t rb_ary_size_as_embedded(VALUE ary);
void rb_ary_make_embedded(VALUE ary);
bool rb_ary_embeddable_p(VALUE ary);
VALUE rb_ary_literal_new(long capa);
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
static inline bool ARY_PTR_USING_P(VALUE ary);