Skip to content

Commit 4de9fe0

Browse files
committed
Pull out deferred freeing into its own function in from gc_sweep_step()
Also, don't call GET_EC() for every call to free_vm_weak_references. We know in advance when this is called from the sweep thread, so just call the correct function in pre_sweep_plane.
1 parent 2180916 commit 4de9fe0

3 files changed

Lines changed: 52 additions & 74 deletions

File tree

gc.c

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,7 +1596,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
15961596
}
15971597
break;
15981598
case T_DATA:
1599-
if (!rb_data_free(objspace, obj)) return FALSE;
1599+
if (!RB_LIKELY(rb_data_free(objspace, obj))) return FALSE;
16001600
break;
16011601
case T_MATCH:
16021602
{
@@ -2420,29 +2420,11 @@ obj_free_object_id(VALUE obj, bool in_user_gc_thread)
24202420
}
24212421

24222422
bool
2423-
rb_gc_obj_has_blacklisted_vm_weak_references(VALUE obj)
2424-
{
2425-
switch (BUILTIN_TYPE(obj)) {
2426-
case T_IMEMO:
2427-
switch (imemo_type(obj)) {
2428-
case imemo_callinfo:
2429-
case imemo_ment:
2430-
return true;
2431-
default:
2432-
break;
2433-
}
2434-
return false;
2435-
default:
2436-
return false;
2437-
}
2438-
}
2439-
2440-
static bool
24412423
rb_gc_obj_free_whitelisted_vm_weak_references_in_sweep_thread(VALUE obj)
24422424
{
24432425
VM_ASSERT(pthread_self() == GET_VM()->gc.sweep_thread);
24442426
bool result = obj_free_object_id(obj, false);
2445-
if (rb_obj_gen_fields_p(obj)) {
2427+
if (RB_UNLIKELY(rb_obj_gen_fields_p(obj))) {
24462428
bool freed_generic = rb_free_generic_ivar(obj);
24472429
if (!freed_generic) result = false;
24482430
}
@@ -2466,14 +2448,9 @@ rb_gc_obj_free_vm_weak_references(VALUE obj)
24662448
{
24672449
ASSUME(!RB_SPECIAL_CONST_P(obj));
24682450

2469-
rb_execution_context_t *ec = rb_current_execution_context(false);
2470-
if (!ec) {
2471-
return rb_gc_obj_free_whitelisted_vm_weak_references_in_sweep_thread(obj);
2472-
}
2473-
24742451
obj_free_object_id(obj, true);
24752452

2476-
if (rb_obj_gen_fields_p(obj)) {
2453+
if (RB_UNLIKELY(rb_obj_gen_fields_p(obj))) {
24772454
rb_free_generic_ivar(obj);
24782455
}
24792456

gc/default/default.c

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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
43414335
zombie_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+
43644360
static inline void
43654361
gc_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.
51615197
static int
51625198
gc_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);

gc/gc.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ MODULAR_GC_FN void rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*call
8282
MODULAR_GC_FN void rb_gc_set_pending_interrupt(void);
8383
MODULAR_GC_FN void rb_gc_unset_pending_interrupt(void);
8484
MODULAR_GC_FN bool rb_gc_obj_free_vm_weak_references(VALUE obj);
85-
MODULAR_GC_FN bool rb_gc_obj_has_blacklisted_vm_weak_references(VALUE obj);
8685
MODULAR_GC_FN bool rb_gc_obj_free(void *objspace, VALUE obj);
8786
MODULAR_GC_FN void rb_gc_save_machine_context(void);
8887
MODULAR_GC_FN void rb_gc_mark_roots(void *objspace, const char **categoryp);

0 commit comments

Comments
 (0)