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
|
num_fnls
|
||||||
Requires:
|
Requires:
|
||||||
is_finalizable_page(gc, p)
|
is_finalizable_page(gc, p)
|
||||||
|
is_in_gen_half(p, gc)
|
||||||
park
|
park
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -22,6 +23,41 @@
|
||||||
#undef splay_insert
|
#undef splay_insert
|
||||||
#undef splay_delete
|
#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 GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *data),
|
||||||
void *data, void (**oldf)(void *p, void *data),
|
void *data, void (**oldf)(void *p, void *data),
|
||||||
void **olddata)
|
void **olddata)
|
||||||
|
@ -36,8 +72,20 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gc->splayed_finalizers = fnl_splay((intptr_t)p, gc->splayed_finalizers);
|
gc->splayed_gen0_finalizers = fnl_splay((intptr_t)p, gc->splayed_gen0_finalizers);
|
||||||
fnl = gc->splayed_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 (fnl && (fnl->p == p)) {
|
||||||
if (oldf) *oldf = fnl->f;
|
if (oldf) *oldf = fnl->f;
|
||||||
if (olddata) *olddata = fnl->data;
|
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;
|
fnl->eager_level = level;
|
||||||
} else {
|
} else {
|
||||||
/* remove finalizer */
|
/* remove finalizer */
|
||||||
if (fnl->prev)
|
remove_finalizer(fnl, 1, gc);
|
||||||
fnl->prev->next = fnl->next;
|
|
||||||
else
|
|
||||||
gc->finalizers = fnl->next;
|
|
||||||
if (fnl->next)
|
|
||||||
fnl->next->prev = fnl->prev;
|
|
||||||
|
|
||||||
--gc->num_fnls;
|
--gc->num_fnls;
|
||||||
gc->splayed_finalizers = fnl_splay_delete((intptr_t)p, gc->splayed_finalizers);
|
|
||||||
}
|
}
|
||||||
return;
|
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[0] = NULL;
|
||||||
gc->park[1] = NULL;
|
gc->park[1] = NULL;
|
||||||
|
|
||||||
|
|
||||||
fnl->p = p;
|
fnl->p = p;
|
||||||
fnl->f = f;
|
fnl->f = f;
|
||||||
fnl->data = data;
|
fnl->data = data;
|
||||||
|
@ -103,32 +143,43 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* push finalizer */
|
add_finalizer(fnl, 1, gc);
|
||||||
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);
|
|
||||||
|
|
||||||
gc->num_fnls++;
|
gc->num_fnls++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_finalizer_tree(GCTYPE *gc)
|
static void merge_finalizer_trees(GCTYPE *gc)
|
||||||
/* After a GC, rebuild the splay tree, since object addresses
|
/* For a full GC, move all finalizers to the gen0 list */
|
||||||
have moved. */
|
|
||||||
{
|
{
|
||||||
Fnl *fnl;
|
Fnl *fnl, *next;
|
||||||
Fnl *prev = NULL;
|
|
||||||
|
|
||||||
gc->splayed_finalizers = NULL;
|
for (fnl = gc->finalizers; fnl; fnl = next) {
|
||||||
|
next = fnl->next;
|
||||||
for (fnl = gc->finalizers; fnl; fnl = fnl->next) {
|
add_finalizer(fnl, 1, gc);
|
||||||
fnl->prev = prev;
|
|
||||||
gc->splayed_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers);
|
|
||||||
prev = fnl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
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"
|
#include "fnls.c"
|
||||||
|
|
||||||
inline static void mark_finalizer_structs(NewGC *gc)
|
inline static void mark_finalizer_structs(NewGC *gc)
|
||||||
{
|
{
|
||||||
Fnl *fnl;
|
Fnl *fnl;
|
||||||
|
|
||||||
set_backtrace_source(gc, &gc->finalizers, BT_ROOT);
|
set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
|
||||||
gcMARK2(gc->finalizers, gc);
|
gcMARK2(gc->gen0_finalizers, gc);
|
||||||
for(fnl = gc->finalizers; fnl; fnl = fnl->next) {
|
for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) {
|
||||||
set_backtrace_source(gc, fnl, BT_FINALIZER);
|
set_backtrace_source(gc, fnl, BT_FINALIZER);
|
||||||
gcMARK2(fnl->data, gc);
|
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);
|
gcMARK2(fnl->next, gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2388,7 +2400,7 @@ inline static void mark_finalizer_structs(NewGC *gc)
|
||||||
set_backtrace_source(gc, fnl, BT_FINALIZER);
|
set_backtrace_source(gc, fnl, BT_FINALIZER);
|
||||||
gcMARK2(fnl->data, gc);
|
gcMARK2(fnl->data, gc);
|
||||||
gcMARK2(fnl->p, 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);
|
gcMARK2(fnl->next, gc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2398,10 +2410,10 @@ inline static void repair_finalizer_structs(NewGC *gc)
|
||||||
Fnl *fnl;
|
Fnl *fnl;
|
||||||
|
|
||||||
/* repair the base parts of the list */
|
/* repair the base parts of the list */
|
||||||
gcFIXUP2(gc->finalizers, gc);
|
gcFIXUP2(gc->gen0_finalizers, gc);
|
||||||
gcFIXUP2(gc->run_queue, gc);
|
gcFIXUP2(gc->run_queue, gc);
|
||||||
/* then repair the stuff inside them */
|
/* 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->data, gc);
|
||||||
gcFIXUP2(fnl->p, gc);
|
gcFIXUP2(fnl->p, gc);
|
||||||
gcFIXUP2(fnl->next, 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)
|
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;
|
Fnl *prev = NULL;
|
||||||
|
|
||||||
GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level));
|
GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level));
|
||||||
|
@ -2432,7 +2444,7 @@ inline static void check_finalizers(NewGC *gc, int level)
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
else
|
else
|
||||||
gc->finalizers = next;
|
gc->gen0_finalizers = next;
|
||||||
if (next)
|
if (next)
|
||||||
next->prev = work->prev;
|
next->prev = work->prev;
|
||||||
work->prev = NULL; /* queue is singly-linked */
|
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)
|
if (gc->gc_full)
|
||||||
reset_gen1_pages_live_and_scan_boundaries(gc);
|
reset_gen1_pages_live_and_scan_boundaries(gc);
|
||||||
|
|
||||||
|
if (gc->gc_full)
|
||||||
|
merge_finalizer_trees(gc);
|
||||||
|
|
||||||
move_gen_half_pages_to_old(gc);
|
move_gen_half_pages_to_old(gc);
|
||||||
|
|
||||||
init_weak_boxes(gc);
|
init_weak_boxes(gc);
|
||||||
|
|
|
@ -248,9 +248,10 @@ typedef struct NewGC {
|
||||||
|
|
||||||
GC_Immobile_Box *immobile_boxes;
|
GC_Immobile_Box *immobile_boxes;
|
||||||
|
|
||||||
/* Common with CompactGC */
|
|
||||||
Fnl *finalizers;
|
Fnl *finalizers;
|
||||||
Fnl *splayed_finalizers;
|
Fnl *splayed_finalizers;
|
||||||
|
Fnl *gen0_finalizers;
|
||||||
|
Fnl *splayed_gen0_finalizers;
|
||||||
int num_fnls;
|
int num_fnls;
|
||||||
|
|
||||||
void *park[2];
|
void *park[2];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user