Fix Ractor sharing for too complex generic ivars
This commit is contained in:
parent
4938390177
commit
6eb5a9cf8f
50
ractor.c
50
ractor.c
@ -2739,6 +2739,19 @@ obj_traverse_rec(struct obj_traverse_data *data)
|
||||
return data->rec;
|
||||
}
|
||||
|
||||
static int
|
||||
obj_traverse_ivar_foreach_i(ID key, VALUE val, st_data_t ptr)
|
||||
{
|
||||
struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
|
||||
|
||||
if (obj_traverse_i(val, d->data)) {
|
||||
d->stop = true;
|
||||
return ST_STOP;
|
||||
}
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
|
||||
{
|
||||
@ -2755,14 +2768,12 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
VALUE val = ivtbl->as.shape.ivptr[i];
|
||||
if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
|
||||
}
|
||||
}
|
||||
struct obj_traverse_callback_data d = {
|
||||
.stop = false,
|
||||
.data = data,
|
||||
};
|
||||
rb_ivar_foreach(obj, obj_traverse_ivar_foreach_i, (st_data_t)&d);
|
||||
if (d.stop) return 1;
|
||||
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
// no child node
|
||||
@ -3229,9 +3240,26 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
|
||||
CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
|
||||
|
||||
if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
|
||||
struct obj_traverse_replace_callback_data d = {
|
||||
.stop = false,
|
||||
.data = data,
|
||||
.src = obj,
|
||||
};
|
||||
rb_st_foreach_with_replace(
|
||||
ivtbl->as.complex.table,
|
||||
obj_iv_hash_traverse_replace_foreach_i,
|
||||
obj_iv_hash_traverse_replace_i,
|
||||
(st_data_t)&d
|
||||
);
|
||||
if (d.stop) return 1;
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
|
||||
CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -621,6 +621,24 @@ class TestShapes < Test::Unit::TestCase
|
||||
end;
|
||||
end
|
||||
|
||||
def test_too_complex_generic_ivar_ractor_share
|
||||
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
$VERBOSE = nil
|
||||
|
||||
RubyVM::Shape.exhaust_shapes
|
||||
|
||||
r = Ractor.new do
|
||||
o = []
|
||||
o.instance_variable_set(:@a, "hello")
|
||||
Ractor.yield(o)
|
||||
end
|
||||
|
||||
o = r.take
|
||||
assert_equal "hello", o.instance_variable_get(:@a)
|
||||
end;
|
||||
end
|
||||
|
||||
def test_read_iv_after_complex
|
||||
ensure_complex
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user