@@ -948,9 +948,15 @@ RVALUE_AGE_SET_BITMAP(VALUE obj, int age)
948948 RUBY_ASSERT (age <= RVALUE_OLD_AGE );
949949 bits_t * age_bits = GET_HEAP_PAGE (obj )-> age_bits ;
950950 // clear the bits
951- age_bits [RVALUE_AGE_BITMAP_INDEX (obj )] &= ~(RVALUE_AGE_BIT_MASK << (RVALUE_AGE_BITMAP_OFFSET (obj )));
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 );
952958 // shift the correct value in
953- age_bits [RVALUE_AGE_BITMAP_INDEX (obj )] |= (( bits_t ) age << RVALUE_AGE_BITMAP_OFFSET ( obj ) );
959+ RUBY_ATOMIC_VALUE_OR ( age_bits [RVALUE_AGE_BITMAP_INDEX (obj )], set_mask );
954960}
955961
956962static void
@@ -4098,6 +4104,20 @@ deferred_free(rb_objspace_t *objspace, VALUE obj)
40984104 return result ;
40994105}
41004106
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+
41014121// Clear bits for the page that was swept by the background thread.
41024122static inline void
41034123gc_post_sweep_page (rb_objspace_t * objspace , rb_heap_t * heap , struct heap_page * sweep_page , bool force_setup_mark_bits )
@@ -4143,8 +4163,16 @@ gc_post_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *s
41434163 for (int i = 0 ; i < bitmap_plane_count ; i ++ ) {
41444164 bits_t unmarked = ~bits [i ] & slot_mask ;
41454165 RUBY_ATOMIC_VALUE_AND (wb_unprotected_bits [i ], ~unmarked );
4146- RUBY_ATOMIC_VALUE_AND (age_bits [i * 2 ], ~unmarked );
4147- RUBY_ATOMIC_VALUE_AND (age_bits [i * 2 + 1 ], ~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 );
41484176 }
41494177 }
41504178
@@ -4217,8 +4245,16 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
42174245 for (int i = 0 ; i < bitmap_plane_count ; i ++ ) {
42184246 bits_t unmarked = ~bits [i ] & slot_mask ;
42194247 RUBY_ATOMIC_VALUE_AND (wb_unprotected_bits [i ], ~unmarked );
4220- RUBY_ATOMIC_VALUE_AND (age_bits [i * 2 ], ~unmarked );
4221- RUBY_ATOMIC_VALUE_AND (age_bits [i * 2 + 1 ], ~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 );
42224258 }
42234259 }
42244260
0 commit comments