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,7 +4163,6 @@ 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);
@ -4181,15 +4180,12 @@ static int propagate_incremental_marks(NewGC *gc, int do_emph, int fuel)
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;
} }