Skip to content

Commit 40c2aa7

Browse files
committed
Use planar age bits like 4.1.0
1 parent 8378219 commit 40c2aa7

1 file changed

Lines changed: 22 additions & 47 deletions

File tree

gc/default/default.c

Lines changed: 22 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -932,31 +932,36 @@ heap_page_in_global_empty_pages_pool(rb_objspace_t *objspace, struct heap_page *
932932
#define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0])
933933
#define GET_HEAP_MARKING_BITS(x) (&GET_HEAP_PAGE(x)->marking_bits[0])
934934

935-
#define RVALUE_AGE_BITMAP_INDEX(n) (NUM_IN_PAGE(n) / (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT))
936-
#define RVALUE_AGE_BITMAP_OFFSET(n) ((NUM_IN_PAGE(n) % (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT)) * RVALUE_AGE_BIT_COUNT)
935+
/* Planar age_bits layout: two bit-planes, each with the same 1-bit-per-slot
936+
* layout as mark_bits. age_bits[i*2] holds bit 0, age_bits[i*2+1] holds
937+
* bit 1 of the age for the slots covered by mark_bits[i]. */
937938

938939
static int
939940
RVALUE_AGE_GET(VALUE obj)
940941
{
941942
bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
942-
return (int)(age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] >> RVALUE_AGE_BITMAP_OFFSET(obj)) & RVALUE_AGE_BIT_MASK;
943+
int idx = BITMAP_INDEX(obj) * 2;
944+
int shift = BITMAP_OFFSET(obj);
945+
int bit0 = (age_bits[idx] >> shift) & 1;
946+
int bit1 = (age_bits[idx + 1] >> shift) & 1;
947+
return bit0 | (bit1 << 1);
943948
}
944949

945950
static void
946951
RVALUE_AGE_SET_BITMAP(VALUE obj, int age)
947952
{
948953
RUBY_ASSERT(age <= RVALUE_OLD_AGE);
949954
bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
950-
// clear the bits
951-
/*age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] &= ~(RVALUE_AGE_BIT_MASK << (RVALUE_AGE_BITMAP_OFFSET(obj)));*/
952-
/*// shift the correct value in*/
953-
/*age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] |= ((bits_t)age << RVALUE_AGE_BITMAP_OFFSET(obj));*/
954-
bits_t clear_mask = RVALUE_AGE_BIT_MASK << RVALUE_AGE_BITMAP_OFFSET(obj);
955-
bits_t set_mask = (bits_t)age << RVALUE_AGE_BITMAP_OFFSET(obj);
956-
// clear the bits
957-
RUBY_ATOMIC_VALUE_AND(age_bits[RVALUE_AGE_BITMAP_INDEX(obj)], ~clear_mask);
958-
// shift the correct value in
959-
RUBY_ATOMIC_VALUE_OR(age_bits[RVALUE_AGE_BITMAP_INDEX(obj)], set_mask);
955+
int idx = BITMAP_INDEX(obj) * 2;
956+
int shift = BITMAP_OFFSET(obj);
957+
bits_t mask = (bits_t)1 << shift;
958+
959+
/* Use atomic operations because the sweep thread may concurrently clear
960+
* age bits for dead objects in the same bitmap word. */
961+
if (age & 1) { RUBY_ATOMIC_VALUE_OR(age_bits[idx], mask); }
962+
else { RUBY_ATOMIC_VALUE_AND(age_bits[idx], ~mask); }
963+
if (age & 2) { RUBY_ATOMIC_VALUE_OR(age_bits[idx + 1], mask); }
964+
else { RUBY_ATOMIC_VALUE_AND(age_bits[idx + 1], ~mask); }
960965
}
961966

962967
static void
@@ -4104,20 +4109,6 @@ deferred_free(rb_objspace_t *objspace, VALUE obj)
41044109
return result;
41054110
}
41064111

4107-
// Spread N bits into 2N bits: bit k → bits 2k and 2k+1.
4108-
// e.g. 0b1010 → 0b11001100
4109-
static inline bits_t
4110-
spread_bits(bits_t x)
4111-
{
4112-
bits_t result = 0;
4113-
for (int b = 0; b < BITS_BITLENGTH / 2; b++) {
4114-
if (x & ((bits_t)1 << b)) {
4115-
result |= (bits_t)RVALUE_AGE_BIT_MASK << (b * RVALUE_AGE_BIT_COUNT);
4116-
}
4117-
}
4118-
return result;
4119-
}
4120-
41214112
// Clear bits for the page that was swept by the background thread.
41224113
static inline void
41234114
gc_post_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_page, bool force_setup_mark_bits)
@@ -4163,16 +4154,8 @@ gc_post_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *s
41634154
for (int i = 0; i < bitmap_plane_count; i++) {
41644155
bits_t unmarked = ~bits[i] & slot_mask;
41654156
RUBY_ATOMIC_VALUE_AND(wb_unprotected_bits[i], ~unmarked);
4166-
// Expand 1-bit-per-slot unmarked mask to 2-bit-per-slot age mask.
4167-
// age_bits[i*2] covers the lower half of slots in mark_bits[i],
4168-
// age_bits[i*2+1] covers the upper half.
4169-
bits_t unmarked_lo = unmarked & (((bits_t)1 << (BITS_BITLENGTH / 2)) - 1);
4170-
bits_t unmarked_hi = unmarked >> (BITS_BITLENGTH / 2);
4171-
// Spread each bit into 2 adjacent bits: bit N -> bits 2N and 2N+1
4172-
bits_t age_mask_lo = spread_bits(unmarked_lo);
4173-
bits_t age_mask_hi = spread_bits(unmarked_hi);
4174-
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2], ~age_mask_lo);
4175-
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2 + 1], ~age_mask_hi);
4157+
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2], ~unmarked);
4158+
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2 + 1], ~unmarked);
41764159
}
41774160
}
41784161

@@ -4245,16 +4228,8 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
42454228
for (int i = 0; i < bitmap_plane_count; i++) {
42464229
bits_t unmarked = ~bits[i] & slot_mask;
42474230
RUBY_ATOMIC_VALUE_AND(wb_unprotected_bits[i], ~unmarked);
4248-
// Expand 1-bit-per-slot unmarked mask to 2-bit-per-slot age mask.
4249-
// age_bits[i*2] covers the lower half of slots in mark_bits[i],
4250-
// age_bits[i*2+1] covers the upper half.
4251-
bits_t unmarked_lo = unmarked & (((bits_t)1 << (BITS_BITLENGTH / 2)) - 1);
4252-
bits_t unmarked_hi = unmarked >> (BITS_BITLENGTH / 2);
4253-
// Spread each bit into 2 adjacent bits: bit N -> bits 2N and 2N+1
4254-
bits_t age_mask_lo = spread_bits(unmarked_lo);
4255-
bits_t age_mask_hi = spread_bits(unmarked_hi);
4256-
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2], ~age_mask_lo);
4257-
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2 + 1], ~age_mask_hi);
4231+
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2], ~unmarked);
4232+
RUBY_ATOMIC_VALUE_AND(age_bits[i * 2 + 1], ~unmarked);
42584233
}
42594234
}
42604235

0 commit comments

Comments
 (0)