Move responsibility of heap walking into Ruby

This commit removes the need for the GC implementation to implement heap
walking and instead Ruby will implement it.
This commit is contained in:
Peter Zhu 2024-08-30 13:05:24 -04:00
parent a2243ee48b
commit 3c63a01295
Notes: git 2024-09-03 14:05:57 +00:00
6 changed files with 160 additions and 172 deletions

274
gc.c
View File

@ -187,7 +187,7 @@ rb_gc_event_hook(VALUE obj, rb_event_flag_t event)
void * void *
rb_gc_get_objspace(void) rb_gc_get_objspace(void)
{ {
return GET_VM()->objspace; return GET_VM()->gc.objspace;
} }
void void
@ -337,7 +337,7 @@ void rb_vm_update_references(void *ptr);
#define unless_objspace(objspace) \ #define unless_objspace(objspace) \
void *objspace; \ void *objspace; \
rb_vm_t *unless_objspace_vm = GET_VM(); \ rb_vm_t *unless_objspace_vm = GET_VM(); \
if (unless_objspace_vm) objspace = unless_objspace_vm->objspace; \ if (unless_objspace_vm) objspace = unless_objspace_vm->gc.objspace; \
else /* return; or objspace will be warned uninitialized */ else /* return; or objspace will be warned uninitialized */
#define RMOVED(obj) ((struct RMoved *)(obj)) #define RMOVED(obj) ((struct RMoved *)(obj))
@ -865,7 +865,7 @@ rb_objspace_alloc(void)
#endif #endif
void *objspace = rb_gc_impl_objspace_alloc(); void *objspace = rb_gc_impl_objspace_alloc();
ruby_current_vm_ptr->objspace = objspace; ruby_current_vm_ptr->gc.objspace = objspace;
rb_gc_impl_objspace_init(objspace); rb_gc_impl_objspace_init(objspace);
@ -2036,54 +2036,62 @@ ruby_stack_check(void)
/* ==================== Marking ==================== */ /* ==================== Marking ==================== */
static inline void #define RB_GC_MARK_OR_TRAVERSE(func, obj_or_ptr, obj, check_obj) do { \
gc_mark_internal(void *objspace, VALUE obj) if (!RB_SPECIAL_CONST_P(obj)) { \
{ rb_vm_t *vm = GET_VM(); \
if (RB_SPECIAL_CONST_P(obj)) return; if (LIKELY(vm->gc.mark_func_data == NULL)) { \
(func)(vm->gc.objspace, (obj_or_ptr)); \
} \
else if (check_obj ? rb_gc_impl_pointer_to_heap_p(vm->gc.objspace, (const void *)obj) : true) { \
GC_ASSERT(!rb_gc_impl_during_gc_p(vm->gc.objspace)); \
struct gc_mark_func_data_struct *mark_func_data = vm->gc.mark_func_data; \
vm->gc.mark_func_data = NULL; \
mark_func_data->mark_func((obj), mark_func_data->data); \
vm->gc.mark_func_data = mark_func_data; \
} \
} \
} while (0)
rb_gc_impl_mark(objspace, obj); static inline void
gc_mark_internal(VALUE obj)
{
RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark, obj, obj, false);
} }
void void
rb_gc_mark_movable(VALUE obj) rb_gc_mark_movable(VALUE obj)
{ {
gc_mark_internal(rb_gc_get_objspace(), obj); gc_mark_internal(obj);
} }
void void
rb_gc_mark_and_move(VALUE *ptr) rb_gc_mark_and_move(VALUE *ptr)
{ {
if (SPECIAL_CONST_P(*ptr)) return; RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_and_move, ptr, *ptr, false);
rb_gc_impl_mark_and_move(rb_gc_get_objspace(), ptr);
} }
static inline void static inline void
gc_mark_and_pin_internal(void *objspace, VALUE obj) gc_mark_and_pin_internal(VALUE obj)
{ {
if (RB_SPECIAL_CONST_P(obj)) return; RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_and_pin, obj, obj, false);
rb_gc_impl_mark_and_pin(objspace, obj);
} }
void void
rb_gc_mark(VALUE obj) rb_gc_mark(VALUE obj)
{ {
gc_mark_and_pin_internal(rb_gc_get_objspace(), obj); gc_mark_and_pin_internal(obj);
} }
static inline void static inline void
gc_mark_maybe_internal(void *objspace, VALUE obj) gc_mark_maybe_internal(VALUE obj)
{ {
if (RB_SPECIAL_CONST_P(obj)) return; RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_maybe, obj, obj, true);
rb_gc_impl_mark_maybe(objspace, obj);
} }
void void
rb_gc_mark_maybe(VALUE obj) rb_gc_mark_maybe(VALUE obj)
{ {
gc_mark_maybe_internal(rb_gc_get_objspace(), obj); gc_mark_maybe_internal(obj);
} }
void void
@ -2098,36 +2106,42 @@ rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr)
rb_gc_impl_remove_weak(rb_gc_get_objspace(), parent_obj, ptr); rb_gc_impl_remove_weak(rb_gc_get_objspace(), parent_obj, ptr);
} }
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void each_location(register const VALUE *x, register long n, void (*cb)(void *data, VALUE), void *data)); ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data));
static void static void
each_location(register const VALUE *x, register long n, void (*cb)(void *data, VALUE obj), void *data) each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data)
{ {
VALUE v; VALUE v;
while (n--) { while (n--) {
v = *x; v = *x;
cb(data, v); cb(v, data);
x++; x++;
} }
} }
static void static void
each_location_ptr(const VALUE *start, const VALUE *end, void (*cb)(void *, VALUE), void *data) each_location_ptr(const VALUE *start, const VALUE *end, void (*cb)(VALUE, void *), void *data)
{ {
if (end <= start) return; if (end <= start) return;
each_location(start, end - start, cb, data); each_location(start, end - start, cb, data);
} }
static void
gc_mark_maybe_each_location(VALUE obj, void *data)
{
gc_mark_maybe_internal(obj);
}
void void
rb_gc_mark_locations(const VALUE *start, const VALUE *end) rb_gc_mark_locations(const VALUE *start, const VALUE *end)
{ {
each_location_ptr(start, end, rb_gc_impl_mark_maybe, rb_gc_get_objspace()); each_location_ptr(start, end, gc_mark_maybe_each_location, NULL);
} }
void void
rb_gc_mark_values(long n, const VALUE *values) rb_gc_mark_values(long n, const VALUE *values)
{ {
for (long i = 0; i < n; i++) { for (long i = 0; i < n; i++) {
gc_mark_internal(rb_gc_get_objspace(), values[i]); gc_mark_internal(values[i]);
} }
} }
@ -2135,16 +2149,14 @@ void
rb_gc_mark_vm_stack_values(long n, const VALUE *values) rb_gc_mark_vm_stack_values(long n, const VALUE *values)
{ {
for (long i = 0; i < n; i++) { for (long i = 0; i < n; i++) {
gc_mark_and_pin_internal(rb_gc_get_objspace(), values[i]); gc_mark_and_pin_internal(values[i]);
} }
} }
static int static int
mark_key(st_data_t key, st_data_t value, st_data_t data) mark_key(st_data_t key, st_data_t value, st_data_t data)
{ {
void *objspace = (void *)data; gc_mark_and_pin_internal((VALUE)key);
gc_mark_and_pin_internal(objspace, (VALUE)key);
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -2160,10 +2172,8 @@ rb_mark_set(st_table *tbl)
static int static int
mark_keyvalue(st_data_t key, st_data_t value, st_data_t data) mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
{ {
void *objspace = (void *)data; gc_mark_internal((VALUE)key);
gc_mark_internal((VALUE)value);
gc_mark_internal(objspace, (VALUE)key);
gc_mark_internal(objspace, (VALUE)value);
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -2171,10 +2181,8 @@ mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
static int static int
pin_key_pin_value(st_data_t key, st_data_t value, st_data_t data) pin_key_pin_value(st_data_t key, st_data_t value, st_data_t data)
{ {
void *objspace = (void *)data; gc_mark_and_pin_internal((VALUE)key);
gc_mark_and_pin_internal((VALUE)value);
gc_mark_and_pin_internal(objspace, (VALUE)key);
gc_mark_and_pin_internal(objspace, (VALUE)value);
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -2182,25 +2190,23 @@ pin_key_pin_value(st_data_t key, st_data_t value, st_data_t data)
static int static int
pin_key_mark_value(st_data_t key, st_data_t value, st_data_t data) pin_key_mark_value(st_data_t key, st_data_t value, st_data_t data)
{ {
void *objspace = (void *)data; gc_mark_and_pin_internal((VALUE)key);
gc_mark_internal((VALUE)value);
gc_mark_and_pin_internal(objspace, (VALUE)key);
gc_mark_internal(objspace, (VALUE)value);
return ST_CONTINUE; return ST_CONTINUE;
} }
static void static void
mark_hash(void *objspace, VALUE hash) mark_hash(VALUE hash)
{ {
if (rb_hash_compare_by_id_p(hash)) { if (rb_hash_compare_by_id_p(hash)) {
rb_hash_stlike_foreach(hash, pin_key_mark_value, (st_data_t)objspace); rb_hash_stlike_foreach(hash, pin_key_mark_value, 0);
} }
else { else {
rb_hash_stlike_foreach(hash, mark_keyvalue, (st_data_t)objspace); rb_hash_stlike_foreach(hash, mark_keyvalue, 0);
} }
gc_mark_internal(objspace, RHASH(hash)->ifnone); gc_mark_internal(RHASH(hash)->ifnone);
} }
void void
@ -2208,13 +2214,13 @@ rb_mark_hash(st_table *tbl)
{ {
if (!tbl) return; if (!tbl) return;
st_foreach(tbl, pin_key_pin_value, (st_data_t)rb_gc_get_objspace()); st_foreach(tbl, pin_key_pin_value, 0);
} }
static enum rb_id_table_iterator_result static enum rb_id_table_iterator_result
mark_method_entry_i(VALUE me, void *objspace) mark_method_entry_i(VALUE me, void *objspace)
{ {
gc_mark_internal(objspace, me); gc_mark_internal(me);
return ID_TABLE_CONTINUE; return ID_TABLE_CONTINUE;
} }
@ -2237,22 +2243,13 @@ mark_m_tbl(void *objspace, struct rb_id_table *tbl)
((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix))) ((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
#endif #endif
struct mark_machine_stack_location_maybe_data {
void *objspace;
#ifdef RUBY_ASAN_ENABLED
const rb_execution_context_t *ec;
#endif
};
static void static void
gc_mark_machine_stack_location_maybe(void *data, VALUE obj) gc_mark_machine_stack_location_maybe(VALUE obj, void *data)
{ {
void *objspace = ((struct mark_machine_stack_location_maybe_data *)data)->objspace; gc_mark_maybe_internal(obj);
gc_mark_maybe_internal(objspace, obj);
#ifdef RUBY_ASAN_ENABLED #ifdef RUBY_ASAN_ENABLED
const rb_execution_context_t *ec = ((struct mark_machine_stack_location_maybe_data *)data)->ec; const rb_execution_context_t *ec = (const rb_execution_context_t *)data;
void *fake_frame_start; void *fake_frame_start;
void *fake_frame_end; void *fake_frame_end;
bool is_fake_frame = asan_get_fake_stack_extents( bool is_fake_frame = asan_get_fake_stack_extents(
@ -2261,7 +2258,7 @@ gc_mark_machine_stack_location_maybe(void *data, VALUE obj)
&fake_frame_start, &fake_frame_end &fake_frame_start, &fake_frame_end
); );
if (is_fake_frame) { if (is_fake_frame) {
each_location_ptr(fake_frame_start, fake_frame_end, rb_gc_impl_mark_maybe, objspace); each_location_ptr(fake_frame_start, fake_frame_end, gc_mark_maybe_each_location, NULL);
} }
#endif #endif
} }
@ -2281,26 +2278,26 @@ rb_mark_locations(void *begin, void *end)
# if defined(__EMSCRIPTEN__) # if defined(__EMSCRIPTEN__)
static void static void
mark_current_machine_context(void *objspace, rb_execution_context_t *ec) mark_current_machine_context(rb_execution_context_t *ec)
{ {
emscripten_scan_stack(rb_mark_locations); emscripten_scan_stack(rb_mark_locations);
each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], rb_gc_impl_mark_maybe, objspace); each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
emscripten_scan_registers(rb_mark_locations); emscripten_scan_registers(rb_mark_locations);
each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], rb_gc_impl_mark_maybe, objspace); each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
} }
# else // use Asyncify version # else // use Asyncify version
static void static void
mark_current_machine_context(void *objspace, rb_execution_context_t *ec) mark_current_machine_context(rb_execution_context_t *ec)
{ {
VALUE *stack_start, *stack_end; VALUE *stack_start, *stack_end;
SET_STACK_END; SET_STACK_END;
GET_STACK_BOUNDS(stack_start, stack_end, 1); GET_STACK_BOUNDS(stack_start, stack_end, 1);
each_location_ptr(stack_start, stack_end, rb_gc_impl_mark_maybe, objspace); each_location_ptr(stack_start, stack_end, gc_mark_maybe_each_location, NULL);
rb_wasm_scan_locals(rb_mark_locations); rb_wasm_scan_locals(rb_mark_locations);
each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], rb_gc_impl_mark_maybe, objspace); each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
} }
# endif # endif
@ -2308,7 +2305,7 @@ mark_current_machine_context(void *objspace, rb_execution_context_t *ec)
#else // !defined(__wasm__) #else // !defined(__wasm__)
static void static void
mark_current_machine_context(void *objspace, rb_execution_context_t *ec) mark_current_machine_context(rb_execution_context_t *ec)
{ {
union { union {
rb_jmp_buf j; rb_jmp_buf j;
@ -2327,15 +2324,15 @@ mark_current_machine_context(void *objspace, rb_execution_context_t *ec)
SET_STACK_END; SET_STACK_END;
GET_STACK_BOUNDS(stack_start, stack_end, 1); GET_STACK_BOUNDS(stack_start, stack_end, 1);
struct mark_machine_stack_location_maybe_data data = { void *data =
.objspace = objspace,
#ifdef RUBY_ASAN_ENABLED #ifdef RUBY_ASAN_ENABLED
.ec = ec ec;
#else
NULL;
#endif #endif
};
each_location(save_regs_gc_mark.v, numberof(save_regs_gc_mark.v), gc_mark_machine_stack_location_maybe, &data); each_location(save_regs_gc_mark.v, numberof(save_regs_gc_mark.v), gc_mark_machine_stack_location_maybe, data);
each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, &data); each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, data);
} }
#endif #endif
@ -2347,24 +2344,22 @@ rb_gc_mark_machine_context(const rb_execution_context_t *ec)
GET_STACK_BOUNDS(stack_start, stack_end, 0); GET_STACK_BOUNDS(stack_start, stack_end, 0);
RUBY_DEBUG_LOG("ec->th:%u stack_start:%p stack_end:%p", rb_ec_thread_ptr(ec)->serial, stack_start, stack_end); RUBY_DEBUG_LOG("ec->th:%u stack_start:%p stack_end:%p", rb_ec_thread_ptr(ec)->serial, stack_start, stack_end);
struct mark_machine_stack_location_maybe_data data = { void *data =
.objspace = rb_gc_get_objspace(),
#ifdef RUBY_ASAN_ENABLED #ifdef RUBY_ASAN_ENABLED
.ec = ec ec;
#else
NULL;
#endif #endif
};
each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, &data); each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, data);
int num_regs = sizeof(ec->machine.regs)/(sizeof(VALUE)); int num_regs = sizeof(ec->machine.regs)/(sizeof(VALUE));
each_location((VALUE*)&ec->machine.regs, num_regs, gc_mark_machine_stack_location_maybe, &data); each_location((VALUE*)&ec->machine.regs, num_regs, gc_mark_machine_stack_location_maybe, data);
} }
static int static int
rb_mark_tbl_i(st_data_t key, st_data_t value, st_data_t data) rb_mark_tbl_i(st_data_t key, st_data_t value, st_data_t data)
{ {
void *objspace = (void *)data; gc_mark_and_pin_internal((VALUE)value);
gc_mark_and_pin_internal(objspace, (VALUE)value);
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -2374,21 +2369,21 @@ rb_mark_tbl(st_table *tbl)
{ {
if (!tbl || tbl->num_entries == 0) return; if (!tbl || tbl->num_entries == 0) return;
st_foreach(tbl, rb_mark_tbl_i, (st_data_t)rb_gc_get_objspace()); st_foreach(tbl, rb_mark_tbl_i, 0);
} }
static void static void
gc_mark_tbl_no_pin(void *objspace, st_table *tbl) gc_mark_tbl_no_pin(st_table *tbl)
{ {
if (!tbl || tbl->num_entries == 0) return; if (!tbl || tbl->num_entries == 0) return;
st_foreach(tbl, gc_mark_tbl_no_pin_i, (st_data_t)objspace); st_foreach(tbl, gc_mark_tbl_no_pin_i, 0);
} }
void void
rb_mark_tbl_no_pin(st_table *tbl) rb_mark_tbl_no_pin(st_table *tbl)
{ {
gc_mark_tbl_no_pin(rb_gc_get_objspace(), tbl); gc_mark_tbl_no_pin(tbl);
} }
static enum rb_id_table_iterator_result static enum rb_id_table_iterator_result
@ -2399,7 +2394,7 @@ mark_cvc_tbl_i(VALUE cvc_entry, void *objspace)
entry = (struct rb_cvar_class_tbl_entry *)cvc_entry; entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref))); RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref)));
gc_mark_internal(objspace, (VALUE)entry->cref); gc_mark_internal((VALUE)entry->cref);
return ID_TABLE_CONTINUE; return ID_TABLE_CONTINUE;
} }
@ -2424,8 +2419,8 @@ mark_const_table_i(VALUE value, void *objspace)
{ {
const rb_const_entry_t *ce = (const rb_const_entry_t *)value; const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
gc_mark_internal(objspace, ce->value); gc_mark_internal(ce->value);
gc_mark_internal(objspace, ce->file); gc_mark_internal(ce->file);
return ID_TABLE_CONTINUE; return ID_TABLE_CONTINUE;
} }
@ -2442,10 +2437,10 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
MARK_CHECKPOINT("vm"); MARK_CHECKPOINT("vm");
rb_vm_mark(vm); rb_vm_mark(vm);
if (vm->self) gc_mark_internal(objspace, vm->self); if (vm->self) gc_mark_internal(vm->self);
MARK_CHECKPOINT("machine_context"); MARK_CHECKPOINT("machine_context");
mark_current_machine_context(objspace, ec); mark_current_machine_context(ec);
MARK_CHECKPOINT("end_proc"); MARK_CHECKPOINT("end_proc");
rb_mark_end_proc(); rb_mark_end_proc();
@ -2500,28 +2495,28 @@ rb_gc_mark_children(void *objspace, VALUE obj)
break; break;
} }
gc_mark_internal(objspace, RBASIC(obj)->klass); gc_mark_internal(RBASIC(obj)->klass);
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
if (FL_TEST(obj, FL_SINGLETON)) { if (FL_TEST(obj, FL_SINGLETON)) {
gc_mark_internal(objspace, RCLASS_ATTACHED_OBJECT(obj)); gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj));
} }
// Continue to the shared T_CLASS/T_MODULE // Continue to the shared T_CLASS/T_MODULE
case T_MODULE: case T_MODULE:
if (RCLASS_SUPER(obj)) { if (RCLASS_SUPER(obj)) {
gc_mark_internal(objspace, RCLASS_SUPER(obj)); gc_mark_internal(RCLASS_SUPER(obj));
} }
mark_m_tbl(objspace, RCLASS_M_TBL(obj)); mark_m_tbl(objspace, RCLASS_M_TBL(obj));
mark_cvc_tbl(objspace, obj); mark_cvc_tbl(objspace, obj);
rb_cc_table_mark(obj); rb_cc_table_mark(obj);
if (rb_shape_obj_too_complex(obj)) { if (rb_shape_obj_too_complex(obj)) {
gc_mark_tbl_no_pin(objspace, (st_table *)RCLASS_IVPTR(obj)); gc_mark_tbl_no_pin((st_table *)RCLASS_IVPTR(obj));
} }
else { else {
for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) { for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
gc_mark_internal(objspace, RCLASS_IVPTR(obj)[i]); gc_mark_internal(RCLASS_IVPTR(obj)[i]);
} }
} }
@ -2529,7 +2524,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
rb_id_table_foreach_values(RCLASS_CONST_TBL(obj), mark_const_table_i, objspace); rb_id_table_foreach_values(RCLASS_CONST_TBL(obj), mark_const_table_i, objspace);
} }
gc_mark_internal(objspace, RCLASS_EXT(obj)->classpath); gc_mark_internal(RCLASS_EXT(obj)->classpath);
break; break;
case T_ICLASS: case T_ICLASS:
@ -2537,11 +2532,11 @@ rb_gc_mark_children(void *objspace, VALUE obj)
mark_m_tbl(objspace, RCLASS_M_TBL(obj)); mark_m_tbl(objspace, RCLASS_M_TBL(obj));
} }
if (RCLASS_SUPER(obj)) { if (RCLASS_SUPER(obj)) {
gc_mark_internal(objspace, RCLASS_SUPER(obj)); gc_mark_internal(RCLASS_SUPER(obj));
} }
if (RCLASS_INCLUDER(obj)) { if (RCLASS_INCLUDER(obj)) {
gc_mark_internal(objspace, RCLASS_INCLUDER(obj)); gc_mark_internal(RCLASS_INCLUDER(obj));
} }
mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj)); mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
rb_cc_table_mark(obj); rb_cc_table_mark(obj);
@ -2550,19 +2545,19 @@ rb_gc_mark_children(void *objspace, VALUE obj)
case T_ARRAY: case T_ARRAY:
if (ARY_SHARED_P(obj)) { if (ARY_SHARED_P(obj)) {
VALUE root = ARY_SHARED_ROOT(obj); VALUE root = ARY_SHARED_ROOT(obj);
gc_mark_internal(objspace, root); gc_mark_internal(root);
} }
else { else {
long len = RARRAY_LEN(obj); long len = RARRAY_LEN(obj);
const VALUE *ptr = RARRAY_CONST_PTR(obj); const VALUE *ptr = RARRAY_CONST_PTR(obj);
for (long i = 0; i < len; i++) { for (long i = 0; i < len; i++) {
gc_mark_internal(objspace, ptr[i]); gc_mark_internal(ptr[i]);
} }
} }
break; break;
case T_HASH: case T_HASH:
mark_hash(objspace, obj); mark_hash(obj);
break; break;
case T_STRING: case T_STRING:
@ -2572,10 +2567,10 @@ rb_gc_mark_children(void *objspace, VALUE obj)
* points into the slot of the shared string. There may be code * points into the slot of the shared string. There may be code
* using the RSTRING_PTR on the stack, which would pin this * using the RSTRING_PTR on the stack, which would pin this
* string but not pin the shared string, causing it to move. */ * string but not pin the shared string, causing it to move. */
gc_mark_and_pin_internal(objspace, RSTRING(obj)->as.heap.aux.shared); gc_mark_and_pin_internal(RSTRING(obj)->as.heap.aux.shared);
} }
else { else {
gc_mark_internal(objspace, RSTRING(obj)->as.heap.aux.shared); gc_mark_internal(RSTRING(obj)->as.heap.aux.shared);
} }
} }
break; break;
@ -2588,7 +2583,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
size_t *offset_list = (size_t *)RTYPEDDATA(obj)->type->function.dmark; size_t *offset_list = (size_t *)RTYPEDDATA(obj)->type->function.dmark;
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) { for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
gc_mark_internal(objspace, *(VALUE *)((char *)ptr + offset)); gc_mark_internal(*(VALUE *)((char *)ptr + offset));
} }
} }
else { else {
@ -2606,14 +2601,14 @@ rb_gc_mark_children(void *objspace, VALUE obj)
rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj)); rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
if (rb_shape_obj_too_complex(obj)) { if (rb_shape_obj_too_complex(obj)) {
gc_mark_tbl_no_pin(objspace, ROBJECT_IV_HASH(obj)); gc_mark_tbl_no_pin(ROBJECT_IV_HASH(obj));
} }
else { else {
const VALUE * const ptr = ROBJECT_IVPTR(obj); const VALUE * const ptr = ROBJECT_IVPTR(obj);
uint32_t len = ROBJECT_IV_COUNT(obj); uint32_t len = ROBJECT_IV_COUNT(obj);
for (uint32_t i = 0; i < len; i++) { for (uint32_t i = 0; i < len; i++) {
gc_mark_internal(objspace, ptr[i]); gc_mark_internal(ptr[i]);
} }
} }
@ -2632,36 +2627,36 @@ rb_gc_mark_children(void *objspace, VALUE obj)
case T_FILE: case T_FILE:
if (RFILE(obj)->fptr) { if (RFILE(obj)->fptr) {
gc_mark_internal(objspace, RFILE(obj)->fptr->self); gc_mark_internal(RFILE(obj)->fptr->self);
gc_mark_internal(objspace, RFILE(obj)->fptr->pathv); gc_mark_internal(RFILE(obj)->fptr->pathv);
gc_mark_internal(objspace, RFILE(obj)->fptr->tied_io_for_writing); gc_mark_internal(RFILE(obj)->fptr->tied_io_for_writing);
gc_mark_internal(objspace, RFILE(obj)->fptr->writeconv_asciicompat); gc_mark_internal(RFILE(obj)->fptr->writeconv_asciicompat);
gc_mark_internal(objspace, RFILE(obj)->fptr->writeconv_pre_ecopts); gc_mark_internal(RFILE(obj)->fptr->writeconv_pre_ecopts);
gc_mark_internal(objspace, RFILE(obj)->fptr->encs.ecopts); gc_mark_internal(RFILE(obj)->fptr->encs.ecopts);
gc_mark_internal(objspace, RFILE(obj)->fptr->write_lock); gc_mark_internal(RFILE(obj)->fptr->write_lock);
gc_mark_internal(objspace, RFILE(obj)->fptr->timeout); gc_mark_internal(RFILE(obj)->fptr->timeout);
} }
break; break;
case T_REGEXP: case T_REGEXP:
gc_mark_internal(objspace, RREGEXP(obj)->src); gc_mark_internal(RREGEXP(obj)->src);
break; break;
case T_MATCH: case T_MATCH:
gc_mark_internal(objspace, RMATCH(obj)->regexp); gc_mark_internal(RMATCH(obj)->regexp);
if (RMATCH(obj)->str) { if (RMATCH(obj)->str) {
gc_mark_internal(objspace, RMATCH(obj)->str); gc_mark_internal(RMATCH(obj)->str);
} }
break; break;
case T_RATIONAL: case T_RATIONAL:
gc_mark_internal(objspace, RRATIONAL(obj)->num); gc_mark_internal(RRATIONAL(obj)->num);
gc_mark_internal(objspace, RRATIONAL(obj)->den); gc_mark_internal(RRATIONAL(obj)->den);
break; break;
case T_COMPLEX: case T_COMPLEX:
gc_mark_internal(objspace, RCOMPLEX(obj)->real); gc_mark_internal(RCOMPLEX(obj)->real);
gc_mark_internal(objspace, RCOMPLEX(obj)->imag); gc_mark_internal(RCOMPLEX(obj)->imag);
break; break;
case T_STRUCT: { case T_STRUCT: {
@ -2669,7 +2664,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
const VALUE * const ptr = RSTRUCT_CONST_PTR(obj); const VALUE * const ptr = RSTRUCT_CONST_PTR(obj);
for (long i = 0; i < len; i++) { for (long i = 0; i < len; i++) {
gc_mark_internal(objspace, ptr[i]); gc_mark_internal(ptr[i]);
} }
break; break;
@ -3523,13 +3518,6 @@ ruby_gc_set_params(void)
rb_gc_impl_set_params(rb_gc_get_objspace()); rb_gc_impl_set_params(rb_gc_get_objspace());
} }
void
rb_gc_reachable_objects_from_callback(VALUE obj)
{
rb_ractor_t *cr = GET_RACTOR();
cr->mfd->mark_func(obj, cr->mfd->data);
}
void void
rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data) rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data)
{ {
@ -3538,15 +3526,16 @@ rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *
if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_objspace_reachable_objects_from() is not supported while during GC"); if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_objspace_reachable_objects_from() is not supported while during GC");
if (!RB_SPECIAL_CONST_P(obj)) { if (!RB_SPECIAL_CONST_P(obj)) {
rb_ractor_t *cr = GET_RACTOR(); rb_vm_t *vm = GET_VM();
struct gc_mark_func_data_struct *prev_mfd = vm->gc.mark_func_data;
struct gc_mark_func_data_struct mfd = { struct gc_mark_func_data_struct mfd = {
.mark_func = func, .mark_func = func,
.data = data, .data = data,
}, *prev_mfd = cr->mfd; };
cr->mfd = &mfd; vm->gc.mark_func_data = &mfd;
rb_gc_mark_children(rb_gc_get_objspace(), obj); rb_gc_mark_children(rb_gc_get_objspace(), obj);
cr->mfd = prev_mfd; vm->gc.mark_func_data = prev_mfd;
} }
} }
RB_VM_LOCK_LEAVE(); RB_VM_LOCK_LEAVE();
@ -3570,19 +3559,22 @@ rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE,
{ {
if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_gc_impl_objspace_reachable_objects_from_root() is not supported while during GC"); if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_gc_impl_objspace_reachable_objects_from_root() is not supported while during GC");
rb_ractor_t *cr = GET_RACTOR(); rb_vm_t *vm = GET_VM();
struct root_objects_data data = { struct root_objects_data data = {
.func = func, .func = func,
.data = passing_data, .data = passing_data,
}; };
struct gc_mark_func_data_struct *prev_mfd = vm->gc.mark_func_data;
struct gc_mark_func_data_struct mfd = { struct gc_mark_func_data_struct mfd = {
.mark_func = root_objects_from, .mark_func = root_objects_from,
.data = &data, .data = &data,
}, *prev_mfd = cr->mfd; };
cr->mfd = &mfd; vm->gc.mark_func_data = &mfd;
rb_gc_mark_roots(rb_gc_get_objspace(), &data.category); rb_gc_mark_roots(rb_gc_get_objspace(), &data.category);
cr->mfd = prev_mfd; vm->gc.mark_func_data = prev_mfd;
} }
/* /*

View File

@ -4650,7 +4650,8 @@ gc_grey(rb_objspace_t *objspace, VALUE obj)
static void static void
gc_mark(rb_objspace_t *objspace, VALUE obj) gc_mark(rb_objspace_t *objspace, VALUE obj)
{ {
if (RB_LIKELY(during_gc)) { GC_ASSERT(during_gc);
rgengc_check_relation(objspace, obj); rgengc_check_relation(objspace, obj);
if (!gc_mark_set(objspace, obj)) return; /* already marked */ if (!gc_mark_set(objspace, obj)) return; /* already marked */
@ -4672,10 +4673,6 @@ gc_mark(rb_objspace_t *objspace, VALUE obj)
gc_aging(objspace, obj); gc_aging(objspace, obj);
gc_grey(objspace, obj); gc_grey(objspace, obj);
}
else {
rb_gc_reachable_objects_from_callback(obj);
}
} }
static inline void static inline void

