diff options
author | Peter Zhu <peter@peterzhu.ca> | 2023-07-24 14:21:50 -0400 |
---|---|---|
committer | Peter Zhu <peter@peterzhu.ca> | 2023-08-25 09:01:21 -0400 |
commit | bfb395c620b811b4b3cb7d535d58721268af285d (patch) | |
tree | e32046e9dbff33ef2bdfe0bb8a51fb81613cbfbb /gc.c | |
parent | 633243958c1b19e7d934442e23ed3d7cc3d7691b (diff) | |
download | ruby-bfb395c620b811b4b3cb7d535d58721268af285d.tar.gz |
Implement weak references in the GC
[Feature #19783]
This commit adds support for weak references in the GC through the
function `rb_gc_mark_weak`. Unlike strong references, weak references
does not mark the object, but rather lets the GC know that an object
refers to another one. If the child object is freed, the pointer from
the parent object is overwritten with `Qundef`.
Co-Authored-By: Jean Boussier <byroot@ruby-lang.org>
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 48 |
1 files changed, 48 insertions, 0 deletions
@@ -95,6 +95,7 @@ #undef LIST_HEAD /* ccan/list conflicts with BSD-origin sys/queue.h. */ #include "constant.h" +#include "darray.h" #include "debug_counter.h" #include "eval_intern.h" #include "id_table.h" @@ -869,6 +870,8 @@ typedef struct rb_objspace { #if GC_DEBUG_STRESS_TO_CLASS VALUE stress_to_class; #endif + + rb_darray(VALUE *) weak_references; } rb_objspace_t; @@ -1831,6 +1834,8 @@ rb_objspace_alloc(void) ccan_list_head_init(&SIZE_POOL_TOMB_HEAP(size_pool)->pages); } + rb_darray_make_without_gc(&objspace->weak_references, 0); + dont_gc_on(); return objspace; @@ -1879,6 +1884,8 @@ rb_objspace_free(rb_objspace_t *objspace) free_stack_chunks(&objspace->mark_stack); mark_stack_free_cache(&objspace->mark_stack); + rb_darray_free_without_gc(objspace->weak_references); + free(objspace); } @@ -6878,6 +6885,23 @@ rb_gc_mark_and_move(VALUE *ptr) } } +void +rb_gc_mark_weak(VALUE *ptr) +{ + rb_objspace_t *objspace = &rb_objspace; + + if (UNLIKELY(!during_gc)) return; + + VALUE obj = *ptr; + if (RB_SPECIAL_CONST_P(obj)) return; + + GC_ASSERT(objspace->rgengc.parent_object == 0 || FL_TEST(objspace->rgengc.parent_object, FL_WB_PROTECTED)); + + rgengc_check_relation(objspace, obj); + + rb_darray_append_without_gc(&objspace->weak_references, ptr); +} + /* CAUTION: THIS FUNCTION ENABLE *ONLY BEFORE* SWEEPING. * This function is only for GC_END_MARK timing. */ @@ -8100,6 +8124,28 @@ gc_marks_wb_unprotected_objects(rb_objspace_t *objspace, rb_heap_t *heap) } static void +gc_update_weak_references(rb_objspace_t *objspace) +{ + size_t retained_weak_references_count = 0; + VALUE **ptr_ptr; + rb_darray_foreach(objspace->weak_references, i, ptr_ptr) { + VALUE obj = **ptr_ptr; + + if (RB_SPECIAL_CONST_P(obj)) continue; + + if (!RVALUE_MARKED(obj)) { + **ptr_ptr = Qundef; + } + else { + retained_weak_references_count++; + } + } + + rb_darray_clear(objspace->weak_references); + rb_darray_resize_capa_without_gc(&objspace->weak_references, retained_weak_references_count); +} + +static void gc_marks_finish(rb_objspace_t *objspace) { /* finish incremental GC */ @@ -8125,6 +8171,8 @@ gc_marks_finish(rb_objspace_t *objspace) } } + gc_update_weak_references(objspace); + #if RGENGC_CHECK_MODE >= 2 gc_verify_internal_consistency(objspace); #endif |