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:
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
46
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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue