/* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.44 1999/02/26 13:36:12 simonm Exp $
+ * $Id: GC.c,v 1.57 1999/03/26 10:29:04 simonm Exp $
*
* (c) The GHC Team 1998-1999
*
static void revert_dead_CAFs ( void );
static rtsBool traverse_weak_ptr_list ( void );
-static void cleanup_weak_ptr_list ( void );
+static void cleanup_weak_ptr_list ( StgWeak **list );
static void scavenge_stack ( StgPtr p, StgPtr stack_end );
static void scavenge_large ( step *step );
for ( bd = current_nursery->link; bd != NULL; bd = bd->link ) {
allocated -= BLOCK_SIZE_W;
}
+ if (current_nursery->free < current_nursery->start + BLOCK_SIZE_W) {
+ allocated -= (current_nursery->start + BLOCK_SIZE_W)
+ - current_nursery->free;
+ }
/* Figure out which generation to collect
*/
* the CAF document.
*/
extern void markHugsObjects(void);
-#if 0
- /* ToDo: This (undefined) function should contain the scavenge
- * loop immediately below this block of code - but I'm not sure
- * enough of the details to do this myself.
- */
- scavengeEverything();
- /* revert dead CAFs and update enteredCAFs list */
- revert_dead_CAFs();
-#endif
markHugsObjects();
-#if 0
- /* This will keep the CAFs and the attached BCOs alive
- * but the values will have been reverted
- */
- scavengeEverything();
-#endif
}
#endif
/* Final traversal of the weak pointer list (see comment by
* cleanUpWeakPtrList below).
*/
- cleanup_weak_ptr_list();
+ cleanup_weak_ptr_list(&weak_ptr_list);
/* Now see which stable names are still alive.
*/
gcStablePtrTable(major_gc);
+ /* revert dead CAFs and update enteredCAFs list */
+ revert_dead_CAFs();
+
/* Set the maximum blocks for the oldest generation, based on twice
* the amount of live data now, adjusted to fit the maximum heap
* size if necessary.
}
}
- /* revert dead CAFs and update enteredCAFs list */
- revert_dead_CAFs();
-
- /* mark the garbage collected CAFs as dead */
+ /* mark the garbage collected CAFs as dead */
#ifdef DEBUG
if (major_gc) { gcCAFs(); }
#endif
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.
* of pending finalizers later on.
*/
if (flag == rtsFalse) {
+ cleanup_weak_ptr_list(&old_weak_ptr_list);
for (w = old_weak_ptr_list; w; w = w->link) {
- w->value = evacuate(w->value);
w->finalizer = evacuate(w->finalizer);
}
weak_done = rtsTrue;
-------------------------------------------------------------------------- */
static void
-cleanup_weak_ptr_list ( void )
+cleanup_weak_ptr_list ( StgWeak **list )
{
StgWeak *w, **last_w;
- last_w = &weak_ptr_list;
- for (w = weak_ptr_list; w; w = w->link) {
+ last_w = list;
+ for (w = *list; w; w = w->link) {
if (get_itbl(w)->type == EVACUATED) {
w = (StgWeak *)((StgEvacuated *)w)->evacuee;
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
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) {
q = ((StgInd*)q)->indirectee;
goto loop;
- /* ToDo: optimise STATIC_LINK for known cases.
- - FUN_STATIC : payload[0]
- - THUNK_STATIC : payload[1]
- - IND_STATIC : payload[1]
- */
case THUNK_STATIC:
+ if (info->srt_len > 0 && major_gc &&
+ 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_len == 0) { /* small optimisation */
- return q;
+ if (info->srt_len > 0 && major_gc &&
+ FUN_STATIC_LINK((StgClosure *)q) == NULL) {
+ FUN_STATIC_LINK((StgClosure *)q) = static_objects;
+ static_objects = (StgClosure *)q;
}
- /* fall through */
- case CONSTR_STATIC:
+ return q;
+
case IND_STATIC:
- /* don't want to evacuate these, but we do want to follow pointers
- * from SRTs - see scavenge_static.
- */
+ if (major_gc && IND_STATIC_LINK((StgClosure *)q) == NULL) {
+ IND_STATIC_LINK((StgClosure *)q) = static_objects;
+ static_objects = (StgClosure *)q;
+ }
+ return q;
- /* put the object on the static list, if necessary.
- */
+ case CONSTR_STATIC:
if (major_gc && STATIC_LINK(info,(StgClosure *)q) == NULL) {
STATIC_LINK(info,(StgClosure *)q) = static_objects;
static_objects = (StgClosure *)q;
}
- /* fall through */
+ return q;
case CONSTR_INTLIKE:
case CONSTR_CHARLIKE:
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
}
}
case WEAK:
case FOREIGN:
case STABLE_NAME:
- case IND_PERM:
- case IND_OLDGEN_PERM:
- case CAF_UNENTERED:
- case CAF_ENTERED:
{
StgPtr end;
break;
}
+ case IND_PERM:
+ if (step->gen->no != 0) {
+ SET_INFO(((StgClosure *)p), &IND_OLDGEN_PERM_info);
+ }
+ /* fall through */
+ case IND_OLDGEN_PERM:
+ ((StgIndOldGen *)p)->indirectee =
+ evacuate(((StgIndOldGen *)p)->indirectee);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ recordOldToNewPtrs((StgMutClosure *)p);
+ }
+ p += sizeofW(StgIndOldGen);
+ break;
+
+ case CAF_UNENTERED:
+ {
+ StgCAF *caf = (StgCAF *)p;
+
+ caf->body = evacuate(caf->body);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ recordOldToNewPtrs((StgMutClosure *)p);
+ } else {
+ caf->mut_link = NULL;
+ }
+ p += sizeofW(StgCAF);
+ break;
+ }
+
+ case CAF_ENTERED:
+ {
+ StgCAF *caf = (StgCAF *)p;
+
+ caf->body = evacuate(caf->body);
+ caf->value = evacuate(caf->value);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ recordOldToNewPtrs((StgMutClosure *)p);
+ } else {
+ caf->mut_link = NULL;
+ }
+ p += sizeofW(StgCAF);
+ break;
+ }
+
case MUT_VAR:
/* ignore MUT_CONSs */
if (((StgMutVar *)p)->header.info != &MUT_CONS_info) {
evac_gen = 0;
/* chase the link field for any TSOs on the same queue */
(StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+ if (tso->blocked_on) {
+ tso->blocked_on = evacuate(tso->blocked_on);
+ }
/* scavenge this thread's stack */
scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
evac_gen = saved_evac_gen;
case IND_PERM:
case IND_OLDGEN_PERM:
case CAF_UNENTERED:
- case CAF_ENTERED:
{
StgPtr q, end;
}
continue;
+ case CAF_ENTERED:
+ {
+ StgCAF *caf = (StgCAF *)p;
+ caf->body = evacuate(caf->body);
+ caf->value = evacuate(caf->value);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ p->mut_link = new_list;
+ new_list = p;
+ } else {
+ p->mut_link = NULL;
+ }
+ }
+ continue;
+
+ case CAF_UNENTERED:
+ {
+ StgCAF *caf = (StgCAF *)p;
+ caf->body = evacuate(caf->body);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ p->mut_link = new_list;
+ new_list = p;
+ } else {
+ p->mut_link = NULL;
+ }
+ }
+ continue;
+
default:
/* shouldn't have anything else on the mutables list */
barf("scavenge_mut_once_list: strange object?");
}
case TSO:
- /* follow ptrs and remove this from the mutable list */
{
StgTSO *tso = (StgTSO *)p;
- /* Don't bother scavenging if this thread is dead
- */
- if (!(tso->whatNext == ThreadComplete ||
- tso->whatNext == ThreadKilled)) {
- /* Don't need to chase the link field for any TSOs on the
- * same queue. Just scavenge this thread's stack
- */
- scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
+ (StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+ if (tso->blocked_on) {
+ tso->blocked_on = evacuate(tso->blocked_on);
}
+ scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
/* Don't take this TSO off the mutable list - it might still
* point to some younger objects (because we set evac_gen to 0
{
StgPtr q;
const StgInfoTable* info;
- StgNat32 bitmap;
+ StgWord32 bitmap;
/*
* Each time around this loop, we are looking at a chunk of stack
*/
while (p < stack_end) {
- q = *stgCast(StgPtr*,p);
+ q = *(P_ *)p;
/* If we've got a tag, skip over that many words on the stack */
- if (IS_ARG_TAG(stgCast(StgWord,q))) {
+ if (IS_ARG_TAG((W_)q)) {
p += ARG_SIZE(q);
p++; continue;
}
/* 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);
* record. All activation records have 'bitmap' style layout
* info.
*/
- info = get_itbl(stgCast(StgClosure*,p));
+ info = get_itbl((StgClosure *)p);
switch (info->type) {
/* Dynamic bitmap: the mask is stored on the stack */
case RET_DYN:
- bitmap = stgCast(StgRetDyn*,p)->liveness;
- p = &payloadWord(stgCast(StgRetDyn*,p),0);
+ bitmap = ((StgRetDyn *)p)->liveness;
+ p = (P_)&((StgRetDyn *)p)->payload[0];
goto small_bitmap;
/* probably a slow-entry point return address: */
{
StgUpdateFrame *frame = (StgUpdateFrame *)p;
StgClosure *to;
- StgClosureType type = get_itbl(frame->updatee)->type;
+ nat type = get_itbl(frame->updatee)->type;
p += sizeofW(StgUpdateFrame);
if (type == EVACUATED) {
tso = (StgTSO *)p;
/* chase the link field for any TSOs on the same queue */
(StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+ if (tso->blocked_on) {
+ tso->blocked_on = evacuate(tso->blocked_on);
+ }
/* scavenge this thread's stack */
scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
continue;
caf->value = stgCast(StgClosure*,0xdeadbeef);
caf->link = stgCast(StgCAF*,0xdeadbeef);
}
+ enteredCAFs = END_CAF_LIST;
}
void revert_dead_CAFs(void)
StgCAF* caf = enteredCAFs;
enteredCAFs = END_CAF_LIST;
while (caf != END_CAF_LIST) {
- StgCAF* next = caf->link;
-
- switch(GET_INFO(caf)->type) {
- case EVACUATED:
- {
- /* This object has been evacuated, it must be live. */
- StgCAF* new = stgCast(StgCAF*,stgCast(StgEvacuated*,caf)->evacuee);
- new->link = enteredCAFs;
- enteredCAFs = new;
- break;
- }
- case CAF_ENTERED:
- {
- SET_INFO(caf,&CAF_UNENTERED_info);
- caf->value = stgCast(StgClosure*,0xdeadbeef);
- caf->link = stgCast(StgCAF*,0xdeadbeef);
- break;
- }
- default:
- barf("revert_dead_CAFs: enteredCAFs list corrupted");
- }
- caf = next;
+ StgCAF *next, *new;
+ next = caf->link;
+ new = (StgCAF*)isAlive((StgClosure*)caf);
+ if (new) {
+ new->link = enteredCAFs;
+ enteredCAFs = new;
+ } else {
+ ASSERT(0);
+ SET_INFO(caf,&CAF_UNENTERED_info);
+ caf->value = (StgClosure*)0xdeadbeef;
+ caf->link = (StgCAF*)0xdeadbeef;
+ }
+ caf = next;
}
}
*/
next_frame = NULL;
- while ((P_)frame < bottom - 1) { /* bottom - 1 is the STOP_FRAME */
+ /* bottom - sizeof(StgStopFrame) is the STOP_FRAME */
+ while ((P_)frame < bottom - sizeofW(StgStopFrame)) {
prev_frame = frame->link;
frame->link = next_frame;
next_frame = frame;