summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-08-02 03:23:16 +0900
committerKoichi Sasada <ko1@atdot.net>2020-08-02 03:31:58 +0900
commitf7cf600c8ba483d389ea400071aa2aea2e5a57e0 (patch)
tree2ca7f71544e3ba2334b441a2a3338565e43c45ee
parentd5bed288894d8a7cec277e4c4079abb40c8e1179 (diff)
fix mark bit operation.
To optimize the sweep phase, there is bit operation to set mark bits for out-of-range bits in the last bit_t. However, if there is no out-of-ragnge bits, it set all last bit_t as mark bits and it braek the assumption (unmarked objects will be swept). GC_DEBUG=1 makes sizeof(RVALUE)=64 on my machine and this condition happens. It took me one Saturday to debug this.
-rw-r--r--gc.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/gc.c b/gc.c
index d2d7b06ab2..03649a213d 100644
--- a/gc.c
+++ b/gc.c
@@ -4247,7 +4247,11 @@ gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_
/* create guard : fill 1 out-of-range */
bits[BITMAP_INDEX(p)] |= BITMAP_BIT(p)-1;
- bits[BITMAP_INDEX(p) + sweep_page->total_slots / BITS_BITLENGTH] |= ~(((bits_t)1 << ((NUM_IN_PAGE(p) + sweep_page->total_slots) % BITS_BITLENGTH)) - 1);
+
+ int out_of_range_bits = (NUM_IN_PAGE(p) + sweep_page->total_slots) % BITS_BITLENGTH;
+ if (out_of_range_bits != 0) { // sizeof(RVALUE) == 64
+ bits[BITMAP_INDEX(p) + sweep_page->total_slots / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1);
+ }
for (i=0; i < HEAP_PAGE_BITMAP_LIMIT; i++) {
bitset = ~bits[i];