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:
parent
7ff1cf3619
commit
bcc65ac92e
|
@ -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;
|
||||
|
||||
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;
|
||||
for (fnl = gc->finalizers; fnl; fnl = next) {
|
||||
next = fnl->next;
|
||||
add_finalizer(fnl, 1, gc);
|
||||
}
|
||||
|
||||
gc->finalizers = NULL;
|
||||
gc->splayed_finalizers = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue
Block a user