GC: separate old-generation finalizers from now ones

Avoiding a traversals of old-generation finalizers can
save a couple of milliseconds for a minor GC in DrRacket.
This commit is contained in:
Matthew Flatt 2015-09-19 16:49:58 -06:00
parent 7ff1cf3619
commit bcc65ac92e
3 changed files with 109 additions and 42 deletions

View File

@ -8,6 +8,7 @@
num_fnls
Requires:
is_finalizable_page(gc, p)
is_in_gen_half(p, gc)
park
*/
@ -22,6 +23,41 @@
#undef splay_insert
#undef splay_delete
static void remove_finalizer(Fnl *fnl, int gen0, GCTYPE *gc)
{
if (fnl->prev)
fnl->prev->next = fnl->next;
else {
if (gen0)
gc->gen0_finalizers = fnl->next;
else
gc->finalizers = 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);
}
static void add_finalizer(Fnl *fnl, int gen0, GCTYPE *gc)
{
fnl->next = (gen0 ? gc->gen0_finalizers : gc->finalizers);
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);
}
}
void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *data),
void *data, void (**oldf)(void *p, void *data),
void **olddata)
@ -36,8 +72,20 @@ 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))
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);
}
}
if (fnl && (fnl->p == p)) {
if (oldf) *oldf = fnl->f;
if (olddata) *olddata = fnl->data;
@ -47,15 +95,8 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
fnl->eager_level = level;
} else {
/* remove finalizer */
if (fnl->prev)
fnl->prev->next = fnl->next;
else
gc->finalizers = fnl->next;
if (fnl->next)
fnl->next->prev = fnl->prev;
remove_finalizer(fnl, 1, gc);
--gc->num_fnls;
gc->splayed_finalizers = fnl_splay_delete((intptr_t)p, gc->splayed_finalizers);
}
return;
}
@ -79,7 +120,6 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
gc->park[0] = NULL;
gc->park[1] = NULL;
fnl->p = p;
fnl->f = f;
fnl->data = data;
@ -103,32 +143,43 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
}
#endif
/* push finalizer */
fnl->next = gc->finalizers;
fnl->prev = NULL;
if (gc->finalizers) {
gc->finalizers->prev = fnl;
}
gc->finalizers = fnl;
gc->splayed_finalizers = fnl_splay_insert((intptr_t)p, fnl, gc->splayed_finalizers);
add_finalizer(fnl, 1, gc);
gc->num_fnls++;
}
static void reset_finalizer_tree(GCTYPE *gc)
/* After a GC, rebuild the splay tree, since object addresses
have moved. */
static void merge_finalizer_trees(GCTYPE *gc)
/* For a full GC, move all finalizers to the gen0 list */
{
Fnl *fnl;
Fnl *prev = NULL;
Fnl *fnl, *next;
for (fnl = gc->finalizers; fnl; fnl = next) {
next = fnl->next;
add_finalizer(fnl, 1, gc);
}
gc->finalizers = NULL;
gc->splayed_finalizers = NULL;
for (fnl = gc->finalizers; fnl; fnl = fnl->next) {
fnl->prev = prev;
gc->splayed_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers);
prev = fnl;
}
}
static void reset_finalizer_tree(GCTYPE *gc)
/* After a GC, move gen0 finalizers to the old finalizer list. Note
that the old gen0 splay tree is otherwise broken, since object
addresses have moved. */
{
Fnl *fnl, *next;
fnl = gc->gen0_finalizers;
gc->gen0_finalizers = NULL;
gc->splayed_gen0_finalizers = NULL;
for (; fnl; fnl = next) {
next = fnl->next;
if (is_in_gen_half(fnl, gc)
|| is_in_gen_half(fnl->f, gc)
|| is_in_gen_half(fnl->data, gc))
add_finalizer(fnl, 1, gc);
else
add_finalizer(fnl, 0, gc);
}
}

View File

@ -2367,18 +2367,30 @@ static int is_finalizable_page(NewGC *gc, void *p)
return !!pagemap_find_page(gc->page_maps, p);
}
static int is_in_gen_half(void *p, NewGC *gc)
{
mpage *page;
if (gc->gc_full)
return 0;
page = pagemap_find_page(gc->page_maps, p);
return (page && (page->generation == AGE_GEN_HALF));
}
#include "fnls.c"
inline static void mark_finalizer_structs(NewGC *gc)
{
Fnl *fnl;
set_backtrace_source(gc, &gc->finalizers, BT_ROOT);
gcMARK2(gc->finalizers, gc);
for(fnl = gc->finalizers; fnl; fnl = fnl->next) {
set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
gcMARK2(gc->gen0_finalizers, gc);
for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) {
set_backtrace_source(gc, fnl, BT_FINALIZER);
gcMARK2(fnl->data, gc);
set_backtrace_source(gc, &gc->finalizers, BT_ROOT);
set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
gcMARK2(fnl->next, gc);
}
@ -2388,7 +2400,7 @@ inline static void mark_finalizer_structs(NewGC *gc)
set_backtrace_source(gc, fnl, BT_FINALIZER);
gcMARK2(fnl->data, gc);
gcMARK2(fnl->p, gc);
set_backtrace_source(gc, &gc->finalizers, BT_ROOT);
set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
gcMARK2(fnl->next, gc);
}
}
@ -2398,10 +2410,10 @@ inline static void repair_finalizer_structs(NewGC *gc)
Fnl *fnl;
/* repair the base parts of the list */
gcFIXUP2(gc->finalizers, gc);
gcFIXUP2(gc->gen0_finalizers, gc);
gcFIXUP2(gc->run_queue, gc);
/* then repair the stuff inside them */
for(fnl = gc->finalizers; fnl; fnl = fnl->next) {
for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) {
gcFIXUP2(fnl->data, gc);
gcFIXUP2(fnl->p, gc);
gcFIXUP2(fnl->next, gc);
@ -2416,7 +2428,7 @@ inline static void repair_finalizer_structs(NewGC *gc)
inline static void check_finalizers(NewGC *gc, int level)
{
Fnl *work = GC_resolve2(gc->finalizers, gc);
Fnl *work = GC_resolve2(gc->gen0_finalizers, gc);
Fnl *prev = NULL;
GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level));
@ -2432,7 +2444,7 @@ inline static void check_finalizers(NewGC *gc, int level)
if (prev)
prev->next = next;
else
gc->finalizers = next;
gc->gen0_finalizers = next;
if (next)
next->prev = work->prev;
work->prev = NULL; /* queue is singly-linked */
@ -5034,6 +5046,9 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
if (gc->gc_full)
reset_gen1_pages_live_and_scan_boundaries(gc);
if (gc->gc_full)
merge_finalizer_trees(gc);
move_gen_half_pages_to_old(gc);
init_weak_boxes(gc);

View File

@ -248,9 +248,10 @@ typedef struct NewGC {
GC_Immobile_Box *immobile_boxes;
/* Common with CompactGC */
Fnl *finalizers;
Fnl *splayed_finalizers;
Fnl *gen0_finalizers;
Fnl *splayed_gen0_finalizers;
int num_fnls;
void *park[2];