track whether a closure uses syntax objects

For GC purposes, if a "prefix" (a closure frame that caprues
top-level or module-level bindings) may refer to syntax objects
that are not used by any reachable closure, in which case the
syntax object can be dropped. This pruning of syntax objects
uses the infrastructure already in place to prune variables.

Syntax objects were not included in the original pruning
implementation, because they are unlikely to create
finalization cycles in the way that global-variable
references can. A syntax object can retain a namespace's
table of module imports, however, which can be substantial
and worth releasing of a closure is only held, say, for
a low-level finalization action.
This commit is contained in:
Matthew Flatt 2015-01-19 13:37:31 -07:00
parent df88e0dd8a
commit 3eef017911
8 changed files with 100 additions and 55 deletions

View File

@ -307,21 +307,27 @@ binding, constructor, etc.}
values; also, this information is redundant, since it can be inferred
by the bindings referenced though @racket[closure-map].
Which a closure captures top-level or module-level variables, they
are represented in the closure by capturing a prefix (in the sense
Which a closure captures top-level or module-level variables or
refers to a syntax-object constant, the variables and constants are
represented in the closure by capturing a prefix (in the sense
of @racket[prefix]). The @racket[toplevel-map] field indicates
which top-level and lifted variables are actually used by the
closure (so that variables in a prefix can be pruned by the run-time
system if they become unused). A @racket[#f] value indicates either
that no prefix is captured or all variables in the prefix should be
system if they become unused) and whether any syntax objects are
used (so that the syntax objects as a group can be similarly
pruned). A @racket[#f] value indicates either that no prefix is
captured or all variables and syntax objects in the prefix should be
considered used. Otherwise, numbers in the set indicate which
variables and lifted variables are used. Variables are numbered
consecutively by position in the prefix starting from
@racket[0]. Lifted variables are numbered immediately
@racket[0], but the number equal to the number of non-lifted
variables corresponds to syntax objects (i.e., the number is
include if any syntax-object constant is used). Lifted variables
are numbered immediately
afterward---which means that, if the prefix contains any syntax
objects, lifted-variable numbers are shifted down relative to a
@racket[toplevel] by the number of syntax object in the prefix plus
one (which makes the @racket[toplevel-map] set more compact).
@racket[toplevel] by the number of syntax object in the prefix
(which makes the @racket[toplevel-map] set more compact).
When the function is called, the rest-argument list (if any) is pushed
onto the stack, then the normal arguments in reverse order, then the
@ -332,7 +338,12 @@ binding, constructor, etc.}
The @racket[max-let-depth] field indicates the maximum stack depth
created by @racket[body] plus the arguments and closure-captured
values pushed onto the stack. The @racket[body] field is the
expression for the closure's body.}
expression for the closure's body.
@history[#:changed "6.1.1.8" @elem{Added a number to
@racket[toplevel-map] to indicate whether any syntax object is used,
shifting numbers for lifted variables up by one if any syntax object
is in the prefix.}]}
@defstruct+[(closure expr)
([code lam?] [gen-id symbol?])]{

View File

@ -1,5 +1,5 @@
{
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,55,84,0,0,0,0,0,0,0,0,0,0,
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,56,84,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,51,0,0,0,1,0,0,10,0,14,0,
19,0,24,0,37,0,42,0,45,0,52,0,56,0,60,0,67,0,74,0,83,
0,87,0,93,0,107,0,121,0,124,0,130,0,134,0,136,0,147,0,149,0,
@ -16,12 +16,12 @@
108,101,116,114,101,99,45,118,97,108,117,101,115,66,108,97,109,98,100,97,1,
20,112,97,114,97,109,101,116,101,114,105,122,97,116,105,111,110,45,107,101,121,
61,118,73,100,101,102,105,110,101,45,118,97,108,117,101,115,97,36,11,8,240,
20,89,0,0,95,144,2,17,36,36,144,2,16,36,36,144,2,16,36,36,16,
61,89,0,0,95,144,2,17,36,36,144,2,16,36,36,144,2,16,36,36,16,
20,2,3,2,2,2,4,2,2,2,5,2,2,2,6,2,2,2,7,2,2,
2,8,2,2,2,9,2,2,2,10,2,2,2,11,2,2,2,12,2,2,97,
37,11,8,240,20,89,0,0,93,144,2,16,36,37,16,2,2,13,146,2,2,
37,2,13,2,2,2,13,96,11,11,8,240,20,89,0,0,16,0,96,38,11,
8,240,20,89,0,0,16,0,18,98,64,104,101,114,101,13,16,6,36,2,14,
37,11,8,240,61,89,0,0,93,144,2,16,36,37,16,2,2,13,146,2,2,
37,2,13,2,2,2,13,96,11,11,8,240,61,89,0,0,16,0,96,38,11,
8,240,61,89,0,0,16,0,18,98,64,104,101,114,101,13,16,6,36,2,14,
2,2,11,11,11,8,32,8,31,8,30,8,29,27,248,22,166,4,195,249,22,
159,4,80,143,39,36,251,22,92,2,18,248,22,104,199,12,249,22,82,2,19,
248,22,106,201,27,248,22,166,4,195,249,22,159,4,80,143,39,36,251,22,92,
@ -30,14 +30,14 @@
84,194,248,22,159,20,193,249,22,159,4,80,143,39,36,251,22,92,2,18,248,
22,159,20,199,249,22,82,2,10,248,22,160,20,201,11,18,100,10,13,16,6,
36,2,14,2,2,11,11,11,8,32,8,31,8,30,8,29,16,4,11,11,2,
20,3,1,8,101,110,118,49,55,57,52,55,16,4,11,11,2,21,3,1,8,
101,110,118,49,55,57,52,56,27,248,22,84,248,22,166,4,196,28,248,22,90,
20,3,1,8,101,110,118,49,55,57,56,52,16,4,11,11,2,21,3,1,8,
101,110,118,49,55,57,56,53,27,248,22,84,248,22,166,4,196,28,248,22,90,
193,20,14,144,37,36,37,28,248,22,90,248,22,84,194,248,22,159,20,193,249,
22,159,4,80,143,39,36,250,22,92,2,22,248,22,92,249,22,92,248,22,92,
2,23,248,22,159,20,201,251,22,92,2,18,2,23,2,23,249,22,82,2,7,
248,22,160,20,204,18,100,11,13,16,6,36,2,14,2,2,11,11,11,8,32,
8,31,8,30,8,29,16,4,11,11,2,20,3,1,8,101,110,118,49,55,57,
53,48,16,4,11,11,2,21,3,1,8,101,110,118,49,55,57,53,49,248,22,
56,55,16,4,11,11,2,21,3,1,8,101,110,118,49,55,57,56,56,248,22,
166,4,193,27,248,22,166,4,194,249,22,82,248,22,92,248,22,83,196,248,22,
160,20,195,27,248,22,84,248,22,166,4,23,197,1,249,22,159,4,80,143,39,
36,28,248,22,66,248,22,160,4,248,22,83,23,198,2,27,249,22,2,32,0,
@ -68,8 +68,8 @@
28,249,22,170,9,248,22,160,4,248,22,83,200,64,101,108,115,101,10,248,22,
159,20,197,250,22,93,2,22,9,248,22,160,20,200,249,22,82,2,3,248,22,
160,20,202,99,13,16,6,36,2,14,2,2,11,11,11,8,32,8,31,8,30,
8,29,16,4,11,11,2,20,3,1,8,101,110,118,49,55,57,55,51,16,4,
11,11,2,21,3,1,8,101,110,118,49,55,57,55,52,18,143,94,10,64,118,
8,29,16,4,11,11,2,20,3,1,8,101,110,118,49,56,48,49,48,16,4,
11,11,2,21,3,1,8,101,110,118,49,56,48,49,49,18,143,94,10,64,118,
111,105,100,8,48,27,248,22,84,248,22,166,4,196,249,22,159,4,80,143,39,
36,28,248,22,66,248,22,160,4,248,22,83,197,250,22,92,2,28,248,22,92,
248,22,159,20,199,248,22,104,198,27,248,22,160,4,248,22,159,20,197,250,22,
@ -85,22 +85,22 @@
20,114,144,36,16,1,2,13,16,1,33,33,10,16,5,2,8,88,148,8,36,
37,53,37,9,223,0,33,34,36,20,114,144,36,16,1,2,13,16,0,11,16,
5,2,4,88,148,8,36,37,53,37,9,223,0,33,35,36,20,114,144,36,16,
1,2,13,16,0,11,16,5,2,10,88,148,8,36,37,53,37,9,223,0,33,
1,2,13,16,0,11,16,5,2,10,88,148,8,36,37,53,39,9,223,0,33,
36,36,20,114,144,36,16,1,2,13,16,1,33,37,11,16,5,2,7,88,148,
8,36,37,56,37,9,223,0,33,38,36,20,114,144,36,16,1,2,13,16,1,
8,36,37,56,39,9,223,0,33,38,36,20,114,144,36,16,1,2,13,16,1,
33,39,11,16,5,2,9,88,148,8,36,37,58,37,9,223,0,33,42,36,20,
114,144,36,16,1,2,13,16,0,11,16,5,2,12,88,148,8,36,37,53,37,
9,223,0,33,44,36,20,114,144,36,16,1,2,13,16,0,11,16,5,2,6,
88,148,8,36,37,54,37,9,223,0,33,45,36,20,114,144,36,16,1,2,13,
16,0,11,16,5,2,5,88,148,8,36,37,56,37,9,223,0,33,46,36,20,
114,144,36,16,1,2,13,16,0,11,16,5,2,3,88,148,8,36,37,58,37,
114,144,36,16,1,2,13,16,0,11,16,5,2,3,88,148,8,36,37,58,39,
9,223,0,33,47,36,20,114,144,36,16,1,2,13,16,1,33,49,11,16,5,
2,11,88,148,8,36,37,54,37,9,223,0,33,50,36,20,114,144,36,16,1,
2,13,16,0,11,16,0,94,2,16,2,17,93,2,16,9,9,36,9,0};
EVAL_ONE_SIZED_STR((char *)expr, 2056);
}
{
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,55,84,0,0,0,0,0,0,0,0,0,0,
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,56,84,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,193,0,0,0,1,0,0,8,0,21,0,
26,0,43,0,55,0,77,0,106,0,150,0,156,0,165,0,172,0,187,0,205,
0,217,0,233,0,247,0,13,1,32,1,39,1,73,1,90,1,107,1,130,1,
@ -1044,7 +1044,7 @@
EVAL_ONE_SIZED_STR((char *)expr, 19746);
}
{
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,55,84,0,0,0,0,0,0,0,0,0,0,
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,56,84,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,14,0,0,0,1,0,0,15,0,40,0,
57,0,75,0,97,0,120,0,140,0,162,0,171,0,180,0,187,0,196,0,203,
0,0,0,231,1,0,0,74,35,37,112,108,97,99,101,45,115,116,114,117,99,
@ -1074,7 +1074,7 @@
EVAL_ONE_SIZED_STR((char *)expr, 557);
}
{
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,55,84,0,0,0,0,0,0,0,0,0,0,
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,56,84,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,102,0,0,0,1,0,0,7,0,18,0,
45,0,51,0,60,0,67,0,89,0,102,0,128,0,145,0,167,0,175,0,187,
0,202,0,218,0,236,0,0,1,12,1,28,1,51,1,75,1,87,1,118,1,
@ -1541,7 +1541,7 @@
EVAL_ONE_SIZED_STR((char *)expr, 9735);
}
{
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,55,84,0,0,0,0,0,0,0,0,0,0,
SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,49,46,49,46,56,84,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,11,0,0,0,1,0,0,10,0,16,0,
29,0,44,0,58,0,78,0,90,0,104,0,118,0,170,0,0,0,101,1,0,
0,69,35,37,98,117,105,108,116,105,110,65,113,117,111,116,101,29,94,2,2,
@ -1549,7 +1549,7 @@
114,107,11,29,94,2,2,68,35,37,112,97,114,97,109,122,11,29,94,2,2,
74,35,37,112,108,97,99,101,45,115,116,114,117,99,116,11,29,94,2,2,66,
35,37,98,111,111,116,11,29,94,2,2,68,35,37,101,120,112,111,98,115,11,
29,94,2,2,68,35,37,107,101,114,110,101,108,11,97,36,11,8,240,161,91,
29,94,2,2,68,35,37,107,101,114,110,101,108,11,97,36,11,8,240,202,91,
0,0,100,144,2,3,36,36,144,2,4,36,36,144,2,5,36,36,144,2,6,
36,36,144,2,7,36,36,144,2,8,36,36,144,2,9,36,36,144,2,9,36,
36,16,0,144,36,20,114,144,36,16,1,11,16,0,20,26,15,53,9,2,1,

View File

@ -5682,7 +5682,7 @@ Scheme_Object **scheme_push_prefix(Scheme_Env *genv, Resolve_Prefix *rp,
}
i += rp->num_lifts;
tl_map_len = ((rp->num_toplevels + rp->num_lifts) + 31) / 32;
tl_map_len = ((rp->num_toplevels + rp->num_lifts + (rp->num_stxes ? 1 : 0)) + 31) / 32;
pf = scheme_malloc_tagged(sizeof(Scheme_Prefix)
+ ((i-mzFLEX_DELTA) * sizeof(Scheme_Object *))
@ -5788,7 +5788,7 @@ static void mark_pruned_prefixes(struct NewGC *gc) XFORM_SKIP_PROC
/* If not marked, only references are through closures: */
if (!GC_is_marked2(pf, gc)) {
/* Clear slots that are not use in map */
maxpos = (pf->num_slots - pf->num_stxes - (pf->num_stxes ? 1 : 0));
maxpos = (pf->num_slots - pf->num_stxes);
use_bits = PREFIX_TO_USE_BITS(pf);
for (i = (maxpos + 31) / 32; i--; ) {
int j;
@ -5797,12 +5797,19 @@ static void mark_pruned_prefixes(struct NewGC *gc) XFORM_SKIP_PROC
int pos;
pos = (i * 32) + j;
if (pos < pf->num_toplevels)
pf->a[pos] = NULL;
pf->a[pos] = NULL; /* top level */
else if (pos < maxpos) {
if (pf->num_stxes)
pf->a[pos + pf->num_stxes + 1] = NULL;
else
pf->a[pos] = NULL;
if (pf->num_stxes) {
if (pos == pf->num_toplevels) {
/* any syntax object */
int k;
for (k = pf->num_stxes+1; k--;) {
pf->a[k + pf->num_toplevels] = NULL;
}
} else
pf->a[pos + pf->num_stxes] = NULL; /* lifted */
} else
pf->a[pos] = NULL; /* lifted */
}
}
}
@ -5817,7 +5824,7 @@ static void mark_pruned_prefixes(struct NewGC *gc) XFORM_SKIP_PROC
/* Clear use map */
use_bits = PREFIX_TO_USE_BITS(pf);
maxpos = (pf->num_slots - pf->num_stxes - (pf->num_stxes ? 1 : 0));
maxpos = (pf->num_slots - pf->num_stxes);
for (i = (maxpos + 31) / 32; i--; )
use_bits[i] = 0;

View File

@ -15,20 +15,16 @@
/* Since pf hasn't been marked, we don't need a GC_resolve(): */
int *use_bits = PREFIX_TO_USE_BITS(pf);
uintptr_t map;
int mark_stxes;
if (!pf->next_final) {
/* We're the first to look at this prefix... */
if (pf->num_stxes) {
/* Mark all syntax-object references */
for (i = pf->num_stxes+1; i--;) {
gcMARK2(pf->a[i+pf->num_toplevels], gc);
}
}
/* Add it to the chain of prefixes to finish after
all other marking: */
pf->next_final = scheme_prefix_finalize;
scheme_prefix_finalize = pf;
}
mark_stxes = 0;
/* Mark just the elements of the prefix that are (newly) used: */
if ((uintptr_t)data->tl_map & 0x1) {
@ -37,9 +33,11 @@
if (map & (1 << i)) {
if (!(use_bits[0] & (1 << i))) {
if ((i < pf->num_toplevels) || !pf->num_stxes)
gcMARK2(pf->a[i], gc);
gcMARK2(pf->a[i], gc); /* top level */
else if (i == pf->num_toplevels)
mark_stxes = 1; /* any syntax object */
else
gcMARK2(pf->a[i + pf->num_stxes + 1], gc);
gcMARK2(pf->a[i + pf->num_stxes], gc); /* lifted */
}
}
}
@ -54,14 +52,22 @@
if (!(use_bits[i] & (1 << j))) {
pos = (i * 32) + j;
if ((pos < pf->num_toplevels) || !pf->num_stxes)
gcMARK2(pf->a[pos], gc);
gcMARK2(pf->a[pos], gc); /* top level */
else if (pos == pf->num_toplevels)
mark_stxes = 1; /* any syntax object */
else
gcMARK2(pf->a[pos + pf->num_stxes + 1], gc);
gcMARK2(pf->a[pos + pf->num_stxes], gc); /* lifted */
}
}
}
use_bits[i] |= map;
}
}
if (mark_stxes) {
/* Mark all syntax-object references */
for (i = pf->num_stxes+1; i--;) {
gcMARK2(pf->a[i+pf->num_toplevels], gc);
}
}
}
}