View File

@ -23,7 +23,6 @@ size_t rb_gc_obj_optimal_size(VALUE obj);
void rb_gc_mark_children(void *objspace, VALUE obj); void rb_gc_mark_children(void *objspace, VALUE obj);
void rb_gc_update_object_references(void *objspace, VALUE obj); void rb_gc_update_object_references(void *objspace, VALUE obj);
void rb_gc_update_vm_references(void *objspace); void rb_gc_update_vm_references(void *objspace);
void rb_gc_reachable_objects_from_callback(VALUE obj);
void rb_gc_event_hook(VALUE obj, rb_event_flag_t event); void rb_gc_event_hook(VALUE obj, rb_event_flag_t event);
void *rb_gc_get_objspace(void); void *rb_gc_get_objspace(void);
size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc); size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc);

View File

@ -188,12 +188,6 @@ struct rb_ractor_struct {
VALUE debug; VALUE debug;
void *newobj_cache; void *newobj_cache;
// gc.c rb_objspace_reachable_objects_from
struct gc_mark_func_data_struct {
void *data;
void (*mark_func)(VALUE v, void *data);
} *mfd;
}; // rb_ractor_t is defined in vm_core.h }; // rb_ractor_t is defined in vm_core.h

4
vm.c
View File

@ -3099,7 +3099,7 @@ ruby_vm_destruct(rb_vm_t *vm)
} }
} }
struct rb_objspace *objspace = vm->objspace; struct rb_objspace *objspace = vm->gc.objspace;
rb_vm_living_threads_init(vm); rb_vm_living_threads_init(vm);
ruby_vm_run_at_exit_hooks(vm); ruby_vm_run_at_exit_hooks(vm);
@ -4209,7 +4209,7 @@ Init_VM(void)
rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new()); rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
#ifdef _WIN32 #ifdef _WIN32
rb_objspace_gc_enable(vm->objspace); rb_objspace_gc_enable(vm->gc.objspace);
#endif #endif
} }
vm_init_redefined_flag(); vm_init_redefined_flag();

View File

@ -748,7 +748,13 @@ typedef struct rb_vm_struct {
VALUE coverages, me2counter; VALUE coverages, me2counter;
int coverage_mode; int coverage_mode;
struct {
struct rb_objspace *objspace; struct rb_objspace *objspace;
struct gc_mark_func_data_struct {
void *data;
void (*mark_func)(VALUE v, void *data);
} *mark_func_data;
} gc;
rb_at_exit_list *at_exit; rb_at_exit_list *at_exit;