gc repairs

* Fix calculation of segment index for 32-bit platforms

 * Fix allocation of mark-bit and list-bit arrays in certain unusual
   cases.

 * Fix dirty sweep of records on marked pages that have non-pointer
   fields.

 * Fix allocation of eveen-sized immobile vectors; a pad word needs to
   be cleared.

 * Fix and extend the heap checker (which was used to find several of
   the other problems).

original commit: 8b5e65f5eafac5aea7394901e1dd2f2fc3ccf2bd
This commit is contained in:
Matthew Flatt 2020-05-15 11:20:39 -06:00
parent 96616baa47
commit a106c50798
7 changed files with 94 additions and 24 deletions

View File

@ -17,7 +17,7 @@ m = ti3osx
Cpu = I386
mdclib = -liconv -lm ${ncursesLib}
C = ${CC} ${CPPFLAGS} -m32 -Wpointer-arith -Wall -Wextra -Wno-implicit-fallthrough -Werror -O2 -msse2 -I/opt/X11/include/ ${CFLAGS}
C = ${CC} ${CPPFLAGS} -m32 -Wpointer-arith -Wall -Wextra -Wno-implicit-fallthrough -Werror -g -O2 -msse2 -I/opt/X11/include/ ${CFLAGS}
o = o
mdsrc = i3le.c
mdobj = i3le.o

View File

@ -168,7 +168,7 @@ extern void S_immobilize_object PROTO((ptr v));
extern void S_mobilize_object PROTO((ptr v));
extern ptr S_unregister_guardian PROTO((ptr tconc));
extern void S_compact_heap PROTO((void));
extern void S_check_heap PROTO((IBOOL aftergc));
extern void S_check_heap PROTO((IBOOL aftergc, IGEN target_gen));
/* gc-ocd.c */
extern ptr S_gc_ocd PROTO((ptr tc, IGEN mcg, IGEN tg, ptr count_roots));

26
c/gc.c
View File

