inctemental GC: make finalization more incremental
Allow the process of discovering finalizers to be incremental, including allow interruptions in later levels of ordered finalization.
This commit is contained in:
parent
6f106d9adc
commit
c0f4eb8287
|
@ -23,39 +23,28 @@
|
|||
#undef splay_insert
|
||||
#undef splay_delete
|
||||
|
||||
static void remove_finalizer(Fnl *fnl, int gen0, GCTYPE *gc)
|
||||
static void remove_finalizer(Fnl *fnl, int lvl, GCTYPE *gc)
|
||||
{
|
||||
if (fnl->prev)
|
||||
fnl->prev->next = fnl->next;
|
||||
else {
|
||||
if (gen0)
|
||||
gc->gen0_finalizers = fnl->next;
|
||||
else
|
||||
gc->finalizers = fnl->next;
|
||||
}
|
||||
else
|
||||
gc->finalizers[lvl] = fnl->next;
|
||||
if (fnl->next)
|
||||
fnl->next->prev = fnl->prev;
|
||||
|
||||
if (gen0)
|
||||
gc->splayed_gen0_finalizers = fnl_splay_delete((intptr_t)fnl->p, gc->splayed_gen0_finalizers);
|
||||
else
|
||||
gc->splayed_finalizers = fnl_splay_delete((intptr_t)fnl->p, gc->splayed_finalizers);
|
||||
gc->splayed_finalizers[lvl] = fnl_splay_delete((intptr_t)fnl->p, gc->splayed_finalizers[lvl]);
|
||||
}
|
||||
|
||||
static void add_finalizer(Fnl *fnl, int gen0, GCTYPE *gc)
|
||||
static void add_finalizer(Fnl *fnl, int lvl, GCTYPE *gc)
|
||||
{
|
||||
fnl->next = (gen0 ? gc->gen0_finalizers : gc->finalizers);
|
||||
fnl->next = gc->finalizers[lvl];
|
||||
|
||||
fnl->prev = NULL;
|
||||
if (fnl->next)
|
||||
fnl->next->prev = fnl;
|
||||
|
||||
if (gen0) {
|
||||
gc->gen0_finalizers = fnl;
|
||||
gc->splayed_gen0_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_gen0_finalizers);
|
||||
} else {
|
||||
gc->finalizers = fnl;
|
||||
gc->splayed_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers);
|
||||
}
|
||||
gc->finalizers[lvl] = fnl;
|
||||
gc->splayed_finalizers[lvl] = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers[lvl]);
|
||||
}
|
||||
|
||||
void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *data),
|
||||
|
@ -64,6 +53,7 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
|
|||
{
|
||||
GCTYPE *gc = GC_get_GC();
|
||||
Fnl *fnl;
|
||||
int lvl;
|
||||
|
||||
if (!is_finalizable_page(gc, p)) {
|
||||
/* Never collected. Don't finalize it. */
|
||||
|
@ -72,17 +62,18 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
|
|||
return;
|
||||
}
|
||||
|
||||
gc->splayed_gen0_finalizers = fnl_splay((intptr_t)p, gc->splayed_gen0_finalizers);
|
||||
fnl = gc->splayed_gen0_finalizers;
|
||||
if (!fnl || (fnl->p != p)) {
|
||||
gc->splayed_finalizers = fnl_splay((intptr_t)p, gc->splayed_finalizers);
|
||||
fnl = gc->splayed_finalizers;
|
||||
if (!fnl || (fnl->p != p))
|
||||
for (lvl = 0; lvl < NUM_FNL_LEVELS; lvl++) {
|
||||
gc->splayed_finalizers[lvl] = fnl_splay((intptr_t)p, gc->splayed_finalizers[lvl]);
|
||||
fnl = gc->splayed_finalizers[lvl];
|
||||
if (!fnl || (fnl->p != p)) {
|
||||
fnl = NULL;
|
||||
else {
|
||||
/* since we're mutating this finalizer, move it to the gen0 list and tree */
|
||||
remove_finalizer(fnl, 0, gc);
|
||||
add_finalizer(fnl, 1, gc);
|
||||
} else {
|
||||
if (lvl > FNL_LEVEL_GEN_0) {
|
||||
/* since we're mutating this finalizer, move it to the gen0 set */
|
||||
remove_finalizer(fnl, lvl, gc);
|
||||
add_finalizer(fnl, FNL_LEVEL_GEN_0, gc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +86,7 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
|
|||
fnl->eager_level = level;
|
||||
} else {
|
||||
/* remove finalizer */
|
||||
remove_finalizer(fnl, 1, gc);
|
||||
remove_finalizer(fnl, FNL_LEVEL_GEN_0, gc);
|
||||
--gc->num_fnls;
|
||||
}
|
||||
return;
|
||||
|
@ -143,7 +134,7 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
|
|||
}
|
||||
#endif
|
||||
|
||||
add_finalizer(fnl, 1, gc);
|
||||
add_finalizer(fnl, FNL_LEVEL_GEN_0, gc);
|
||||
gc->num_fnls++;
|
||||
}
|
||||
|
||||
|
@ -151,14 +142,16 @@ static void merge_finalizer_trees(GCTYPE *gc)
|
|||
/* For a full GC, move all finalizers to the gen0 list */
|
||||
{
|
||||
Fnl *fnl, *next;
|
||||
int lvl;
|
||||
|
||||
for (fnl = gc->finalizers; fnl; fnl = next) {
|
||||
next = fnl->next;
|
||||
add_finalizer(fnl, 1, gc);
|
||||
for (lvl = FNL_LEVEL_GEN_1; lvl < NUM_FNL_LEVELS; lvl++) {
|
||||
for (fnl = gc->finalizers[lvl]; fnl; fnl = next) {
|
||||
next = fnl->next;
|
||||
add_finalizer(fnl, FNL_LEVEL_GEN_0, gc);
|
||||
}
|
||||
gc->finalizers[lvl] = NULL;
|
||||
gc->splayed_finalizers[lvl] = NULL;
|
||||
}
|
||||
|
||||
gc->finalizers = NULL;
|
||||
gc->splayed_finalizers = NULL;
|
||||
}
|
||||
|
||||
static void reset_finalizer_tree(GCTYPE *gc)
|
||||
|
@ -168,9 +161,30 @@ static void reset_finalizer_tree(GCTYPE *gc)
|
|||
{
|
||||
Fnl *fnl, *next;
|
||||
|
||||
fnl = gc->gen0_finalizers;
|
||||
gc->gen0_finalizers = NULL;
|
||||
gc->splayed_gen0_finalizers = NULL;
|
||||
if (gc->gc_full) {
|
||||
GC_ASSERT(!gc->finalizers[FNL_LEVEL_INC_1]);
|
||||
GC_ASSERT(!gc->splayed_finalizers[FNL_LEVEL_INC_1]);
|
||||
GC_ASSERT(!gc->finalizers[FNL_LEVEL_INC_2]);
|
||||
GC_ASSERT(!gc->splayed_finalizers[FNL_LEVEL_INC_2]);
|
||||
if (gc->finished_incremental) {
|
||||
fnl = gc->finalizers[FNL_LEVEL_GEN_1];
|
||||
for (; fnl; fnl = next) {
|
||||
next = fnl->next;
|
||||
add_finalizer(fnl, FNL_LEVEL_INC_3, gc);
|
||||
}
|
||||
gc->finalizers[FNL_LEVEL_GEN_1] = gc->finalizers[FNL_LEVEL_INC_3];
|
||||
gc->splayed_finalizers[FNL_LEVEL_GEN_1] = gc->splayed_finalizers[FNL_LEVEL_INC_3];
|
||||
gc->finalizers[FNL_LEVEL_INC_3] = NULL;
|
||||
gc->splayed_finalizers[FNL_LEVEL_INC_3] = NULL;
|
||||
} else {
|
||||
GC_ASSERT(!gc->finalizers[FNL_LEVEL_INC_3]);
|
||||
GC_ASSERT(!gc->splayed_finalizers[FNL_LEVEL_INC_3]);
|
||||
}
|
||||
}
|
||||
|
||||
fnl = gc->finalizers[FNL_LEVEL_GEN_0];
|
||||
gc->finalizers[FNL_LEVEL_GEN_0] = NULL;
|
||||
gc->splayed_finalizers[FNL_LEVEL_GEN_0] = NULL;
|
||||
|
||||
for (; fnl; fnl = next) {
|
||||
next = fnl->next;
|
||||
|
@ -182,22 +196,8 @@ static void reset_finalizer_tree(GCTYPE *gc)
|
|||
|| is_in_generation_half(gc, fnl->f)
|
||||
|| is_in_generation_half(gc, fnl->p)
|
||||
|| is_in_generation_half(gc, fnl->data))
|
||||
add_finalizer(fnl, 1, gc);
|
||||
add_finalizer(fnl, FNL_LEVEL_GEN_0, gc);
|
||||
else
|
||||
add_finalizer(fnl, 0, gc);
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_gen1_finalizer_tree(GCTYPE *gc)
|
||||
{
|
||||
Fnl *fnl, *next;
|
||||
|
||||
fnl = gc->finalizers;
|
||||
gc->finalizers = NULL;
|
||||
gc->splayed_finalizers = NULL;
|
||||
|
||||
for (; fnl; fnl = next) {
|
||||
next = fnl->next;
|
||||
add_finalizer(fnl, 0, gc);
|
||||
add_finalizer(fnl, FNL_LEVEL_GEN_1, gc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,8 @@ enum {
|
|||
AGE_GEN_0 = 0,
|
||||
AGE_GEN_HALF = 1,
|
||||
AGE_GEN_1 = 2,
|
||||
AGE_VACATED = 3
|
||||
AGE_VACATED = 3, /* used for pages to be removed */
|
||||
AGE_GEN_INC = 4 /* used for naming a finalizer set */
|
||||
};
|
||||
|
||||
static const char *type_name[PAGE_TYPES] = {
|
||||
|
@ -2472,23 +2473,20 @@ static int is_finalizable_page(NewGC *gc, void *p)
|
|||
|
||||
#include "fnls.c"
|
||||
|
||||
inline static void mark_finalizer_structs(NewGC *gc, int old_gen)
|
||||
inline static void mark_finalizer_structs(NewGC *gc, int lvl)
|
||||
{
|
||||
Fnl *fnl;
|
||||
|
||||
set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
|
||||
if (old_gen)
|
||||
gcMARK2(gc->finalizers, gc);
|
||||
else
|
||||
gcMARK2(gc->gen0_finalizers, gc);
|
||||
for(fnl = (old_gen ? gc->finalizers : gc->gen0_finalizers); fnl; fnl = fnl->next) {
|
||||
set_backtrace_source(gc, &gc->finalizers[lvl], BT_ROOT);
|
||||
gcMARK2(gc->finalizers[lvl], gc);
|
||||
for(fnl = gc->finalizers[lvl]; fnl; fnl = fnl->next) {
|
||||
set_backtrace_source(gc, fnl, BT_FINALIZER);
|
||||
gcMARK2(fnl->data, gc);
|
||||
set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
|
||||
set_backtrace_source(gc, &gc->finalizers[lvl], BT_ROOT);
|
||||
gcMARK2(fnl->next, gc);
|
||||
}
|
||||
|
||||
if (!old_gen) {
|
||||
if (lvl == FNL_LEVEL_GEN_0) {
|
||||
set_backtrace_source(gc, &gc->run_queue, BT_ROOT);
|
||||
gcMARK2(gc->run_queue, gc);
|
||||
for(fnl = gc->run_queue; fnl; fnl = fnl->next) {
|
||||
|
@ -2509,20 +2507,20 @@ inline static void mark_finalizer_structs(NewGC *gc, int old_gen)
|
|||
gcMARK2(fnl->next, gc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline static void repair_finalizer_structs(NewGC *gc)
|
||||
{
|
||||
Fnl *fnl;
|
||||
|
||||
/* repair the base parts of the list */
|
||||
gcFIXUP2(gc->gen0_finalizers, gc);
|
||||
gcFIXUP2(gc->finalizers[FNL_LEVEL_GEN_0], gc);
|
||||
gcFIXUP2(gc->run_queue, gc);
|
||||
gcFIXUP2(gc->last_in_queue, gc);
|
||||
gcFIXUP2(gc->inc_run_queue, gc);
|
||||
gcFIXUP2(gc->inc_last_in_queue, gc);
|
||||
/* then repair the stuff inside them */
|
||||
for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) {
|
||||
for(fnl = gc->finalizers[FNL_LEVEL_GEN_0]; fnl; fnl = fnl->next) {
|
||||
gcFIXUP2(fnl->data, gc);
|
||||
gcFIXUP2(fnl->p, gc);
|
||||
gcFIXUP2(fnl->next, gc);
|
||||
|
@ -2552,45 +2550,61 @@ static void merge_run_queues(NewGC *gc)
|
|||
}
|
||||
}
|
||||
|
||||
inline static void check_finalizers(NewGC *gc, int level, int old_gen)
|
||||
inline static int check_finalizers(NewGC *gc, int level, int old_gen, int fuel)
|
||||
{
|
||||
Fnl *work = (old_gen
|
||||
? GC_resolve2(gc->finalizers, gc)
|
||||
: GC_resolve2(gc->gen0_finalizers, gc));
|
||||
int lvl = (old_gen
|
||||
? (FNL_LEVEL_GEN_1 + level - 1)
|
||||
: FNL_LEVEL_GEN_0);
|
||||
Fnl *work = GC_resolve2(gc->finalizers[lvl], gc);
|
||||
Fnl *prev = NULL;
|
||||
|
||||
if (!fuel) return 0;
|
||||
|
||||
GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level));
|
||||
while(work) {
|
||||
if (!fuel) {
|
||||
GC_ASSERT(old_gen);
|
||||
return 0;
|
||||
}
|
||||
if (fuel > 0) {
|
||||
fuel -= 4;
|
||||
if (fuel < 0) fuel = 0;
|
||||
}
|
||||
|
||||
if((work->eager_level == level) && !marked(gc, work->p)) {
|
||||
struct finalizer *next = GC_resolve2(work->next, gc);
|
||||
struct finalizer *next;
|
||||
|
||||
GCDEBUG((DEBUGOUTF,
|
||||
"CFNL: Level %i finalizer %p on %p queued for finalization.\n",
|
||||
work->eager_level, work, work->p));
|
||||
set_backtrace_source(gc, work, BT_FINALIZER);
|
||||
gcMARK2(work->p, gc);
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else if (old_gen)
|
||||
gc->finalizers = next;
|
||||
else
|
||||
gc->gen0_finalizers = next;
|
||||
if (next)
|
||||
next->prev = work->prev;
|
||||
work->prev = NULL; /* queue is singly-linked */
|
||||
work->left = NULL;
|
||||
work->right = NULL;
|
||||
if (old_gen) {
|
||||
remove_finalizer(work, lvl, gc);
|
||||
next = gc->finalizers[lvl];
|
||||
|
||||
if (gc->inc_last_in_queue)
|
||||
gc->inc_last_in_queue = gc->inc_last_in_queue->next = work;
|
||||
else
|
||||
gc->inc_run_queue = gc->inc_last_in_queue = work;
|
||||
} else {
|
||||
next = GC_resolve2(work->next, gc);
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else
|
||||
gc->finalizers[lvl] = next;
|
||||
if (next)
|
||||
next->prev = work->prev;
|
||||
work->prev = NULL; /* queue is singly-linked */
|
||||
work->left = NULL;
|
||||
work->right = NULL;
|
||||
|
||||
if (gc->last_in_queue)
|
||||
gc->last_in_queue = gc->last_in_queue->next = work;
|
||||
else
|
||||
gc->run_queue = gc->last_in_queue = work;
|
||||
}
|
||||
|
||||
work->next = NULL;
|
||||
--gc->num_fnls;
|
||||
|
||||
|
@ -2600,13 +2614,23 @@ inline static void check_finalizers(NewGC *gc, int level, int old_gen)
|
|||
GCDEBUG((DEBUGOUTF, "CFNL: Not finalizing %p (level %i on %p): %p / %i\n",
|
||||
work, work->eager_level, work->p, pagemap_find_page(gc->page_maps, work->p),
|
||||
marked(work->p)));
|
||||
p = GC_resolve2(work->p, gc);
|
||||
if (p != work->p)
|
||||
work->p = p;
|
||||
prev = work;
|
||||
work = GC_resolve2(work->next, gc);
|
||||
if (old_gen) {
|
||||
/* Move to next set of finalizers */
|
||||
GC_ASSERT(lvl < FNL_LEVEL_INC_3);
|
||||
remove_finalizer(work, lvl, gc);
|
||||
add_finalizer(work, lvl+1, gc);
|
||||
work = gc->finalizers[lvl];
|
||||
} else {
|
||||
p = GC_resolve2(work->p, gc);
|
||||
if (p != work->p)
|
||||
work->p = p;
|
||||
prev = work;
|
||||
work = GC_resolve2(work->next, gc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fuel;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -3089,10 +3113,14 @@ static int designate_modified_gc(NewGC *gc, void *p)
|
|||
/* Some marking functions, like the one for weak boxes,
|
||||
update the record, so it's ok to make the page writable. */
|
||||
&& (gc->inc_gen1
|
||||
/* Finalization in incremental mode can touch otherwise
|
||||
pages that are otherwise unmodified in the current pass: */
|
||||
|| gc->fnl_gen1
|
||||
/* Memory accounting can also modify otherwise unadjusted
|
||||
pages after incrementa mode: */
|
||||
|| (gc->doing_memory_accounting && gc->finished_incremental))) {
|
||||
check_incremental_unprotect(gc, page);
|
||||
gc->unprotected_page = 1; /* for using fuel */
|
||||
return 1;
|
||||
}
|
||||
GCPRINT(GCOUTF, "Seg fault (internal error during gc) at %p\n", p);
|
||||
|
@ -4199,6 +4227,8 @@ static int propagate_incremental_marks(NewGC *gc, int do_emph, int fuel)
|
|||
{
|
||||
int save_inc, save_check, init_fuel = fuel;
|
||||
|
||||
if (!fuel) return 0;
|
||||
|
||||
GC_ASSERT(gc->mark_gen1);
|
||||
|
||||
save_inc = gc->inc_gen1;
|
||||
|
@ -4220,6 +4250,10 @@ static int propagate_incremental_marks(NewGC *gc, int do_emph, int fuel)
|
|||
fuel--;
|
||||
fuel -= (gc->copy_count >> 2);
|
||||
fuel -= (gc->traverse_count >> 2);
|
||||
if (gc->unprotected_page) {
|
||||
gc->unprotected_page = 0;
|
||||
fuel -= 100;
|
||||
}
|
||||
if (fuel < 0)
|
||||
fuel = 0;
|
||||
}
|
||||
|
@ -5913,101 +5947,106 @@ extern double scheme_get_inexact_milliseconds(void);
|
|||
|
||||
#define AS_100M(c) ((c / (1024 * 1024 * 100)) + 1)
|
||||
|
||||
static int mark_and_finalize_all(NewGC *gc, int old_gen TIME_FORMAL_ARGS)
|
||||
static int mark_and_finalize_all(NewGC *gc, int old_gen, int no_full TIME_FORMAL_ARGS)
|
||||
{
|
||||
int fuel = (INCREMENTAL_COLLECT_FUEL_PER_100M * AS_100M(gc->memory_in_use)) / 2;
|
||||
int fuel = (old_gen
|
||||
? (no_full
|
||||
? INCREMENTAL_COLLECT_FUEL_PER_100M / INCREMENTAL_MINOR_REQUEST_DIVISOR
|
||||
: (INCREMENTAL_COLLECT_FUEL_PER_100M * AS_100M(gc->memory_in_use)) / 2)
|
||||
: -1);
|
||||
int reset_gen1;
|
||||
|
||||
/* Propagate marks */
|
||||
if (!old_gen)
|
||||
propagate_marks_plus_ephemerons(gc);
|
||||
else
|
||||
fuel = propagate_incremental_marks(gc, 1, fuel);
|
||||
|
||||
/* check finalizers at level 1 */
|
||||
fuel = check_finalizers(gc, 1, old_gen, fuel);
|
||||
|
||||
if (!old_gen)
|
||||
propagate_marks_plus_ephemerons(gc);
|
||||
else
|
||||
(void)propagate_incremental_marks(gc, 1, -1);
|
||||
|
||||
check_finalizers(gc, 1, old_gen);
|
||||
if (!old_gen)
|
||||
propagate_marks_plus_ephemerons(gc);
|
||||
else {
|
||||
fuel = propagate_incremental_marks(gc, 1, fuel);
|
||||
if (!fuel)
|
||||
return 1;
|
||||
}
|
||||
|
||||
TIME_STEP("marked");
|
||||
|
||||
if (old_gen) {
|
||||
if (old_gen || (gc->gc_full && gc->finished_incremental)) {
|
||||
GC_ASSERT(!gc->fnl_gen1);
|
||||
gc->fnl_gen1 = 1;
|
||||
}
|
||||
reset_gen1 = 1;
|
||||
} else
|
||||
reset_gen1 = 0;
|
||||
|
||||
if (gc->gc_full)
|
||||
(void)zero_weak_boxes(gc, 0, 0, 1, -1);
|
||||
fuel = zero_weak_boxes(gc, 0, 0, old_gen, (old_gen ? fuel : -1));
|
||||
if (old_gen && !fuel) {
|
||||
gc->fnl_gen1 = 0;
|
||||
return 1;
|
||||
}
|
||||
(void)zero_weak_boxes(gc, 0, 0, 1, 1, -1);
|
||||
fuel = zero_weak_boxes(gc, 0, 0, old_gen, !old_gen, fuel);
|
||||
|
||||
if (gc->gc_full)
|
||||
(void)zero_weak_arrays(gc, 0, 1, -1);
|
||||
fuel = zero_weak_arrays(gc, 0, old_gen, (old_gen ? fuel : -1));
|
||||
if (old_gen && !fuel) {
|
||||
gc->fnl_gen1 = 0;
|
||||
return 1;
|
||||
}
|
||||
(void)zero_weak_arrays(gc, 0, 1, 1, -1);
|
||||
fuel = zero_weak_arrays(gc, 0, old_gen, !old_gen, fuel);
|
||||
|
||||
if (gc->gc_full)
|
||||
zero_remaining_ephemerons(gc, 1);
|
||||
zero_remaining_ephemerons(gc, old_gen);
|
||||
if (fuel)
|
||||
zero_remaining_ephemerons(gc, old_gen);
|
||||
|
||||
TIME_STEP("zeroed");
|
||||
|
||||
check_finalizers(gc, 2, old_gen);
|
||||
|
||||
fuel = check_finalizers(gc, 2, old_gen, fuel);
|
||||
|
||||
if (!old_gen)
|
||||
propagate_marks(gc);
|
||||
else
|
||||
(void)propagate_incremental_marks(gc, 0, -1);
|
||||
fuel = propagate_incremental_marks(gc, 0, fuel);
|
||||
|
||||
if (gc->gc_full)
|
||||
(void)zero_weak_boxes(gc, 1, 0, 1, -1);
|
||||
(void)zero_weak_boxes(gc, 1, 0, old_gen, -1);
|
||||
(void)zero_weak_boxes(gc, 1, 0, 1, 1, -1);
|
||||
fuel = zero_weak_boxes(gc, 1, 0, old_gen, !old_gen, fuel);
|
||||
|
||||
fuel = check_finalizers(gc, 3, old_gen, fuel);
|
||||
|
||||
check_finalizers(gc, 3, old_gen);
|
||||
if (!old_gen)
|
||||
propagate_marks(gc);
|
||||
else
|
||||
(void)propagate_incremental_marks(gc, 0, -1);
|
||||
fuel = propagate_incremental_marks(gc, 0, fuel);
|
||||
|
||||
if (gc->GC_post_propagate_hook)
|
||||
if (fuel && gc->GC_post_propagate_hook)
|
||||
gc->GC_post_propagate_hook(gc);
|
||||
|
||||
if (fuel) {
|
||||
/* for any new ones that appeared: */
|
||||
(void)zero_weak_boxes(gc, 0, 1, old_gen, 0, -1);
|
||||
(void)zero_weak_boxes(gc, 1, 1, old_gen, 0, -1);
|
||||
(void)zero_weak_arrays(gc, 1, old_gen, 0, -1);
|
||||
zero_remaining_ephemerons(gc, old_gen);
|
||||
|
||||
/* for any new ones that appeared: */
|
||||
(void)zero_weak_boxes(gc, 0, 1, old_gen, -1);
|
||||
(void)zero_weak_boxes(gc, 1, 1, old_gen, -1);
|
||||
(void)zero_weak_arrays(gc, 1, old_gen, -1);
|
||||
zero_remaining_ephemerons(gc, old_gen);
|
||||
|
||||
GC_ASSERT(!gc->weak_arrays);
|
||||
GC_ASSERT(!gc->bp_weak_arrays);
|
||||
GC_ASSERT(!gc->weak_boxes[0]);
|
||||
GC_ASSERT(!gc->weak_boxes[1]);
|
||||
GC_ASSERT(!gc->bp_weak_boxes[0]);
|
||||
GC_ASSERT(!gc->bp_weak_boxes[1]);
|
||||
GC_ASSERT(!gc->ephemerons);
|
||||
GC_ASSERT(!gc->bp_ephemerons);
|
||||
if (gc->gc_full) {
|
||||
GC_ASSERT(!gc->inc_weak_arrays);
|
||||
GC_ASSERT(!gc->inc_weak_boxes[0]);
|
||||
GC_ASSERT(!gc->inc_weak_boxes[1]);
|
||||
GC_ASSERT(!gc->inc_ephemerons);
|
||||
GC_ASSERT(!gc->weak_arrays);
|
||||
GC_ASSERT(!gc->bp_weak_arrays);
|
||||
GC_ASSERT(!gc->weak_boxes[0]);
|
||||
GC_ASSERT(!gc->weak_boxes[1]);
|
||||
GC_ASSERT(!gc->bp_weak_boxes[0]);
|
||||
GC_ASSERT(!gc->bp_weak_boxes[1]);
|
||||
GC_ASSERT(!gc->ephemerons);
|
||||
GC_ASSERT(!gc->bp_ephemerons);
|
||||
if (gc->gc_full) {
|
||||
GC_ASSERT(!gc->inc_weak_arrays);
|
||||
GC_ASSERT(!gc->inc_weak_boxes[0]);
|
||||
GC_ASSERT(!gc->inc_weak_boxes[1]);
|
||||
GC_ASSERT(!gc->inc_ephemerons);
|
||||
}
|
||||
}
|
||||
|
||||
if (old_gen)
|
||||
if (reset_gen1)
|
||||
gc->fnl_gen1 = 0;
|
||||
|
||||
TIME_STEP("finalized");
|
||||
|
||||
return 0;
|
||||
return !fuel;
|
||||
}
|
||||
|
||||
static int mark_and_finalize_all_incremental(NewGC *gc TIME_FORMAL_ARGS)
|
||||
static int mark_and_finalize_all_incremental(NewGC *gc, int no_full TIME_FORMAL_ARGS)
|
||||
{
|
||||
int save_inc, save_check, more_to_do;
|
||||
|
||||
|
@ -6019,7 +6058,7 @@ static int mark_and_finalize_all_incremental(NewGC *gc TIME_FORMAL_ARGS)
|
|||
gc->inc_gen1 = 1;
|
||||
gc->check_gen1 = 1;
|
||||
|
||||
more_to_do = mark_and_finalize_all(gc, 1 TIME_ARGS);
|
||||
more_to_do = mark_and_finalize_all(gc, 1, no_full TIME_ARGS);
|
||||
|
||||
gc->inc_gen1 = save_inc;
|
||||
gc->check_gen1 = save_check;
|
||||
|
@ -6168,7 +6207,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
|
|||
/* mark and repair the roots for collection */
|
||||
mark_backpointers(gc);
|
||||
TIME_STEP("backpointered");
|
||||
mark_finalizer_structs(gc, 0);
|
||||
mark_finalizer_structs(gc, FNL_LEVEL_GEN_0);
|
||||
TIME_STEP("pre-rooted");
|
||||
mark_roots(gc);
|
||||
mark_immobiles(gc);
|
||||
|
@ -6183,11 +6222,11 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
|
|||
|
||||
/* now propagate/repair the marks we got from these roots, and do the
|
||||
finalizer passes */
|
||||
(void)mark_and_finalize_all(gc, 0 TIME_ARGS);
|
||||
(void)mark_and_finalize_all(gc, 0, no_full TIME_ARGS);
|
||||
|
||||
if (do_incremental) {
|
||||
if (!gc->all_marked_incremental) {
|
||||
mark_finalizer_structs(gc, 1);
|
||||
mark_finalizer_structs(gc, FNL_LEVEL_GEN_1);
|
||||
if (!mark_stack_is_empty(gc->inc_mark_stack)) {
|
||||
int fuel = (no_full
|
||||
? INCREMENTAL_COLLECT_FUEL_PER_100M / INCREMENTAL_MINOR_REQUEST_DIVISOR
|
||||
|
@ -6197,12 +6236,10 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
|
|||
} else {
|
||||
/* We ran out of incremental marking work, so
|
||||
perform major-GC finalization */
|
||||
if (mark_and_finalize_all_incremental(gc TIME_ARGS)) {
|
||||
if (mark_and_finalize_all_incremental(gc, no_full TIME_ARGS)) {
|
||||
/* More finalizaton work to do */
|
||||
reset_gen1_finalizer_tree(gc);
|
||||
} else {
|
||||
BTC_clean_up_gen1(gc);
|
||||
reset_gen1_finalizer_tree(gc);
|
||||
/* Switch to incrementally reparing pages */
|
||||
gc->all_marked_incremental = 1;
|
||||
}
|
||||
|
@ -6244,10 +6281,10 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
|
|||
repair_heap(gc);
|
||||
TIME_STEP("repaired");
|
||||
if (check_inc_repair) {
|
||||
GC_ASSERT(gc->all_marked_incremental);
|
||||
int fuel = (no_full
|
||||
? INCREMENTAL_REPAIR_FUEL_PER_100M / INCREMENTAL_MINOR_REQUEST_DIVISOR
|
||||
: INCREMENTAL_REPAIR_FUEL_PER_100M * AS_100M(gc->memory_in_use));
|
||||
GC_ASSERT(gc->all_marked_incremental);
|
||||
incremental_repair_pages(gc, fuel);
|
||||
TIME_STEP("inc-repaired");
|
||||
if (!gc->inc_repair_next)
|
||||
|
|
|
@ -149,6 +149,15 @@ typedef mpage **PageMap;
|
|||
|
||||
#define NUM_MED_PAGE_SIZES (((LOG_APAGE_SIZE - 1) - 3) + 1)
|
||||
|
||||
enum {
|
||||
FNL_LEVEL_GEN_0,
|
||||
FNL_LEVEL_GEN_1,
|
||||
FNL_LEVEL_INC_1,
|
||||
FNL_LEVEL_INC_2,
|
||||
FNL_LEVEL_INC_3,
|
||||
NUM_FNL_LEVELS
|
||||
};
|
||||
|
||||
typedef struct NewGC {
|
||||
Gen0 gen0;
|
||||
Gen_Half gen_half;
|
||||
|
@ -221,6 +230,7 @@ typedef struct NewGC {
|
|||
unsigned char during_backpointer :1;
|
||||
unsigned char incremental_requested :1;
|
||||
unsigned char high_fragmentation :1;
|
||||
unsigned char unprotected_page :1;
|
||||
|
||||
/* blame the child */
|
||||
unsigned int doing_memory_accounting :1;
|
||||
|
@ -282,10 +292,8 @@ typedef struct NewGC {
|
|||
|
||||
GC_Immobile_Box *immobile_boxes;
|
||||
|
||||
Fnl *finalizers;
|
||||
Fnl *splayed_finalizers;
|
||||
Fnl *gen0_finalizers;
|
||||
Fnl *splayed_gen0_finalizers;
|
||||
Fnl *finalizers[NUM_FNL_LEVELS];
|
||||
Fnl *splayed_finalizers[NUM_FNL_LEVELS];
|
||||
int num_fnls;
|
||||
|
||||
void *park[2];
|
||||
|
|
|
@ -155,11 +155,13 @@ static GC_Weak_Array *append_weak_arrays(GC_Weak_Array *wa, GC_Weak_Array *bp_wa
|
|||
return bp_wa;
|
||||
}
|
||||
|
||||
static int zero_weak_arrays(GCTYPE *gc, int force_zero, int from_inc, int fuel)
|
||||
static int zero_weak_arrays(GCTYPE *gc, int force_zero, int from_inc, int need_resolve, int fuel)
|
||||
{
|
||||
GC_Weak_Array *wa;
|
||||
int i, num_gen0;
|
||||
|
||||
if (!fuel) return 0;
|
||||
|
||||
if (from_inc) {
|
||||
wa = gc->inc_weak_arrays;
|
||||
num_gen0 = 0;
|
||||
|
@ -177,11 +179,13 @@ static int zero_weak_arrays(GCTYPE *gc, int force_zero, int from_inc, int fuel)
|
|||
void *p = data[i];
|
||||
if (p && (force_zero || !is_marked(gc, p)))
|
||||
data[i] = wa->replace_val;
|
||||
else
|
||||
else if (need_resolve)
|
||||
data[i] = GC_resolve2(p, gc);
|
||||
}
|
||||
if (fuel > 0)
|
||||
fuel = ((fuel > wa->count) ? (fuel - wa->count) : 0);
|
||||
if (fuel > 0) {
|
||||
fuel -= (4 * wa->count);
|
||||
if (fuel < 0) fuel = 0;
|
||||
}
|
||||
|
||||
if (num_gen0 > 0) {
|
||||
if (!is_in_generation_half(gc, wa)) {
|
||||
|
@ -348,11 +352,13 @@ static GC_Weak_Box *append_weak_boxes(GC_Weak_Box *wb, GC_Weak_Box *bp_wb, int *
|
|||
return bp_wb;
|
||||
}
|
||||
|
||||
static int zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc, int fuel)
|
||||
static int zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc, int need_resolve, int fuel)
|
||||
{
|
||||
GC_Weak_Box *wb;
|
||||
int num_gen0;
|
||||
|
||||
if (!fuel) return 0;
|
||||
|
||||
if (from_inc) {
|
||||
wb = gc->inc_weak_boxes[is_late];
|
||||
num_gen0 = 0;
|
||||
|
@ -388,9 +394,9 @@ static int zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc
|
|||
*(p + wb->soffset) = NULL;
|
||||
wb->secondary_erase = NULL;
|
||||
}
|
||||
} else {
|
||||
} else if (need_resolve)
|
||||
wb->val = GC_resolve2(wb->val, gc);
|
||||
}
|
||||
|
||||
if (num_gen0 > 0) {
|
||||
if (!is_in_generation_half(gc, wb)) {
|
||||
if (!gc->all_marked_incremental) {
|
||||
|
@ -405,6 +411,7 @@ static int zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (from_inc) {
|
||||
GC_Weak_Box *next;
|
||||
next = wb->inc_next;
|
||||
|
@ -416,9 +423,14 @@ static int zero_weak_boxes(GCTYPE *gc, int is_late, int force_zero, int from_inc
|
|||
num_gen0--;
|
||||
|
||||
if (fuel >= 0) {
|
||||
if (fuel > 0)
|
||||
fuel--;
|
||||
else {
|
||||
if (fuel > 0) {
|
||||
if (gc->unprotected_page) {
|
||||
fuel -= 100;
|
||||
gc->unprotected_page = 0;
|
||||
} else
|
||||
fuel -= 4;
|
||||
if (fuel < 0) fuel = 0;
|
||||
} else {
|
||||
GC_ASSERT(from_inc);
|
||||
gc->inc_weak_boxes[is_late] = wb;
|
||||
return 0;
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
/* We're the first to look at this prefix... */
|
||||
/* Add it to the chain of prefixes to finish after
|
||||
all other marking: */
|
||||
if (gc_mode == GC_CURRENT_MODE_INCREMENTAL) {
|
||||
if ((gc_mode == GC_CURRENT_MODE_INCREMENTAL)
|
||||
|| (gc_mode == GC_CURRENT_MODE_INCREMENTAL_FINAL)) {
|
||||
pf->next_final = scheme_inc_prefix_finalize;
|
||||
scheme_inc_prefix_finalize = pf;
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue
Block a user