Merge branch 'gcbt' of github.com:mflatt/ChezScheme
original commit: 51c6b2a880000ce754e1595f4481957e9fc7f722
This commit is contained in:
commit
efb93d2653
6
LOG
6
LOG
|
@ -1035,3 +1035,9 @@
|
||||||
cmacros.ss, cpnanopass.ss, interpret.ss, library.ss,
|
cmacros.ss, cpnanopass.ss, interpret.ss, library.ss,
|
||||||
primdata.ss, prims.ss, gc.c, objects.stex, release_notes.stex
|
primdata.ss, prims.ss, gc.c, objects.stex, release_notes.stex
|
||||||
misc.ms, mats/patch*, mats/root*
|
misc.ms, mats/patch*, mats/root*
|
||||||
|
- add object-backreferences and enable-object-backreferences as an aid
|
||||||
|
to debugging memory leaks
|
||||||
|
back.ss, cmacros.ss, inspect.ss, primdata.ss,
|
||||||
|
gc-oce.c, gc.c, gcwrapper.c, prim.c, scheme.c,
|
||||||
|
globals.h, externs.h,
|
||||||
|
system.stex, 7.ms
|
||||||
|
|
|
@ -132,6 +132,9 @@ extern void S_register_child_process PROTO((INT child));
|
||||||
extern IBOOL S_enable_object_counts PROTO((void));
|
extern IBOOL S_enable_object_counts PROTO((void));
|
||||||
extern void S_set_enable_object_counts PROTO((IBOOL eoc));
|
extern void S_set_enable_object_counts PROTO((IBOOL eoc));
|
||||||
extern ptr S_object_counts PROTO((void));
|
extern ptr S_object_counts PROTO((void));
|
||||||
|
extern IBOOL S_enable_object_backreferences PROTO((void));
|
||||||
|
extern void S_set_enable_object_backreferences PROTO((IBOOL eoc));
|
||||||
|
extern ptr S_object_backreferences PROTO((void));
|
||||||
extern void S_do_gc PROTO((IGEN g, IGEN gtarget));
|
extern void S_do_gc PROTO((IGEN g, IGEN gtarget));
|
||||||
extern ptr S_locked_objects PROTO((void));
|
extern ptr S_locked_objects PROTO((void));
|
||||||
extern void S_compact_heap PROTO((void));
|
extern void S_compact_heap PROTO((void));
|
||||||
|
|
|
@ -16,4 +16,5 @@
|
||||||
|
|
||||||
#define GCENTRY S_gc_oce
|
#define GCENTRY S_gc_oce
|
||||||
#define ENABLE_OBJECT_COUNTS
|
#define ENABLE_OBJECT_COUNTS
|
||||||
|
#define ENABLE_BACKREFERENCE
|
||||||
#include "gc.c"
|
#include "gc.c"
|
||||||
|
|
165
c/gc.c
165
c/gc.c
|
@ -39,7 +39,7 @@ static void resweep_weak_pairs PROTO((IGEN g));
|
||||||
static void forward_or_bwp PROTO((ptr *pp, ptr p));
|
static void forward_or_bwp PROTO((ptr *pp, ptr p));
|
||||||
static void sweep_generation PROTO((ptr tc, IGEN g));
|
static void sweep_generation PROTO((ptr tc, IGEN g));
|
||||||
static iptr size_object PROTO((ptr p));
|
static iptr size_object PROTO((ptr p));
|
||||||
static iptr sweep_typed_object PROTO((ptr p));
|
static iptr sweep_typed_object PROTO((ptr tc, ptr p));
|
||||||
static void sweep_symbol PROTO((ptr p));
|
static void sweep_symbol PROTO((ptr p));
|
||||||
static void sweep_port PROTO((ptr p));
|
static void sweep_port PROTO((ptr p));
|
||||||
static void sweep_thread PROTO((ptr p));
|
static void sweep_thread PROTO((ptr p));
|
||||||
|
@ -79,6 +79,31 @@ static ptr sorted_locked_objects;
|
||||||
static ptr tlcs_to_rehash;
|
static ptr tlcs_to_rehash;
|
||||||
static ptr recheck_guardians_ls;
|
static ptr recheck_guardians_ls;
|
||||||
|
|
||||||
|
#ifdef ENABLE_BACKREFERENCE
|
||||||
|
static ptr sweep_from;
|
||||||
|
# define BACKREFERENCES_ENABLED S_G.enable_object_backreferences
|
||||||
|
# define SET_SWEEP_FROM(p) if (S_G.enable_object_backreferences) sweep_from = p
|
||||||
|
# define WITH_TOP_BACKREFERENCE(v, e) SET_SWEEP_FROM(v); e; SET_SWEEP_FROM(Sfalse)
|
||||||
|
# define SET_BACKREFERENCE(p) sweep_from = p;
|
||||||
|
# define PUSH_BACKREFERENCE(p) ptr old_sweep_from = sweep_from; SET_SWEEP_FROM(p);
|
||||||
|
# define POP_BACKREFERENCE() SET_SWEEP_FROM(old_sweep_from);
|
||||||
|
# define ADD_BACKREFERENCE_FROM(p, from_p) \
|
||||||
|
{ IGEN tg = target_generation; \
|
||||||
|
if ((S_G.enable_object_backreferences) && (target_generation < static_generation)) \
|
||||||
|
S_G.gcbackreference[tg] = S_cons_in(space_impure, tg, \
|
||||||
|
S_cons_in(space_impure, tg, p, from_p), \
|
||||||
|
S_G.gcbackreference[tg]); }
|
||||||
|
# define ADD_BACKREFERENCE(p) ADD_BACKREFERENCE_FROM(p, sweep_from)
|
||||||
|
#else
|
||||||
|
# define BACKREFERENCES_ENABLED 0
|
||||||
|
# define WITH_TOP_BACKREFERENCE(v, e) e
|
||||||
|
# define SET_BACKREFERENCE(p)
|
||||||
|
# define PUSH_BACKREFERENCE(p)
|
||||||
|
# define POP_BACKREFERENCE()
|
||||||
|
# define ADD_BACKREFERENCE(p)
|
||||||
|
# define ADD_BACKREFERENCE_FROM(p, from_p)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Values for a guardian entry's `pending` field when it's added to a
|
/* Values for a guardian entry's `pending` field when it's added to a
|
||||||
seginfo's pending list: */
|
seginfo's pending list: */
|
||||||
enum {
|
enum {
|
||||||
|
@ -280,7 +305,7 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
carefully we may reduce fragmentation and sweeping cost */
|
carefully we may reduce fragmentation and sweeping cost */
|
||||||
s = RECORDDESCPM(rtd) == FIX(1) && RECORDDESCMPM(rtd) == FIX(0) ?
|
s = RECORDDESCPM(rtd) == FIX(1) && RECORDDESCMPM(rtd) == FIX(0) ?
|
||||||
space_data :
|
space_data :
|
||||||
RECORDDESCPM(rtd) == FIX(-1) ?
|
((RECORDDESCPM(rtd) == FIX(-1)) && !BACKREFERENCES_ENABLED) ?
|
||||||
RECORDDESCMPM(rtd) == FIX(0) ?
|
RECORDDESCMPM(rtd) == FIX(0) ?
|
||||||
space_pure :
|
space_pure :
|
||||||
space_impure :
|
space_impure :
|
||||||
|
@ -302,6 +327,7 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
}
|
}
|
||||||
} else if (TYPEP(tf, mask_vector, type_vector)) {
|
} else if (TYPEP(tf, mask_vector, type_vector)) {
|
||||||
iptr len, n;
|
iptr len, n;
|
||||||
|
ISPC s;
|
||||||
len = Svector_length(pp);
|
len = Svector_length(pp);
|
||||||
n = size_vector(len);
|
n = size_vector(len);
|
||||||
#ifdef ENABLE_OBJECT_COUNTS
|
#ifdef ENABLE_OBJECT_COUNTS
|
||||||
|
@ -309,11 +335,10 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
S_G.bytesof[tg][countof_vector] += n;
|
S_G.bytesof[tg][countof_vector] += n;
|
||||||
#endif /* ENABLE_OBJECT_COUNTS */
|
#endif /* ENABLE_OBJECT_COUNTS */
|
||||||
/* assumes vector lengths look like fixnums; if not, vectors will need their own space */
|
/* assumes vector lengths look like fixnums; if not, vectors will need their own space */
|
||||||
if ((uptr)tf & vector_immutable_flag) {
|
s = (((uptr)tf & vector_immutable_flag)
|
||||||
find_room(space_pure, tg, type_typed_object, n, p);
|
? (BACKREFERENCES_ENABLED ? space_pure_typed_object : space_pure)
|
||||||
} else {
|
: (BACKREFERENCES_ENABLED ? space_impure_typed_object : space_impure));
|
||||||
find_room(space_impure, tg, type_typed_object, n, p);
|
find_room(s, tg, type_typed_object, n, p);
|
||||||
}
|
|
||||||
copy_ptrs(type_typed_object, p, pp, n);
|
copy_ptrs(type_typed_object, p, pp, n);
|
||||||
/* pad if necessary */
|
/* pad if necessary */
|
||||||
if ((len & 1) == 0) INITVECTIT(p, len) = FIX(0);
|
if ((len & 1) == 0) INITVECTIT(p, len) = FIX(0);
|
||||||
|
@ -350,7 +375,7 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
#ifdef ENABLE_OBJECT_COUNTS
|
#ifdef ENABLE_OBJECT_COUNTS
|
||||||
S_G.countof[tg][countof_tlc] += 1;
|
S_G.countof[tg][countof_tlc] += 1;
|
||||||
#endif /* ENABLE_OBJECT_COUNTS */
|
#endif /* ENABLE_OBJECT_COUNTS */
|
||||||
find_room(space_impure, tg, type_typed_object, size_tlc, p);
|
find_room((BACKREFERENCES_ENABLED ? space_impure_typed_object : space_impure), tg, type_typed_object, size_tlc, p);
|
||||||
TLCTYPE(p) = type_tlc;
|
TLCTYPE(p) = type_tlc;
|
||||||
INITTLCKEYVAL(p) = keyval = TLCKEYVAL(pp);
|
INITTLCKEYVAL(p) = keyval = TLCKEYVAL(pp);
|
||||||
INITTLCHT(p) = TLCHT(pp);
|
INITTLCHT(p) = TLCHT(pp);
|
||||||
|
@ -364,14 +389,14 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
if (next != Sfalse && SPACE(keyval) & space_old)
|
if (next != Sfalse && SPACE(keyval) & space_old)
|
||||||
tlcs_to_rehash = S_cons_in(space_new, 0, p, tlcs_to_rehash);
|
tlcs_to_rehash = S_cons_in(space_new, 0, p, tlcs_to_rehash);
|
||||||
} else if (TYPEP(tf, mask_box, type_box)) {
|
} else if (TYPEP(tf, mask_box, type_box)) {
|
||||||
|
ISPC s;
|
||||||
#ifdef ENABLE_OBJECT_COUNTS
|
#ifdef ENABLE_OBJECT_COUNTS
|
||||||
S_G.countof[tg][countof_box] += 1;
|
S_G.countof[tg][countof_box] += 1;
|
||||||
#endif /* ENABLE_OBJECT_COUNTS */
|
#endif /* ENABLE_OBJECT_COUNTS */
|
||||||
if ((uptr)tf == type_immutable_box) {
|
s = (((uptr)tf == type_immutable_box)
|
||||||
find_room(space_pure, tg, type_typed_object, size_box, p);
|
? (BACKREFERENCES_ENABLED ? space_pure_typed_object : space_pure)
|
||||||
} else {
|
: (BACKREFERENCES_ENABLED ? space_impure_typed_object : space_impure));
|
||||||
find_room(space_impure, tg, type_typed_object, size_box, p);
|
find_room(s, tg, type_typed_object, size_box, p);
|
||||||
}
|
|
||||||
BOXTYPE(p) = (iptr)tf;
|
BOXTYPE(p) = (iptr)tf;
|
||||||
INITBOXREF(p) = Sunbox(pp);
|
INITBOXREF(p) = Sunbox(pp);
|
||||||
} else if ((iptr)tf == type_ratnum) {
|
} else if ((iptr)tf == type_ratnum) {
|
||||||
|
@ -489,6 +514,7 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
INITCDR(q) = Scdr(qq);
|
INITCDR(q) = Scdr(qq);
|
||||||
FWDMARKER(qq) = forward_marker;
|
FWDMARKER(qq) = forward_marker;
|
||||||
FWDADDRESS(qq) = q;
|
FWDADDRESS(qq) = q;
|
||||||
|
ADD_BACKREFERENCE_FROM(q, p)
|
||||||
} else {
|
} else {
|
||||||
if (si->space == (space_weakpair | space_old)) {
|
if (si->space == (space_weakpair | space_old)) {
|
||||||
#ifdef ENABLE_OBJECT_COUNTS
|
#ifdef ENABLE_OBJECT_COUNTS
|
||||||
|
@ -536,7 +562,9 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
S_G.countof[tg][countof_closure] += 1;
|
S_G.countof[tg][countof_closure] += 1;
|
||||||
S_G.bytesof[tg][countof_closure] += n;
|
S_G.bytesof[tg][countof_closure] += n;
|
||||||
#endif /* ENABLE_OBJECT_COUNTS */
|
#endif /* ENABLE_OBJECT_COUNTS */
|
||||||
if (CODETYPE(code) & (code_flag_mutable_closure << code_flags_offset)) {
|
if (BACKREFERENCES_ENABLED) {
|
||||||
|
find_room(space_closure, tg, type_closure, n, p);
|
||||||
|
} else if (CODETYPE(code) & (code_flag_mutable_closure << code_flags_offset)) {
|
||||||
/* Using `space_impure` is ok because the code slot of a mutable
|
/* Using `space_impure` is ok because the code slot of a mutable
|
||||||
closure is never mutated, so the code is never newer than the
|
closure is never mutated, so the code is never newer than the
|
||||||
closure. If it were, then because the code pointer looks like
|
closure. If it were, then because the code pointer looks like
|
||||||
|
@ -577,6 +605,8 @@ static ptr copy(pp, si) ptr pp; seginfo *si; {
|
||||||
FWDMARKER(pp) = forward_marker;
|
FWDMARKER(pp) = forward_marker;
|
||||||
FWDADDRESS(pp) = p;
|
FWDADDRESS(pp) = p;
|
||||||
|
|
||||||
|
ADD_BACKREFERENCE(p)
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,6 +622,8 @@ static void sweep_ptrs(pp, n) ptr *pp; iptr n; {
|
||||||
static void sweep(ptr tc, ptr p, IBOOL sweep_pure) {
|
static void sweep(ptr tc, ptr p, IBOOL sweep_pure) {
|
||||||
ptr tf; ITYPE t;
|
ptr tf; ITYPE t;
|
||||||
|
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
|
|
||||||
if ((t = TYPEBITS(p)) == type_pair) {
|
if ((t = TYPEBITS(p)) == type_pair) {
|
||||||
ISPC s = SPACE(p) & ~(space_locked | space_old);
|
ISPC s = SPACE(p) & ~(space_locked | space_old);
|
||||||
if (s == space_ephemeron)
|
if (s == space_ephemeron)
|
||||||
|
@ -635,6 +667,10 @@ static void sweep(ptr tc, ptr p, IBOOL sweep_pure) {
|
||||||
relocate(&RATNUM(p))
|
relocate(&RATNUM(p))
|
||||||
relocate(&RATDEN(p))
|
relocate(&RATDEN(p))
|
||||||
}
|
}
|
||||||
|
} else if ((iptr)tf == type_tlc) {
|
||||||
|
relocate(&INITTLCKEYVAL(p));
|
||||||
|
relocate(&INITTLCHT(p));
|
||||||
|
relocate(&INITTLCNEXT(p));
|
||||||
} else if ((iptr)tf == type_exactnum) {
|
} else if ((iptr)tf == type_exactnum) {
|
||||||
if (sweep_pure) {
|
if (sweep_pure) {
|
||||||
relocate(&EXACTNUM_REAL_PART(p))
|
relocate(&EXACTNUM_REAL_PART(p))
|
||||||
|
@ -657,6 +693,8 @@ static void sweep(ptr tc, ptr p, IBOOL sweep_pure) {
|
||||||
} else {
|
} else {
|
||||||
S_error_abort("sweep(gc): illegal type");
|
S_error_abort("sweep(gc): illegal type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sweep_in_old() is like sweep(), but the goal is to sweep the
|
/* sweep_in_old() is like sweep(), but the goal is to sweep the
|
||||||
|
@ -909,6 +947,13 @@ void GCENTRY(ptr tc, IGEN mcg, IGEN tg) {
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_OBJECT_COUNTS */
|
#endif /* ENABLE_OBJECT_COUNTS */
|
||||||
|
|
||||||
|
/* Clear any backreference lists for copied generations */
|
||||||
|
for (g = 0; g <= mcg; g += 1) {
|
||||||
|
S_G.gcbackreference[g] = Snil;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_BACKREFERENCE(Sfalse) /* #f => root or locked */
|
||||||
|
|
||||||
/* pre-collection handling of locked objects. */
|
/* pre-collection handling of locked objects. */
|
||||||
|
|
||||||
/* create a single sorted_locked_object vector for all copied generations
|
/* create a single sorted_locked_object vector for all copied generations
|
||||||
|
@ -966,7 +1011,10 @@ void GCENTRY(ptr tc, IGEN mcg, IGEN tg) {
|
||||||
v = sorted_locked_objects;
|
v = sorted_locked_objects;
|
||||||
i = Svector_length(v);
|
i = Svector_length(v);
|
||||||
x = *(vp = &INITVECTIT(v, 0));
|
x = *(vp = &INITVECTIT(v, 0));
|
||||||
do sweep(tc, x, 1); while (--i != 0 && (x = *++vp) != MAXPTR);
|
do {
|
||||||
|
sweep(tc, x, 1);
|
||||||
|
ADD_BACKREFERENCE(x)
|
||||||
|
} while (--i != 0 && (x = *++vp) != MAXPTR);
|
||||||
}
|
}
|
||||||
/* sweep non-oldspace threads, since any thread may have an active stack */
|
/* sweep non-oldspace threads, since any thread may have an active stack */
|
||||||
for (ls = S_threads; ls != Snil; ls = Scdr(ls)) {
|
for (ls = S_threads; ls != Snil; ls = Scdr(ls)) {
|
||||||
|
@ -1092,17 +1140,20 @@ void GCENTRY(ptr tc, IGEN mcg, IGEN tg) {
|
||||||
pend_hold_ls = ls;
|
pend_hold_ls = ls;
|
||||||
} else {
|
} else {
|
||||||
seginfo *si;
|
seginfo *si;
|
||||||
if (!IMMEDIATE(rep) && (si = MaybeSegInfo(ptr_get_segment(rep))) != NULL && (si->space & space_old) && !locked(rep))
|
if (!IMMEDIATE(rep) && (si = MaybeSegInfo(ptr_get_segment(rep))) != NULL && (si->space & space_old) && !locked(rep)) {
|
||||||
|
PUSH_BACKREFERENCE(rep)
|
||||||
sweep_in_old(tc, rep);
|
sweep_in_old(tc, rep);
|
||||||
|
POP_BACKREFERENCE()
|
||||||
|
}
|
||||||
INITGUARDIANNEXT(ls) = maybe_final_ordered_ls;
|
INITGUARDIANNEXT(ls) = maybe_final_ordered_ls;
|
||||||
maybe_final_ordered_ls = ls;
|
maybe_final_ordered_ls = ls;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
relocate(&rep);
|
|
||||||
|
|
||||||
/* if tconc was old it's been forwarded */
|
/* if tconc was old it's been forwarded */
|
||||||
tconc = GUARDIANTCONC(ls);
|
tconc = GUARDIANTCONC(ls);
|
||||||
|
|
||||||
|
WITH_TOP_BACKREFERENCE(tconc, relocate(&rep));
|
||||||
|
|
||||||
old_end = Scdr(tconc);
|
old_end = Scdr(tconc);
|
||||||
/* allocating pair in tg means it will be swept, which is wasted effort, but should cause no harm */
|
/* allocating pair in tg means it will be swept, which is wasted effort, but should cause no harm */
|
||||||
new_end = S_cons_in(space_impure, tg, FIX(0), FIX(0));
|
new_end = S_cons_in(space_impure, tg, FIX(0), FIX(0));
|
||||||
|
@ -1134,12 +1185,15 @@ void GCENTRY(ptr tc, IGEN mcg, IGEN tg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rep = GUARDIANREP(ls);
|
rep = GUARDIANREP(ls);
|
||||||
relocate(&rep);
|
WITH_TOP_BACKREFERENCE(tconc, relocate(&rep));
|
||||||
relocate_rep = 1;
|
relocate_rep = 1;
|
||||||
|
|
||||||
#ifdef ENABLE_OBJECT_COUNTS
|
#ifdef ENABLE_OBJECT_COUNTS
|
||||||
S_G.countof[tg][countof_guardian] += 1;
|
S_G.countof[tg][countof_guardian] += 1;
|
||||||
#endif /* ENABLE_OBJECT_COUNTS */
|
#endif /* ENABLE_OBJECT_COUNTS */
|
||||||
|
/* In backreference mode, we rely on sweep of the guardian
|
||||||
|
entry not registering any backreferences. Otherwise,
|
||||||
|
bogus pair pointers would get created. */
|
||||||
find_room(space_pure, tg, typemod, size_guardian_entry, p);
|
find_room(space_pure, tg, typemod, size_guardian_entry, p);
|
||||||
INITGUARDIANOBJ(p) = GUARDIANOBJ(ls);
|
INITGUARDIANOBJ(p) = GUARDIANOBJ(ls);
|
||||||
INITGUARDIANREP(p) = rep;
|
INITGUARDIANREP(p) = rep;
|
||||||
|
@ -1496,11 +1550,13 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; {
|
||||||
do {
|
do {
|
||||||
change = 0;
|
change = 0;
|
||||||
sweep_space(space_impure, {
|
sweep_space(space_impure, {
|
||||||
|
SET_BACKREFERENCE(TYPE((ptr)pp, type_pair)) /* only pairs put here in backreference mode */
|
||||||
relocate_help(pp, p)
|
relocate_help(pp, p)
|
||||||
p = *(pp += 1);
|
p = *(pp += 1);
|
||||||
relocate_help(pp, p)
|
relocate_help(pp, p)
|
||||||
pp += 1;
|
pp += 1;
|
||||||
})
|
})
|
||||||
|
SET_BACKREFERENCE(Sfalse)
|
||||||
|
|
||||||
sweep_space(space_symbol, {
|
sweep_space(space_symbol, {
|
||||||
p = TYPE((ptr)pp, type_symbol);
|
p = TYPE((ptr)pp, type_symbol);
|
||||||
|
@ -1515,10 +1571,12 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; {
|
||||||
})
|
})
|
||||||
|
|
||||||
sweep_space(space_weakpair, {
|
sweep_space(space_weakpair, {
|
||||||
|
SET_BACKREFERENCE(TYPE((ptr)pp, type_pair))
|
||||||
p = *(pp += 1);
|
p = *(pp += 1);
|
||||||
relocate_help(pp, p)
|
relocate_help(pp, p)
|
||||||
pp += 1;
|
pp += 1;
|
||||||
})
|
})
|
||||||
|
SET_BACKREFERENCE(Sfalse)
|
||||||
|
|
||||||
sweep_space(space_ephemeron, {
|
sweep_space(space_ephemeron, {
|
||||||
p = TYPE((ptr)pp, type_pair);
|
p = TYPE((ptr)pp, type_pair);
|
||||||
|
@ -1527,11 +1585,13 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; {
|
||||||
})
|
})
|
||||||
|
|
||||||
sweep_space(space_pure, {
|
sweep_space(space_pure, {
|
||||||
|
SET_BACKREFERENCE(TYPE((ptr)pp, type_pair)) /* only pairs put here in backreference mode */
|
||||||
relocate_help(pp, p)
|
relocate_help(pp, p)
|
||||||
p = *(pp += 1);
|
p = *(pp += 1);
|
||||||
relocate_help(pp, p)
|
relocate_help(pp, p)
|
||||||
pp += 1;
|
pp += 1;
|
||||||
})
|
})
|
||||||
|
SET_BACKREFERENCE(Sfalse)
|
||||||
|
|
||||||
sweep_space(space_continuation, {
|
sweep_space(space_continuation, {
|
||||||
p = TYPE((ptr)pp, type_closure);
|
p = TYPE((ptr)pp, type_closure);
|
||||||
|
@ -1541,7 +1601,7 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; {
|
||||||
|
|
||||||
sweep_space(space_pure_typed_object, {
|
sweep_space(space_pure_typed_object, {
|
||||||
p = TYPE((ptr)pp, type_typed_object);
|
p = TYPE((ptr)pp, type_typed_object);
|
||||||
pp = (ptr *)((uptr)pp + sweep_typed_object(p));
|
pp = (ptr *)((uptr)pp + sweep_typed_object(tc, p));
|
||||||
})
|
})
|
||||||
|
|
||||||
sweep_space(space_code, {
|
sweep_space(space_code, {
|
||||||
|
@ -1557,6 +1617,19 @@ static void sweep_generation(tc, g) ptr tc; IGEN g; {
|
||||||
size_record_inst(UNFIX(RECORDDESCSIZE(RECORDINSTTYPE(p)))));
|
size_record_inst(UNFIX(RECORDDESCSIZE(RECORDINSTTYPE(p)))));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* space used only as needed for backreferences: */
|
||||||
|
sweep_space(space_impure_typed_object, {
|
||||||
|
p = TYPE((ptr)pp, type_typed_object);
|
||||||
|
pp = (ptr *)((uptr)pp + sweep_typed_object(tc, p));
|
||||||
|
})
|
||||||
|
|
||||||
|
/* space used only as needed for backreferences: */
|
||||||
|
sweep_space(space_closure, {
|
||||||
|
p = TYPE((ptr)pp, type_closure);
|
||||||
|
sweep(tc, p, 1);
|
||||||
|
pp = (ptr *)((uptr)pp + size_object(p));
|
||||||
|
})
|
||||||
|
|
||||||
/* Waiting until sweeping doesn't trigger a change reduces the
|
/* Waiting until sweeping doesn't trigger a change reduces the
|
||||||
chance that an ephemeron must be reigistered as a
|
chance that an ephemeron must be reigistered as a
|
||||||
segment-specific trigger or gets triggered for recheck, but
|
segment-specific trigger or gets triggered for recheck, but
|
||||||
|
@ -1598,6 +1671,8 @@ static iptr size_object(p) ptr p; {
|
||||||
return size_fxvector(Sfxvector_length(p));
|
return size_fxvector(Sfxvector_length(p));
|
||||||
} else if (TYPEP(tf, mask_box, type_box)) {
|
} else if (TYPEP(tf, mask_box, type_box)) {
|
||||||
return size_box;
|
return size_box;
|
||||||
|
} else if ((iptr)tf == type_tlc) {
|
||||||
|
return size_tlc;
|
||||||
} else if ((iptr)tf == type_ratnum) {
|
} else if ((iptr)tf == type_ratnum) {
|
||||||
return size_ratnum;
|
return size_ratnum;
|
||||||
} else if ((iptr)tf == type_exactnum) {
|
} else if ((iptr)tf == type_exactnum) {
|
||||||
|
@ -1620,7 +1695,7 @@ static iptr size_object(p) ptr p; {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static iptr sweep_typed_object(p) ptr p; {
|
static iptr sweep_typed_object(tc, p) ptr tc; ptr p; {
|
||||||
ptr tf = TYPEFIELD(p);
|
ptr tf = TYPEFIELD(p);
|
||||||
|
|
||||||
if (TYPEP(tf, mask_record, type_record)) {
|
if (TYPEP(tf, mask_record, type_record)) {
|
||||||
|
@ -1630,13 +1705,16 @@ static iptr sweep_typed_object(p) ptr p; {
|
||||||
sweep_thread(p);
|
sweep_thread(p);
|
||||||
return size_thread;
|
return size_thread;
|
||||||
} else {
|
} else {
|
||||||
S_error_abort("sweep_typed_object(gc): unexpected type");
|
/* We get here only if backreference mode pushed othertyped objects into
|
||||||
return 0 /* not reached */;
|
a typed space */
|
||||||
|
sweep(tc, p, 1);
|
||||||
|
return size_object(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sweep_symbol(p) ptr p; {
|
static void sweep_symbol(p) ptr p; {
|
||||||
ptr val, code;
|
ptr val, code;
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
|
|
||||||
val = SYMVAL(p);
|
val = SYMVAL(p);
|
||||||
relocate(&val);
|
relocate(&val);
|
||||||
|
@ -1648,9 +1726,12 @@ static void sweep_symbol(p) ptr p; {
|
||||||
relocate(&INITSYMSPLIST(p))
|
relocate(&INITSYMSPLIST(p))
|
||||||
relocate(&INITSYMNAME(p))
|
relocate(&INITSYMNAME(p))
|
||||||
relocate(&INITSYMHASH(p))
|
relocate(&INITSYMHASH(p))
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sweep_port(p) ptr p; {
|
static void sweep_port(p) ptr p; {
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
relocate(&PORTHANDLER(p))
|
relocate(&PORTHANDLER(p))
|
||||||
relocate(&PORTINFO(p))
|
relocate(&PORTINFO(p))
|
||||||
relocate(&PORTNAME(p))
|
relocate(&PORTNAME(p))
|
||||||
|
@ -1666,11 +1747,13 @@ static void sweep_port(p) ptr p; {
|
||||||
relocate(&PORTIBUF(p))
|
relocate(&PORTIBUF(p))
|
||||||
PORTILAST(p) = (ptr)((iptr)PORTIBUF(p) + n);
|
PORTILAST(p) = (ptr)((iptr)PORTIBUF(p) + n);
|
||||||
}
|
}
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sweep_thread(p) ptr p; {
|
static void sweep_thread(p) ptr p; {
|
||||||
ptr tc = (ptr)THREADTC(p);
|
ptr tc = (ptr)THREADTC(p);
|
||||||
INT i;
|
INT i;
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
|
|
||||||
if (tc != (ptr)0) {
|
if (tc != (ptr)0) {
|
||||||
ptr old_stack = SCHEMESTACK(tc);
|
ptr old_stack = SCHEMESTACK(tc);
|
||||||
|
@ -1730,9 +1813,12 @@ static void sweep_thread(p) ptr p; {
|
||||||
relocate(&VIRTREG(tc, i));
|
relocate(&VIRTREG(tc, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sweep_continuation(p) ptr p; {
|
static void sweep_continuation(p) ptr p; {
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
relocate(&CONTWINDERS(p))
|
relocate(&CONTWINDERS(p))
|
||||||
|
|
||||||
/* bug out for shot 1-shot continuations */
|
/* bug out for shot 1-shot continuations */
|
||||||
|
@ -1746,6 +1832,8 @@ static void sweep_continuation(p) ptr p; {
|
||||||
|
|
||||||
/* use CLENGTH to avoid sweeping unoccupied portion of one-shots */
|
/* use CLENGTH to avoid sweeping unoccupied portion of one-shots */
|
||||||
sweep_stack((uptr)CONTSTACK(p), (uptr)CONTSTACK(p) + CONTCLENGTH(p), (uptr)CONTRET(p));
|
sweep_stack((uptr)CONTSTACK(p), (uptr)CONTSTACK(p) + CONTCLENGTH(p), (uptr)CONTRET(p));
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assumes stack has already been copied to newspace */
|
/* assumes stack has already been copied to newspace */
|
||||||
|
@ -1838,7 +1926,9 @@ static void sweep_stack(base, fp, ret) uptr base, fp, ret; {
|
||||||
} \
|
} \
|
||||||
|
|
||||||
static void sweep_record(x) ptr x; {
|
static void sweep_record(x) ptr x; {
|
||||||
|
PUSH_BACKREFERENCE(x)
|
||||||
sweep_or_check_record(x, relocate)
|
sweep_or_check_record(x, relocate)
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
#define check_self(pp) if (*(pp) == x) return 1;
|
#define check_self(pp) if (*(pp) == x) return 1;
|
||||||
|
@ -1850,6 +1940,7 @@ static int scan_record_for_self(x) ptr x; {
|
||||||
|
|
||||||
static IGEN sweep_dirty_record(x) ptr x; {
|
static IGEN sweep_dirty_record(x) ptr x; {
|
||||||
ptr *pp; ptr num; ptr rtd; IGEN tg, youngest;
|
ptr *pp; ptr num; ptr rtd; IGEN tg, youngest;
|
||||||
|
PUSH_BACKREFERENCE(x)
|
||||||
|
|
||||||
tg = target_generation;
|
tg = target_generation;
|
||||||
youngest = 0xff;
|
youngest = 0xff;
|
||||||
|
@ -1890,12 +1981,16 @@ static IGEN sweep_dirty_record(x) ptr x; {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
|
|
||||||
return youngest;
|
return youngest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sweep_code_object(tc, co) ptr tc, co; {
|
static void sweep_code_object(tc, co) ptr tc, co; {
|
||||||
ptr t, oldco; iptr a, m, n;
|
ptr t, oldco; iptr a, m, n;
|
||||||
|
|
||||||
|
PUSH_BACKREFERENCE(co)
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if ((CODETYPE(co) & mask_code) != type_code) {
|
if ((CODETYPE(co) & mask_code) != type_code) {
|
||||||
(void)printf("unexpected type %x sweeping code object %p\n", CODETYPE(co), co);
|
(void)printf("unexpected type %x sweeping code object %p\n", CODETYPE(co), co);
|
||||||
|
@ -1950,6 +2045,8 @@ static void sweep_code_object(tc, co) ptr tc, co; {
|
||||||
}
|
}
|
||||||
|
|
||||||
S_record_code_mod(tc, (uptr)&CODEIT(co,0), (uptr)CODELEN(co));
|
S_record_code_mod(tc, (uptr)&CODEIT(co,0), (uptr)CODELEN(co));
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _weakseginfo {
|
typedef struct _weakseginfo {
|
||||||
|
@ -1983,6 +2080,8 @@ static void sweep_dirty(void) {
|
||||||
IGEN from_g, to_g;
|
IGEN from_g, to_g;
|
||||||
seginfo *dirty_si, *nextsi;
|
seginfo *dirty_si, *nextsi;
|
||||||
|
|
||||||
|
PUSH_BACKREFERENCE(Snil) /* '() => from unspecified old object */
|
||||||
|
|
||||||
tg = target_generation;
|
tg = target_generation;
|
||||||
mcg = max_copied_generation;
|
mcg = max_copied_generation;
|
||||||
weaksegments_to_resweep = NULL;
|
weaksegments_to_resweep = NULL;
|
||||||
|
@ -2040,7 +2139,7 @@ static void sweep_dirty(void) {
|
||||||
/* assume we won't find any wrong-way pointers */
|
/* assume we won't find any wrong-way pointers */
|
||||||
youngest = 0xff;
|
youngest = 0xff;
|
||||||
|
|
||||||
if (s == space_impure) {
|
if ((s == space_impure) || (s == space_impure_typed_object) || (s == space_closure)) {
|
||||||
while (pp < ppend && *pp != forward_marker) {
|
while (pp < ppend && *pp != forward_marker) {
|
||||||
/* handle two pointers at a time */
|
/* handle two pointers at a time */
|
||||||
relocate_dirty(pp,tg,youngest)
|
relocate_dirty(pp,tg,youngest)
|
||||||
|
@ -2060,9 +2159,8 @@ static void sweep_dirty(void) {
|
||||||
(size_symbol / sizeof(ptr));
|
(size_symbol / sizeof(ptr));
|
||||||
|
|
||||||
while (pp < ppend && *pp != forward_marker) { /* might overshoot card by part of a symbol. no harm. */
|
while (pp < ppend && *pp != forward_marker) { /* might overshoot card by part of a symbol. no harm. */
|
||||||
ptr p, val, code;
|
ptr val, code, p = TYPE((ptr)pp, type_symbol);
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
p = TYPE((ptr)pp, type_symbol);
|
|
||||||
|
|
||||||
val = SYMVAL(p);
|
val = SYMVAL(p);
|
||||||
relocate_dirty(&val,tg,youngest)
|
relocate_dirty(&val,tg,youngest)
|
||||||
|
@ -2076,6 +2174,8 @@ static void sweep_dirty(void) {
|
||||||
relocate_dirty(&INITSYMHASH(p),tg,youngest)
|
relocate_dirty(&INITSYMHASH(p),tg,youngest)
|
||||||
|
|
||||||
pp += size_symbol / sizeof(ptr);
|
pp += size_symbol / sizeof(ptr);
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
} else if (s == space_port) {
|
} else if (s == space_port) {
|
||||||
/* old ports cannot overlap segment boundaries
|
/* old ports cannot overlap segment boundaries
|
||||||
|
@ -2090,6 +2190,7 @@ static void sweep_dirty(void) {
|
||||||
|
|
||||||
while (pp < ppend && *pp != forward_marker) { /* might overshoot card by part of a port. no harm. */
|
while (pp < ppend && *pp != forward_marker) { /* might overshoot card by part of a port. no harm. */
|
||||||
ptr p = TYPE((ptr)pp, type_typed_object);
|
ptr p = TYPE((ptr)pp, type_typed_object);
|
||||||
|
PUSH_BACKREFERENCE(p)
|
||||||
|
|
||||||
relocate_dirty(&PORTHANDLER(p),tg,youngest)
|
relocate_dirty(&PORTHANDLER(p),tg,youngest)
|
||||||
relocate_dirty(&PORTINFO(p),tg,youngest)
|
relocate_dirty(&PORTINFO(p),tg,youngest)
|
||||||
|
@ -2108,6 +2209,8 @@ static void sweep_dirty(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pp += size_port / sizeof(ptr);
|
pp += size_port / sizeof(ptr);
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
} else if (s == space_impure_record) { /* abandon hope all ye who enter here */
|
} else if (s == space_impure_record) { /* abandon hope all ye who enter here */
|
||||||
uptr j; ptr p, pnext; seginfo *si;
|
uptr j; ptr p, pnext; seginfo *si;
|
||||||
|
@ -2192,6 +2295,8 @@ static void sweep_dirty(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resweep_dirty_weak_pairs() {
|
static void resweep_dirty_weak_pairs() {
|
||||||
|
@ -2319,6 +2424,7 @@ static void add_trigger_ephemerons_to_repending(ptr pe) {
|
||||||
static void check_ephemeron(ptr pe, int add_to_trigger) {
|
static void check_ephemeron(ptr pe, int add_to_trigger) {
|
||||||
ptr p;
|
ptr p;
|
||||||
seginfo *si;
|
seginfo *si;
|
||||||
|
PUSH_BACKREFERENCE(pe);
|
||||||
|
|
||||||
p = Scar(pe);
|
p = Scar(pe);
|
||||||
if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->space & space_old && !locked(p)) {
|
if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && si->space & space_old && !locked(p)) {
|
||||||
|
@ -2340,6 +2446,8 @@ static void check_ephemeron(ptr pe, int add_to_trigger) {
|
||||||
} else {
|
} else {
|
||||||
relocate(&INITCDR(pe))
|
relocate(&INITCDR(pe))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POP_BACKREFERENCE();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_pending_ephemerons() {
|
static void check_pending_ephemerons() {
|
||||||
|
@ -2369,6 +2477,7 @@ static void check_pending_ephemerons() {
|
||||||
static int check_dirty_ephemeron(ptr pe, int tg, int youngest) {
|
static int check_dirty_ephemeron(ptr pe, int tg, int youngest) {
|
||||||
ptr p;
|
ptr p;
|
||||||
seginfo *si;
|
seginfo *si;
|
||||||
|
PUSH_BACKREFERENCE(pe);
|
||||||
|
|
||||||
p = Scar(pe);
|
p = Scar(pe);
|
||||||
if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL) {
|
if (!IMMEDIATE(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL) {
|
||||||
|
@ -2399,6 +2508,8 @@ static int check_dirty_ephemeron(ptr pe, int tg, int youngest) {
|
||||||
relocate_dirty(&INITCDR(pe), tg, youngest)
|
relocate_dirty(&INITCDR(pe), tg, youngest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POP_BACKREFERENCE()
|
||||||
|
|
||||||
return youngest;
|
return youngest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,6 +349,27 @@ ptr S_object_counts(void) {
|
||||||
return outer_alist;
|
return outer_alist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IBOOL S_enable_object_backreferences(void) {
|
||||||
|
return S_G.enable_object_backreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
void S_set_enable_object_backreferences(IBOOL eoc) {
|
||||||
|
S_G.enable_object_backreferences = eoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr S_object_backreferences(void) {
|
||||||
|
IGEN g; ptr ls = Snil;
|
||||||
|
|
||||||
|
tc_mutex_acquire()
|
||||||
|
|
||||||
|
for (g = S_G.max_nonstatic_generation+1; g--; )
|
||||||
|
ls = Scons(S_G.gcbackreference[g], ls);
|
||||||
|
|
||||||
|
tc_mutex_release()
|
||||||
|
|
||||||
|
return ls;
|
||||||
|
}
|
||||||
|
|
||||||
/* Scompact_heap(). Compact into as few O/S chunks as possible and
|
/* Scompact_heap(). Compact into as few O/S chunks as possible and
|
||||||
* move objects into static generation
|
* move objects into static generation
|
||||||
*/
|
*/
|
||||||
|
@ -819,7 +840,7 @@ void S_do_gc(IGEN mcg, IGEN tg) {
|
||||||
|
|
||||||
|
|
||||||
void S_gc(ptr tc, IGEN mcg, IGEN tg) {
|
void S_gc(ptr tc, IGEN mcg, IGEN tg) {
|
||||||
if (tg == static_generation || S_G.enable_object_counts)
|
if (tg == static_generation || S_G.enable_object_counts || S_G.enable_object_backreferences)
|
||||||
S_gc_oce(tc, mcg, tg);
|
S_gc_oce(tc, mcg, tg);
|
||||||
else
|
else
|
||||||
S_gc_ocd(tc, mcg, tg);
|
S_gc_ocd(tc, mcg, tg);
|
||||||
|
|
|
@ -73,6 +73,7 @@ EXTERN struct {
|
||||||
ptr heap_reserve_ratio_id;
|
ptr heap_reserve_ratio_id;
|
||||||
IBOOL retain_static_relocation;
|
IBOOL retain_static_relocation;
|
||||||
IBOOL enable_object_counts;
|
IBOOL enable_object_counts;
|
||||||
|
IBOOL enable_object_backreferences;
|
||||||
ptr scheme_version_id;
|
ptr scheme_version_id;
|
||||||
ptr make_load_binary_id;
|
ptr make_load_binary_id;
|
||||||
ptr load_binary;
|
ptr load_binary;
|
||||||
|
@ -126,6 +127,7 @@ EXTERN struct {
|
||||||
uptr countof_size[countof_types];
|
uptr countof_size[countof_types];
|
||||||
ptr static_id;
|
ptr static_id;
|
||||||
ptr countof_names;
|
ptr countof_names;
|
||||||
|
ptr gcbackreference[static_generation+1];
|
||||||
|
|
||||||
/* intern.c */
|
/* intern.c */
|
||||||
iptr *oblist_length_pointer;
|
iptr *oblist_length_pointer;
|
||||||
|
|
3
c/prim.c
3
c/prim.c
|
@ -184,6 +184,9 @@ void S_prim_init() {
|
||||||
Sforeign_symbol("(cs)set_enable_object_counts", (void *)S_set_enable_object_counts);
|
Sforeign_symbol("(cs)set_enable_object_counts", (void *)S_set_enable_object_counts);
|
||||||
Sforeign_symbol("(cs)object_counts", (void *)S_object_counts);
|
Sforeign_symbol("(cs)object_counts", (void *)S_object_counts);
|
||||||
Sforeign_symbol("(cs)fire_collector", (void *)S_fire_collector);
|
Sforeign_symbol("(cs)fire_collector", (void *)S_fire_collector);
|
||||||
|
Sforeign_symbol("(cs)enable_object_backreferences", (void *)S_enable_object_backreferences);
|
||||||
|
Sforeign_symbol("(cs)set_enable_object_backreferences", (void *)S_set_enable_object_backreferences);
|
||||||
|
Sforeign_symbol("(cs)object_backreferences", (void *)S_object_backreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s_instantiate_code_object() {
|
static void s_instantiate_code_object() {
|
||||||
|
|
|
@ -996,6 +996,7 @@ extern void Sscheme_init(abnormal_exit) void (*abnormal_exit) PROTO((void)); {
|
||||||
|
|
||||||
S_G.retain_static_relocation = 0;
|
S_G.retain_static_relocation = 0;
|
||||||
S_G.enable_object_counts = 0;
|
S_G.enable_object_counts = 0;
|
||||||
|
S_G.enable_object_backreferences = 0;
|
||||||
|
|
||||||
boot_count = 0;
|
boot_count = 0;
|
||||||
|
|
||||||
|
|
|
@ -4622,6 +4622,81 @@ of \scheme{(collect-maximum-generation)}, inclusive, or the symbol
|
||||||
(object-counts))))) ;=> (2 . 16)
|
(object-counts))))) ;=> (2 . 16)
|
||||||
\endschemedisplay
|
\endschemedisplay
|
||||||
|
|
||||||
|
%----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
\entryheader
|
||||||
|
\formdef{enable-object-backreferences}{\categoryglobalparameter}{enable-object-backreferences}
|
||||||
|
\listlibraries
|
||||||
|
\endentryheader
|
||||||
|
|
||||||
|
The value of \scheme{enable-object-backreferences} is a boolean value that
|
||||||
|
determines whether the collector records information about which other object
|
||||||
|
caused an object to be retained and
|
||||||
|
hence whether the backreferences reported by the procedure
|
||||||
|
\scheme{object-backreferences} are accurate.
|
||||||
|
The parameter is set to \scheme{#f} by default, since backreference recording
|
||||||
|
adds overhead to collection.
|
||||||
|
|
||||||
|
Beware that backreference recording can have small performance affects
|
||||||
|
even after it is disabled---at least until the next collection over
|
||||||
|
the same generations---since backreference records constrain the way
|
||||||
|
that the collector stores some objects.
|
||||||
|
|
||||||
|
\entryheader
|
||||||
|
\formdef{object-backreferences}{\categoryprocedure}{(object-backreferences)}
|
||||||
|
\returns a list of list of pairs
|
||||||
|
\listlibraries
|
||||||
|
\endentryheader
|
||||||
|
|
||||||
|
The procedure \scheme{object-backreferences} returns a list of
|
||||||
|
backreference lists. Each backreference list is a list of pairs, where
|
||||||
|
the \scheme{car} of the pair is a referenced object, and the
|
||||||
|
\scheme{cdr} of the pair is either \scheme{#f} or a value that caused
|
||||||
|
the \scheme{car}'s value or be retained during collection. The
|
||||||
|
\scheme{cdr} of a backreference pair is \scheme{#f} if the object in
|
||||||
|
the \scheme{car} is retained by a root reference within the system's
|
||||||
|
implementation or static generation. By locating the \scheme{cdr} of
|
||||||
|
one pair as the \scheme{car} of another, chains of objects as
|
||||||
|
discovered by the collector can be traced back to roots.
|
||||||
|
|
||||||
|
The list returned by \scheme{object-backreferences} contains one
|
||||||
|
backreference list for each nonstatic generation (in order, starting
|
||||||
|
with generation \scheme{0}). An object is recorded in a backreference
|
||||||
|
list for the destination generation to which it is moved by
|
||||||
|
collection. The collector records backreference information only when
|
||||||
|
\scheme{enable-object-backreferences} is set to a true value, and only
|
||||||
|
for objects that start in generations that are collected.
|
||||||
|
|
||||||
|
For example, assuming that backreferences have not been previously
|
||||||
|
enabled, the result of
|
||||||
|
%
|
||||||
|
\schemedisplay
|
||||||
|
(collect-request-handler void)
|
||||||
|
(enable-object-backreferences #t)
|
||||||
|
(collect 0)
|
||||||
|
(enable-object-backreferences #f)
|
||||||
|
(object-backreferences)
|
||||||
|
\endschemedisplay
|
||||||
|
%
|
||||||
|
will have a non-empty backreference list only for the second
|
||||||
|
list in the result (i.e., the list for generation \scheme{1}).
|
||||||
|
|
||||||
|
Although \scheme{object-backreferences} reports generation-specific
|
||||||
|
information to reflect its cooperation with generational collection,
|
||||||
|
backreference information is most useful after a collection of all
|
||||||
|
generations up to the maximum nonstatic generation. In that case,
|
||||||
|
backreference information can be used to discover why a particular
|
||||||
|
value or kind of value remains allocated or remains in a weak pair
|
||||||
|
after garbage collection.
|
||||||
|
|
||||||
|
\schemedisplay
|
||||||
|
(collect-request-handler void)
|
||||||
|
(enable-object-backreferences #t)
|
||||||
|
(define b (box "hello"))
|
||||||
|
(collect 0)
|
||||||
|
(assq (unbox b) (cadr (object-backreferences))) ;=> ("hello" . #&"hello")
|
||||||
|
\endschemedisplay
|
||||||
|
|
||||||
\section{Cost Centers\label{SECTMISCCOSTCENTERS}}
|
\section{Cost Centers\label{SECTMISCCOSTCENTERS}}
|
||||||
|
|
||||||
Cost centers are used to track the bytes allocated, instructions executed,
|
Cost centers are used to track the bytes allocated, instructions executed,
|
||||||
|
|
84
mats/7.ms
84
mats/7.ms
|
@ -3841,6 +3841,90 @@ evaluating module init
|
||||||
(or (not a) (not (assq 'static (cdr a)))))
|
(or (not a) (not (assq 'static (cdr a)))))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(mat object-references
|
||||||
|
(begin
|
||||||
|
(define variable-whose-value-is-a-gensym (gensym))
|
||||||
|
(define guardian-to-hold-gensyms (make-guardian))
|
||||||
|
;; works on tree-shaped objects, except that
|
||||||
|
;; weak/ephemeron pairs can create DAGs; if a weak pair has
|
||||||
|
;; a non-#!bwp in the `car`, it must be referenced
|
||||||
|
;; by a box or by `guardian-to-hold-gensyms`
|
||||||
|
(define (check-references obj)
|
||||||
|
(let ([backrefs (make-eq-hashtable)]
|
||||||
|
[old-collect (collect-request-handler)])
|
||||||
|
(enable-object-backreferences #t)
|
||||||
|
(collect-request-handler void)
|
||||||
|
(collect (collect-maximum-generation))
|
||||||
|
(for-each (lambda (brs)
|
||||||
|
(for-each (lambda (br)
|
||||||
|
(hashtable-set! backrefs (car br) (cdr br)))
|
||||||
|
brs))
|
||||||
|
(object-backreferences))
|
||||||
|
(enable-object-backreferences #f)
|
||||||
|
(collect-request-handler old-collect)
|
||||||
|
(and
|
||||||
|
;; Check the given object
|
||||||
|
(let loop ([obj obj] [parent #f])
|
||||||
|
(and (or (not parent)
|
||||||
|
(null? obj)
|
||||||
|
(boolean? obj)
|
||||||
|
(eq? parent (hashtable-ref backrefs obj #f)))
|
||||||
|
(cond
|
||||||
|
[(pair? obj)
|
||||||
|
(and (cond
|
||||||
|
[(weak-pair? obj)
|
||||||
|
(let ([a (car obj)])
|
||||||
|
(or (eq? a #!bwp)
|
||||||
|
(let ([p (hashtable-ref backrefs a #f)])
|
||||||
|
(or (box? p)
|
||||||
|
;; retained by `guardian-to-hold-gensyms`
|
||||||
|
;; means retains by it's tconc
|
||||||
|
(and (pair? p)
|
||||||
|
(eq? guardian-to-hold-gensyms
|
||||||
|
(hashtable-ref backrefs p #f)))))))]
|
||||||
|
[(ephemeron-pair? obj) #t]
|
||||||
|
[else
|
||||||
|
(loop (car obj) obj)])
|
||||||
|
(loop (cdr obj) obj))]
|
||||||
|
[(vector? obj)
|
||||||
|
(let vloop ([i 0])
|
||||||
|
(or (= i (vector-length obj))
|
||||||
|
(and (loop (vector-ref obj i) obj)
|
||||||
|
(vloop (add1 i)))))]
|
||||||
|
[(box? obj)
|
||||||
|
(loop (unbox obj) obj)]
|
||||||
|
[(procedure? obj)
|
||||||
|
(let ([insp (inspect/object obj)])
|
||||||
|
(let ploop ([i 0])
|
||||||
|
(or (= i (insp 'length))
|
||||||
|
(and (loop (((insp 'ref i) 'ref) 'value) obj)
|
||||||
|
(ploop (add1 i))))))]
|
||||||
|
[else #t])))
|
||||||
|
;; Check a symbol binding
|
||||||
|
(let ([var (hashtable-ref backrefs variable-whose-value-is-a-gensym #f)])
|
||||||
|
(and (eq? 'symbol ((inspect/object var) 'type))
|
||||||
|
(equal? "variable-whose-value-is-a-gensym"
|
||||||
|
(((inspect/object var) 'name) 'value)))))))
|
||||||
|
#t)
|
||||||
|
(check-references (list (gensym)
|
||||||
|
(vector (gensym) (box (cons (gensym) (gensym))) (gensym))
|
||||||
|
(let ([v (gensym)])
|
||||||
|
(lambda ()
|
||||||
|
v))
|
||||||
|
;; make sure `weak-cons` doesn't retain
|
||||||
|
(weak-cons (gensym) #f)
|
||||||
|
(let ([v (gensym)])
|
||||||
|
;; weak pair won't count as retaining reference
|
||||||
|
(weak-cons v
|
||||||
|
;; containing box will count
|
||||||
|
(box v)))
|
||||||
|
(let ([v (gensym)])
|
||||||
|
(guardian-to-hold-gensyms v)
|
||||||
|
(weak-cons v #f))
|
||||||
|
(let ([v (gensym)])
|
||||||
|
(list v (ephemeron-cons v (gensym))))))
|
||||||
|
)
|
||||||
|
|
||||||
(mat collect-rendezvous
|
(mat collect-rendezvous
|
||||||
(begin
|
(begin
|
||||||
(define (check-working-gc collect)
|
(define (check-working-gc collect)
|
||||||
|
|
|
@ -73,6 +73,13 @@
|
||||||
[() ($get-enable-object-counts)]
|
[() ($get-enable-object-counts)]
|
||||||
[(b) ($set-enable-object-counts b)])))
|
[(b) ($set-enable-object-counts b)])))
|
||||||
|
|
||||||
|
(define-who enable-object-backreferences
|
||||||
|
(let ([$get-enable-object-backreferences (foreign-procedure "(cs)enable_object_backreferences" () boolean)]
|
||||||
|
[$set-enable-object-backreferences (foreign-procedure "(cs)set_enable_object_backreferences" (boolean) void)])
|
||||||
|
(case-lambda
|
||||||
|
[() ($get-enable-object-backreferences)]
|
||||||
|
[(b) ($set-enable-object-backreferences b)])))
|
||||||
|
|
||||||
(define-who collect-trip-bytes
|
(define-who collect-trip-bytes
|
||||||
(make-parameter
|
(make-parameter
|
||||||
(constant default-collect-trip-bytes)
|
(constant default-collect-trip-bytes)
|
||||||
|
|
|
@ -645,11 +645,13 @@
|
||||||
(continuation "cont" #\k 7) ;
|
(continuation "cont" #\k 7) ;
|
||||||
(code "code" #\c 8) ;
|
(code "code" #\c 8) ;
|
||||||
(pure-typed-object "p-tobj" #\r 9) ;
|
(pure-typed-object "p-tobj" #\r 9) ;
|
||||||
(impure-record "ip-rec" #\s 10)) ;
|
(impure-record "ip-rec" #\s 10) ;
|
||||||
|
(impure-typed-object "ip-tobj" #\t 11) ; as needed (instead of impure) for backtraces
|
||||||
|
(closure "closure" #\l 12)) ; as needed (instead of pure/impure) for backtraces
|
||||||
(unswept
|
(unswept
|
||||||
(data "data" #\d 11))) ; unswept objects allocated here
|
(data "data" #\d 13))) ; unswept objects allocated here
|
||||||
(unreal
|
(unreal
|
||||||
(empty "empty" #\e 12))) ; available segments
|
(empty "empty" #\e 14))) ; available segments
|
||||||
|
|
||||||
;;; enumeration of types for which gc tracks object counts
|
;;; enumeration of types for which gc tracks object counts
|
||||||
;;; also update gc.c
|
;;; also update gc.c
|
||||||
|
|
|
@ -2880,3 +2880,5 @@
|
||||||
[(x g) ($compute-composition x (filter-generation who g))])))
|
[(x g) ($compute-composition x (filter-generation who g))])))
|
||||||
|
|
||||||
(define object-counts (foreign-procedure "(cs)object_counts" () ptr))
|
(define object-counts (foreign-procedure "(cs)object_counts" () ptr))
|
||||||
|
|
||||||
|
(define object-backreferences (foreign-procedure "(cs)object_backreferences" () ptr))
|
||||||
|
|
|
@ -947,6 +947,7 @@
|
||||||
(default-record-equal-procedure [sig [() -> (maybe-procedure)] [(maybe-procedure) -> (void)]] [flags])
|
(default-record-equal-procedure [sig [() -> (maybe-procedure)] [(maybe-procedure) -> (void)]] [flags])
|
||||||
(default-record-hash-procedure [sig [() -> (maybe-procedure)] [(maybe-procedure) -> (void)]] [flags])
|
(default-record-hash-procedure [sig [() -> (maybe-procedure)] [(maybe-procedure) -> (void)]] [flags])
|
||||||
(enable-cross-library-optimization [sig [() -> (boolean)] [(ptr) -> (void)]] [flags unrestricted])
|
(enable-cross-library-optimization [sig [() -> (boolean)] [(ptr) -> (void)]] [flags unrestricted])
|
||||||
|
(enable-object-backreferences [sig [() -> (boolean)] [(ptr) -> (void)]] [flags])
|
||||||
(enable-object-counts [sig [() -> (boolean)] [(ptr) -> (void)]] [flags])
|
(enable-object-counts [sig [() -> (boolean)] [(ptr) -> (void)]] [flags])
|
||||||
(eval-syntax-expanders-when [sig [() -> (list)] [(sub-list) -> (void)]] [flags])
|
(eval-syntax-expanders-when [sig [() -> (list)] [(sub-list) -> (void)]] [flags])
|
||||||
(expand-output [sig [() -> (maybe-textual-output-port)] [(maybe-textual-output-port) -> (void)]] [flags])
|
(expand-output [sig [() -> (maybe-textual-output-port)] [(maybe-textual-output-port) -> (void)]] [flags])
|
||||||
|
@ -1470,6 +1471,7 @@
|
||||||
(nonnegative? [sig [(real) -> (boolean)]] [flags pure mifoldable discard])
|
(nonnegative? [sig [(real) -> (boolean)]] [flags pure mifoldable discard])
|
||||||
(nonpositive? [sig [(real) -> (boolean)]] [flags pure mifoldable discard])
|
(nonpositive? [sig [(real) -> (boolean)]] [flags pure mifoldable discard])
|
||||||
(number->string [sig [(number) (number sub-ufixnum) (number sub-ufixnum sub-ufixnum) -> (string)]] [flags alloc]) ; radix not restricted to 2, 4, 8, 16
|
(number->string [sig [(number) (number sub-ufixnum) (number sub-ufixnum sub-ufixnum) -> (string)]] [flags alloc]) ; radix not restricted to 2, 4, 8, 16
|
||||||
|
(object-backreferences [sig [() -> (ptr)]] [flags alloc])
|
||||||
(object-counts [sig [() -> (ptr)]] [flags alloc])
|
(object-counts [sig [() -> (ptr)]] [flags alloc])
|
||||||
(oblist [sig [() -> (list)]] [flags alloc])
|
(oblist [sig [() -> (list)]] [flags alloc])
|
||||||
(open-fd-input-port [sig [(sub-ufixnum) (sub-ufixnum sub-symbol) (sub-ufixnum sub-symbol maybe-transcoder) -> (input-port)]] [flags true])
|
(open-fd-input-port [sig [(sub-ufixnum) (sub-ufixnum sub-symbol) (sub-ufixnum sub-symbol maybe-transcoder) -> (input-port)]] [flags true])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user