/* -----------------------------------------------------------------------------
- * $Id: GCCompact.c,v 1.14 2003/03/24 14:46:54 simonmar Exp $
*
* (c) The GHC Team 2001
*
#include "Rts.h"
#include "RtsUtils.h"
#include "RtsFlags.h"
+#include "OSThreads.h"
#include "Storage.h"
#include "BlockAlloc.h"
#include "MBlock.h"
#include "GCCompact.h"
#include "Schedule.h"
-#include "StablePriv.h"
#include "Apply.h"
// Turn off inlining when debugging - it obfuscates things
#ifdef DEBUG
-#define INLINE
-#else
-#define INLINE inline
+# undef STATIC_INLINE
+# define STATIC_INLINE static
#endif
/* -----------------------------------------------------------------------------
except for the info pointer.
-------------------------------------------------------------------------- */
-static INLINE void
+STATIC_INLINE void
thread( StgPtr p )
{
StgPtr q = (StgPtr)*p;
}
}
-static INLINE void
+STATIC_INLINE void
unthread( StgPtr p, StgPtr free )
{
- StgPtr q = (StgPtr)*p, r;
+ StgWord q = *p, r;
- while (((StgWord)q & 1) != 0) {
- (StgWord)q -= 1; // unset the low bit again
- r = (StgPtr)*q;
- *q = (StgWord)free;
+ while ((q & 1) != 0) {
+ q -= 1; // unset the low bit again
+ r = *((StgPtr)q);
+ *((StgPtr)q) = (StgWord)free;
q = r;
}
- *p = (StgWord)q;
+ *p = q;
}
-static INLINE StgInfoTable *
+STATIC_INLINE StgInfoTable *
get_threaded_info( StgPtr p )
{
StgPtr q = (P_)GET_INFO((StgClosure *)p);
// A word-aligned memmove will be faster for small objects than libc's or gcc's.
// Remember, the two regions *might* overlap, but: to <= from.
-static INLINE void
+STATIC_INLINE void
move(StgPtr to, StgPtr from, nat size)
{
for(; size > 0; --size) {
}
}
-static INLINE nat
-obj_sizeW( StgClosure *p, StgInfoTable *info )
-{
- switch (info->type) {
- case FUN_0_1:
- case CONSTR_0_1:
- case FUN_1_0:
- case CONSTR_1_0:
- return sizeofW(StgHeader) + 1;
- case THUNK_0_1:
- case THUNK_0_2:
- case FUN_0_2:
- case CONSTR_0_2:
- case THUNK_1_0:
- case THUNK_1_1:
- case FUN_1_1:
- case CONSTR_1_1:
- case THUNK_2_0:
- case FUN_2_0:
- case CONSTR_2_0:
- return sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
- case THUNK_SELECTOR:
- return THUNK_SELECTOR_sizeW();
- case AP_STACK:
- return ap_stack_sizeW((StgAP_STACK *)p);
- case AP:
- case PAP:
- return pap_sizeW((StgPAP *)p);
- case ARR_WORDS:
- return arr_words_sizeW((StgArrWords *)p);
- case MUT_ARR_PTRS:
- case MUT_ARR_PTRS_FROZEN:
- return mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
- case TSO:
- return tso_sizeW((StgTSO *)p);
- case BCO:
- return bco_sizeW((StgBCO *)p);
- default:
- return sizeW_fromITBL(info);
- }
-}
-
static void
thread_static( StgClosure* p )
{
case IND_STATIC:
thread((StgPtr)&((StgInd *)p)->indirectee);
- p = IND_STATIC_LINK(p);
+ p = *IND_STATIC_LINK(p);
continue;
case THUNK_STATIC:
- p = THUNK_STATIC_LINK(p);
+ p = *THUNK_STATIC_LINK(p);
continue;
case FUN_STATIC:
- p = FUN_STATIC_LINK(p);
+ p = *FUN_STATIC_LINK(p);
continue;
case CONSTR_STATIC:
- p = STATIC_LINK(info,p);
+ p = *STATIC_LINK(info,p);
continue;
default:
}
}
-static INLINE void
+STATIC_INLINE void
thread_large_bitmap( StgPtr p, StgLargeBitmap *large_bitmap, nat size )
{
nat i, b;
}
}
-static INLINE StgPtr
+STATIC_INLINE StgPtr
thread_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
{
StgPtr p;
nat size;
p = (StgPtr)args;
- switch (fun_info->fun_type) {
+ switch (fun_info->f.fun_type) {
case ARG_GEN:
- bitmap = BITMAP_BITS(fun_info->bitmap);
- size = BITMAP_SIZE(fun_info->bitmap);
+ bitmap = BITMAP_BITS(fun_info->f.b.bitmap);
+ size = BITMAP_SIZE(fun_info->f.b.bitmap);
goto small_bitmap;
case ARG_GEN_BIG:
- size = ((StgLargeBitmap *)fun_info->bitmap)->size;
- thread_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+ size = GET_FUN_LARGE_BITMAP(fun_info)->size;
+ thread_large_bitmap(p, GET_FUN_LARGE_BITMAP(fun_info), size);
p += size;
break;
default:
- bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
- size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->fun_type]);
+ bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
+ size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
small_bitmap:
while (size > 0) {
if ((bitmap & 1) == 0) {
dyn = ((StgRetDyn *)p)->liveness;
// traverse the bitmap first
- bitmap = GET_LIVENESS(dyn);
+ bitmap = RET_DYN_LIVENESS(dyn);
p = (P_)&((StgRetDyn *)p)->payload[0];
- size = RET_DYN_SIZE;
+ size = RET_DYN_BITMAP_SIZE;
while (size > 0) {
if ((bitmap & 1) == 0) {
thread(p);
}
// skip over the non-ptr words
- p += GET_NONPTRS(dyn);
+ p += RET_DYN_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
// follow the ptr words
- for (size = GET_PTRS(dyn); size > 0; size--) {
+ for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
thread(p);
p++;
}
}
// small bitmap (<= 32 entries, or 64 on a 64-bit machine)
+ case CATCH_RETRY_FRAME:
+ case CATCH_STM_FRAME:
+ case ATOMICALLY_FRAME:
case UPDATE_FRAME:
case STOP_FRAME:
case CATCH_FRAME:
nat size;
p++;
- thread(p);
bco = (StgBCO *)*p;
+ thread(p);
p++;
size = BCO_BITMAP_SIZE(bco);
thread_large_bitmap(p, BCO_BITMAP(bco), size);
case RET_BIG:
case RET_VEC_BIG:
p++;
- size = info->i.layout.large_bitmap->size;
- thread_large_bitmap(p, info->i.layout.large_bitmap, size);
+ size = GET_LARGE_BITMAP(&info->i)->size;
+ thread_large_bitmap(p, GET_LARGE_BITMAP(&info->i), size);
p += size;
continue;
StgRetFun *ret_fun = (StgRetFun *)p;
StgFunInfoTable *fun_info;
- fun_info = itbl_to_fun_itbl(get_threaded_info(ret_fun->fun));
+ fun_info = itbl_to_fun_itbl(
+ get_threaded_info((StgPtr)ret_fun->fun));
// *before* threading it!
thread((StgPtr)&ret_fun->fun);
p = thread_arg_block(fun_info, ret_fun->payload);
}
}
-static INLINE StgPtr
-thread_PAP (StgPAP *pap)
+STATIC_INLINE StgPtr
+thread_PAP_payload (StgClosure *fun, StgClosure **payload, StgWord size)
{
StgPtr p;
- StgWord bitmap, size;
+ StgWord bitmap;
StgFunInfoTable *fun_info;
-
- fun_info = itbl_to_fun_itbl(get_threaded_info(pap->fun));
+
+ fun_info = itbl_to_fun_itbl(get_threaded_info((StgPtr)fun));
ASSERT(fun_info->i.type != PAP);
- p = (StgPtr)pap->payload;
- size = pap->n_args;
+ p = (StgPtr)payload;
- switch (fun_info->fun_type) {
+ switch (fun_info->f.fun_type) {
case ARG_GEN:
- bitmap = BITMAP_BITS(fun_info->bitmap);
+ bitmap = BITMAP_BITS(fun_info->f.b.bitmap);
goto small_bitmap;
case ARG_GEN_BIG:
- thread_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+ thread_large_bitmap(p, GET_FUN_LARGE_BITMAP(fun_info), size);
p += size;
break;
case ARG_BCO:
- thread_large_bitmap((StgPtr)pap->payload, BCO_BITMAP(pap->fun), size);
+ thread_large_bitmap((StgPtr)payload, BCO_BITMAP(fun), size);
p += size;
break;
default:
- bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
+ bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
small_bitmap:
- size = pap->n_args;
while (size > 0) {
if ((bitmap & 1) == 0) {
thread(p);
break;
}
+ return p;
+}
+
+STATIC_INLINE StgPtr
+thread_PAP (StgPAP *pap)
+{
+ StgPtr p;
+ p = thread_PAP_payload(pap->fun, pap->payload, pap->n_args);
thread((StgPtr)&pap->fun);
return p;
}
+
+STATIC_INLINE StgPtr
+thread_AP (StgAP *ap)
+{
+ StgPtr p;
+ p = thread_PAP_payload(ap->fun, ap->payload, ap->n_args);
+ thread((StgPtr)&ap->fun);
+ return p;
+}
-static INLINE StgPtr
+STATIC_INLINE StgPtr
thread_AP_STACK (StgAP_STACK *ap)
{
thread((StgPtr)&ap->fun);
thread((StgPtr)&tso->blocked_exceptions);
}
+ thread((StgPtr)&tso->trec);
+
thread_stack(tso->sp, &(tso->stack[tso->stack_size]));
return (StgPtr)tso + tso_sizeW(tso);
}
// nothing to follow
continue;
- case MUT_ARR_PTRS:
+ case MUT_ARR_PTRS_CLEAN:
+ case MUT_ARR_PTRS_DIRTY:
case MUT_ARR_PTRS_FROZEN:
+ case MUT_ARR_PTRS_FROZEN0:
// follow everything
{
StgPtr next;
thread_PAP((StgPAP *)p);
continue;
+ case TREC_CHUNK:
+ {
+ StgWord i;
+ StgTRecChunk *tc = (StgTRecChunk *)p;
+ TRecEntry *e = &(tc -> entries[0]);
+ thread((StgPtr)&tc->prev_chunk);
+ for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
+ thread((StgPtr)&e->tvar);
+ thread((StgPtr)&e->expected_value);
+ thread((StgPtr)&e->new_value);
+ }
+ continue;
+ }
+
default:
barf("update_fwd_large: unknown/strange object %d", (int)(info->type));
}
}
}
-static INLINE StgPtr
+STATIC_INLINE StgPtr
thread_obj (StgInfoTable *info, StgPtr p)
{
switch (info->type) {
+ case THUNK_0_1:
+ return p + sizeofW(StgThunk) + 1;
+
case FUN_0_1:
case CONSTR_0_1:
return p + sizeofW(StgHeader) + 1;
return p + sizeofW(StgHeader) + 1;
case THUNK_1_0:
- thread((StgPtr)&((StgClosure *)p)->payload[0]);
- return p + sizeofW(StgHeader) + 2; // MIN_UPD_SIZE
+ thread((StgPtr)&((StgThunk *)p)->payload[0]);
+ return p + sizeofW(StgThunk) + 1;
- case THUNK_0_1: // MIN_UPD_SIZE
case THUNK_0_2:
+ return p + sizeofW(StgThunk) + 2;
+
case FUN_0_2:
case CONSTR_0_2:
return p + sizeofW(StgHeader) + 2;
case THUNK_1_1:
+ thread((StgPtr)&((StgThunk *)p)->payload[0]);
+ return p + sizeofW(StgThunk) + 2;
+
case FUN_1_1:
case CONSTR_1_1:
thread((StgPtr)&((StgClosure *)p)->payload[0]);
return p + sizeofW(StgHeader) + 2;
case THUNK_2_0:
+ thread((StgPtr)&((StgThunk *)p)->payload[0]);
+ thread((StgPtr)&((StgThunk *)p)->payload[1]);
+ return p + sizeofW(StgThunk) + 2;
+
case FUN_2_0:
case CONSTR_2_0:
thread((StgPtr)&((StgClosure *)p)->payload[0]);
return p + bco_sizeW(bco);
}
- case FUN:
case THUNK:
+ {
+ StgPtr end;
+
+ end = (P_)((StgThunk *)p)->payload +
+ info->layout.payload.ptrs;
+ for (p = (P_)((StgThunk *)p)->payload; p < end; p++) {
+ thread(p);
+ }
+ return p + info->layout.payload.nptrs;
+ }
+
+ case FUN:
case CONSTR:
- case FOREIGN:
case STABLE_NAME:
case IND_PERM:
- case MUT_VAR:
- case MUT_CONS:
+ case MUT_VAR_CLEAN:
+ case MUT_VAR_DIRTY:
case CAF_BLACKHOLE:
case SE_CAF_BLACKHOLE:
case SE_BLACKHOLE:
case BLACKHOLE:
- case BLACKHOLE_BQ:
{
StgPtr end;
case IND_OLDGEN:
case IND_OLDGEN_PERM:
- thread((StgPtr)&((StgIndOldGen *)p)->indirectee);
- return p + sizeofW(StgIndOldGen);
+ thread((StgPtr)&((StgInd *)p)->indirectee);
+ return p + sizeofW(StgInd);
case THUNK_SELECTOR:
{
return thread_AP_STACK((StgAP_STACK *)p);
case PAP:
- case AP:
return thread_PAP((StgPAP *)p);
+
+ case AP:
+ return thread_AP((StgAP *)p);
case ARR_WORDS:
return p + arr_words_sizeW((StgArrWords *)p);
- case MUT_ARR_PTRS:
+ case MUT_ARR_PTRS_CLEAN:
+ case MUT_ARR_PTRS_DIRTY:
case MUT_ARR_PTRS_FROZEN:
+ case MUT_ARR_PTRS_FROZEN0:
// follow everything
{
StgPtr next;
case TSO:
return thread_TSO((StgTSO *)p);
+ case TVAR_WAIT_QUEUE:
+ {
+ StgTVarWaitQueue *wq = (StgTVarWaitQueue *)p;
+ thread((StgPtr)&wq->waiting_tso);
+ thread((StgPtr)&wq->next_queue_entry);
+ thread((StgPtr)&wq->prev_queue_entry);
+ return p + sizeofW(StgTVarWaitQueue);
+ }
+
+ case TVAR:
+ {
+ StgTVar *tvar = (StgTVar *)p;
+ thread((StgPtr)&tvar->current_value);
+ thread((StgPtr)&tvar->first_wait_queue_entry);
+ return p + sizeofW(StgTVar);
+ }
+
+ case TREC_HEADER:
+ {
+ StgTRecHeader *trec = (StgTRecHeader *)p;
+ thread((StgPtr)&trec->enclosing_trec);
+ thread((StgPtr)&trec->current_chunk);
+ return p + sizeofW(StgTRecHeader);
+ }
+
+ case TREC_CHUNK:
+ {
+ StgWord i;
+ StgTRecChunk *tc = (StgTRecChunk *)p;
+ TRecEntry *e = &(tc -> entries[0]);
+ thread((StgPtr)&tc->prev_chunk);
+ for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
+ thread((StgPtr)&e->tvar);
+ thread((StgPtr)&e->expected_value);
+ thread((StgPtr)&e->new_value);
+ }
+ return p + sizeofW(StgTRecChunk);
+ }
+
default:
barf("update_fwd: unknown/strange object %d", (int)(info->type));
+ return NULL;
}
}
StgInfoTable *info;
nat size, free_blocks;
- bd = free_bd = stp->blocks;
+ bd = free_bd = stp->old_blocks;
free = free_bd->start;
free_blocks = 1;
unthread(p,free);
ASSERT(LOOKS_LIKE_INFO_PTR(((StgClosure *)p)->header.info));
info = get_itbl((StgClosure *)p);
- size = obj_sizeW((StgClosure *)p,info);
+ size = closure_sizeW_((StgClosure *)p,info);
if (free != p) {
move(free,p,size);
}
- // Rebuild the mutable list for the old generation.
- if (ip_MUTABLE(info)) {
- recordMutable((StgMutClosure *)free);
- }
-
// relocate TSOs
if (info->type == TSO) {
move_TSO((StgTSO *)p, (StgTSO *)free);
freeChain(free_bd->link);
free_bd->link = NULL;
}
- stp->n_blocks = free_blocks;
return free_blocks;
}
-static void
-thread_mut_once_list( generation *g )
-{
- StgMutClosure *p, *next;
-
- for (p = g->mut_once_list; p != END_MUT_LIST; p = next) {
- next = p->mut_link;
- thread((StgPtr)&p->mut_link);
- }
-
- thread((StgPtr)&g->mut_once_list);
-}
-
void
compact( void (*get_roots)(evac_fn) )
{
// the weak pointer lists...
if (weak_ptr_list != NULL) {
- thread((StgPtr)&weak_ptr_list);
+ thread((StgPtr)(void *)&weak_ptr_list);
}
if (old_weak_ptr_list != NULL) {
- thread((StgPtr)&old_weak_ptr_list); // tmp
+ thread((StgPtr)(void *)&old_weak_ptr_list); // tmp
}
// mutable lists
for (g = 1; g < RtsFlags.GcFlags.generations; g++) {
- thread((StgPtr)&generations[g].mut_list);
- thread_mut_once_list(&generations[g]);
+ bdescr *bd;
+ StgPtr p;
+ for (bd = generations[g].mut_list; bd != NULL; bd = bd->link) {
+ for (p = bd->start; p < bd->free; p++) {
+ thread(p);
+ }
+ }
}
// the global thread list
- thread((StgPtr)&all_threads);
+ thread((StgPtr)(void *)&all_threads);
// any threads resurrected during this GC
- thread((StgPtr)&resurrected_threads);
+ thread((StgPtr)(void *)&resurrected_threads);
- // the main threads list
+ // the task list
{
- StgMainThread *m;
- for (m = main_threads; m != NULL; m = m->link) {
- thread((StgPtr)&m->tso);
+ Task *task;
+ for (task = all_tasks; task != NULL; task = task->all_link) {
+ if (task->tso) {
+ thread((StgPtr)&task->tso);
+ }
}
}
// 2. update forward ptrs
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
for (s = 0; s < generations[g].n_steps; s++) {
+ if (g==0 && s ==0) continue;
stp = &generations[g].steps[s];
- IF_DEBUG(gc, fprintf(stderr,"update_fwd: %d.%d\n", stp->gen->no, stp->no););
+ IF_DEBUG(gc, debugBelch("update_fwd: %d.%d\n", stp->gen->no, stp->no););
- update_fwd(stp->to_blocks);
+ update_fwd(stp->blocks);
update_fwd_large(stp->scavenged_large_objects);
- if (g == RtsFlags.GcFlags.generations-1 && stp->blocks != NULL) {
- IF_DEBUG(gc, fprintf(stderr,"update_fwd: %d.%d (compact)\n", stp->gen->no, stp->no););
- update_fwd_compact(stp->blocks);
+ if (g == RtsFlags.GcFlags.generations-1 && stp->old_blocks != NULL) {
+ IF_DEBUG(gc, debugBelch("update_fwd: %d.%d (compact)\n", stp->gen->no, stp->no););
+ update_fwd_compact(stp->old_blocks);
}
}
}
// 3. update backward ptrs
stp = &oldest_gen->steps[0];
- if (stp->blocks != NULL) {
+ if (stp->old_blocks != NULL) {
blocks = update_bkwd_compact(stp);
- IF_DEBUG(gc, fprintf(stderr,"update_bkwd: %d.%d (compact, old: %d blocks, now %d blocks)\n",
+ IF_DEBUG(gc, debugBelch("update_bkwd: %d.%d (compact, old: %d blocks, now %d blocks)\n",
stp->gen->no, stp->no,
- stp->n_blocks, blocks););
- stp->n_blocks = blocks;
+ stp->n_old_blocks, blocks););
+ stp->n_old_blocks = blocks;
}
}