Skip to content

Commit a9d6f31

Browse files
committed
Fix age bits
1 parent c702823 commit a9d6f31

1 file changed

Lines changed: 23 additions & 34 deletions

File tree

gc/default/default.c

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -926,36 +926,36 @@ heap_page_in_global_empty_pages_pool(rb_objspace_t *objspace, struct heap_page *
926926
#define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0])
927927
#define GET_HEAP_MARKING_BITS(x) (&GET_HEAP_PAGE(x)->marking_bits[0])
928928

929-
/* Planar age_bits layout: two bit-planes, each with the same 1-bit-per-slot
930-
* layout as mark_bits. age_bits[i*2] holds bit 0, age_bits[i*2+1] holds
931-
* bit 1 of the age for the slots covered by mark_bits[i]. */
929+
// Planar layout: age_bits[i*2] = plane 0 (low bit), age_bits[i*2+1] = plane 1 (high bit)
930+
// This matches the mark_bits layout so bulk clearing with ~unmarked works directly.
931+
#define RVALUE_AGE_BITMAP_PLANE_INDEX(n) BITMAP_INDEX(n)
932+
#define RVALUE_AGE_BITMAP_OFFSET(n) BITMAP_OFFSET(n)
932933

933934
static int
934935
RVALUE_AGE_GET(VALUE obj)
935936
{
936937
bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
937-
int idx = BITMAP_INDEX(obj) * 2;
938-
int shift = BITMAP_OFFSET(obj);
939-
int bit0 = (age_bits[idx] >> shift) & 1;
940-
int bit1 = (age_bits[idx + 1] >> shift) & 1;
941-
return bit0 | (bit1 << 1);
938+
int idx = RVALUE_AGE_BITMAP_PLANE_INDEX(obj);
939+
int offset = RVALUE_AGE_BITMAP_OFFSET(obj);
940+
int lo = (age_bits[idx * 2] >> offset) & 1;
941+
int hi = (age_bits[idx * 2 + 1] >> offset) & 1;
942+
return lo | (hi << 1);
942943
}
943944

944945
static void
945946
RVALUE_AGE_SET_BITMAP(VALUE obj, int age)
946947
{
947948
RUBY_ASSERT(age <= RVALUE_OLD_AGE);
948949
bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
949-
int idx = BITMAP_INDEX(obj) * 2;
950-
int shift = BITMAP_OFFSET(obj);
951-
bits_t mask = (bits_t)1 << shift;
952-
953-
/* Use atomic operations because the sweep thread may concurrently clear
954-
* age bits for dead objects in the same bitmap word. */
955-
if (age & 1) { age_bits[idx] |= mask; }
956-
else { age_bits[idx] &= ~mask; }
957-
if (age & 2) { age_bits[idx + 1] |= mask; }
958-
else { age_bits[idx + 1] &= ~mask; }
950+
int idx = RVALUE_AGE_BITMAP_PLANE_INDEX(obj);
951+
int offset = RVALUE_AGE_BITMAP_OFFSET(obj);
952+
bits_t mask = (bits_t)1 << offset;
953+
// clear both planes
954+
age_bits[idx * 2] &= ~mask;
955+
age_bits[idx * 2 + 1] &= ~mask;
956+
// set the bits
957+
if (age & 1) age_bits[idx * 2] |= mask;
958+
if (age & 2) age_bits[idx * 2 + 1] |= mask;
959959
}
960960

961961
static void
@@ -2559,6 +2559,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
25592559
}
25602560
#endif
25612561
GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
2562+
GC_ASSERT(RVALUE_AGE_GET(obj) == 0);
25622563
GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
25632564
RBASIC(obj)->flags = flags;
25642565
*((VALUE *)&RBASIC(obj)->klass) = klass;
@@ -3969,6 +3970,8 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
39693970
}
39703971
#endif
39713972

3973+
if (RVALUE_WB_UNPROTECTED(objspace, vp)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(vp), vp);
3974+
39723975
#if RGENGC_CHECK_MODE
39733976
#define CHECK(x) if (x(objspace, vp) != FALSE) rb_bug("obj_free: " #x "(%s) != FALSE", rb_obj_info(vp))
39743977
CHECK(RVALUE_WB_UNPROTECTED);
@@ -3984,6 +3987,7 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
39843987
}
39853988

39863989
(void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE);
3990+
RVALUE_AGE_SET_BITMAP(vp, 0);
39873991
heap_page_add_freeobj(objspace, sweep_page, vp);
39883992
gc_report(3, objspace, "page_sweep: %s (fast path) added to freelist\n", rb_obj_info(vp));
39893993
ctx->freed_slots++;
@@ -3998,6 +4002,7 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
39984002
}
39994003
if (rb_gc_obj_free(objspace, vp)) {
40004004
(void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE);
4005+
RVALUE_AGE_SET_BITMAP(vp, 0);
40014006
heap_page_add_freeobj(objspace, sweep_page, vp);
40024007
gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
40034008
ctx->freed_slots++;
@@ -4140,8 +4145,6 @@ gc_post_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *s
41404145
bits_t slot_mask = heap->slot_bits_mask;
41414146

41424147
// Clear wb_unprotected and age bits for all unmarked slots.
4143-
// Use atomic operations because mutator write barriers may concurrently
4144-
// modify bits for live objects in the same bitmap word.
41454148
{
41464149
bits_t *wb_unprotected_bits = sweep_page->wb_unprotected_bits;
41474150
bits_t *age_bits = sweep_page->age_bits;
@@ -4204,20 +4207,6 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
42044207

42054208
bits_t slot_mask = heap->slot_bits_mask;
42064209

4207-
// Clear wb_unprotected and age bits for all unmarked slots.
4208-
// Use atomic operations because mutator write barriers may concurrently
4209-
// modify bits for live objects in the same bitmap word.
4210-
{
4211-
bits_t *wb_unprotected_bits = sweep_page->wb_unprotected_bits;
4212-
bits_t *age_bits = sweep_page->age_bits;
4213-
for (int i = 0; i < bitmap_plane_count; i++) {
4214-
bits_t unmarked = ~bits[i] & slot_mask;
4215-
wb_unprotected_bits[i] &= ~unmarked;
4216-
age_bits[i * 2] &= ~unmarked;
4217-
age_bits[i * 2 + 1] &= ~unmarked;
4218-
}
4219-
}
4220-
42214210
// Skip out of range slots at the head of the page
42224211
bitset = ~bits[0];
42234212
bitset >>= NUM_IN_PAGE(p);

0 commit comments

Comments
 (0)