/* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.41 1999/02/24 17:24:07 simonm Exp $
+ * $Id: GC.c,v 1.47 1999/03/03 18:58:53 sof Exp $
*
* (c) The GHC Team 1998-1999
*
Static function declarations
-------------------------------------------------------------------------- */
-static StgClosure *evacuate(StgClosure *q);
-static void zeroStaticObjectList(StgClosure* first_static);
-static rtsBool traverse_weak_ptr_list(void);
-static void zeroMutableList(StgMutClosure *first);
-static void revertDeadCAFs(void);
+static StgClosure * evacuate ( StgClosure *q );
+static void zero_static_object_list ( StgClosure* first_static );
+static void zero_mutable_list ( StgMutClosure *first );
+static void revert_dead_CAFs ( void );
-static void scavenge_stack(StgPtr p, StgPtr stack_end);
-static void scavenge_large(step *step);
-static void scavenge(step *step);
-static void scavenge_static(void);
-static void scavenge_mutable_list(generation *g);
-static void scavenge_mut_once_list(generation *g);
+static rtsBool traverse_weak_ptr_list ( void );
+static void cleanup_weak_ptr_list ( void );
+
+static void scavenge_stack ( StgPtr p, StgPtr stack_end );
+static void scavenge_large ( step *step );
+static void scavenge ( step *step );
+static void scavenge_static ( void );
+static void scavenge_mutable_list ( generation *g );
+static void scavenge_mut_once_list ( generation *g );
#ifdef DEBUG
-static void gcCAFs(void);
+static void gcCAFs ( void );
#endif
/* -----------------------------------------------------------------------------
scavenged_static_objects = END_OF_STATIC_LIST;
/* zero the mutable list for the oldest generation (see comment by
- * zeroMutableList below).
+ * zero_mutable_list below).
*/
if (major_gc) {
- zeroMutableList(generations[RtsFlags.GcFlags.generations-1].mut_once_list);
+ zero_mutable_list(generations[RtsFlags.GcFlags.generations-1].mut_once_list);
}
/* Save the old to-space if we're doing a two-space collection
/* Mark the weak pointer list, and prepare to detect dead weak
* pointers.
*/
- markWeakList();
old_weak_ptr_list = weak_ptr_list;
weak_ptr_list = NULL;
weak_done = rtsFalse;
*/
scavengeEverything();
/* revert dead CAFs and update enteredCAFs list */
- revertDeadCAFs();
+ revert_dead_CAFs();
#endif
markHugsObjects();
#if 0
}
}
- /* Now see which stable names are still alive
+ /* Final traversal of the weak pointer list (see comment by
+ * cleanUpWeakPtrList below).
+ */
+ cleanup_weak_ptr_list();
+
+ /* Now see which stable names are still alive.
*/
gcStablePtrTable(major_gc);
}
/* revert dead CAFs and update enteredCAFs list */
- revertDeadCAFs();
+ revert_dead_CAFs();
/* mark the garbage collected CAFs as dead */
#ifdef DEBUG
/* zero the scavenged static object list */
if (major_gc) {
- zeroStaticObjectList(scavenged_static_objects);
+ zero_static_object_list(scavenged_static_objects);
}
/* Reset the nursery
last_w = &old_weak_ptr_list;
for (w = old_weak_ptr_list; w; w = next_w) {
+ /* First, this weak pointer might have been evacuated. If so,
+ * remove the forwarding pointer from the weak_ptr_list.
+ */
+ if (get_itbl(w)->type == EVACUATED) {
+ w = (StgWeak *)((StgEvacuated *)w)->evacuee;
+ *last_w = w;
+ }
+
+ /* There might be a DEAD_WEAK on the list if finalizeWeak# was
+ * called on a live weak pointer object. Just remove it.
+ */
+ if (w->header.info == &DEAD_WEAK_info) {
+ next_w = ((StgDeadWeak *)w)->link;
+ *last_w = next_w;
+ continue;
+ }
+
+ ASSERT(get_itbl(w)->type == WEAK);
+
+ /* Now, check whether the key is reachable.
+ */
if ((new = isAlive(w->key))) {
w->key = new;
/* evacuate the value and finalizer */
}
/* -----------------------------------------------------------------------------
+ After GC, the live weak pointer list may have forwarding pointers
+ on it, because a weak pointer object was evacuated after being
+ moved to the live weak pointer list. We remove those forwarding
+ pointers here.
+
+ Also, we don't consider weak pointer objects to be reachable, but
+ we must nevertheless consider them to be "live" and retain them.
+ Therefore any weak pointer objects which haven't as yet been
+ evacuated need to be evacuated now.
+ -------------------------------------------------------------------------- */
+
+static void
+cleanup_weak_ptr_list ( void )
+{
+ StgWeak *w, **last_w;
+
+ last_w = &weak_ptr_list;
+ for (w = weak_ptr_list; w; w = w->link) {
+
+ if (get_itbl(w)->type == EVACUATED) {
+ w = (StgWeak *)((StgEvacuated *)w)->evacuee;
+ *last_w = w;
+ }
+
+ if (Bdescr((P_)w)->evacuated == 0) {
+ (StgClosure *)w = evacuate((StgClosure *)w);
+ *last_w = w;
+ }
+ last_w = &(w->link);
+ }
+}
+
+/* -----------------------------------------------------------------------------
isAlive determines whether the given closure is still alive (after
a garbage collection) or not. It returns the new address of the
closure if it is alive, or NULL otherwise.
new_blocks++;
}
+static __inline__ void
+upd_evacuee(StgClosure *p, StgClosure *dest)
+{
+ p->header.info = &EVACUATED_info;
+ ((StgEvacuated *)p)->evacuee = dest;
+}
+
static __inline__ StgClosure *
copy(StgClosure *src, nat size, step *step)
{
dest = step->hp;
step->hp = to;
+ upd_evacuee(src,(StgClosure *)dest);
return (StgClosure *)dest;
}
dest = step->hp;
step->hp += size_to_reserve;
+ upd_evacuee(src,(StgClosure *)dest);
return (StgClosure *)dest;
}
-static __inline__ void
-upd_evacuee(StgClosure *p, StgClosure *dest)
-{
- StgEvacuated *q = (StgEvacuated *)p;
-
- SET_INFO(q,&EVACUATED_info);
- q->evacuee = dest;
-}
-
/* -----------------------------------------------------------------------------
Evacuate a large object
const StgInfoTable *info;
loop:
- if (!LOOKS_LIKE_STATIC(q)) {
+ if (HEAP_ALLOCED(q)) {
bd = Bdescr((P_)q);
if (bd->gen->no > N) {
/* Can't evacuate this object, because it's in a generation
switch (info -> type) {
case BCO:
- to = copy(q,bco_sizeW(stgCast(StgBCO*,q)),step);
- upd_evacuee(q,to);
- return to;
+ return copy(q,bco_sizeW(stgCast(StgBCO*,q)),step);
case MUT_VAR:
ASSERT(q->header.info != &MUT_CONS_info);
case MVAR:
to = copy(q,sizeW_fromITBL(info),step);
- upd_evacuee(q,to);
recordMutable((StgMutClosure *)to);
return to;
- case STABLE_NAME:
- stable_ptr_table[((StgStableName *)q)->sn].keep = rtsTrue;
- to = copy(q,sizeofW(StgStableName),step);
- upd_evacuee(q,to);
- return to;
-
case FUN_1_0:
case FUN_0_1:
case CONSTR_1_0:
case CONSTR_0_1:
- to = copy(q,sizeofW(StgHeader)+1,step);
- upd_evacuee(q,to);
- return to;
+ return copy(q,sizeofW(StgHeader)+1,step);
case THUNK_1_0: /* here because of MIN_UPD_SIZE */
case THUNK_0_1:
- case FUN_1_1:
- case FUN_0_2:
- case FUN_2_0:
case THUNK_1_1:
case THUNK_0_2:
case THUNK_2_0:
+#ifdef NO_PROMOTE_THUNKS
+ if (bd->gen->no == 0 &&
+ bd->step->no != 0 &&
+ bd->step->no == bd->gen->n_steps-1) {
+ step = bd->step;
+ }
+#endif
+ return copy(q,sizeofW(StgHeader)+2,step);
+
+ case FUN_1_1:
+ case FUN_0_2:
+ case FUN_2_0:
case CONSTR_1_1:
case CONSTR_0_2:
case CONSTR_2_0:
- to = copy(q,sizeofW(StgHeader)+2,step);
- upd_evacuee(q,to);
- return to;
+ return copy(q,sizeofW(StgHeader)+2,step);
case FUN:
case THUNK:
case CAF_ENTERED:
case WEAK:
case FOREIGN:
- to = copy(q,sizeW_fromITBL(info),step);
- upd_evacuee(q,to);
- return to;
+ case STABLE_NAME:
+ return copy(q,sizeW_fromITBL(info),step);
case CAF_BLACKHOLE:
case BLACKHOLE:
- to = copyPart(q,BLACKHOLE_sizeW(),sizeofW(StgHeader),step);
- upd_evacuee(q,to);
- return to;
+ return copyPart(q,BLACKHOLE_sizeW(),sizeofW(StgHeader),step);
case BLACKHOLE_BQ:
to = copy(q,BLACKHOLE_sizeW(),step);
- upd_evacuee(q,to);
recordMutable((StgMutClosure *)to);
return to;
case CONSTR_0_2:
case CONSTR_STATIC:
{
- StgNat32 offset = info->layout.selector_offset;
+ StgWord32 offset = info->layout.selector_offset;
/* check that the size is in range */
ASSERT(offset <
- (StgNat32)(selectee_info->layout.payload.ptrs +
+ (StgWord32)(selectee_info->layout.payload.ptrs +
selectee_info->layout.payload.nptrs));
/* perform the selection! */
* with the evacuation, just update the source address with
* a pointer to the (evacuated) constructor field.
*/
- if (IS_USER_PTR(q)) {
+ if (HEAP_ALLOCED(q)) {
bdescr *bd = Bdescr((P_)q);
if (bd->evacuated) {
if (bd->gen->no < evac_gen) {
barf("evacuate: THUNK_SELECTOR: strange selectee");
}
}
- to = copy(q,THUNK_SELECTOR_sizeW(),step);
- upd_evacuee(q,to);
- return to;
+ return copy(q,THUNK_SELECTOR_sizeW(),step);
case IND:
case IND_OLDGEN:
case PAP:
/* these are special - the payload is a copy of a chunk of stack,
tagging and all. */
- to = copy(q,pap_sizeW(stgCast(StgPAP*,q)),step);
- upd_evacuee(q,to);
- return to;
+ return copy(q,pap_sizeW(stgCast(StgPAP*,q)),step);
case EVACUATED:
/* Already evacuated, just return the forwarding address.
return q;
} else {
/* just copy the block */
- to = copy(q,size,step);
- upd_evacuee(q,to);
- return to;
+ return copy(q,size,step);
}
}
} else {
/* just copy the block */
to = copy(q,size,step);
- upd_evacuee(q,to);
if (info->type == MUT_ARR_PTRS) {
recordMutable((StgMutClosure *)to);
}
new_tso->splim = (StgPtr)new_tso->splim + diff;
relocate_TSO(tso, new_tso);
- upd_evacuee(q,(StgClosure *)new_tso);
recordMutable((StgMutClosure *)new_tso);
return (StgClosure *)new_tso;
srt = stgCast(StgClosure **,info->srt);
srt_end = srt + info->srt_len;
for (; srt < srt_end; srt++) {
- evacuate(*srt);
+ /* Special-case to handle references to closures hiding out in DLLs, since
+ double indirections required to get at those. The code generator knows
+ which is which when generating the SRT, so it stores the (indirect)
+ reference to the DLL closure in the table by first adding one to it.
+ We check for this here, and undo the addition before evacuating it.
+
+ If the SRT entry hasn't got bit 0 set, the SRT entry points to a
+ closure that's fixed at link-time, and no extra magic is required.
+ */
+#ifdef HAVE_WIN32_DLL_SUPPORT
+ if ( stgCast(unsigned long,*srt) & 0x1 ) {
+ evacuate(*stgCast(StgClosure**,(stgCast(unsigned long, *srt) & ~0x1)));
+ } else {
+ evacuate(*srt);
+ }
+#else
+ evacuate(*srt);
+#endif
}
}
{
StgPtr q;
const StgInfoTable* info;
- StgNat32 bitmap;
+ StgWord32 bitmap;
/*
* Each time around this loop, we are looking at a chunk of stack
/* Is q a pointer to a closure?
*/
- if (! LOOKS_LIKE_GHC_INFO(q)) {
+ if (! LOOKS_LIKE_GHC_INFO(q)) {
#ifdef DEBUG
- if (LOOKS_LIKE_STATIC(q)) { /* Is it a static closure? */
+ if ( 0 && LOOKS_LIKE_STATIC_CLOSURE(q) ) { /* Is it a static closure? */
ASSERT(closure_STATIC(stgCast(StgClosure*,q)));
- }
- /* otherwise, must be a pointer into the allocation space.
- */
+ }
+ /* otherwise, must be a pointer into the allocation space. */
#endif
(StgClosure *)*p = evacuate((StgClosure *)q);
case CAF_BLACKHOLE:
to = copyPart(frame->updatee, BLACKHOLE_sizeW(),
sizeofW(StgHeader), step);
- upd_evacuee(frame->updatee,to);
frame->updatee = to;
continue;
case BLACKHOLE_BQ:
to = copy(frame->updatee, BLACKHOLE_sizeW(), step);
- upd_evacuee(frame->updatee,to);
frame->updatee = to;
recordMutable((StgMutClosure *)to);
continue;
}
static void
-zeroStaticObjectList(StgClosure* first_static)
+zero_static_object_list(StgClosure* first_static)
{
StgClosure* p;
StgClosure* link;
* mutable list.
*/
static void
-zeroMutableList(StgMutClosure *first)
+zero_mutable_list( StgMutClosure *first )
{
StgMutClosure *next, *c;
}
}
-void revertDeadCAFs(void)
+void revert_dead_CAFs(void)
{
StgCAF* caf = enteredCAFs;
enteredCAFs = END_CAF_LIST;
break;
}
default:
- barf("revertDeadCAFs: enteredCAFs list corrupted");
+ barf("revert_dead_CAFs: enteredCAFs list corrupted");
}
caf = next;
}