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:
Matthew Flatt 2015-12-07 16:56:52 -07:00
parent 6f106d9adc
commit c0f4eb8287
5 changed files with 228 additions and 170 deletions

View File

@ -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;
}
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;
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)) {
gc->splayed_finalizers = fnl_splay((intptr_t)p, gc->splayed_finalizers);
fnl = gc->splayed_finalizers;
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) {
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, 1, gc);
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);
}
}

View File

@ -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) {
@ -2516,13 +2514,13 @@ 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,6 +2614,13 @@ 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)));
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;
@ -2609,6 +2630,9 @@ inline static void check_finalizers(NewGC *gc, int level, int old_gen)
}
}
return fuel;
}
/*****************************************************************************/
/* weak boxes and arrays */
/*****************************************************************************/
@ -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,75 +5947,79 @@ 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);
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, -1);
(void)zero_weak_boxes(gc, 1, 1, old_gen, -1);
(void)zero_weak_arrays(gc, 1, old_gen, -1);
(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);
GC_ASSERT(!gc->weak_arrays);
@ -5998,16 +6036,17 @@ static int mark_and_finalize_all(NewGC *gc, int old_gen TIME_FORMAL_ARGS)
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)

View File

@ -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];

View File

@ -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;

View File

@ -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 {