diff options
author | Peter Zhu <peter@peterzhu.ca> | 2024-02-28 16:29:22 -0500 |
---|---|---|
committer | Peter Zhu <peter@peterzhu.ca> | 2024-02-29 10:57:24 -0500 |
commit | 8a918b456c6fe7449dbffc8bfdc321a2969aea58 (patch) | |
tree | ed06a213c27452f9ebe02f383d8e2d2cb342ee46 /gc.c | |
parent | cb784082bc38299a1669d2d593f7a796411d752b (diff) | |
download | ruby-8a918b456c6fe7449dbffc8bfdc321a2969aea58.tar.gz |
Add gc_each_object for walking the heap
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 178 |
1 files changed, 92 insertions, 86 deletions
@@ -4254,10 +4254,8 @@ force_chain_object(st_data_t key, st_data_t val, st_data_t arg) return ST_CONTINUE; } -bool rb_obj_is_main_ractor(VALUE gv); - -void -rb_objspace_free_objects(rb_objspace_t *objspace) +static void +gc_each_object(rb_objspace_t *objspace, void (*func)(VALUE obj, void *data), void *data) { for (size_t i = 0; i < heap_allocated_pages; i++) { struct heap_page *page = heap_pages_sorted[i]; @@ -4266,25 +4264,76 @@ rb_objspace_free_objects(rb_objspace_t *objspace) uintptr_t p = (uintptr_t)page->start; uintptr_t pend = p + page->total_slots * stride; for (; p < pend; p += stride) { - VALUE vp = (VALUE)p; - switch (BUILTIN_TYPE(vp)) { - case T_NONE: - case T_SYMBOL: - break; - default: - obj_free(objspace, vp); - break; + VALUE obj = (VALUE)p; + + void *poisoned = asan_unpoison_object_temporary(obj); + + func(obj, data); + + if (poisoned) { + GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE); + asan_poison_object(obj); } } } } +bool rb_obj_is_main_ractor(VALUE gv); + +static void +rb_objspace_free_objects_i(VALUE obj, void *data) +{ + rb_objspace_t *objspace = (rb_objspace_t *)data; + + switch (BUILTIN_TYPE(obj)) { + case T_NONE: + case T_SYMBOL: + break; + default: + obj_free(objspace, obj); + break; + } +} void -rb_objspace_call_finalizer(rb_objspace_t *objspace) +rb_objspace_free_objects(rb_objspace_t *objspace) { - size_t i; + gc_each_object(objspace, rb_objspace_free_objects_i, objspace); +} + +static void +rb_objspace_call_finalizer_i(VALUE obj, void *data) +{ + rb_objspace_t *objspace = (rb_objspace_t *)data; + + switch (BUILTIN_TYPE(obj)) { + case T_DATA: + if (!rb_free_at_exit && (!DATA_PTR(obj) || !RANY(obj)->as.data.dfree)) break; + if (rb_obj_is_thread(obj)) break; + if (rb_obj_is_mutex(obj)) break; + if (rb_obj_is_fiber(obj)) break; + if (rb_obj_is_main_ractor(obj)) break; + + obj_free(objspace, obj); + break; + case T_FILE: + obj_free(objspace, obj); + break; + case T_SYMBOL: + case T_ARRAY: + case T_NONE: + break; + default: + if (rb_free_at_exit) { + obj_free(objspace, obj); + } + break; + } +} +void +rb_objspace_call_finalizer(rb_objspace_t *objspace) +{ #if RGENGC_CHECK_MODE >= 2 gc_verify_internal_consistency(objspace); #endif @@ -4325,45 +4374,7 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace) unsigned int lock_lev; gc_enter(objspace, gc_enter_event_finalizer, &lock_lev); - /* run data/file object's finalizers */ - for (i = 0; i < heap_allocated_pages; i++) { - struct heap_page *page = heap_pages_sorted[i]; - short stride = page->slot_size; - - uintptr_t p = (uintptr_t)page->start; - uintptr_t pend = p + page->total_slots * stride; - for (; p < pend; p += stride) { - VALUE vp = (VALUE)p; - void *poisoned = asan_unpoison_object_temporary(vp); - switch (BUILTIN_TYPE(vp)) { - case T_DATA: - if (!rb_free_at_exit && (!DATA_PTR(p) || !RANY(p)->as.data.dfree)) break; - if (rb_obj_is_thread(vp)) break; - if (rb_obj_is_mutex(vp)) break; - if (rb_obj_is_fiber(vp)) break; - if (rb_obj_is_main_ractor(vp)) break; - - obj_free(objspace, vp); - break; - case T_FILE: - obj_free(objspace, vp); - break; - case T_SYMBOL: - case T_ARRAY: - case T_NONE: - break; - default: - if (rb_free_at_exit) { - obj_free(objspace, vp); - } - break; - } - if (poisoned) { - GC_ASSERT(BUILTIN_TYPE(vp) == T_NONE); - asan_poison_object(vp); - } - } - } + gc_each_object(objspace, rb_objspace_call_finalizer_i, objspace); gc_exit(objspace, gc_enter_event_finalizer, &lock_lev); @@ -4820,6 +4831,27 @@ type_sym(size_t type) } } +struct count_objects_data { + size_t counts[T_MASK+1]; + size_t freed; + size_t total; +}; + +static void +count_objects_i(VALUE obj, void *d) +{ + struct count_objects_data *data = (struct count_objects_data *)d; + + if (RANY(obj)->as.basic.flags) { + data->counts[BUILTIN_TYPE(obj)]++; + } + else { + data->freed++; + } + + data->total++; +} + /* * call-seq: * ObjectSpace.count_objects([result_hash]) -> hash @@ -4859,10 +4891,7 @@ static VALUE count_objects(int argc, VALUE *argv, VALUE os) { rb_objspace_t *objspace = &rb_objspace; - size_t counts[T_MASK + 1] = { 0 }; - size_t freed = 0; - size_t total = 0; - size_t i; + struct count_objects_data data = { 0 }; VALUE hash = Qnil; if (rb_check_arity(argc, 0, 1) == 1) { @@ -4871,30 +4900,7 @@ count_objects(int argc, VALUE *argv, VALUE os) rb_raise(rb_eTypeError, "non-hash given"); } - for (i = 0; i < heap_allocated_pages; i++) { - struct heap_page *page = heap_pages_sorted[i]; - short stride = page->slot_size; - - uintptr_t p = (uintptr_t)page->start; - uintptr_t pend = p + page->total_slots * stride; - for (;p < pend; p += stride) { - VALUE vp = (VALUE)p; - GC_ASSERT((NUM_IN_PAGE(vp) * BASE_SLOT_SIZE) % page->slot_size == 0); - - void *poisoned = asan_unpoison_object_temporary(vp); - if (RANY(p)->as.basic.flags) { - counts[BUILTIN_TYPE(vp)]++; - } - else { - freed++; - } - if (poisoned) { - GC_ASSERT(BUILTIN_TYPE(vp) == T_NONE); - asan_poison_object(vp); - } - } - total += page->total_slots; - } + gc_each_object(objspace, count_objects_i, &data); if (NIL_P(hash)) { hash = rb_hash_new(); @@ -4902,13 +4908,13 @@ count_objects(int argc, VALUE *argv, VALUE os) else if (!RHASH_EMPTY_P(hash)) { rb_hash_stlike_foreach(hash, set_zero, hash); } - rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total)); - rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed)); + rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(data.total)); + rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(data.freed)); - for (i = 0; i <= T_MASK; i++) { + for (size_t i = 0; i <= T_MASK; i++) { VALUE type = type_sym(i); - if (counts[i]) - rb_hash_aset(hash, type, SIZET2NUM(counts[i])); + if (data.counts[i]) + rb_hash_aset(hash, type, SIZET2NUM(data.counts[i])); } return hash; |