|
17 | 17 |
|
18 | 18 | #ifdef BUILDING_MODULAR_GC |
19 | 19 | # define nlz_int64(x) (x == 0 ? 64 : (unsigned int)__builtin_clzll((unsigned long long)x)) |
| 20 | +# define ntz_intptr(x) \ |
| 21 | + ((x) == 0 ? (int)(sizeof(uintptr_t) * CHAR_BIT) : \ |
| 22 | + (int)__builtin_ctzll((unsigned long long)(x))) |
20 | 23 | #else |
21 | 24 | # include "internal/bits.h" |
22 | 25 | #endif |
@@ -3470,81 +3473,83 @@ struct gc_sweep_context { |
3470 | 3473 | }; |
3471 | 3474 |
|
3472 | 3475 | static inline void |
3473 | | -gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct gc_sweep_context *ctx) |
| 3476 | +gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t base, bits_t bitset, struct gc_sweep_context *ctx) |
3474 | 3477 | { |
3475 | 3478 | struct heap_page *sweep_page = ctx->page; |
3476 | | - short slot_size = sweep_page->slot_size; |
3477 | | - short slot_bits = slot_size / BASE_SLOT_SIZE; |
3478 | | - GC_ASSERT(slot_bits > 0); |
3479 | 3479 |
|
| 3480 | + /* Callers guarantee bitset != 0 on entry, and mask it with |
| 3481 | + * heap->slot_bits_mask so only the aligned starting bit of each slot is |
| 3482 | + * set. The lowest set bit therefore always lands on a slot boundary, and |
| 3483 | + * we can jump straight from one marked slot to the next instead of |
| 3484 | + * walking every slot in the plane. */ |
3480 | 3485 | do { |
| 3486 | + int bit = ntz_intptr(bitset); |
| 3487 | + uintptr_t p = base + (uintptr_t)bit * BASE_SLOT_SIZE; |
3481 | 3488 | VALUE vp = (VALUE)p; |
3482 | 3489 | GC_ASSERT(vp % BASE_SLOT_SIZE == 0); |
| 3490 | + GC_ASSERT(((uintptr_t)bit * BASE_SLOT_SIZE) % sweep_page->slot_size == 0); |
3483 | 3491 |
|
3484 | 3492 | rb_asan_unpoison_object(vp, false); |
3485 | | - if (bitset & 1) { |
3486 | | - switch (BUILTIN_TYPE(vp)) { |
3487 | | - default: /* majority case */ |
3488 | | - gc_report(2, objspace, "page_sweep: free %p\n", (void *)p); |
| 3493 | + switch (BUILTIN_TYPE(vp)) { |
| 3494 | + default: /* majority case */ |
| 3495 | + gc_report(2, objspace, "page_sweep: free %p\n", (void *)p); |
3489 | 3496 | #if RGENGC_CHECK_MODE |
3490 | | - if (!is_full_marking(objspace)) { |
3491 | | - if (RVALUE_OLD_P(objspace, vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p); |
3492 | | - if (RVALUE_REMEMBERED(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p); |
3493 | | - } |
| 3497 | + if (!is_full_marking(objspace)) { |
| 3498 | + if (RVALUE_OLD_P(objspace, vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p); |
| 3499 | + if (RVALUE_REMEMBERED(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p); |
| 3500 | + } |
3494 | 3501 | #endif |
3495 | 3502 |
|
3496 | | - if (RVALUE_WB_UNPROTECTED(objspace, vp)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(vp), vp); |
| 3503 | + if (RVALUE_WB_UNPROTECTED(objspace, vp)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(vp), vp); |
3497 | 3504 |
|
3498 | 3505 | #if RGENGC_CHECK_MODE |
3499 | 3506 | #define CHECK(x) if (x(objspace, vp) != FALSE) rb_bug("obj_free: " #x "(%s) != FALSE", rb_obj_info(vp)) |
3500 | | - CHECK(RVALUE_WB_UNPROTECTED); |
3501 | | - CHECK(RVALUE_MARKED); |
3502 | | - CHECK(RVALUE_MARKING); |
3503 | | - CHECK(RVALUE_UNCOLLECTIBLE); |
| 3507 | + CHECK(RVALUE_WB_UNPROTECTED); |
| 3508 | + CHECK(RVALUE_MARKED); |
| 3509 | + CHECK(RVALUE_MARKING); |
| 3510 | + CHECK(RVALUE_UNCOLLECTIBLE); |
3504 | 3511 | #undef CHECK |
3505 | 3512 | #endif |
3506 | 3513 |
|
3507 | | - rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ); |
| 3514 | + rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ); |
3508 | 3515 |
|
3509 | | - rb_gc_obj_free_vm_weak_references(vp); |
3510 | | - if (rb_gc_obj_free(objspace, vp)) { |
3511 | | - // always add free slots back to the swept pages freelist, |
3512 | | - // so that if we're compacting, we can re-use the slots |
3513 | | - (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE); |
3514 | | - RVALUE_AGE_SET_BITMAP(vp, 0); |
3515 | | - heap_page_add_freeobj(objspace, sweep_page, vp); |
3516 | | - gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp)); |
3517 | | - ctx->freed_slots++; |
3518 | | - } |
3519 | | - else { |
3520 | | - ctx->final_slots++; |
3521 | | - } |
3522 | | - break; |
3523 | | - |
3524 | | - case T_MOVED: |
3525 | | - if (objspace->flags.during_compacting) { |
3526 | | - /* The sweep cursor shouldn't have made it to any |
3527 | | - * T_MOVED slots while the compact flag is enabled. |
3528 | | - * The sweep cursor and compact cursor move in |
3529 | | - * opposite directions, and when they meet references will |
3530 | | - * get updated and "during_compacting" should get disabled */ |
3531 | | - rb_bug("T_MOVED shouldn't be seen until compaction is finished"); |
3532 | | - } |
3533 | | - gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp)); |
3534 | | - ctx->empty_slots++; |
| 3516 | + rb_gc_obj_free_vm_weak_references(vp); |
| 3517 | + if (rb_gc_obj_free(objspace, vp)) { |
| 3518 | + // always add free slots back to the swept pages freelist, |
| 3519 | + // so that if we're compacting, we can re-use the slots |
| 3520 | + (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE); |
3535 | 3521 | RVALUE_AGE_SET_BITMAP(vp, 0); |
3536 | 3522 | heap_page_add_freeobj(objspace, sweep_page, vp); |
3537 | | - break; |
3538 | | - case T_ZOMBIE: |
3539 | | - /* already counted */ |
3540 | | - break; |
3541 | | - case T_NONE: |
3542 | | - ctx->empty_slots++; /* already freed */ |
3543 | | - break; |
| 3523 | + gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp)); |
| 3524 | + ctx->freed_slots++; |
| 3525 | + } |
| 3526 | + else { |
| 3527 | + ctx->final_slots++; |
3544 | 3528 | } |
| 3529 | + break; |
| 3530 | + |
| 3531 | + case T_MOVED: |
| 3532 | + if (objspace->flags.during_compacting) { |
| 3533 | + /* The sweep cursor shouldn't have made it to any |
| 3534 | + * T_MOVED slots while the compact flag is enabled. |
| 3535 | + * The sweep cursor and compact cursor move in |
| 3536 | + * opposite directions, and when they meet references will |
| 3537 | + * get updated and "during_compacting" should get disabled */ |
| 3538 | + rb_bug("T_MOVED shouldn't be seen until compaction is finished"); |
| 3539 | + } |
| 3540 | + gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp)); |
| 3541 | + ctx->empty_slots++; |
| 3542 | + RVALUE_AGE_SET_BITMAP(vp, 0); |
| 3543 | + heap_page_add_freeobj(objspace, sweep_page, vp); |
| 3544 | + break; |
| 3545 | + case T_ZOMBIE: |
| 3546 | + /* already counted */ |
| 3547 | + break; |
| 3548 | + case T_NONE: |
| 3549 | + ctx->empty_slots++; /* already freed */ |
| 3550 | + break; |
3545 | 3551 | } |
3546 | | - p += slot_size; |
3547 | | - bitset >>= slot_bits; |
| 3552 | + bitset &= bitset - 1; |
3548 | 3553 | } while (bitset); |
3549 | 3554 | } |
3550 | 3555 |
|
|
0 commit comments