incremental GC: fix handling of ephemerons

Fix the case that an old-generation finalizer ends up
on a modified page after all old-generation marking
is complete.

Also, make sure epehemerons are checked after previous
marking that may have left the stack empty.
This commit is contained in:
Matthew Flatt 2015-12-01 04:18:52 -07:00
parent 03302c3f30
commit bef34606cb
2 changed files with 27 additions and 22 deletions

View File

@ -4163,33 +4163,29 @@ static void propagate_marks_plus_ephemerons(NewGC *gc)
static int propagate_incremental_marks(NewGC *gc, int do_emph, int fuel) static int propagate_incremental_marks(NewGC *gc, int do_emph, int fuel)
{ {
if (gc->inc_mark_stack) { int save_inc, save_check, init_fuel = fuel;
int save_inc, save_check, init_fuel = fuel;
GC_ASSERT(gc->mark_gen1); GC_ASSERT(gc->mark_gen1);
save_inc = gc->inc_gen1; save_inc = gc->inc_gen1;
save_check = gc->check_gen1; save_check = gc->check_gen1;
gc->inc_gen1 = 1; gc->inc_gen1 = 1;
gc->check_gen1 = 1; gc->check_gen1 = 1;
do { do {
void *p; void *p;
while (fuel && pop_ptr(gc, &p, 1)) { while (fuel && pop_ptr(gc, &p, 1)) {
GCDEBUG((DEBUGOUTF, "Popped incremental pointer %p\n", p)); GCDEBUG((DEBUGOUTF, "Popped incremental pointer %p\n", p));
propagate_marks_worker(gc, p, 1); propagate_marks_worker(gc, p, 1);
fuel--; fuel--;
} }
} while (do_emph } while (do_emph && fuel && mark_ready_ephemerons(gc, 1));
&& (fuel || mark_stack_is_empty(gc->inc_mark_stack))
&& mark_ready_ephemerons(gc, 1));
gc->inc_prop_count += (init_fuel - fuel); gc->inc_prop_count += (init_fuel - fuel);
gc->inc_gen1 = save_inc; gc->inc_gen1 = save_inc;
gc->check_gen1 = save_check; gc->check_gen1 = save_check;
}
return fuel; return fuel;
} }
@ -5782,6 +5778,8 @@ static int mark_and_finalize_all(NewGC *gc, int old_gen TIME_FORMAL_ARGS)
if (!old_gen) if (!old_gen)
propagate_marks_plus_ephemerons(gc); propagate_marks_plus_ephemerons(gc);
else
(void)propagate_incremental_marks(gc, 1, -1);
check_finalizers(gc, 1, old_gen); check_finalizers(gc, 1, old_gen);
if (!old_gen) if (!old_gen)

View File

@ -474,7 +474,14 @@ static int mark_ephemeron(void *p, struct NewGC *gc)
eph->inc_next = gc->inc_ephemerons; eph->inc_next = gc->inc_ephemerons;
gc->inc_ephemerons = eph; gc->inc_ephemerons = eph;
} else if (gc->during_backpointer) { } else if (gc->during_backpointer) {
if (!gc->gc_full) { if (!gc->gc_full
/* If this old-generation object is not yet marked
and we're finishing an incremental pass, then
it won't get marked (and it can only refer to
other old-generation objects), so ignore in that case */
&& (gc->mark_gen1
|| !gc->started_incremental
|| !gc->finishing_incremental)) {
eph->next = gc->bp_ephemerons; eph->next = gc->bp_ephemerons;
gc->bp_ephemerons = eph; gc->bp_ephemerons = eph;
} }