#include <string.h>
+// Turn off inlining when debugging - it obfuscates things
+#ifdef DEBUG
+# undef STATIC_INLINE
+# define STATIC_INLINE static
+#endif
+
/* STATIC OBJECT LIST.
*
* During GC:
blocks = RtsFlags.GcFlags.minAllocAreaSize;
}
}
- resizeNursery(blocks);
+ resizeNurseries(blocks);
} else {
/* Generational collector:
* percentage of g0s0 that was live at the last minor GC.
*/
if (N == 0) {
- g0s0_pcnt_kept = (new_blocks * 100) / g0s0->n_blocks;
+ g0s0_pcnt_kept = (new_blocks * 100) / countNurseryBlocks();
}
/* Estimate a size for the allocation area based on the
blocks = RtsFlags.GcFlags.minAllocAreaSize;
}
- resizeNursery((nat)blocks);
+ resizeNurseries((nat)blocks);
} else {
// we might have added extra large blocks to the nursery, so
// resize back to minAllocAreaSize again.
- resizeNursery(RtsFlags.GcFlags.minAllocAreaSize);
+ resizeNurseries(RtsFlags.GcFlags.minAllocAreaSize);
}
}
case FUN_1_0:
case FUN_0_1:
case CONSTR_1_0:
+ return copy(q,sizeofW(StgHeader)+1,stp);
+
case THUNK_1_0:
case THUNK_0_1:
- return copy(q,sizeofW(StgHeader)+1,stp);
+ return copy(q,sizeofW(StgThunk)+1,stp);
case THUNK_1_1:
case THUNK_0_2:
stp = bd->step;
}
#endif
- return copy(q,sizeofW(StgHeader)+2,stp);
+ return copy(q,sizeofW(StgThunk)+2,stp);
case FUN_1_1:
case FUN_0_2:
case CONSTR_2_0:
return copy(q,sizeofW(StgHeader)+2,stp);
- case FUN:
case THUNK:
+ return copy(q,thunk_sizeW_fromITBL(info),stp);
+
+ case FUN:
case CONSTR:
case IND_PERM:
case IND_OLDGEN_PERM:
case THUNK_STATIC:
if (info->srt_bitmap != 0 && major_gc &&
- THUNK_STATIC_LINK((StgClosure *)q) == NULL) {
- THUNK_STATIC_LINK((StgClosure *)q) = static_objects;
+ *THUNK_STATIC_LINK((StgClosure *)q) == NULL) {
+ *THUNK_STATIC_LINK((StgClosure *)q) = static_objects;
static_objects = (StgClosure *)q;
}
return q;
case FUN_STATIC:
if (info->srt_bitmap != 0 && major_gc &&
- FUN_STATIC_LINK((StgClosure *)q) == NULL) {
- FUN_STATIC_LINK((StgClosure *)q) = static_objects;
+ *FUN_STATIC_LINK((StgClosure *)q) == NULL) {
+ *FUN_STATIC_LINK((StgClosure *)q) = static_objects;
static_objects = (StgClosure *)q;
}
return q;
*/
if (major_gc
&& ((StgIndStatic *)q)->saved_info == NULL
- && IND_STATIC_LINK((StgClosure *)q) == NULL) {
- IND_STATIC_LINK((StgClosure *)q) = static_objects;
+ && *IND_STATIC_LINK((StgClosure *)q) == NULL) {
+ *IND_STATIC_LINK((StgClosure *)q) = static_objects;
static_objects = (StgClosure *)q;
}
return q;
case CONSTR_STATIC:
- if (major_gc && STATIC_LINK(info,(StgClosure *)q) == NULL) {
- STATIC_LINK(info,(StgClosure *)q) = static_objects;
+ if (major_gc && *STATIC_LINK(info,(StgClosure *)q) == NULL) {
+ *STATIC_LINK(info,(StgClosure *)q) = static_objects;
static_objects = (StgClosure *)q;
}
return q;
barf("evacuate: stack frame at %p\n", q);
case PAP:
- case AP:
return copy(q,pap_sizeW((StgPAP*)q),stp);
+ case AP:
+ return copy(q,ap_sizeW((StgAP*)q),stp);
+
case AP_STACK:
return copy(q,ap_stack_sizeW((StgAP_STACK*)q),stp);
been BLACKHOLE'd, and should be updated with an indirection or a
forwarding pointer. If the return value is NULL, then the selector
thunk is unchanged.
+
+ ***
+ ToDo: the treatment of THUNK_SELECTORS could be improved in the
+ following way (from a suggestion by Ian Lynagh):
+
+ We can have a chain like this:
+
+ sel_0 --> (a,b)
+ |
+ |-----> sel_0 --> (a,b)
+ |
+ |-----> sel_0 --> ...
+
+ and the depth limit means we don't go all the way to the end of the
+ chain, which results in a space leak. This affects the recursive
+ call to evacuate() in the THUNK_SELECTOR case in evacuate(): *not*
+ the recursive call to eval_thunk_selector() in
+ eval_thunk_selector().
+
+ We could eliminate the depth bound in this case, in the following
+ way:
+
+ - traverse the chain once to discover the *value* of the
+ THUNK_SELECTOR. Mark all THUNK_SELECTORS that we
+ visit on the way as having been visited already (somehow).
+
+ - in a second pass, traverse the chain again updating all
+ THUNK_SEELCTORS that we find on the way with indirections to
+ the value.
+
+ - if we encounter a "marked" THUNK_SELECTOR in a normal
+ evacuate(), we konw it can't be updated so just evac it.
+
+ Program that illustrates the problem:
+
+ foo [] = ([], [])
+ foo (x:xs) = let (ys, zs) = foo xs
+ in if x >= 0 then (x:ys, zs) else (ys, x:zs)
+
+ main = bar [1..(100000000::Int)]
+ bar xs = (\(ys, zs) -> print ys >> print zs) (foo xs)
+
-------------------------------------------------------------------------- */
static inline rtsBool
scavenge_srt((StgClosure **)GET_FUN_SRT(fun_info), fun_info->i.srt_bitmap);
}
-STATIC_INLINE void
-scavenge_ret_srt(const StgInfoTable *info)
-{
- StgRetInfoTable *ret_info;
-
- ret_info = itbl_to_ret_itbl(info);
- scavenge_srt((StgClosure **)GET_SRT(ret_info), ret_info->i.srt_bitmap);
-}
-
/* -----------------------------------------------------------------------------
Scavenge a TSO.
-------------------------------------------------------------------------- */
}
STATIC_INLINE StgPtr
-scavenge_PAP (StgPAP *pap)
+scavenge_PAP_payload (StgClosure *fun, StgClosure **payload, StgWord size)
{
StgPtr p;
- StgWord bitmap, size;
+ StgWord bitmap;
StgFunInfoTable *fun_info;
-
- pap->fun = evacuate(pap->fun);
- fun_info = get_fun_itbl(pap->fun);
+
+ fun_info = get_fun_itbl(fun);
ASSERT(fun_info->i.type != PAP);
-
- p = (StgPtr)pap->payload;
- size = pap->n_args;
+ p = (StgPtr)payload;
switch (fun_info->f.fun_type) {
case ARG_GEN:
p += size;
break;
case ARG_BCO:
- scavenge_large_bitmap((StgPtr)pap->payload, BCO_BITMAP(pap->fun), size);
+ scavenge_large_bitmap((StgPtr)payload, BCO_BITMAP(fun), size);
p += size;
break;
default:
bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
small_bitmap:
- size = pap->n_args;
while (size > 0) {
if ((bitmap & 1) == 0) {
*p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
return p;
}
+STATIC_INLINE StgPtr
+scavenge_PAP (StgPAP *pap)
+{
+ pap->fun = evacuate(pap->fun);
+ return scavenge_PAP_payload (pap->fun, pap->payload, pap->n_args);
+}
+
+STATIC_INLINE StgPtr
+scavenge_AP (StgAP *ap)
+{
+ ap->fun = evacuate(ap->fun);
+ return scavenge_PAP_payload (ap->fun, ap->payload, ap->n_args);
+}
+
/* -----------------------------------------------------------------------------
Scavenge a given step until there are no more objects in this step
to scavenge.
case THUNK_2_0:
scavenge_thunk_srt(info);
+ ((StgThunk *)p)->payload[1] = evacuate(((StgThunk *)p)->payload[1]);
+ ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
+ p += sizeofW(StgThunk) + 2;
+ break;
+
case CONSTR_2_0:
((StgClosure *)p)->payload[1] = evacuate(((StgClosure *)p)->payload[1]);
((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
case THUNK_1_0:
scavenge_thunk_srt(info);
- ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
- p += sizeofW(StgHeader) + 1;
+ ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
+ p += sizeofW(StgThunk) + 1;
break;
case FUN_1_0:
case THUNK_0_1:
scavenge_thunk_srt(info);
- p += sizeofW(StgHeader) + 1;
+ p += sizeofW(StgThunk) + 1;
break;
case FUN_0_1:
case THUNK_0_2:
scavenge_thunk_srt(info);
- p += sizeofW(StgHeader) + 2;
+ p += sizeofW(StgThunk) + 2;
break;
case FUN_0_2:
case THUNK_1_1:
scavenge_thunk_srt(info);
- ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
- p += sizeofW(StgHeader) + 2;
+ ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
+ p += sizeofW(StgThunk) + 2;
break;
case FUN_1_1:
goto gen_obj;
case THUNK:
+ {
+ StgPtr end;
+
scavenge_thunk_srt(info);
- // fall through
+ end = (P_)((StgThunk *)p)->payload + info->layout.payload.ptrs;
+ for (p = (P_)((StgThunk *)p)->payload; p < end; p++) {
+ *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
+ }
+ p += info->layout.payload.nptrs;
+ break;
+ }
gen_obj:
case CONSTR:
}
case PAP:
- case AP:
p = scavenge_PAP((StgPAP *)p);
break;
+ case AP:
+ p = scavenge_AP((StgAP *)p);
+ break;
+
case ARR_WORDS:
// nothing to follow
p += arr_words_sizeW((StgArrWords *)p);
case THUNK_2_0:
scavenge_thunk_srt(info);
+ ((StgThunk *)p)->payload[1] = evacuate(((StgThunk *)p)->payload[1]);
+ ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
+ break;
+
case CONSTR_2_0:
((StgClosure *)p)->payload[1] = evacuate(((StgClosure *)p)->payload[1]);
((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
case THUNK_1_0:
case THUNK_1_1:
scavenge_thunk_srt(info);
+ ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
+ break;
+
case CONSTR_1_0:
case CONSTR_1_1:
((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
goto gen_obj;
case THUNK:
+ {
+ StgPtr end;
+
scavenge_thunk_srt(info);
- // fall through
+ end = (P_)((StgThunk *)p)->payload + info->layout.payload.ptrs;
+ for (p = (P_)((StgThunk *)p)->payload; p < end; p++) {
+ *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
+ }
+ break;
+ }
gen_obj:
case CONSTR:
}
case PAP:
- case AP:
scavenge_PAP((StgPAP *)p);
break;
+
+ case AP:
+ scavenge_AP((StgAP *)p);
+ break;
case MUT_ARR_PTRS:
// follow everything
break;
}
- case FUN:
- case FUN_1_0: // hardly worth specialising these guys
- case FUN_0_1:
- case FUN_1_1:
- case FUN_0_2:
- case FUN_2_0:
case THUNK:
case THUNK_1_0:
case THUNK_0_1:
case THUNK_1_1:
case THUNK_0_2:
case THUNK_2_0:
+ {
+ StgPtr q, end;
+
+ end = (StgPtr)((StgThunk *)p)->payload + info->layout.payload.ptrs;
+ for (q = (StgPtr)((StgThunk *)p)->payload; q < end; q++) {
+ *q = (StgWord)(StgPtr)evacuate((StgClosure *)*q);
+ }
+ break;
+ }
+
+ case FUN:
+ case FUN_1_0: // hardly worth specialising these guys
+ case FUN_0_1:
+ case FUN_1_1:
+ case FUN_0_2:
+ case FUN_2_0:
case CONSTR:
case CONSTR_1_0:
case CONSTR_0_1:
}
case PAP:
+ p = scavenge_AP((StgAP *)p);
+ break;
+
case AP:
p = scavenge_PAP((StgPAP *)p);
break;
/* Take this object *off* the static_objects list,
* and put it on the scavenged_static_objects list.
*/
- static_objects = STATIC_LINK(info,p);
- STATIC_LINK(info,p) = scavenged_static_objects;
+ static_objects = *STATIC_LINK(info,p);
+ *STATIC_LINK(info,p) = scavenged_static_objects;
scavenged_static_objects = p;
switch (info -> type) {
for (p = first_static; p != END_OF_STATIC_LIST; p = link) {
info = get_itbl(p);
- link = STATIC_LINK(info, p);
- STATIC_LINK(info,p) = NULL;
+ link = *STATIC_LINK(info, p);
+ *STATIC_LINK(info,p) = NULL;
}
}
if (bh->header.info != &stg_CAF_BLACKHOLE_info) {
#if (!defined(LAZY_BLACKHOLING)) && defined(DEBUG)
- debugBelch("Unexpected lazy BHing required at 0x%04x",(int)bh);
+ debugBelch("Unexpected lazy BHing required at 0x%04x\n",(int)bh);
#endif
#ifdef PROFILING
// @LDV profiling
}
debugBelch("\n");
}
-
-STATIC_INLINE rtsBool
-maybeLarge(StgClosure *closure)
-{
- StgInfoTable *info = get_itbl(closure);
-
- /* closure types that may be found on the new_large_objects list;
- see scavenge_large */
- return (info->type == MUT_ARR_PTRS ||
- info->type == MUT_ARR_PTRS_FROZEN ||
- info->type == MUT_ARR_PTRS_FROZEN0 ||
- info->type == TSO ||
- info->type == ARR_WORDS);
-}
-
-
#endif /* DEBUG */