View File

@ -2449,7 +2449,7 @@ static int prefix_val_SIZE(void *p, struct NewGC *gc) {
return
gcBYTES_TO_WORDS((sizeof(Scheme_Prefix)
+ ((pf->num_slots-mzFLEX_DELTA) * sizeof(Scheme_Object *))
+ ((((pf->num_slots - (pf->num_stxes ? (pf->num_stxes+1) : 0)) + 31) / 32)
+ ((((pf->num_slots - pf->num_stxes) + 31) / 32)
* sizeof(int))));
}
@ -2461,7 +2461,7 @@ static int prefix_val_MARK(void *p, struct NewGC *gc) {
return
gcBYTES_TO_WORDS((sizeof(Scheme_Prefix)
+ ((pf->num_slots-mzFLEX_DELTA) * sizeof(Scheme_Object *))
+ ((((pf->num_slots - (pf->num_stxes ? (pf->num_stxes+1) : 0)) + 31) / 32)
+ ((((pf->num_slots - pf->num_stxes) + 31) / 32)
* sizeof(int))));
}
@ -2473,7 +2473,7 @@ static int prefix_val_FIXUP(void *p, struct NewGC *gc) {
return
gcBYTES_TO_WORDS((sizeof(Scheme_Prefix)
+ ((pf->num_slots-mzFLEX_DELTA) * sizeof(Scheme_Object *))
+ ((((pf->num_slots - (pf->num_stxes ? (pf->num_stxes+1) : 0)) + 31) / 32)
+ ((((pf->num_slots - pf->num_stxes) + 31) / 32)
* sizeof(int))));
}

View File

@ -990,7 +990,7 @@ prefix_val {
size:
gcBYTES_TO_WORDS((sizeof(Scheme_Prefix)
+ ((pf->num_slots-mzFLEX_DELTA) * sizeof(Scheme_Object *))
+ ((((pf->num_slots - (pf->num_stxes ? (pf->num_stxes+1) : 0)) + 31) / 32)
+ ((((pf->num_slots - pf->num_stxes) + 31) / 32)
* sizeof(int))));
}

View File

@ -81,6 +81,7 @@ static Scheme_Object *shift_toplevel(Scheme_Object *expr, int delta);
static int resolving_in_procedure(Resolve_Info *info);
static int is_nonconstant_procedure(Scheme_Object *data, Resolve_Info *info, int skip);
static int resolve_is_inside_proc(Resolve_Info *info);
static void set_tl_pos_used(Resolve_Info *info, int pos);
#ifdef MZ_PRECISE_GC
static void register_traversers(void);
@ -2421,6 +2422,8 @@ Scheme_Object *scheme_resolve_expr(Scheme_Object *expr, Resolve_Info *info)
c = resolve_toplevel_pos(info);
p = resolve_quote_syntax_pos(info);
set_tl_pos_used(info, i+p+1);
qs = MALLOC_ONE_TAGGED(Scheme_Quote_Syntax);
qs->so.type = scheme_quote_syntax_type;
qs->depth = c;
@ -2744,14 +2747,16 @@ static void set_tl_pos_used(Resolve_Info *info, int pos)
/* Fixnum-like bit packing avoids allocation in the common case of a
small prefix. We use 31 fixnum-like bits (even on a 64-bit
platform, and even though fixnums are only 30 bits). */
platform, and even though fixnums are only 30 bits). There's one
bit for each normal top-level, one bit for all syntax objects,
and one bit for each lifted top-level. */
if (pos >= info->prefix->num_toplevels)
tl_pos = pos - (info->prefix->num_stxes
? (info->prefix->num_stxes + 1)
: 0);
if (pos > (info->prefix->num_toplevels + info->prefix->num_stxes))
tl_pos = pos - info->prefix->num_stxes; /* lifted */
else if (pos >= info->prefix->num_toplevels)
tl_pos = info->prefix->num_toplevels; /* any syntax object */
else
tl_pos = pos;
tl_pos = pos; /* normal top level */
tl_map = ensure_tl_map_len(info->tl_map, tl_pos + 1);
info->tl_map = tl_map;

View File

@ -1350,7 +1350,9 @@ static int validate_expr(Mz_CPort *port, Scheme_Object *expr,
if (tl_use_map) {
int p2 = ((p < num_toplevels)
? p
: (num_stxes ? (p - num_stxes - 1) : p));
: (p - num_stxes));
if (num_stxes && (p >= num_toplevels) && (p < (num_toplevels + num_stxes + 1)))
scheme_ill_formed_code(port);
if ((uintptr_t)tl_use_map & 0x1) {
if (p2 > 31)
scheme_ill_formed_code(port);
@ -1732,6 +1734,20 @@ static int validate_expr(Mz_CPort *port, Scheme_Object *expr,
|| (i >= num_stxes))
scheme_ill_formed_code(port);
if (tl_use_map) {
if ((uintptr_t)tl_use_map & 0x1) {
if (p > 31)
scheme_ill_formed_code(port);
if (!((uintptr_t)tl_use_map & (1 << (p + 1))))
scheme_ill_formed_code(port);
} else {
if (p >= (*(int *)tl_use_map * 32))
scheme_ill_formed_code(port);
if (!(((int *)tl_use_map)[1 + (p / 32)] & (1 << (p & 31))))
scheme_ill_formed_code(port);
}
}
result = validate_join_const(result, expected_results);
}
break;