incremental GC: avoid extra traverals of weak-link lists
When incremental mode has already gone through weak boxes and arrays, a major GC doesn't need to see them again.
This commit is contained in:
parent
ad2dd24fb8
commit
46fe53fadb
|
@ -3390,6 +3390,8 @@ static NewGC *init_type_tags_worker(NewGC *inheritgc, NewGC *parentgc,
|
||||||
GC_add_roots(&gc->park_fsave, (char *)&gc->park_fsave + sizeof(gc->park_fsave) + 1);
|
GC_add_roots(&gc->park_fsave, (char *)&gc->park_fsave + sizeof(gc->park_fsave) + 1);
|
||||||
GC_add_roots(&gc->park_isave, (char *)&gc->park_isave + sizeof(gc->park_isave) + 1);
|
GC_add_roots(&gc->park_isave, (char *)&gc->park_isave + sizeof(gc->park_isave) + 1);
|
||||||
|
|
||||||
|
gc->weak_incremental_done = WEAK_INCREMENTAL_DONE_1;
|
||||||
|
|
||||||
return gc;
|
return gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5710,17 +5712,13 @@ static void mark_and_finalize_all(NewGC *gc, int old_gen TIME_FORMAL_ARGS)
|
||||||
TIME_STEP("marked");
|
TIME_STEP("marked");
|
||||||
|
|
||||||
if (old_gen) {
|
if (old_gen) {
|
||||||
/* move gen1 into active positions: */
|
|
||||||
init_weak_boxes(gc, 1);
|
|
||||||
init_weak_arrays(gc, 1);
|
|
||||||
init_ephemerons(gc, 1);
|
|
||||||
GC_ASSERT(!gc->fnl_gen1);
|
GC_ASSERT(!gc->fnl_gen1);
|
||||||
gc->fnl_gen1 = 1;
|
gc->fnl_gen1 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
zero_weak_boxes(gc, 0, 0);
|
zero_weak_boxes(gc, 0, 0, old_gen);
|
||||||
zero_weak_arrays(gc, 0);
|
zero_weak_arrays(gc, 0, old_gen);
|
||||||
zero_remaining_ephemerons(gc);
|
zero_remaining_ephemerons(gc, old_gen);
|
||||||
|
|
||||||
TIME_STEP("zeroed");
|
TIME_STEP("zeroed");
|
||||||
|
|
||||||
|
@ -5729,7 +5727,7 @@ static void mark_and_finalize_all(NewGC *gc, int old_gen TIME_FORMAL_ARGS)
|
||||||
propagate_marks(gc);
|
propagate_marks(gc);
|
||||||
else
|
else
|
||||||
propagate_incremental_marks(gc, 0, -1);
|
propagate_incremental_marks(gc, 0, -1);
|
||||||
zero_weak_boxes(gc, 1, 0);
|
zero_weak_boxes(gc, 1, 0, old_gen);
|
||||||
|
|
||||||
check_finalizers(gc, 3, old_gen);
|
check_finalizers(gc, 3, old_gen);
|
||||||
if (!old_gen)
|
if (!old_gen)
|
||||||
|
@ -5741,10 +5739,10 @@ static void mark_and_finalize_all(NewGC *gc, int old_gen TIME_FORMAL_ARGS)
|
||||||
gc->GC_post_propagate_hook(gc);
|
gc->GC_post_propagate_hook(gc);
|
||||||
|
|
||||||
/* for any new ones that appeared: */
|
/* for any new ones that appeared: */
|
||||||
zero_weak_boxes(gc, 0, 1);
|
zero_weak_boxes(gc, 0, 1, old_gen);
|
||||||
zero_weak_boxes(gc, 1, 1);
|
zero_weak_boxes(gc, 1, 1, old_gen);
|
||||||
zero_weak_arrays(gc, 1);
|
zero_weak_arrays(gc, 1, old_gen);
|
||||||
zero_remaining_ephemerons(gc);
|
zero_remaining_ephemerons(gc, old_gen);
|
||||||
|
|
||||||
if (old_gen)
|
if (old_gen)
|
||||||
gc->fnl_gen1 = 0;
|
gc->fnl_gen1 = 0;
|
||||||
|
@ -6024,8 +6022,17 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
|
||||||
|
|
||||||
gc->no_further_modifications = 0;
|
gc->no_further_modifications = 0;
|
||||||
|
|
||||||
if (gc->gc_full)
|
if (gc->gc_full) {
|
||||||
free_incremental_admin_pages(gc);
|
free_incremental_admin_pages(gc);
|
||||||
|
if (gc->started_incremental) {
|
||||||
|
/* Flip `weak_incremental_done`, so we can detect
|
||||||
|
whether a weak reference is handled on a given pass. */
|
||||||
|
if (gc->weak_incremental_done == WEAK_INCREMENTAL_DONE_1)
|
||||||
|
gc->weak_incremental_done = WEAK_INCREMENTAL_DONE_2;
|
||||||
|
else
|
||||||
|
gc->weak_incremental_done = WEAK_INCREMENTAL_DONE_1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
check_excessive_free_pages(gc);
|
check_excessive_free_pages(gc);
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,8 @@ typedef struct NewGC {
|
||||||
GC_Ephemeron *ephemerons, *inc_ephemerons, *bp_ephemerons;
|
GC_Ephemeron *ephemerons, *inc_ephemerons, *bp_ephemerons;
|
||||||
int num_last_seen_ephemerons;
|
int num_last_seen_ephemerons;
|
||||||
|
|
||||||
|
void *weak_incremental_done;
|
||||||
|
|
||||||
Allocator *saved_allocator;
|
Allocator *saved_allocator;
|
||||||
|
|
||||||
#ifdef MZ_USE_PLACES
|
#ifdef MZ_USE_PLACES
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
Type_Tag
|
Type_Tag
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define WEAK_INCREMENTAL_DONE_1 ((void *)0x1)
|
||||||
|
#define WEAK_INCREMENTAL_DONE_2 ((void *)0x3)
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* weak arrays */
|
/* weak arrays */
|
||||||
|
@ -42,12 +44,17 @@ static int mark_weak_array(void *p, struct NewGC *gc)
|
||||||
|
|
||||||
if (gc->doing_memory_accounting) {
|
if (gc->doing_memory_accounting) {
|
||||||
/* skip */
|
/* skip */
|
||||||
} else if (gc->inc_gen1 && !gc->fnl_gen1) {
|
} else if (gc->inc_gen1) {
|
||||||
/* inc_next field is at the end of the `data` array: */
|
/* inc_next field is at the end of the `data` array: */
|
||||||
a->data[a->count] = gc->inc_weak_arrays;
|
a->data[a->count] = gc->inc_weak_arrays;
|
||||||
gc->inc_weak_arrays = a;
|
gc->inc_weak_arrays = a;
|
||||||
} else if (gc->during_backpointer) {
|
} else if (gc->during_backpointer) {
|
||||||
if (!gc->gc_full) {
|
if (!gc->gc_full
|
||||||
|
|| (gc->started_incremental
|
||||||
|
/* `a` must have been marked and must be in the old
|
||||||
|
generation, or we wouldn't get here; `a` may have been
|
||||||
|
fully processed in incremental mode, though */
|
||||||
|
&& (a->data[a->count] == gc->weak_incremental_done))) {
|
||||||
/* Keep backpointered weak arrays separate, because we
|
/* Keep backpointered weak arrays separate, because we
|
||||||
should not merge them to the incremental list
|
should not merge them to the incremental list
|
||||||
in incremental mode. */
|
in incremental mode. */
|
||||||
|
@ -57,6 +64,8 @@ static int mark_weak_array(void *p, struct NewGC *gc)
|
||||||
} else {
|
} else {
|
||||||
a->next = gc->weak_arrays;
|
a->next = gc->weak_arrays;
|
||||||
gc->weak_arrays = a;
|
gc->weak_arrays = a;
|
||||||
|
if (gc->gc_full)
|
||||||
|
a->data[a->count] = NULL; /* ensure not a future weak_incremental_done */
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CHECKS
|
#if CHECKS
|
||||||
|
@ -158,13 +167,15 @@ static GC_Weak_Array *append_weak_arrays(GC_Weak_Array *wa, GC_Weak_Array *bp_wa
|
||||||
return bp_wa;
|
return bp_wa;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zero_weak_arrays(GCTYPE *gc, int force_zero)
|
static void zero_weak_arrays(GCTYPE *gc, int force_zero, int from_inc)
|
||||||
{
|
{
|
||||||
GC_Weak_Array *wa;
|
GC_Weak_Array *wa;
|
||||||
int i, num_gen0;
|
int i, num_gen0;
|
||||||
|
|
||||||
GC_ASSERT(!gc->bp_weak_arrays || !gc->gc_full);
|
if (from_inc) {
|
||||||
|
wa = gc->inc_weak_arrays;
|
||||||
|
num_gen0 = 0;
|
||||||
|
} else
|
||||||
wa = append_weak_arrays(gc->weak_arrays, gc->bp_weak_arrays, &num_gen0);
|
wa = append_weak_arrays(gc->weak_arrays, gc->bp_weak_arrays, &num_gen0);
|
||||||
|
|
||||||
if (gc->gc_full || !gc->started_incremental)
|
if (gc->gc_full || !gc->started_incremental)
|
||||||
|
@ -191,13 +202,22 @@ static void zero_weak_arrays(GCTYPE *gc, int force_zero)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (from_inc) {
|
||||||
|
GC_Weak_Array *next;
|
||||||
|
next = (GC_Weak_Array *)wa->data[wa->count];
|
||||||
|
wa->data[wa->count] = gc->weak_incremental_done;
|
||||||
|
wa = next;
|
||||||
|
} else
|
||||||
wa = wa->next;
|
wa = wa->next;
|
||||||
num_gen0--;
|
num_gen0--;
|
||||||
}
|
}
|
||||||
|
if (from_inc)
|
||||||
|
gc->inc_weak_arrays = NULL;
|
||||||
|
else {
|
||||||
gc->weak_arrays = NULL;
|
gc->weak_arrays = NULL;
|
||||||
gc->bp_weak_arrays = NULL;
|
gc->bp_weak_arrays = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* weak boxes */
|
/* weak boxes */
|
||||||
|
@ -236,12 +256,17 @@ static int mark_weak_box(void *p, struct NewGC *gc)
|
||||||
|
|
||||||
if (gc->doing_memory_accounting) {
|
if (gc->doing_memory_accounting) {
|
||||||
/* skip */
|
/* skip */
|
||||||
} else if (gc->inc_gen1 && !gc->fnl_gen1) {
|
} else if (gc->inc_gen1) {
|
||||||
check_weak_box_not_already_in_inc_chain(wb, gc->inc_weak_boxes[wb->is_late]);
|
check_weak_box_not_already_in_inc_chain(wb, gc->inc_weak_boxes[wb->is_late]);
|
||||||
wb->inc_next = gc->inc_weak_boxes[wb->is_late];
|
wb->inc_next = gc->inc_weak_boxes[wb->is_late];
|
||||||
gc->inc_weak_boxes[wb->is_late] = wb;
|
gc->inc_weak_boxes[wb->is_late] = wb;
|
||||||
} else if (gc->during_backpointer) {
|
} else if (gc->during_backpointer) {
|
||||||
if (!gc->gc_full && (wb->val || gc->started_incremental)) {
|
if ((!gc->gc_full
|
||||||
|
|| (gc->started_incremental
|
||||||
|
/* see note with `gc->weak_incremental_done` for weak arrays */
|
||||||
|
&& (wb->inc_next == gc->weak_incremental_done)
|
||||||
|
&& wb->val))
|
||||||
|
&& (wb->val || gc->started_incremental)) {
|
||||||
/* Keep backpointered weak arrays separate, because we
|
/* Keep backpointered weak arrays separate, because we
|
||||||
should not merge them to the incremental list
|
should not merge them to the incremental list
|
||||||
in incremental mode. */
|
in incremental mode. */
|
||||||
|
@ -255,6 +280,8 @@ static int mark_weak_box(void *p, struct NewGC *gc)
|
||||||
check_weak_box_not_already_in_chain(wb, gc->bp_weak_boxes[wb->is_late]);
|
check_weak_box_not_already_in_chain(wb, gc->bp_weak_boxes[wb->is_late]);
|
||||||
wb->next = gc->weak_boxes[wb->is_late];
|
wb->next = gc->weak_boxes[wb->is_late];
|
||||||
gc->weak_boxes[wb->is_late] = wb;
|
gc->weak_boxes[wb->is_late] = wb;
|
||||||
|
if (gc->gc_full)
|
||||||
|
wb->inc_next = NULL; /* ensure not a future weak_incremental_done */
|
||||||
}
|
}
|
||||||
|
|
||||||
return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
|
return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
|
||||||
|
@ -340,18 +367,21 @@ static GC_Weak_Box *append_weak_boxes(GC_Weak_Box *wb, GC_Weak_Box *bp_wb, int *
|
||||||
return bp_wb;
|
return bp_wb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero)
|
static void zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc)
|
||||||
{
|
{
|
||||||
GC_Weak_Box *wb;
|
GC_Weak_Box *wb;
|
||||||
int num_gen0;
|
int num_gen0;
|
||||||
|
|
||||||
GC_ASSERT(!gc->bp_weak_boxes[is_late] || !gc->gc_full);
|
if (from_inc) {
|
||||||
|
wb = gc->inc_weak_boxes[is_late];
|
||||||
|
num_gen0 = 0;
|
||||||
|
} else {
|
||||||
wb = append_weak_boxes(gc->weak_boxes[is_late],
|
wb = append_weak_boxes(gc->weak_boxes[is_late],
|
||||||
gc->bp_weak_boxes[is_late],
|
gc->bp_weak_boxes[is_late],
|
||||||
&num_gen0);
|
&num_gen0);
|
||||||
if (gc->gc_full || !gc->started_incremental)
|
if (gc->gc_full || !gc->started_incremental)
|
||||||
num_gen0 = 0;
|
num_gen0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
while (wb) {
|
while (wb) {
|
||||||
GC_ASSERT(is_marked(gc, wb));
|
GC_ASSERT(is_marked(gc, wb));
|
||||||
|
@ -384,18 +414,29 @@ static void zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero)
|
||||||
if (!is_in_generation_half(gc, wb)) {
|
if (!is_in_generation_half(gc, wb)) {
|
||||||
/* For incremental mode, preserve this weak box
|
/* For incremental mode, preserve this weak box
|
||||||
in the incremental list for re-checking later. */
|
in the incremental list for re-checking later. */
|
||||||
|
check_weak_box_not_already_in_inc_chain(wb, gc->inc_weak_boxes[wb->is_late]);
|
||||||
wb->inc_next = gc->inc_weak_boxes[is_late];
|
wb->inc_next = gc->inc_weak_boxes[is_late];
|
||||||
gc->inc_weak_boxes[is_late] = wb;
|
gc->inc_weak_boxes[is_late] = wb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (from_inc) {
|
||||||
|
GC_Weak_Box *next;
|
||||||
|
next = wb->inc_next;
|
||||||
|
wb->inc_next = gc->weak_incremental_done;
|
||||||
|
wb = next;
|
||||||
|
} else
|
||||||
wb = wb->next;
|
wb = wb->next;
|
||||||
num_gen0--;
|
num_gen0--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset, in case we have a second round */
|
/* reset, in case we have a second round */
|
||||||
|
if (from_inc) {
|
||||||
|
gc->inc_weak_boxes[is_late] = NULL;
|
||||||
|
} else {
|
||||||
gc->weak_boxes[is_late] = NULL;
|
gc->weak_boxes[is_late] = NULL;
|
||||||
gc->bp_weak_boxes[is_late] = NULL;
|
gc->bp_weak_boxes[is_late] = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* ephemeron */
|
/* ephemeron */
|
||||||
|
@ -412,7 +453,7 @@ static int mark_ephemeron(void *p, struct NewGC *gc)
|
||||||
|
|
||||||
if (eph->val) {
|
if (eph->val) {
|
||||||
GC_ASSERT(!gc->doing_memory_accounting);
|
GC_ASSERT(!gc->doing_memory_accounting);
|
||||||
if (gc->inc_gen1 && !gc->fnl_gen1) {
|
if (gc->inc_gen1) {
|
||||||
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) {
|
||||||
|
@ -559,15 +600,23 @@ static int mark_ready_ephemerons(GCTYPE *gc, int inc_gen1)
|
||||||
return did_one;
|
return did_one;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zero_remaining_ephemerons(GCTYPE *gc)
|
static void zero_remaining_ephemerons(GCTYPE *gc, int from_inc)
|
||||||
{
|
{
|
||||||
GC_Ephemeron *eph;
|
GC_Ephemeron *eph;
|
||||||
|
|
||||||
/* After level-1 finalization, any remaining ephemerons
|
/* After level-1 finalization, any remaining ephemerons
|
||||||
should be zeroed. */
|
should be zeroed. */
|
||||||
|
if (from_inc) {
|
||||||
|
for (eph = gc->inc_ephemerons; eph; eph = eph->inc_next) {
|
||||||
|
eph->key = NULL;
|
||||||
|
eph->val = NULL;
|
||||||
|
}
|
||||||
|
gc->inc_ephemerons = NULL;
|
||||||
|
} else {
|
||||||
for (eph = gc->ephemerons; eph; eph = eph->next) {
|
for (eph = gc->ephemerons; eph; eph = eph->next) {
|
||||||
eph->key = NULL;
|
eph->key = NULL;
|
||||||
eph->val = NULL;
|
eph->val = NULL;
|
||||||
}
|
}
|
||||||
gc->ephemerons = NULL;
|
gc->ephemerons = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user