@@ -872,7 +872,6 @@ struct heap_page {
872872 struct free_slot * freelist ;
873873 struct free_slot * deferred_freelist ;
874874 struct ccan_list_node page_node ;
875- rb_ractor_newobj_heap_cache_t * heap_cache ;
876875
877876 bits_t wb_unprotected_bits [HEAP_PAGE_BITMAP_LIMIT ];
878877 /* the following three bitmaps are cleared at the beginning of full GC */
@@ -1255,7 +1254,7 @@ heap_is_sweep_done(rb_objspace_t *objspace, rb_heap_t *heap)
12551254 }
12561255
12571256 // We always dequeue the last page, never the sweep thread. This avoids locking in the common case.
1258- // It should be synchronized, but it's a "benign race" (FIXME: use atomics?)
1257+ // It should be synchronized, but it's a "benign race".
12591258 if (heap -> sweeping_page ) {
12601259 return false;
12611260 }
@@ -2759,15 +2758,10 @@ ractor_cache_set_page(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache,
27592758 GC_ASSERT (page -> free_slots != 0 );
27602759 GC_ASSERT (page -> freelist != NULL );
27612760
2762- if (heap_cache -> using_page ) {
2763- heap_cache -> using_page -> heap_cache = NULL ;
2764- }
2765-
27662761 heap_cache -> using_page = page ;
27672762 heap_cache -> freelist = page -> freelist ;
27682763 page -> free_slots = 0 ;
27692764 page -> freelist = NULL ;
2770- page -> heap_cache = heap_cache ;
27712765
27722766 rb_asan_unpoison_object ((VALUE )heap_cache -> freelist , false);
27732767 GC_ASSERT (RB_TYPE_P ((VALUE )heap_cache -> freelist , T_NONE ));
@@ -3952,7 +3946,7 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
39523946 if (bitset & 1 ) {
39533947 switch (BUILTIN_TYPE (vp )) {
39543948 case T_MOVED :
3955- if (objspace -> flags .during_compacting ) {
3949+ if (RB_UNLIKELY ( objspace -> flags .during_compacting ) ) {
39563950 /* The sweep cursor shouldn't have made it to any
39573951 * T_MOVED slots while the compact flag is enabled.
39583952 * The sweep cursor and compact cursor move in
@@ -4337,7 +4331,7 @@ sweep_in_ruby_thread(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
43374331 MARK_IN_BITMAP (page -> deferred_free_bits , obj );
43384332}
43394333
4340- bool
4334+ static inline bool
43414335zombie_needs_deferred_free (VALUE zombie )
43424336{
43434337 return ZOMBIE_NEEDS_FREE_P (zombie );
@@ -4361,6 +4355,8 @@ debug_free_check(rb_objspace_t *objspace, VALUE vp)
43614355#define debug_free_check (...) (void)0
43624356#endif
43634357
4358+ bool rb_gc_obj_free_whitelisted_vm_weak_references_in_sweep_thread (VALUE obj );
4359+
43644360static inline void
43654361gc_pre_sweep_plane (rb_objspace_t * objspace , rb_heap_t * heap , struct heap_page * page , uintptr_t p , bits_t bitset , short slot_size )
43664362{
@@ -4476,7 +4472,7 @@ gc_pre_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *p
44764472 break ;
44774473 free : {
44784474 debug_free_check (objspace , vp );
4479- if (rb_gc_obj_free_vm_weak_references ( vp )) {
4475+ if (RB_LIKELY ( rb_gc_obj_free_whitelisted_vm_weak_references_in_sweep_thread ( vp ) )) {
44804476 bool can_put_back_on_freelist = rb_gc_obj_free (objspace , vp );
44814477 if (can_put_back_on_freelist ) {
44824478 heap_page_add_deferred_freeobj (objspace , page , vp );
@@ -4872,7 +4868,6 @@ gc_ractor_newobj_cache_clear(void *c, void *data)
48724868
48734869 heap_page_freelist_append (page , freelist );
48744870
4875- if (page ) page -> heap_cache = NULL ;
48764871 cache -> using_page = NULL ;
48774872 cache -> freelist = NULL ;
48784873 }
@@ -5157,6 +5152,47 @@ is_last_heap(rb_objspace_t *objspace, rb_heap_t *heap)
51575152 return heap - heaps == (HEAP_COUNT - 1 );
51585153}
51595154
5155+ static void
5156+ gc_sweep_step_deferred_free (rb_objspace_t * objspace , rb_heap_t * heap , struct heap_page * sweep_page , unsigned short * freed_out , unsigned short * finals_out )
5157+ {
5158+ unsigned short freed = 0 ;
5159+ unsigned short finals = 0 ;
5160+ uintptr_t p = (uintptr_t )sweep_page -> start ;
5161+ bits_t * deferred_bits = sweep_page -> deferred_free_bits ;
5162+ int total_slots = sweep_page -> total_slots ;
5163+ short slot_size = sweep_page -> slot_size ;
5164+
5165+ int bitmap_plane_count = CEILDIV (total_slots , BITS_BITLENGTH );
5166+ int out_of_range_bits = total_slots % BITS_BITLENGTH ;
5167+ bits_t bitset ;
5168+
5169+ if (out_of_range_bits != 0 ) {
5170+ deferred_bits [bitmap_plane_count - 1 ] &= (((bits_t )1 << out_of_range_bits ) - 1 );
5171+ }
5172+
5173+ for (int i = 0 ; i < bitmap_plane_count ; i ++ ) {
5174+ bitset = deferred_bits [i ];
5175+ p = (uintptr_t )sweep_page -> start + (i * BITS_BITLENGTH * slot_size );
5176+ while (bitset ) {
5177+ if (bitset & 1 ) {
5178+ VALUE obj = (VALUE )p ;
5179+ GC_ASSERT (GET_HEAP_PAGE (obj ) == sweep_page );
5180+ GC_ASSERT (!RVALUE_MARKED (objspace , obj ));
5181+ if (deferred_free (objspace , obj )) {
5182+ freed ++ ;
5183+ }
5184+ else {
5185+ finals ++ ;
5186+ }
5187+ }
5188+ p += slot_size ;
5189+ bitset >>= 1 ;
5190+ }
5191+ }
5192+ * freed_out = freed ;
5193+ * finals_out = finals ;
5194+ }
5195+
51605196// Perform incremental (lazy) sweep on a heap.
51615197static int
51625198gc_sweep_step (rb_objspace_t * objspace , rb_heap_t * heap )
@@ -5209,51 +5245,20 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
52095245 .page = sweep_page
52105246 };
52115247
5212- unsigned short deferred_free_final_slots = 0 ;
52135248 if (free_in_user_thread_p ) {
52145249 gc_sweep_page (objspace , heap , & ctx );
52155250 GC_ASSERT (sweep_page -> pre_deferred_free_slots == 0 );
52165251 }
52175252 else {
52185253 unsigned short deferred_free_freed = 0 ;
5254+ unsigned short deferred_free_final_slots = 0 ;
52195255 unsigned short deferred_to_free = sweep_page -> pre_deferred_free_slots ;
52205256
52215257 psweep_debug (-2 , "[gc] gc_sweep_step: (heap:%p %ld, page:%p) free_ruby_th: %d, deferred_to_free:%d, pre_freed:%d, pre_empty:%d\n" ,
52225258 heap , heap - heaps , sweep_page , free_in_user_thread_p , deferred_to_free , sweep_page -> pre_freed_slots , sweep_page -> pre_empty_slots );
52235259
52245260 if (deferred_to_free > 0 ) {
5225- uintptr_t p = (uintptr_t )sweep_page -> start ;
5226- bits_t * deferred_bits = sweep_page -> deferred_free_bits ;
5227- int total_slots = sweep_page -> total_slots ;
5228- short slot_size = sweep_page -> slot_size ;
5229-
5230- int bitmap_plane_count = CEILDIV (total_slots , BITS_BITLENGTH );
5231- int out_of_range_bits = total_slots % BITS_BITLENGTH ;
5232- bits_t bitset ;
5233-
5234- if (out_of_range_bits != 0 ) {
5235- deferred_bits [bitmap_plane_count - 1 ] &= (((bits_t )1 << out_of_range_bits ) - 1 );
5236- }
5237-
5238- for (int i = 0 ; i < bitmap_plane_count ; i ++ ) {
5239- bitset = deferred_bits [i ];
5240- p = (uintptr_t )sweep_page -> start + (i * BITS_BITLENGTH * slot_size );
5241- while (bitset ) {
5242- if (bitset & 1 ) {
5243- VALUE obj = (VALUE )p ;
5244- GC_ASSERT (GET_HEAP_PAGE (obj ) == sweep_page );
5245- GC_ASSERT (!RVALUE_MARKED (objspace , obj ));
5246- if (deferred_free (objspace , obj )) {
5247- deferred_free_freed ++ ;
5248- }
5249- else {
5250- deferred_free_final_slots ++ ;
5251- }
5252- }
5253- p += slot_size ;
5254- bitset >>= 1 ;
5255- }
5256- }
5261+ gc_sweep_step_deferred_free (objspace , heap , sweep_page , & deferred_free_freed , & deferred_free_final_slots );
52575262 }
52585263 GC_ASSERT (deferred_to_free == (deferred_free_freed + deferred_free_final_slots ));
52595264
@@ -5320,9 +5325,6 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
53205325 clear_pre_sweep_fields (sweep_page );
53215326 }
53225327
5323- // We never sweep a page that's currently in free_pages, such as a cached page. Our iterator is past those already.
5324- GC_ASSERT (!sweep_page -> heap_cache );
5325-
53265328#if RGENGC_CHECK_MODE
53275329 short freelist_len = 0 ;
53285330 asan_unlock_freelist (sweep_page );
0 commit comments