Ractor: revert to moving object bytes, but size pool aware
Using `rb_obj_clone` introduce other problems, such as `initialize_*` callbacks invocation in the context of the parent ractor. So we can revert back to copy the content of the object slots, but in a way that is aware of size pools.
This commit is contained in:
parent
eb765913c1
commit
085cc6e434
Notes:
git
2025-04-04 14:26:46 +00:00
@ -2101,3 +2101,24 @@ assert_equal 'ok', %q{
|
|||||||
:fail
|
:fail
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# move objects inside frozen containers
|
||||||
|
assert_equal 'ok', %q{
|
||||||
|
ractor = Ractor.new { Ractor.receive }
|
||||||
|
obj = Array.new(10, 42)
|
||||||
|
original = obj.dup
|
||||||
|
ractor.send([obj].freeze, move: true)
|
||||||
|
roundtripped_obj = ractor.take[0]
|
||||||
|
roundtripped_obj == original ? :ok : roundtripped_obj
|
||||||
|
}
|
||||||
|
|
||||||
|
# move object with generic ivar
|
||||||
|
assert_equal 'ok', %q{
|
||||||
|
ractor = Ractor.new { Ractor.receive }
|
||||||
|
obj = Array.new(10, 42)
|
||||||
|
obj.instance_variable_set(:@array, [1])
|
||||||
|
|
||||||
|
ractor.send(obj, move: true)
|
||||||
|
roundtripped_obj = ractor.take
|
||||||
|
roundtripped_obj.instance_variable_get(:@array) == [1] ? :ok : roundtripped_obj
|
||||||
|
}
|
||||||
|
8
gc.c
8
gc.c
@ -2658,14 +2658,6 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
|
|||||||
|
|
||||||
#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA(d)->type->function.dmark
|
#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA(d)->type->function.dmark
|
||||||
|
|
||||||
void
|
|
||||||
rb_gc_ractor_moved(VALUE dest, VALUE src)
|
|
||||||
{
|
|
||||||
rb_gc_obj_free(rb_gc_get_objspace(), src);
|
|
||||||
MEMZERO((void *)src, char, rb_gc_obj_slot_size(src));
|
|
||||||
RBASIC(src)->flags = T_OBJECT | FL_FREEZE; // Avoid mutations using bind_call, etc.
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_gc_mark_children(void *objspace, VALUE obj)
|
rb_gc_mark_children(void *objspace, VALUE obj)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +183,6 @@ struct rb_gc_object_metadata_entry {
|
|||||||
/* gc.c */
|
/* gc.c */
|
||||||
RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size);
|
RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size);
|
||||||
RUBY_ATTR_MALLOC void *ruby_mimcalloc(size_t num, size_t size);
|
RUBY_ATTR_MALLOC void *ruby_mimcalloc(size_t num, size_t size);
|
||||||
void rb_gc_ractor_moved(VALUE dest, VALUE src);
|
|
||||||
void ruby_mimfree(void *ptr);
|
void ruby_mimfree(void *ptr);
|
||||||
void rb_gc_prepare_heap(void);
|
void rb_gc_prepare_heap(void);
|
||||||
void rb_objspace_set_event_hook(const rb_event_flag_t event);
|
void rb_objspace_set_event_hook(const rb_event_flag_t event);
|
||||||
|
33
ractor.c
33
ractor.c
@ -3539,6 +3539,19 @@ rb_obj_traverse_replace(VALUE obj,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const bool wb_protected_types[RUBY_T_MASK] = {
|
||||||
|
[T_OBJECT] = RGENGC_WB_PROTECTED_OBJECT,
|
||||||
|
[T_HASH] = RGENGC_WB_PROTECTED_HASH,
|
||||||
|
[T_ARRAY] = RGENGC_WB_PROTECTED_ARRAY,
|
||||||
|
[T_STRING] = RGENGC_WB_PROTECTED_STRING,
|
||||||
|
[T_STRUCT] = RGENGC_WB_PROTECTED_STRUCT,
|
||||||
|
[T_COMPLEX] = RGENGC_WB_PROTECTED_COMPLEX,
|
||||||
|
[T_REGEXP] = RGENGC_WB_PROTECTED_REGEXP,
|
||||||
|
[T_MATCH] = RGENGC_WB_PROTECTED_MATCH,
|
||||||
|
[T_FLOAT] = RGENGC_WB_PROTECTED_FLOAT,
|
||||||
|
[T_RATIONAL] = RGENGC_WB_PROTECTED_RATIONAL,
|
||||||
|
};
|
||||||
|
|
||||||
static enum obj_traverse_iterator_result
|
static enum obj_traverse_iterator_result
|
||||||
move_enter(VALUE obj, struct obj_traverse_replace_data *data)
|
move_enter(VALUE obj, struct obj_traverse_replace_data *data)
|
||||||
{
|
{
|
||||||
@ -3547,7 +3560,10 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
|
|||||||
return traverse_skip;
|
return traverse_skip;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
data->replacement = rb_obj_clone(obj);
|
VALUE type = RB_BUILTIN_TYPE(obj);
|
||||||
|
type |= wb_protected_types[type] ? FL_WB_PROTECTED : 0;
|
||||||
|
NEWOBJ_OF(moved, struct RBasic, 0, type, rb_gc_obj_slot_size(obj), 0);
|
||||||
|
data->replacement = (VALUE)moved;
|
||||||
return traverse_cont;
|
return traverse_cont;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3555,7 +3571,20 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
|
|||||||
static enum obj_traverse_iterator_result
|
static enum obj_traverse_iterator_result
|
||||||
move_leave(VALUE obj, struct obj_traverse_replace_data *data)
|
move_leave(VALUE obj, struct obj_traverse_replace_data *data)
|
||||||
{
|
{
|
||||||
rb_gc_ractor_moved(data->replacement, obj);
|
size_t size = rb_gc_obj_slot_size(obj);
|
||||||
|
memcpy((void *)data->replacement, (void *)obj, size);
|
||||||
|
FL_UNSET_RAW(data->replacement, FL_SEEN_OBJ_ID);
|
||||||
|
|
||||||
|
void rb_replace_generic_ivar(VALUE clone, VALUE obj); // variable.c
|
||||||
|
|
||||||
|
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||||
|
rb_replace_generic_ivar(data->replacement, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid mutations using bind_call, etc.
|
||||||
|
// We keep FL_SEEN_OBJ_ID so GC later clean the obj_id_table.
|
||||||
|
MEMZERO((char *)obj + sizeof(struct RBasic), char, size - sizeof(struct RBasic));
|
||||||
|
RBASIC(obj)->flags = T_OBJECT | FL_FREEZE | (RBASIC(obj)->flags & FL_SEEN_OBJ_ID);
|
||||||
RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
|
RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
|
||||||
return traverse_cont;
|
return traverse_cont;
|
||||||
}
|
}
|
||||||
|
21
variable.c
21
variable.c
@ -2157,6 +2157,27 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_replace_generic_ivar(VALUE clone, VALUE obj)
|
||||||
|
{
|
||||||
|
RUBY_ASSERT(FL_TEST(obj, FL_EXIVAR));
|
||||||
|
|
||||||
|
RB_VM_LOCK_ENTER();
|
||||||
|
{
|
||||||
|
st_data_t ivtbl, obj_data = (st_data_t)obj;
|
||||||
|
if (st_delete(generic_iv_tbl_, &obj_data, &ivtbl)) {
|
||||||
|
FL_UNSET_RAW(obj, FL_EXIVAR);
|
||||||
|
|
||||||
|
st_insert(generic_iv_tbl_, (st_data_t)clone, ivtbl);
|
||||||
|
FL_SET_RAW(clone, FL_EXIVAR);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_bug("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RB_VM_LOCK_LEAVE();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user