@ -239,11 +239,11 @@ static ptr sweep_from;
#if ptr_alignment == 2
# define record_full_marked_mask 0x55
# define record_high_marked_mask 0x40
# define record_high_marked_bit 0x40
# define mask_bits_to_list_bits_mask(m) ((m) | ((m) << 1))
#elif ptr_alignment == 1
# define record_full_marked_mask 0xFF
# define record_high_marked_mask 0x80
# define record_high_marked_bit 0x80
# define mask_bits_to_list_bits_mask(m) (m)
#endif
@ -273,7 +273,7 @@ uptr list_length(ptr ls) {
#define marked(si, p) (si->marked_mask && (si->marked_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p)))
static void init_fully_marked_mask() {
init_mask(fully_marked_mask, 0, 0xFF);
init_mask(fully_marked_mask, target_generation, 0xFF);
}
#ifdef PRESERVE_FLONUM_EQ
@ -287,11 +287,8 @@ static void flonum_set_forwarded(ptr p, seginfo *si) {
static int flonum_is_forwarded_p(ptr p, seginfo *si) {
if (!si->forwarded_flonums)
return 0;
else {
uptr delta = (uptr)UNTYPE(p, type_flonum) - (uptr)build_ptr(si->number, 0);
delta >>= log2_ptr_bytes;
return si->forwarded_flonums[delta >> 3] & (1 << (delta & 0x7));
}
else
return si->forwarded_flonums[segment_bitmap_byte(p)] & segment_bitmap_bit(p);
}
# define FLONUM_FWDADDRESS(p) *(ptr*)(UNTYPE(p, type_flonum))
@ -539,7 +536,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
}
/* perform after ScanDirty */
if (S_checkheap) S_check_heap(0);
if (S_checkheap) S_check_heap(0, mcg);
#ifdef DEBUG
(void)printf("mcg = %x; go? ", mcg); (void)fflush(stdout); (void)getc(stdin);
@ -639,7 +636,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
seginfo *si = SegInfo(ptr_get_segment(p));
if (si->space == space_new) {
if (!si->marked_mask)
init_mask(si->marked_mask, 0, 0);
init_mask(si->marked_mask, tg, 0);
si->marked_mask[segment_bitmap_byte(p)] |= segment_bitmap_bit(p);
}
}
@ -1207,7 +1204,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
S_flush_instruction_cache(tc);
if (S_checkheap) S_check_heap(1);
if (S_checkheap) S_check_heap(1, mcg);
/* post-collection rehashing of tlcs.
must come after any use of relocate.
@ -1659,7 +1656,7 @@ static void sweep_dirty(void) {
if (si->marked_mask[byte-1] == record_full_marked_mask) {
/* next byte is full, so keep looking */
byte--;
} else if (si->marked_mask[byte-1] & record_high_marked_mask) {
} else if (si->marked_mask[byte-1] & record_high_marked_bit) {
/* next byte continues, but is not full, so we can start
there */
if (at_seg != seg) {
@ -1671,6 +1668,7 @@ static void sweep_dirty(void) {
si = SegInfo(at_seg);
} else {
byte--;
bit = record_high_marked_bit;
/* find bit contiguous with highest bit */
while (si->marked_mask[byte] & (bit >> ptr_alignment))
bit >>= ptr_alignment;
@ -2080,14 +2078,14 @@ void copy_and_clear_list_bits(seginfo *oldspacesegments, IGEN tg) {
} else {
if (si->marked_mask) {
/* Besides marking or copying `si->list_bits`, clear bits
where there's no corresopnding mark bit, so we don't try to
where there's no corresponding mark bit, so we don't try to
check forwarding in a future GC */
seginfo *bits_si = SegInfo(ptr_get_segment((ptr)si->list_bits));
if (bits_si->old_space) {
if (bits_si->use_marks) {
if (!bits_si->marked_mask)
init_mask(bits_si->marked_mask, 0, 0);
init_mask(bits_si->marked_mask, tg, 0);
bits_si->marked_mask[segment_bitmap_byte((ptr)si->list_bits)] |= segment_bitmap_bit((ptr)si->list_bits);
} else {
octet *copied_bits;

View File

@ -22,6 +22,7 @@ static void check_heap_dirty_msg PROTO((char *msg, ptr *x));
static IBOOL dirty_listedp PROTO((seginfo *x, IGEN from_g, IGEN to_g));
static void check_dirty_space PROTO((ISPC s));
static void check_dirty PROTO((void));
static void check_locked_object PROTO((ptr p, IBOOL locked, IGEN g, IBOOL aftergc, IGEN mcg));
static IBOOL checkheap_noisy;
@ -510,6 +511,8 @@ static void segment_tell(seg) uptr seg; {
else {
printf(" space-%s", spacename[s1]);
if (si->old_space) printf(" oldspace");
if (si->must_mark) printf(" mustmark");
if (si->marked_mask) printf(" marked");
}
printf("\n");
}
@ -534,7 +537,7 @@ static void check_heap_dirty_msg(msg, x) char *msg; ptr *x; {
printf("to "); segment_tell(addr_get_segment(*x));
}
void S_check_heap(aftergc) IBOOL aftergc; {
void S_check_heap(aftergc, mcg) IBOOL aftergc; IGEN mcg; {
uptr seg; INT d; ISPC s; IGEN g; IDIRTYBYTE dirty; IBOOL found_eos; IGEN pg;
ptr p, *pp1, *pp2, *nl;
iptr i;
@ -573,6 +576,10 @@ void S_check_heap(aftergc) IBOOL aftergc; {
seginfo *si;
for (g = 0; g <= S_G.max_nonstatic_generation; INCRGEN(g)) {
for (si = S_G.occupied_segments[s][g]; si != NULL; si = si->next) {
if (si->generation != g) {
S_checkheap_errors += 1;
printf("!!! segment in wrong occupied_segments list\n");
}
nonstatic_segments += 1;
}
}
@ -619,8 +626,11 @@ void S_check_heap(aftergc) IBOOL aftergc; {
s = si->space;
g = si->generation;
if (si->use_marks)
printf("!!! use_marks set on generation %d segment %#tx\n", g, (ptrdiff_t)seg);
if (s == space_new) {
if (g != 0) {
if (g != 0 && !si->marked_mask) {
S_checkheap_errors += 1;
printf("!!! unexpected generation %d segment %#tx in space_new\n", g, (ptrdiff_t)seg);
}
@ -654,9 +664,18 @@ void S_check_heap(aftergc) IBOOL aftergc; {
|| psi->old_space
|| (psi->marked_mask && !(psi->marked_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p)))) {
S_checkheap_errors += 1;
printf("!!! dangling reference at %#tx to %#tx\n", (ptrdiff_t)pp1, (ptrdiff_t)p);
printf("!!! dangling reference at %#tx to %#tx%s\n", (ptrdiff_t)pp1, (ptrdiff_t)p, (aftergc ? " after gc" : ""));
printf("from: "); segment_tell(seg);
printf("to: "); segment_tell(ptr_get_segment(p));
{
ptr l;
for (l = S_G.locked_objects[psi->generation]; l != Snil; l = Scdr(l))
if (Scar(l) == p)
printf(" in locked\n");
for (l = S_G.unlocked_objects[psi->generation]; l != Snil; l = Scdr(l))
if (Scar(l) == p)
printf(" in unlocked\n");
}
}
}
}
@ -745,8 +764,9 @@ void S_check_heap(aftergc) IBOOL aftergc; {
if (aftergc
&& (s != space_empty)
&& (g == 0
|| (s != space_impure && s != space_symbol && s != space_port && s != space_weakpair && s != space_ephemeron
&& s != space_impure_record && s != space_immobile_impure && s != space_count_impure && s != space_closure))) {
|| (s != space_new && s != space_impure && s != space_symbol && s != space_port && s != space_weakpair && s != space_ephemeron
&& s != space_impure_record && s != space_impure_typed_object
&& s != space_immobile_impure && s != space_count_impure && s != space_closure))) {
for (d = 0; d < cards_per_segment; d += 1) {
if (si->dirty_bytes[d] != 0xff) {
S_checkheap_errors += 1;
@ -760,6 +780,21 @@ void S_check_heap(aftergc) IBOOL aftergc; {
chunk = chunk->next;
}
}
{
for (g = 0; g <= S_G.max_nonstatic_generation; INCRGEN(g)) {
ptr l;
for (l = S_G.locked_objects[g]; l != Snil; l = Scdr(l))
check_locked_object(Scar(l), 1, g, aftergc, mcg);
for (l = S_G.unlocked_objects[g]; l != Snil; l = Scdr(l))
check_locked_object(Scar(l), 0, g, aftergc, mcg);
}
}
if (S_checkheap_errors) {
printf("heap check failed%s\n", (aftergc ? " after gc" : ""));
exit(1);
}
}
static IBOOL dirty_listedp(seginfo *x, IGEN from_g, IGEN to_g) {
@ -826,7 +861,9 @@ static void check_dirty() {
S_checkheap_errors += 1;
printf("!!! (check_dirty): dirty byte = %d for segment %#tx in %d -> %d dirty list\n", mingval, (ptrdiff_t)(si->number), from_g, to_g);
}
if (s != space_new && s != space_impure && s != space_symbol && s != space_port && s != space_impure_record && s != space_weakpair && s != space_ephemeron) {
if (s != space_new && s != space_impure && s != space_symbol && s != space_port
&& s != space_impure_record && s != space_impure_typed_object && s != space_immobile_impure
&& s != space_weakpair && s != space_ephemeron) {
S_checkheap_errors += 1;
printf("!!! (check_dirty): unexpected space %d for dirty segment %#tx\n", s, (ptrdiff_t)(si->number));
}
@ -842,10 +879,40 @@ static void check_dirty() {
check_dirty_space(space_impure_record);
check_dirty_space(space_weakpair);
check_dirty_space(space_ephemeron);
check_dirty_space(space_immobile_impure);
fflush(stdout);
}
static void check_locked_object(ptr p, IBOOL locked, IGEN g, IBOOL aftergc, IGEN mcg)
{
const char *what = (locked ? "locked" : "unlocked");
seginfo *psi = MaybeSegInfo(ptr_get_segment(p));
if (!psi) {
S_checkheap_errors += 1;
printf("!!! generation %d %s object has no segment: %p\n", g, what, p);
} else {
if (psi->generation != g) {
S_checkheap_errors += 1;
printf("!!! generation %d %s object in generation %d segment: %p\n", g, what, psi->generation, p);
}
if (!psi->must_mark && locked) {
S_checkheap_errors += 1;
printf("!!! generation %d %s object not on must-mark page: %p\n", g, what, p);
}
if (!psi->marked_mask) {
if (aftergc && (psi->generation <= mcg)) {
S_checkheap_errors += 1;
printf("!!! %s object not in marked segment: %p\n", what, p);
printf(" in: "); segment_tell(psi->number);
}
} else if (!(psi->marked_mask[segment_bitmap_byte(p)] & segment_bitmap_bit(p))) {
S_checkheap_errors += 1;
printf("!!! generation %d %s object not marked: %p\n", g, what, p);
}
}
}
void S_fixup_counts(ptr counts) {
IGEN g; U64 timestamp;

View File

@ -222,6 +222,11 @@ static ptr s_make_immobile_vector(uptr len, ptr fill) {
for (i = 0; i < len; i++)
INITVECTIT(v, i) = fill;
if (!(len & 0x1)) {
/* pad, since we're not going to copy on a GC */
INITVECTIT(v, len) = FIX(0);
}
return v;
}

View File

@ -115,7 +115,7 @@ typedef int IFASLCODE; /* fasl type codes */
#define ptr_get_segment(p) (((uptr)(p) + typemod - 1) >> segment_offset_bits)
#define segment_bitmap_bytes (bytes_per_segment >> (log2_ptr_bytes+3))
#define segment_bitmap_index(p) ((((uptr)(p) + (typemod-1)) & (bytes_per_segment - 1)) >> log2_ptr_bytes)
#define segment_bitmap_index(p) ((((uptr)(p) + (typemod-1)) & ~(typemod-1) & (bytes_per_segment - 1)) >> log2_ptr_bytes)
#define segment_bitmap_byte(p) (segment_bitmap_index(p) >> 3)
#define segment_bitmap_bits(p, b) ((uptr)(b) << (segment_bitmap_index(p) & 0x7))
#define segment_bitmap_bit(p) segment_bitmap_bits(p,1)

View File

@ -5299,7 +5299,7 @@
(mat compacting
;; try to provoke the GC into putting a record into marked
;; (insteda of copied) space and check the write barrier there
;; (instead of copied) space and check the write barrier there
(let loop ([N 2])
(or (= N 8192)
(let sel-loop ([sels (list car cadr)])