Reorganisation of the source tree
[ghc-hetmet.git] / ghc / rts / RetainerProfile.c
diff --git a/ghc/rts/RetainerProfile.c b/ghc/rts/RetainerProfile.c
deleted file mode 100644 (file)
index c5c3de5..0000000
+++ /dev/null
@@ -1,2338 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * (c) The GHC Team, 2001
- * Author: Sungwoo Park
- *
- * Retainer profiling.
- *
- * ---------------------------------------------------------------------------*/
-
-#ifdef PROFILING
-
-// Turn off inlining when debugging - it obfuscates things
-#ifdef DEBUG
-#define INLINE
-#else
-#define INLINE inline
-#endif
-
-#include "Rts.h"
-#include "RtsUtils.h"
-#include "RetainerProfile.h"
-#include "RetainerSet.h"
-#include "Schedule.h"
-#include "Printer.h"
-#include "Storage.h"
-#include "RtsFlags.h"
-#include "Weak.h"
-#include "Sanity.h"
-#include "Profiling.h"
-#include "Stats.h"
-#include "BlockAlloc.h"
-#include "ProfHeap.h"
-#include "Apply.h"
-
-/*
-  Note: what to change in order to plug-in a new retainer profiling scheme?
-    (1) type retainer in ../includes/StgRetainerProf.h
-    (2) retainer function R(), i.e., getRetainerFrom()
-    (3) the two hashing functions, hashKeySingleton() and hashKeyAddElement(),
-        in RetainerSet.h, if needed.
-    (4) printRetainer() and printRetainerSetShort() in RetainerSet.c.
- */
-
-/* -----------------------------------------------------------------------------
- * Declarations...
- * -------------------------------------------------------------------------- */
-
-static nat retainerGeneration; // generation
-
-static nat numObjectVisited;   // total number of objects visited
-static nat timesAnyObjectVisited; // number of times any objects are visited
-
-/*
-  The rs field in the profile header of any object points to its retainer
-  set in an indirect way: if flip is 0, it points to the retainer set;
-  if flip is 1, it points to the next byte after the retainer set (even
-  for NULL pointers). Therefore, with flip 1, (rs ^ 1) is the actual
-  pointer. See retainerSetOf().
- */
-
-StgWord flip = 0;     // flip bit
-                      // must be 0 if DEBUG_RETAINER is on (for static closures)
-
-#define setRetainerSetToNull(c)   \
-  (c)->header.prof.hp.rs = (RetainerSet *)((StgWord)NULL | flip)
-
-static void retainStack(StgClosure *, retainer, StgPtr, StgPtr);
-static void retainClosure(StgClosure *, StgClosure *, retainer);
-#ifdef DEBUG_RETAINER
-static void belongToHeap(StgPtr p);
-#endif
-
-#ifdef DEBUG_RETAINER
-/*
-  cStackSize records how many times retainStack() has been invoked recursively,
-  that is, the number of activation records for retainStack() on the C stack.
-  maxCStackSize records its max value.
-  Invariants:
-    cStackSize <= maxCStackSize
- */
-static nat cStackSize, maxCStackSize;
-
-static nat sumOfNewCost;       // sum of the cost of each object, computed
-                               // when the object is first visited
-static nat sumOfNewCostExtra;   // for those objects not visited during
-                                // retainer profiling, e.g., MUT_VAR
-static nat costArray[N_CLOSURE_TYPES];
-
-nat sumOfCostLinear;           // sum of the costs of all object, computed
-                               // when linearly traversing the heap after
-                               // retainer profiling
-nat costArrayLinear[N_CLOSURE_TYPES];
-#endif
-
-/* -----------------------------------------------------------------------------
- * Retainer stack - header
- *   Note:
- *     Although the retainer stack implementation could be separated *
- *     from the retainer profiling engine, there does not seem to be
- *     any advantage in doing that; retainer stack is an integral part
- *     of retainer profiling engine and cannot be use elsewhere at
- *     all.
- * -------------------------------------------------------------------------- */
-
-typedef enum {
-    posTypeStep,
-    posTypePtrs,
-    posTypeSRT,
-    posTypeLargeSRT,
-} nextPosType;
-
-typedef union {
-    // fixed layout or layout specified by a field in the closure
-    StgWord step;
-
-    // layout.payload
-    struct {
-    // See StgClosureInfo in InfoTables.h
-#if SIZEOF_VOID_P == 8
-       StgWord32 pos;
-       StgWord32 ptrs;
-#else
-       StgWord16 pos;
-       StgWord16 ptrs;
-#endif
-       StgPtr payload;
-    } ptrs;
-
-    // SRT
-    struct {
-       StgClosure **srt;
-       StgWord    srt_bitmap;
-    } srt;
-
-    // Large SRT
-    struct {
-       StgLargeSRT *srt;
-       StgWord offset;
-    } large_srt;
-       
-} nextPos;
-
-typedef struct {
-    nextPosType type;
-    nextPos next;
-} stackPos;
-
-typedef struct {
-    StgClosure *c;
-    retainer c_child_r;
-    stackPos info;
-} stackElement;
-
-/*
-  Invariants:
-    firstStack points to the first block group.
-    currentStack points to the block group currently being used.
-    currentStack->free == stackLimit.
-    stackTop points to the topmost byte in the stack of currentStack.
-    Unless the whole stack is empty, stackTop must point to the topmost
-    object (or byte) in the whole stack. Thus, it is only when the whole stack
-    is empty that stackTop == stackLimit (not during the execution of push()
-    and pop()).
-    stackBottom == currentStack->start.
-    stackLimit == currentStack->start + BLOCK_SIZE_W * currentStack->blocks.
-  Note:
-    When a current stack becomes empty, stackTop is set to point to
-    the topmost element on the previous block group so as to satisfy
-    the invariants described above.
- */
-static bdescr *firstStack = NULL;
-static bdescr *currentStack;
-static stackElement *stackBottom, *stackTop, *stackLimit;
-
-/*
-  currentStackBoundary is used to mark the current stack chunk.
-  If stackTop == currentStackBoundary, it means that the current stack chunk
-  is empty. It is the responsibility of the user to keep currentStackBoundary
-  valid all the time if it is to be employed.
- */
-static stackElement *currentStackBoundary;
-
-/*
-  stackSize records the current size of the stack.
-  maxStackSize records its high water mark.
-  Invariants:
-    stackSize <= maxStackSize
-  Note:
-    stackSize is just an estimate measure of the depth of the graph. The reason
-    is that some heap objects have only a single child and may not result
-    in a new element being pushed onto the stack. Therefore, at the end of
-    retainer profiling, maxStackSize + maxCStackSize is some value no greater
-    than the actual depth of the graph.
- */
-#ifdef DEBUG_RETAINER
-static int stackSize, maxStackSize;
-#endif
-
-// number of blocks allocated for one stack
-#define BLOCKS_IN_STACK 1
-
-/* -----------------------------------------------------------------------------
- * Add a new block group to the stack.
- * Invariants:
- *  currentStack->link == s.
- * -------------------------------------------------------------------------- */
-static INLINE void
-newStackBlock( bdescr *bd )
-{
-    currentStack = bd;
-    stackTop     = (stackElement *)(bd->start + BLOCK_SIZE_W * bd->blocks);
-    stackBottom  = (stackElement *)bd->start;
-    stackLimit   = (stackElement *)stackTop;
-    bd->free     = (StgPtr)stackLimit;
-}
-
-/* -----------------------------------------------------------------------------
- * Return to the previous block group.
- * Invariants:
- *   s->link == currentStack.
- * -------------------------------------------------------------------------- */
-static INLINE void
-returnToOldStack( bdescr *bd )
-{
-    currentStack = bd;
-    stackTop = (stackElement *)bd->free;
-    stackBottom = (stackElement *)bd->start;
-    stackLimit = (stackElement *)(bd->start + BLOCK_SIZE_W * bd->blocks);
-    bd->free = (StgPtr)stackLimit;
-}
-
-/* -----------------------------------------------------------------------------
- *  Initializes the traverse stack.
- * -------------------------------------------------------------------------- */
-static void
-initializeTraverseStack( void )
-{
-    if (firstStack != NULL) {
-       freeChain(firstStack);
-    }
-
-    firstStack = allocGroup(BLOCKS_IN_STACK);
-    firstStack->link = NULL;
-    firstStack->u.back = NULL;
-
-    newStackBlock(firstStack);
-}
-
-/* -----------------------------------------------------------------------------
- * Frees all the block groups in the traverse stack.
- * Invariants:
- *   firstStack != NULL
- * -------------------------------------------------------------------------- */
-static void
-closeTraverseStack( void )
-{
-    freeChain(firstStack);
-    firstStack = NULL;
-}
-
-/* -----------------------------------------------------------------------------
- * Returns rtsTrue if the whole stack is empty.
- * -------------------------------------------------------------------------- */
-static INLINE rtsBool
-isEmptyRetainerStack( void )
-{
-    return (firstStack == currentStack) && stackTop == stackLimit;
-}
-
-/* -----------------------------------------------------------------------------
- * Returns size of stack
- * -------------------------------------------------------------------------- */
-#ifdef DEBUG
-lnat
-retainerStackBlocks( void )
-{
-    bdescr* bd;
-    lnat res = 0;
-
-    for (bd = firstStack; bd != NULL; bd = bd->link) 
-      res += bd->blocks;
-
-    return res;
-}
-#endif
-
-/* -----------------------------------------------------------------------------
- * Returns rtsTrue if stackTop is at the stack boundary of the current stack,
- * i.e., if the current stack chunk is empty.
- * -------------------------------------------------------------------------- */
-static INLINE rtsBool
-isOnBoundary( void )
-{
-    return stackTop == currentStackBoundary;
-}
-
-/* -----------------------------------------------------------------------------
- * Initializes *info from ptrs and payload.
- * Invariants:
- *   payload[] begins with ptrs pointers followed by non-pointers.
- * -------------------------------------------------------------------------- */
-static INLINE void
-init_ptrs( stackPos *info, nat ptrs, StgPtr payload )
-{
-    info->type              = posTypePtrs;
-    info->next.ptrs.pos     = 0;
-    info->next.ptrs.ptrs    = ptrs;
-    info->next.ptrs.payload = payload;
-}
-
-/* -----------------------------------------------------------------------------
- * Find the next object from *info.
- * -------------------------------------------------------------------------- */
-static INLINE StgClosure *
-find_ptrs( stackPos *info )
-{
-    if (info->next.ptrs.pos < info->next.ptrs.ptrs) {
-       return (StgClosure *)info->next.ptrs.payload[info->next.ptrs.pos++];
-    } else {
-       return NULL;
-    }
-}
-
-/* -----------------------------------------------------------------------------
- *  Initializes *info from SRT information stored in *infoTable.
- * -------------------------------------------------------------------------- */
-static INLINE void
-init_srt_fun( stackPos *info, StgFunInfoTable *infoTable )
-{
-    if (infoTable->i.srt_bitmap == (StgHalfWord)(-1)) {
-       info->type = posTypeLargeSRT;
-       info->next.large_srt.srt = (StgLargeSRT *)GET_FUN_SRT(infoTable);
-       info->next.large_srt.offset = 0;
-    } else {
-       info->type = posTypeSRT;
-       info->next.srt.srt = (StgClosure **)GET_FUN_SRT(infoTable);
-       info->next.srt.srt_bitmap = infoTable->i.srt_bitmap;
-    }
-}
-
-static INLINE void
-init_srt_thunk( stackPos *info, StgThunkInfoTable *infoTable )
-{
-    if (infoTable->i.srt_bitmap == (StgHalfWord)(-1)) {
-       info->type = posTypeLargeSRT;
-       info->next.large_srt.srt = (StgLargeSRT *)GET_SRT(infoTable);
-       info->next.large_srt.offset = 0;
-    } else {
-       info->type = posTypeSRT;
-       info->next.srt.srt = (StgClosure **)GET_SRT(infoTable);
-       info->next.srt.srt_bitmap = infoTable->i.srt_bitmap;
-    }
-}
-
-/* -----------------------------------------------------------------------------
- * Find the next object from *info.
- * -------------------------------------------------------------------------- */
-static INLINE StgClosure *
-find_srt( stackPos *info )
-{
-    StgClosure *c;
-    StgWord bitmap;
-
-    if (info->type == posTypeSRT) {
-       // Small SRT bitmap
-       bitmap = info->next.srt.srt_bitmap;
-       while (bitmap != 0) {
-           if ((bitmap & 1) != 0) {
-#ifdef ENABLE_WIN32_DLL_SUPPORT
-               
-               if ((unsigned long)(*(info->next.srt.srt)) & 0x1)
-                   c = (* (StgClosure **)((unsigned long)*(info->next.srt.srt)) & ~0x1);
-               else
-                   c = *(info->next.srt.srt);
-#else
-               c = *(info->next.srt.srt);
-#endif
-               bitmap = bitmap >> 1;
-               info->next.srt.srt++;
-               info->next.srt.srt_bitmap = bitmap;
-               return c;
-           }
-           bitmap = bitmap >> 1;
-           info->next.srt.srt++;
-       }
-       // bitmap is now zero...
-       return NULL;
-    }
-    else {
-       // Large SRT bitmap
-       nat i = info->next.large_srt.offset;
-       StgWord bitmap;
-
-       // Follow the pattern from GC.c:scavenge_large_srt_bitmap().
-       bitmap = info->next.large_srt.srt->l.bitmap[i / BITS_IN(W_)];
-       bitmap = bitmap >> (i % BITS_IN(StgWord));
-       while (i < info->next.large_srt.srt->l.size) {
-           if ((bitmap & 1) != 0) {
-               c = ((StgClosure **)info->next.large_srt.srt->srt)[i];
-               i++;
-               info->next.large_srt.offset = i;
-               return c;
-           }
-           i++;
-           if (i % BITS_IN(W_) == 0) {
-               bitmap = info->next.large_srt.srt->l.bitmap[i / BITS_IN(W_)];
-           } else {
-               bitmap = bitmap >> 1;
-           }
-       }
-       // reached the end of this bitmap.
-       info->next.large_srt.offset = i;
-       return NULL;
-    }
-}
-
-/* -----------------------------------------------------------------------------
- *  push() pushes a stackElement representing the next child of *c
- *  onto the traverse stack. If *c has no child, *first_child is set
- *  to NULL and nothing is pushed onto the stack. If *c has only one
- *  child, *c_chlid is set to that child and nothing is pushed onto
- *  the stack.  If *c has more than two children, *first_child is set
- *  to the first child and a stackElement representing the second
- *  child is pushed onto the stack.
-
- *  Invariants:
- *     *c_child_r is the most recent retainer of *c's children.
- *     *c is not any of TSO, AP, PAP, AP_STACK, which means that
- *        there cannot be any stack objects.
- *  Note: SRTs are considered to  be children as well.
- * -------------------------------------------------------------------------- */
-static INLINE void
-push( StgClosure *c, retainer c_child_r, StgClosure **first_child )
-{
-    stackElement se;
-    bdescr *nbd;      // Next Block Descriptor
-
-#ifdef DEBUG_RETAINER
-    // debugBelch("push(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", stackTop, currentStackBoundary);
-#endif
-
-    ASSERT(get_itbl(c)->type != TSO);
-    ASSERT(get_itbl(c)->type != AP_STACK);
-
-    //
-    // fill in se
-    //
-
-    se.c = c;
-    se.c_child_r = c_child_r;
-
-    // fill in se.info
-    switch (get_itbl(c)->type) {
-       // no child, no SRT
-    case CONSTR_0_1:
-    case CONSTR_0_2:
-    case CAF_BLACKHOLE:
-    case BLACKHOLE:
-    case SE_BLACKHOLE:
-    case SE_CAF_BLACKHOLE:
-    case ARR_WORDS:
-       *first_child = NULL;
-       return;
-
-       // one child (fixed), no SRT
-    case MUT_VAR_CLEAN:
-    case MUT_VAR_DIRTY:
-       *first_child = ((StgMutVar *)c)->var;
-       return;
-    case THUNK_SELECTOR:
-       *first_child = ((StgSelector *)c)->selectee;
-       return;
-    case IND_PERM:
-    case IND_OLDGEN_PERM:
-    case IND_OLDGEN:
-       *first_child = ((StgInd *)c)->indirectee;
-       return;
-    case CONSTR_1_0:
-    case CONSTR_1_1:
-       *first_child = c->payload[0];
-       return;
-
-       // For CONSTR_2_0 and MVAR, we use se.info.step to record the position
-       // of the next child. We do not write a separate initialization code.
-       // Also we do not have to initialize info.type;
-
-       // two children (fixed), no SRT
-       // need to push a stackElement, but nothing to store in se.info
-    case CONSTR_2_0:
-       *first_child = c->payload[0];         // return the first pointer
-       // se.info.type = posTypeStep;
-       // se.info.next.step = 2;            // 2 = second
-       break;
-
-       // three children (fixed), no SRT
-       // need to push a stackElement
-    case MVAR:
-       // head must be TSO and the head of a linked list of TSOs.
-       // Shoule it be a child? Seems to be yes.
-       *first_child = (StgClosure *)((StgMVar *)c)->head;
-       // se.info.type = posTypeStep;
-       se.info.next.step = 2;            // 2 = second
-       break;
-
-       // three children (fixed), no SRT
-    case WEAK:
-       *first_child = ((StgWeak *)c)->key;
-       // se.info.type = posTypeStep;
-       se.info.next.step = 2;
-       break;
-
-       // layout.payload.ptrs, no SRT
-    case CONSTR:
-    case STABLE_NAME:
-    case BCO:
-    case CONSTR_STATIC:
-       init_ptrs(&se.info, get_itbl(c)->layout.payload.ptrs,
-                 (StgPtr)c->payload);
-       *first_child = find_ptrs(&se.info);
-       if (*first_child == NULL)
-           return;   // no child
-       break;
-
-       // StgMutArrPtr.ptrs, no SRT
-    case MUT_ARR_PTRS_CLEAN:
-    case MUT_ARR_PTRS_DIRTY:
-    case MUT_ARR_PTRS_FROZEN:
-    case MUT_ARR_PTRS_FROZEN0:
-       init_ptrs(&se.info, ((StgMutArrPtrs *)c)->ptrs,
-                 (StgPtr)(((StgMutArrPtrs *)c)->payload));
-       *first_child = find_ptrs(&se.info);
-       if (*first_child == NULL)
-           return;
-       break;
-
-    // layout.payload.ptrs, SRT
-    case FUN:           // *c is a heap object.
-    case FUN_2_0:
-       init_ptrs(&se.info, get_itbl(c)->layout.payload.ptrs, (StgPtr)c->payload);
-       *first_child = find_ptrs(&se.info);
-       if (*first_child == NULL)
-           // no child from ptrs, so check SRT
-           goto fun_srt_only;
-       break;
-
-    case THUNK:
-    case THUNK_2_0:
-       init_ptrs(&se.info, get_itbl(c)->layout.payload.ptrs, 
-                 (StgPtr)((StgThunk *)c)->payload);
-       *first_child = find_ptrs(&se.info);
-       if (*first_child == NULL)
-           // no child from ptrs, so check SRT
-           goto thunk_srt_only;
-       break;
-
-       // 1 fixed child, SRT
-    case FUN_1_0:
-    case FUN_1_1:
-       *first_child = c->payload[0];
-       ASSERT(*first_child != NULL);
-       init_srt_fun(&se.info, get_fun_itbl(c));
-       break;
-
-    case THUNK_1_0:
-    case THUNK_1_1:
-       *first_child = ((StgThunk *)c)->payload[0];
-       ASSERT(*first_child != NULL);
-       init_srt_thunk(&se.info, get_thunk_itbl(c));
-       break;
-
-    case FUN_STATIC:      // *c is a heap object.
-       ASSERT(get_itbl(c)->srt_bitmap != 0);
-    case FUN_0_1:
-    case FUN_0_2:
-    fun_srt_only:
-        init_srt_fun(&se.info, get_fun_itbl(c));
-       *first_child = find_srt(&se.info);
-       if (*first_child == NULL)
-           return;     // no child
-       break;
-
-    // SRT only
-    case THUNK_STATIC:
-       ASSERT(get_itbl(c)->srt_bitmap != 0);
-    case THUNK_0_1:
-    case THUNK_0_2:
-    thunk_srt_only:
-        init_srt_thunk(&se.info, get_thunk_itbl(c));
-       *first_child = find_srt(&se.info);
-       if (*first_child == NULL)
-           return;     // no child
-       break;
-       
-    case TVAR_WAIT_QUEUE:
-       *first_child = (StgClosure *)((StgTVarWaitQueue *)c)->waiting_tso;
-       se.info.next.step = 2;            // 2 = second
-       break;
-    case TVAR:
-       *first_child = (StgClosure *)((StgTVar *)c)->current_value;
-       break;
-    case TREC_HEADER:
-       *first_child = (StgClosure *)((StgTRecHeader *)c)->enclosing_trec;
-       break;
-    case TREC_CHUNK:
-       *first_child = (StgClosure *)((StgTRecChunk *)c)->prev_chunk;
-       se.info.next.step = 0;  // entry no.
-       break;
-
-       // cannot appear
-    case PAP:
-    case AP:
-    case AP_STACK:
-    case TSO:
-    case IND_STATIC:
-    case CONSTR_INTLIKE:
-    case CONSTR_CHARLIKE:
-    case CONSTR_NOCAF_STATIC:
-       // stack objects
-    case UPDATE_FRAME:
-    case CATCH_FRAME:
-    case STOP_FRAME:
-    case RET_DYN:
-    case RET_BCO:
-    case RET_SMALL:
-    case RET_VEC_SMALL:
-    case RET_BIG:
-    case RET_VEC_BIG:
-       // invalid objects
-    case IND:
-    case BLOCKED_FETCH:
-    case FETCH_ME:
-    case FETCH_ME_BQ:
-    case RBH:
-    case REMOTE_REF:
-    case EVACUATED:
-    case INVALID_OBJECT:
-    default:
-       barf("Invalid object *c in push()");
-       return;
-    }
-
-    if (stackTop - 1 < stackBottom) {
-#ifdef DEBUG_RETAINER
-       // debugBelch("push() to the next stack.\n");
-#endif
-       // currentStack->free is updated when the active stack is switched
-       // to the next stack.
-       currentStack->free = (StgPtr)stackTop;
-
-       if (currentStack->link == NULL) {
-           nbd = allocGroup(BLOCKS_IN_STACK);
-           nbd->link = NULL;
-           nbd->u.back = currentStack;
-           currentStack->link = nbd;
-       } else
-           nbd = currentStack->link;
-
-       newStackBlock(nbd);
-    }
-
-    // adjust stackTop (acutal push)
-    stackTop--;
-    // If the size of stackElement was huge, we would better replace the
-    // following statement by either a memcpy() call or a switch statement
-    // on the type of the element. Currently, the size of stackElement is
-    // small enough (5 words) that this direct assignment seems to be enough.
-    *stackTop = se;
-
-#ifdef DEBUG_RETAINER
-    stackSize++;
-    if (stackSize > maxStackSize) maxStackSize = stackSize;
-    // ASSERT(stackSize >= 0);
-    // debugBelch("stackSize = %d\n", stackSize);
-#endif
-}
-
-/* -----------------------------------------------------------------------------
- *  popOff() and popOffReal(): Pop a stackElement off the traverse stack.
- *  Invariants:
- *    stackTop cannot be equal to stackLimit unless the whole stack is
- *    empty, in which case popOff() is not allowed.
- *  Note:
- *    You can think of popOffReal() as a part of popOff() which is
- *    executed at the end of popOff() in necessary. Since popOff() is
- *    likely to be executed quite often while popOffReal() is not, we
- *    separate popOffReal() from popOff(), which is declared as an
- *    INLINE function (for the sake of execution speed).  popOffReal()
- *    is called only within popOff() and nowhere else.
- * -------------------------------------------------------------------------- */
-static void
-popOffReal(void)
-{
-    bdescr *pbd;    // Previous Block Descriptor
-
-#ifdef DEBUG_RETAINER
-    // debugBelch("pop() to the previous stack.\n");
-#endif
-
-    ASSERT(stackTop + 1 == stackLimit);
-    ASSERT(stackBottom == (stackElement *)currentStack->start);
-
-    if (firstStack == currentStack) {
-       // The stack is completely empty.
-       stackTop++;
-       ASSERT(stackTop == stackLimit);
-#ifdef DEBUG_RETAINER
-       stackSize--;
-       if (stackSize > maxStackSize) maxStackSize = stackSize;
-       /*
-         ASSERT(stackSize >= 0);
-         debugBelch("stackSize = %d\n", stackSize);
-       */
-#endif
-       return;
-    }
-
-    // currentStack->free is updated when the active stack is switched back
-    // to the previous stack.
-    currentStack->free = (StgPtr)stackLimit;
-
-    // find the previous block descriptor
-    pbd = currentStack->u.back;
-    ASSERT(pbd != NULL);
-
-    returnToOldStack(pbd);
-
-#ifdef DEBUG_RETAINER
-    stackSize--;
-    if (stackSize > maxStackSize) maxStackSize = stackSize;
-    /*
-      ASSERT(stackSize >= 0);
-      debugBelch("stackSize = %d\n", stackSize);
-    */
-#endif
-}
-
-static INLINE void
-popOff(void) {
-#ifdef DEBUG_RETAINER
-    // debugBelch("\tpopOff(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", stackTop, currentStackBoundary);
-#endif
-
-    ASSERT(stackTop != stackLimit);
-    ASSERT(!isEmptyRetainerStack());
-
-    // <= (instead of <) is wrong!
-    if (stackTop + 1 < stackLimit) {
-       stackTop++;
-#ifdef DEBUG_RETAINER
-       stackSize--;
-       if (stackSize > maxStackSize) maxStackSize = stackSize;
-       /*
-         ASSERT(stackSize >= 0);
-         debugBelch("stackSize = %d\n", stackSize);
-       */
-#endif
-       return;
-    }
-
-    popOffReal();
-}
-
-/* -----------------------------------------------------------------------------
- *  Finds the next object to be considered for retainer profiling and store
- *  its pointer to *c.
- *  Test if the topmost stack element indicates that more objects are left,
- *  and if so, retrieve the first object and store its pointer to *c. Also,
- *  set *cp and *r appropriately, both of which are stored in the stack element.
- *  The topmost stack element then is overwritten so as for it to now denote
- *  the next object.
- *  If the topmost stack element indicates no more objects are left, pop
- *  off the stack element until either an object can be retrieved or
- *  the current stack chunk becomes empty, indicated by rtsTrue returned by
- *  isOnBoundary(), in which case *c is set to NULL.
- *  Note:
- *    It is okay to call this function even when the current stack chunk
- *    is empty.
- * -------------------------------------------------------------------------- */
-static INLINE void
-pop( StgClosure **c, StgClosure **cp, retainer *r )
-{
-    stackElement *se;
-
-#ifdef DEBUG_RETAINER
-    // debugBelch("pop(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", stackTop, currentStackBoundary);
-#endif
-
-    do {
-       if (isOnBoundary()) {     // if the current stack chunk is depleted
-           *c = NULL;
-           return;
-       }
-
-       se = stackTop;
-
-       switch (get_itbl(se->c)->type) {
-           // two children (fixed), no SRT
-           // nothing in se.info
-       case CONSTR_2_0:
-           *c = se->c->payload[1];
-           *cp = se->c;
-           *r = se->c_child_r;
-           popOff();
-           return;
-
-           // three children (fixed), no SRT
-           // need to push a stackElement
-       case MVAR:
-           if (se->info.next.step == 2) {
-               *c = (StgClosure *)((StgMVar *)se->c)->tail;
-               se->info.next.step++;             // move to the next step
-               // no popOff
-           } else {
-               *c = ((StgMVar *)se->c)->value;
-               popOff();
-           }
-           *cp = se->c;
-           *r = se->c_child_r;
-           return;
-
-           // three children (fixed), no SRT
-       case WEAK:
-           if (se->info.next.step == 2) {
-               *c = ((StgWeak *)se->c)->value;
-               se->info.next.step++;
-               // no popOff
-           } else {
-               *c = ((StgWeak *)se->c)->finalizer;
-               popOff();
-           }
-           *cp = se->c;
-           *r = se->c_child_r;
-           return;
-
-       case TVAR_WAIT_QUEUE:
-           if (se->info.next.step == 2) {
-               *c = (StgClosure *)((StgTVarWaitQueue *)se->c)->next_queue_entry;
-               se->info.next.step++;             // move to the next step
-               // no popOff
-           } else {
-               *c = (StgClosure *)((StgTVarWaitQueue *)se->c)->prev_queue_entry;
-               popOff();
-           }
-           *cp = se->c;
-           *r = se->c_child_r;
-           return;
-
-       case TVAR:
-           *c = (StgClosure *)((StgTVar *)se->c)->first_wait_queue_entry;
-           *cp = se->c;
-           *r = se->c_child_r;
-           popOff();
-           return;
-
-       case TREC_HEADER:
-           *c = (StgClosure *)((StgTRecHeader *)se->c)->current_chunk;
-           *cp = se->c;
-           *r = se->c_child_r;
-           popOff();
-           return;
-
-       case TREC_CHUNK: {
-           // These are pretty complicated: we have N entries, each
-           // of which contains 3 fields that we want to follow.  So
-           // we divide the step counter: the 2 low bits indicate
-           // which field, and the rest of the bits indicate the
-           // entry number (starting from zero).
-           nat entry_no = se->info.next.step >> 2;
-           nat field_no = se->info.next.step & 3;
-           if (entry_no == ((StgTRecChunk *)se->c)->next_entry_idx) {
-               *c = NULL;
-               popOff();
-               return;
-           }
-           TRecEntry *entry = &((StgTRecChunk *)se->c)->entries[entry_no];
-           if (field_no == 0) {
-               *c = (StgClosure *)entry->tvar;
-           } else if (field_no == 1) {
-               *c = entry->expected_value;
-           } else {
-               *c = entry->new_value;
-           }
-           *cp = se->c;
-           *r = se->c_child_r;
-           se->info.next.step++;
-           return;
-       }
-
-       case CONSTR:
-       case STABLE_NAME:
-       case BCO:
-       case CONSTR_STATIC:
-           // StgMutArrPtr.ptrs, no SRT
-       case MUT_ARR_PTRS_CLEAN:
-       case MUT_ARR_PTRS_DIRTY:
-       case MUT_ARR_PTRS_FROZEN:
-       case MUT_ARR_PTRS_FROZEN0:
-           *c = find_ptrs(&se->info);
-           if (*c == NULL) {
-               popOff();
-               break;
-           }
-           *cp = se->c;
-           *r = se->c_child_r;
-           return;
-
-           // layout.payload.ptrs, SRT
-       case FUN:         // always a heap object
-       case FUN_2_0:
-           if (se->info.type == posTypePtrs) {
-               *c = find_ptrs(&se->info);
-               if (*c != NULL) {
-                   *cp = se->c;
-                   *r = se->c_child_r;
-                   return;
-               }
-               init_srt_fun(&se->info, get_fun_itbl(se->c));
-           }
-           goto do_srt;
-
-       case THUNK:
-       case THUNK_2_0:
-           if (se->info.type == posTypePtrs) {
-               *c = find_ptrs(&se->info);
-               if (*c != NULL) {
-                   *cp = se->c;
-                   *r = se->c_child_r;
-                   return;
-               }
-               init_srt_thunk(&se->info, get_thunk_itbl(se->c));
-           }
-           goto do_srt;
-
-           // SRT
-       do_srt:
-       case THUNK_STATIC:
-       case FUN_STATIC:
-       case FUN_0_1:
-       case FUN_0_2:
-       case THUNK_0_1:
-       case THUNK_0_2:
-       case FUN_1_0:
-       case FUN_1_1:
-       case THUNK_1_0:
-       case THUNK_1_1:
-           *c = find_srt(&se->info);
-           if (*c != NULL) {
-               *cp = se->c;
-               *r = se->c_child_r;
-               return;
-           }
-           popOff();
-           break;
-
-           // no child (fixed), no SRT
-       case CONSTR_0_1:
-       case CONSTR_0_2:
-       case CAF_BLACKHOLE:
-       case BLACKHOLE:
-       case SE_BLACKHOLE:
-       case SE_CAF_BLACKHOLE:
-       case ARR_WORDS:
-           // one child (fixed), no SRT
-       case MUT_VAR_CLEAN:
-       case MUT_VAR_DIRTY:
-       case THUNK_SELECTOR:
-       case IND_PERM:
-       case IND_OLDGEN_PERM:
-       case IND_OLDGEN:
-       case CONSTR_1_1:
-           // cannot appear
-       case PAP:
-       case AP:
-       case AP_STACK:
-       case TSO:
-       case IND_STATIC:
-       case CONSTR_INTLIKE:
-       case CONSTR_CHARLIKE:
-       case CONSTR_NOCAF_STATIC:
-           // stack objects
-       case RET_DYN:
-       case UPDATE_FRAME:
-       case CATCH_FRAME:
-       case STOP_FRAME:
-       case RET_BCO:
-       case RET_SMALL:
-       case RET_VEC_SMALL:
-       case RET_BIG:
-       case RET_VEC_BIG:
-           // invalid objects
-       case IND:
-       case BLOCKED_FETCH:
-       case FETCH_ME:
-       case FETCH_ME_BQ:
-       case RBH:
-       case REMOTE_REF:
-       case EVACUATED:
-       case INVALID_OBJECT:
-       default:
-           barf("Invalid object *c in pop()");
-           return;
-       }
-    } while (rtsTrue);
-}
-
-/* -----------------------------------------------------------------------------
- * RETAINER PROFILING ENGINE
- * -------------------------------------------------------------------------- */
-
-void
-initRetainerProfiling( void )
-{
-    initializeAllRetainerSet();
-    retainerGeneration = 0;
-}
-
-/* -----------------------------------------------------------------------------
- *  This function must be called before f-closing prof_file.
- * -------------------------------------------------------------------------- */
-void
-endRetainerProfiling( void )
-{
-#ifdef SECOND_APPROACH
-    outputAllRetainerSet(prof_file);
-#endif
-}
-
-/* -----------------------------------------------------------------------------
- *  Returns the actual pointer to the retainer set of the closure *c.
- *  It may adjust RSET(c) subject to flip.
- *  Side effects:
- *    RSET(c) is initialized to NULL if its current value does not
- *    conform to flip.
- *  Note:
- *    Even though this function has side effects, they CAN be ignored because
- *    subsequent calls to retainerSetOf() always result in the same return value
- *    and retainerSetOf() is the only way to retrieve retainerSet of a given
- *    closure.
- *    We have to perform an XOR (^) operation each time a closure is examined.
- *    The reason is that we do not know when a closure is visited last.
- * -------------------------------------------------------------------------- */
-static INLINE void
-maybeInitRetainerSet( StgClosure *c )
-{
-    if (!isRetainerSetFieldValid(c)) {
-       setRetainerSetToNull(c);
-    }
-}
-
-/* -----------------------------------------------------------------------------
- * Returns rtsTrue if *c is a retainer.
- * -------------------------------------------------------------------------- */
-static INLINE rtsBool
-isRetainer( StgClosure *c )
-{
-    switch (get_itbl(c)->type) {
-       //
-       //  True case
-       //
-       // TSOs MUST be retainers: they constitute the set of roots.
-    case TSO:
-
-       // mutable objects
-    case MVAR:
-    case MUT_VAR_CLEAN:
-    case MUT_VAR_DIRTY:
-    case MUT_ARR_PTRS_CLEAN:
-    case MUT_ARR_PTRS_DIRTY:
-    case MUT_ARR_PTRS_FROZEN:
-    case MUT_ARR_PTRS_FROZEN0:
-
-       // thunks are retainers.
-    case THUNK:
-    case THUNK_1_0:
-    case THUNK_0_1:
-    case THUNK_2_0:
-    case THUNK_1_1:
-    case THUNK_0_2:
-    case THUNK_SELECTOR:
-    case AP:
-    case AP_STACK:
-
-       // Static thunks, or CAFS, are obviously retainers.
-    case THUNK_STATIC:
-
-       // WEAK objects are roots; there is separate code in which traversing
-       // begins from WEAK objects.
-    case WEAK:
-
-       // Since the other mutvar-type things are retainers, seems
-       // like the right thing to do:
-    case TVAR:
-       return rtsTrue;
-
-       //
-       // False case
-       //
-
-       // constructors
-    case CONSTR:
-    case CONSTR_1_0:
-    case CONSTR_0_1:
-    case CONSTR_2_0:
-    case CONSTR_1_1:
-    case CONSTR_0_2:
-       // functions
-    case FUN:
-    case FUN_1_0:
-    case FUN_0_1:
-    case FUN_2_0:
-    case FUN_1_1:
-    case FUN_0_2:
-       // partial applications
-    case PAP:
-       // blackholes
-    case CAF_BLACKHOLE:
-    case BLACKHOLE:
-    case SE_BLACKHOLE:
-    case SE_CAF_BLACKHOLE:
-       // indirection
-    case IND_PERM:
-    case IND_OLDGEN_PERM:
-    case IND_OLDGEN:
-       // static objects
-    case CONSTR_STATIC:
-    case FUN_STATIC:
-       // misc
-    case STABLE_NAME:
-    case BCO:
-    case ARR_WORDS:
-       // STM
-    case TVAR_WAIT_QUEUE:
-    case TREC_HEADER:
-    case TREC_CHUNK:
-       return rtsFalse;
-
-       //
-       // Error case
-       //
-       // IND_STATIC cannot be *c, *cp, *r in the retainer profiling loop.
-    case IND_STATIC:
-       // CONSTR_INTLIKE, CONSTR_CHARLIKE, and CONSTR_NOCAF_STATIC
-       // cannot be *c, *cp, *r in the retainer profiling loop.
-    case CONSTR_INTLIKE:
-    case CONSTR_CHARLIKE:
-    case CONSTR_NOCAF_STATIC:
-       // Stack objects are invalid because they are never treated as
-       // legal objects during retainer profiling.
-    case UPDATE_FRAME:
-    case CATCH_FRAME:
-    case STOP_FRAME:
-    case RET_DYN:
-    case RET_BCO:
-    case RET_SMALL:
-    case RET_VEC_SMALL:
-    case RET_BIG:
-    case RET_VEC_BIG:
-       // other cases
-    case IND:
-    case BLOCKED_FETCH:
-    case FETCH_ME:
-    case FETCH_ME_BQ:
-    case RBH:
-    case REMOTE_REF:
-    case EVACUATED:
-    case INVALID_OBJECT:
-    default:
-       barf("Invalid object in isRetainer(): %d", get_itbl(c)->type);
-       return rtsFalse;
-    }
-}
-
-/* -----------------------------------------------------------------------------
- *  Returns the retainer function value for the closure *c, i.e., R(*c).
- *  This function does NOT return the retainer(s) of *c.
- *  Invariants:
- *    *c must be a retainer.
- *  Note:
- *    Depending on the definition of this function, the maintenance of retainer
- *    sets can be made easier. If most retainer sets are likely to be created
- *    again across garbage collections, refreshAllRetainerSet() in
- *    RetainerSet.c can simply do nothing.
- *    If this is not the case, we can free all the retainer sets and
- *    re-initialize the hash table.
- *    See refreshAllRetainerSet() in RetainerSet.c.
- * -------------------------------------------------------------------------- */
-static INLINE retainer
-getRetainerFrom( StgClosure *c )
-{
-    ASSERT(isRetainer(c));
-
-#if defined(RETAINER_SCHEME_INFO)
-    // Retainer scheme 1: retainer = info table
-    return get_itbl(c);
-#elif defined(RETAINER_SCHEME_CCS)
-    // Retainer scheme 2: retainer = cost centre stack
-    return c->header.prof.ccs;
-#elif defined(RETAINER_SCHEME_CC)
-    // Retainer scheme 3: retainer = cost centre
-    return c->header.prof.ccs->cc;
-#endif
-}
-
-/* -----------------------------------------------------------------------------
- *  Associates the retainer set *s with the closure *c, that is, *s becomes
- *  the retainer set of *c.
- *  Invariants:
- *    c != NULL
- *    s != NULL
- * -------------------------------------------------------------------------- */
-static INLINE void
-associate( StgClosure *c, RetainerSet *s )
-{
-    // StgWord has the same size as pointers, so the following type
-    // casting is okay.
-    RSET(c) = (RetainerSet *)((StgWord)s | flip);
-}
-
-/* -----------------------------------------------------------------------------
-   Call retainClosure for each of the closures covered by a large bitmap.
-   -------------------------------------------------------------------------- */
-
-static void
-retain_large_bitmap (StgPtr p, StgLargeBitmap *large_bitmap, nat size,
-                    StgClosure *c, retainer c_child_r)
-{
-    nat i, b;
-    StgWord bitmap;
-    
-    b = 0;
-    bitmap = large_bitmap->bitmap[b];
-    for (i = 0; i < size; ) {
-       if ((bitmap & 1) == 0) {
-           retainClosure((StgClosure *)*p, c, c_child_r);
-       }
-       i++;
-       p++;
-       if (i % BITS_IN(W_) == 0) {
-           b++;
-           bitmap = large_bitmap->bitmap[b];
-       } else {
-           bitmap = bitmap >> 1;
-       }
-    }
-}
-
-static INLINE StgPtr
-retain_small_bitmap (StgPtr p, nat size, StgWord bitmap,
-                    StgClosure *c, retainer c_child_r)
-{
-    while (size > 0) {
-       if ((bitmap & 1) == 0) {
-           retainClosure((StgClosure *)*p, c, c_child_r);
-       }
-       p++;
-       bitmap = bitmap >> 1;
-       size--;
-    }
-    return p;
-}
-
-/* -----------------------------------------------------------------------------
- * Call retainClosure for each of the closures in an SRT.
- * ------------------------------------------------------------------------- */
-
-static void
-retain_large_srt_bitmap (StgLargeSRT *srt, StgClosure *c, retainer c_child_r)
-{
-    nat i, b, size;
-    StgWord bitmap;
-    StgClosure **p;
-    
-    b = 0;
-    p = (StgClosure **)srt->srt;
-    size   = srt->l.size;
-    bitmap = srt->l.bitmap[b];
-    for (i = 0; i < size; ) {
-       if ((bitmap & 1) != 0) {
-           retainClosure((StgClosure *)*p, c, c_child_r);
-       }
-       i++;
-       p++;
-       if (i % BITS_IN(W_) == 0) {
-           b++;
-           bitmap = srt->l.bitmap[b];
-       } else {
-           bitmap = bitmap >> 1;
-       }
-    }
-}
-
-static INLINE void
-retainSRT (StgClosure **srt, nat srt_bitmap, StgClosure *c, retainer c_child_r)
-{
-  nat bitmap;
-  StgClosure **p;
-
-  bitmap = srt_bitmap;
-  p = srt;
-
-  if (bitmap == (StgHalfWord)(-1)) {  
-      retain_large_srt_bitmap( (StgLargeSRT *)srt, c, c_child_r );
-      return;
-  }
-
-  while (bitmap != 0) {
-      if ((bitmap & 1) != 0) {
-#ifdef ENABLE_WIN32_DLL_SUPPORT
-         if ( (unsigned long)(*srt) & 0x1 ) {
-             retainClosure(*stgCast(StgClosure**,(stgCast(unsigned long, *srt) & ~0x1)), 
-                           c, c_child_r);
-         } else {
-             retainClosure(*srt,c,c_child_r);
-         }
-#else
-         retainClosure(*srt,c,c_child_r);
-#endif
-      }
-      p++;
-      bitmap = bitmap >> 1;
-  }
-}
-
-/* -----------------------------------------------------------------------------
- *  Process all the objects in the stack chunk from stackStart to stackEnd
- *  with *c and *c_child_r being their parent and their most recent retainer,
- *  respectively. Treat stackOptionalFun as another child of *c if it is
- *  not NULL.
- *  Invariants:
- *    *c is one of the following: TSO, AP_STACK.
- *    If *c is TSO, c == c_child_r.
- *    stackStart < stackEnd.
- *    RSET(c) and RSET(c_child_r) are valid, i.e., their
- *    interpretation conforms to the current value of flip (even when they
- *    are interpreted to be NULL).
- *    If *c is TSO, its state is not any of ThreadRelocated, ThreadComplete,
- *    or ThreadKilled, which means that its stack is ready to process.
- *  Note:
- *    This code was almost plagiarzied from GC.c! For each pointer,
- *    retainClosure() is invoked instead of evacuate().
- * -------------------------------------------------------------------------- */
-static void
-retainStack( StgClosure *c, retainer c_child_r,
-            StgPtr stackStart, StgPtr stackEnd )
-{
-    stackElement *oldStackBoundary;
-    StgPtr p;
-    StgRetInfoTable *info;
-    StgWord32 bitmap;
-    nat size;
-
-#ifdef DEBUG_RETAINER
-    cStackSize++;
-    if (cStackSize > maxCStackSize) maxCStackSize = cStackSize;
-#endif
-
-    /*
-      Each invocation of retainStack() creates a new virtual
-      stack. Since all such stacks share a single common stack, we
-      record the current currentStackBoundary, which will be restored
-      at the exit.
-    */
-    oldStackBoundary = currentStackBoundary;
-    currentStackBoundary = stackTop;
-
-#ifdef DEBUG_RETAINER
-    // debugBelch("retainStack() called: oldStackBoundary = 0x%x, currentStackBoundary = 0x%x\n", oldStackBoundary, currentStackBoundary);
-#endif
-
-    ASSERT(get_itbl(c)->type != TSO || 
-          (((StgTSO *)c)->what_next != ThreadRelocated &&
-           ((StgTSO *)c)->what_next != ThreadComplete &&
-           ((StgTSO *)c)->what_next != ThreadKilled));
-    
-    p = stackStart;
-    while (p < stackEnd) {
-       info = get_ret_itbl((StgClosure *)p);
-
-       switch(info->i.type) {
-
-       case UPDATE_FRAME:
-           retainClosure(((StgUpdateFrame *)p)->updatee, c, c_child_r);
-           p += sizeofW(StgUpdateFrame);
-           continue;
-
-       case STOP_FRAME:
-       case CATCH_FRAME:
-       case CATCH_STM_FRAME:
-       case CATCH_RETRY_FRAME:
-       case ATOMICALLY_FRAME:
-       case RET_SMALL:
-       case RET_VEC_SMALL:
-           bitmap = BITMAP_BITS(info->i.layout.bitmap);
-           size   = BITMAP_SIZE(info->i.layout.bitmap);
-           p++;
-           p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
-
-       follow_srt:
-           retainSRT((StgClosure **)GET_SRT(info), info->i.srt_bitmap, c, c_child_r);
-           continue;
-
-       case RET_BCO: {
-           StgBCO *bco;
-           
-           p++;
-           retainClosure((StgClosure *)*p, c, c_child_r);
-           bco = (StgBCO *)*p;
-           p++;
-           size = BCO_BITMAP_SIZE(bco);
-           retain_large_bitmap(p, BCO_BITMAP(bco), size, c, c_child_r);
-           p += size;
-           continue;
-       }
-
-           // large bitmap (> 32 entries, or > 64 on a 64-bit machine) 
-       case RET_BIG:
-       case RET_VEC_BIG:
-           size = GET_LARGE_BITMAP(&info->i)->size;
-           p++;
-           retain_large_bitmap(p, GET_LARGE_BITMAP(&info->i),
-                               size, c, c_child_r);
-           p += size;
-           // and don't forget to follow the SRT 
-           goto follow_srt;
-
-           // Dynamic bitmap: the mask is stored on the stack 
-       case RET_DYN: {
-           StgWord dyn;
-           dyn = ((StgRetDyn *)p)->liveness;
-
-           // traverse the bitmap first
-           bitmap = RET_DYN_LIVENESS(dyn);
-           p      = (P_)&((StgRetDyn *)p)->payload[0];
-           size   = RET_DYN_BITMAP_SIZE;
-           p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
-           
-           // skip over the non-ptr words
-           p += RET_DYN_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
-           
-           // follow the ptr words
-           for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
-               retainClosure((StgClosure *)*p, c, c_child_r);
-               p++;
-           }
-           continue;
-       }
-
-       case RET_FUN: {
-           StgRetFun *ret_fun = (StgRetFun *)p;
-           StgFunInfoTable *fun_info;
-           
-           retainClosure(ret_fun->fun, c, c_child_r);
-           fun_info = get_fun_itbl(ret_fun->fun);
-           
-           p = (P_)&ret_fun->payload;
-           switch (fun_info->f.fun_type) {
-           case ARG_GEN:
-               bitmap = BITMAP_BITS(fun_info->f.b.bitmap);
-               size = BITMAP_SIZE(fun_info->f.b.bitmap);
-               p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
-               break;
-           case ARG_GEN_BIG:
-               size = GET_FUN_LARGE_BITMAP(fun_info)->size;
-               retain_large_bitmap(p, GET_FUN_LARGE_BITMAP(fun_info), 
-                                   size, c, c_child_r);
-               p += size;
-               break;
-           default:
-               bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
-               size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
-               p = retain_small_bitmap(p, size, bitmap, c, c_child_r);
-               break;
-           }
-           goto follow_srt;
-       }
-
-       default:
-           barf("Invalid object found in retainStack(): %d",
-                (int)(info->i.type));
-       }
-    }
-
-    // restore currentStackBoundary
-    currentStackBoundary = oldStackBoundary;
-#ifdef DEBUG_RETAINER
-    // debugBelch("retainStack() finished: currentStackBoundary = 0x%x\n", currentStackBoundary);
-#endif
-
-#ifdef DEBUG_RETAINER
-    cStackSize--;
-#endif
-}
-
-/* ----------------------------------------------------------------------------
- * Call retainClosure for each of the children of a PAP/AP
- * ------------------------------------------------------------------------- */
-
-static INLINE StgPtr
-retain_PAP_payload (StgClosure *pap,  retainer c_child_r, StgClosure *fun, 
-                   StgClosure** payload, StgWord n_args)
-{
-    StgPtr p;
-    StgWord bitmap;
-    StgFunInfoTable *fun_info;
-
-    retainClosure(fun, pap, c_child_r);
-    fun_info = get_fun_itbl(fun);
-    ASSERT(fun_info->i.type != PAP);
-
-    p = (StgPtr)payload;
-
-    switch (fun_info->f.fun_type) {
-    case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->f.b.bitmap);
-       p = retain_small_bitmap(p, n_args, bitmap, 
-                               pap, c_child_r);
-       break;
-    case ARG_GEN_BIG:
-       retain_large_bitmap(p, GET_FUN_LARGE_BITMAP(fun_info),
-                           n_args, pap, c_child_r);
-       p += n_args;
-       break;
-    case ARG_BCO:
-       retain_large_bitmap((StgPtr)payload, BCO_BITMAP(fun),
-                           n_args, pap, c_child_r);
-       p += n_args;
-       break;
-    default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
-       p = retain_small_bitmap(p, n_args, bitmap, pap, c_child_r);
-       break;
-    }
-    return p;
-}
-
-/* -----------------------------------------------------------------------------
- *  Compute the retainer set of *c0 and all its desecents by traversing.
- *  *cp0 is the parent of *c0, and *r0 is the most recent retainer of *c0.
- *  Invariants:
- *    c0 = cp0 = r0 holds only for root objects.
- *    RSET(cp0) and RSET(r0) are valid, i.e., their
- *    interpretation conforms to the current value of flip (even when they
- *    are interpreted to be NULL).
- *    However, RSET(c0) may be corrupt, i.e., it may not conform to
- *    the current value of flip. If it does not, during the execution
- *    of this function, RSET(c0) must be initialized as well as all
- *    its descendants.
- *  Note:
- *    stackTop must be the same at the beginning and the exit of this function.
- *    *c0 can be TSO (as well as AP_STACK).
- * -------------------------------------------------------------------------- */
-static void
-retainClosure( StgClosure *c0, StgClosure *cp0, retainer r0 )
-{
-    // c = Current closure
-    // cp = Current closure's Parent
-    // r = current closures' most recent Retainer
-    // c_child_r = current closure's children's most recent retainer
-    // first_child = first child of c
-    StgClosure *c, *cp, *first_child;
-    RetainerSet *s, *retainerSetOfc;
-    retainer r, c_child_r;
-    StgWord typeOfc;
-
-#ifdef DEBUG_RETAINER
-    // StgPtr oldStackTop;
-#endif
-
-#ifdef DEBUG_RETAINER
-    // oldStackTop = stackTop;
-    // debugBelch("retainClosure() called: c0 = 0x%x, cp0 = 0x%x, r0 = 0x%x\n", c0, cp0, r0);
-#endif
-
-    // (c, cp, r) = (c0, cp0, r0)
-    c = c0;
-    cp = cp0;
-    r = r0;
-    goto inner_loop;
-
-loop:
-    //debugBelch("loop");
-    // pop to (c, cp, r);
-    pop(&c, &cp, &r);
-
-    if (c == NULL) {
-#ifdef DEBUG_RETAINER
-       // debugBelch("retainClosure() ends: oldStackTop = 0x%x, stackTop = 0x%x\n", oldStackTop, stackTop);
-#endif
-       return;
-    }
-
-    //debugBelch("inner_loop");
-
-inner_loop:
-    // c  = current closure under consideration,
-    // cp = current closure's parent,
-    // r  = current closure's most recent retainer
-    //
-    // Loop invariants (on the meaning of c, cp, r, and their retainer sets):
-    //   RSET(cp) and RSET(r) are valid.
-    //   RSET(c) is valid only if c has been visited before.
-    //
-    // Loop invariants (on the relation between c, cp, and r)
-    //   if cp is not a retainer, r belongs to RSET(cp).
-    //   if cp is a retainer, r == cp.
-
-    typeOfc = get_itbl(c)->type;
-
-#ifdef DEBUG_RETAINER
-    switch (typeOfc) {
-    case IND_STATIC:
-    case CONSTR_INTLIKE:
-    case CONSTR_CHARLIKE:
-    case CONSTR_NOCAF_STATIC:
-    case CONSTR_STATIC:
-    case THUNK_STATIC:
-    case FUN_STATIC:
-       break;
-    default:
-       if (retainerSetOf(c) == NULL) {   // first visit?
-           costArray[typeOfc] += cost(c);
-           sumOfNewCost += cost(c);
-       }
-       break;
-    }
-#endif
-
-    // special cases
-    switch (typeOfc) {
-    case TSO:
-       if (((StgTSO *)c)->what_next == ThreadComplete ||
-           ((StgTSO *)c)->what_next == ThreadKilled) {
-#ifdef DEBUG_RETAINER
-           debugBelch("ThreadComplete or ThreadKilled encountered in retainClosure()\n");
-#endif
-           goto loop;
-       }
-       if (((StgTSO *)c)->what_next == ThreadRelocated) {
-#ifdef DEBUG_RETAINER
-           debugBelch("ThreadRelocated encountered in retainClosure()\n");
-#endif
-           c = (StgClosure *)((StgTSO *)c)->link;
-           goto inner_loop;
-       }
-       break;
-
-    case IND_STATIC:
-       // We just skip IND_STATIC, so its retainer set is never computed.
-       c = ((StgIndStatic *)c)->indirectee;
-       goto inner_loop;
-    case CONSTR_INTLIKE:
-    case CONSTR_CHARLIKE:
-       // static objects with no pointers out, so goto loop.
-    case CONSTR_NOCAF_STATIC:
-       // It is not just enough not to compute the retainer set for *c; it is
-       // mandatory because CONSTR_NOCAF_STATIC are not reachable from
-       // scavenged_static_objects, the list from which is assumed to traverse
-       // all static objects after major garbage collections.
-       goto loop;
-    case THUNK_STATIC:
-    case FUN_STATIC:
-       if (get_itbl(c)->srt_bitmap == 0) {
-           // No need to compute the retainer set; no dynamic objects
-           // are reachable from *c.
-           //
-           // Static objects: if we traverse all the live closures,
-           // including static closures, during each heap census then
-           // we will observe that some static closures appear and
-           // disappear.  eg. a closure may contain a pointer to a
-           // static function 'f' which is not otherwise reachable
-           // (it doesn't indirectly point to any CAFs, so it doesn't
-           // appear in any SRTs), so we would find 'f' during
-           // traversal.  However on the next sweep there may be no
-           // closures pointing to 'f'.
-           //
-           // We must therefore ignore static closures whose SRT is
-           // empty, because these are exactly the closures that may
-           // "appear".  A closure with a non-empty SRT, and which is
-           // still required, will always be reachable.
-           //
-           // But what about CONSTR_STATIC?  Surely these may be able
-           // to appear, and they don't have SRTs, so we can't
-           // check.  So for now, we're calling
-           // resetStaticObjectForRetainerProfiling() from the
-           // garbage collector to reset the retainer sets in all the
-           // reachable static objects.
-           goto loop;
-       }
-    default:
-       break;
-    }
-
-    // The above objects are ignored in computing the average number of times
-    // an object is visited.
-    timesAnyObjectVisited++;
-
-    // If this is the first visit to c, initialize its retainer set.
-    maybeInitRetainerSet(c);
-    retainerSetOfc = retainerSetOf(c);
-
-    // Now compute s:
-    //    isRetainer(cp) == rtsTrue => s == NULL
-    //    isRetainer(cp) == rtsFalse => s == cp.retainer
-    if (isRetainer(cp))
-       s = NULL;
-    else
-       s = retainerSetOf(cp);
-
-    // (c, cp, r, s) is available.
-
-    // (c, cp, r, s, R_r) is available, so compute the retainer set for *c.
-    if (retainerSetOfc == NULL) {
-       // This is the first visit to *c.
-       numObjectVisited++;
-
-       if (s == NULL)
-           associate(c, singleton(r));
-       else
-           // s is actually the retainer set of *c!
-           associate(c, s);
-
-       // compute c_child_r
-       c_child_r = isRetainer(c) ? getRetainerFrom(c) : r;
-    } else {
-       // This is not the first visit to *c.
-       if (isMember(r, retainerSetOfc))
-           goto loop;          // no need to process child
-
-       if (s == NULL)
-           associate(c, addElement(r, retainerSetOfc));
-       else {
-           // s is not NULL and cp is not a retainer. This means that
-           // each time *cp is visited, so is *c. Thus, if s has
-           // exactly one more element in its retainer set than c, s
-           // is also the new retainer set for *c.
-           if (s->num == retainerSetOfc->num + 1) {
-               associate(c, s);
-           }
-           // Otherwise, just add R_r to the current retainer set of *c.
-           else {
-               associate(c, addElement(r, retainerSetOfc));
-           }
-       }
-
-       if (isRetainer(c))
-           goto loop;          // no need to process child
-
-       // compute c_child_r
-       c_child_r = r;
-    }
-
-    // now, RSET() of all of *c, *cp, and *r is valid.
-    // (c, c_child_r) are available.
-
-    // process child
-
-    // Special case closures: we process these all in one go rather
-    // than attempting to save the current position, because doing so
-    // would be hard.
-    switch (typeOfc) {
-    case TSO:
-       retainStack(c, c_child_r,
-                   ((StgTSO *)c)->sp,
-                   ((StgTSO *)c)->stack + ((StgTSO *)c)->stack_size);
-       goto loop;
-
-    case PAP:
-    {
-       StgPAP *pap = (StgPAP *)c;
-       retain_PAP_payload(c, c_child_r, pap->fun, pap->payload, pap->n_args);
-       goto loop;
-    }
-
-    case AP:
-    {
-       StgAP *ap = (StgAP *)c;
-       retain_PAP_payload(c, c_child_r, ap->fun, ap->payload, ap->n_args);
-       goto loop;
-    }
-
-    case AP_STACK:
-       retainClosure(((StgAP_STACK *)c)->fun, c, c_child_r);
-       retainStack(c, c_child_r,
-                   (StgPtr)((StgAP_STACK *)c)->payload,
-                   (StgPtr)((StgAP_STACK *)c)->payload +
-                            ((StgAP_STACK *)c)->size);
-       goto loop;
-    }
-
-    push(c, c_child_r, &first_child);
-
-    // If first_child is null, c has no child.
-    // If first_child is not null, the top stack element points to the next
-    // object. push() may or may not push a stackElement on the stack.
-    if (first_child == NULL)
-       goto loop;
-
-    // (c, cp, r) = (first_child, c, c_child_r)
-    r = c_child_r;
-    cp = c;
-    c = first_child;
-    goto inner_loop;
-}
-
-/* -----------------------------------------------------------------------------
- *  Compute the retainer set for every object reachable from *tl.
- * -------------------------------------------------------------------------- */
-static void
-retainRoot( StgClosure **tl )
-{
-    // We no longer assume that only TSOs and WEAKs are roots; any closure can
-    // be a root.
-
-    ASSERT(isEmptyRetainerStack());
-    currentStackBoundary = stackTop;
-
-    if (*tl != &stg_END_TSO_QUEUE_closure && isRetainer(*tl)) {
-       retainClosure(*tl, *tl, getRetainerFrom(*tl));
-    } else {
-       retainClosure(*tl, *tl, CCS_SYSTEM);
-    }
-
-    // NOT TRUE: ASSERT(isMember(getRetainerFrom(*tl), retainerSetOf(*tl)));
-    // *tl might be a TSO which is ThreadComplete, in which
-    // case we ignore it for the purposes of retainer profiling.
-}
-
-/* -----------------------------------------------------------------------------
- *  Compute the retainer set for each of the objects in the heap.
- * -------------------------------------------------------------------------- */
-static void
-computeRetainerSet( void )
-{
-    StgWeak *weak;
-    RetainerSet *rtl;
-    nat g;
-    StgPtr ml;
-    bdescr *bd;
-#ifdef DEBUG_RETAINER
-    RetainerSet tmpRetainerSet;
-#endif
-
-    GetRoots(retainRoot);      // for scheduler roots
-
-    // This function is called after a major GC, when key, value, and finalizer
-    // all are guaranteed to be valid, or reachable.
-    //
-    // The following code assumes that WEAK objects are considered to be roots
-    // for retainer profilng.
-    for (weak = weak_ptr_list; weak != NULL; weak = weak->link)
-       // retainRoot((StgClosure *)weak);
-       retainRoot((StgClosure **)&weak);
-
-    // Consider roots from the stable ptr table.
-    markStablePtrTable(retainRoot);
-
-    // The following code resets the rs field of each unvisited mutable
-    // object (computing sumOfNewCostExtra and updating costArray[] when
-    // debugging retainer profiler).
-    for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
-       // NOT TRUE: even G0 has a block on its mutable list
-        // ASSERT(g != 0 || (generations[g].mut_list == NULL));
-
-       // Traversing through mut_list is necessary
-       // because we can find MUT_VAR objects which have not been
-       // visited during retainer profiling.
-       for (bd = generations[g].mut_list; bd != NULL; bd = bd->link) {
-           for (ml = bd->start; ml < bd->free; ml++) {
-
-               maybeInitRetainerSet((StgClosure *)*ml);
-               rtl = retainerSetOf((StgClosure *)*ml);
-
-#ifdef DEBUG_RETAINER
-               if (rtl == NULL) {
-                   // first visit to *ml
-                   // This is a violation of the interface rule!
-                   RSET(ml) = (RetainerSet *)((StgWord)(&tmpRetainerSet) | flip);
-                   
-                   switch (get_itbl((StgClosure *)ml)->type) {
-                   case IND_STATIC:
-                       // no cost involved
-                       break;
-                   case CONSTR_INTLIKE:
-                   case CONSTR_CHARLIKE:
-                   case CONSTR_NOCAF_STATIC:
-                   case CONSTR_STATIC:
-                   case THUNK_STATIC:
-                   case FUN_STATIC:
-                       barf("Invalid object in computeRetainerSet(): %d", get_itbl((StgClosure*)ml)->type);
-                       break;
-                   default:
-                       // dynamic objects
-                       costArray[get_itbl((StgClosure *)ml)->type] += cost((StgClosure *)ml);
-                       sumOfNewCostExtra += cost((StgClosure *)ml);
-                       break;
-                   }
-               }
-#endif
-           }
-       }
-    }
-}
-
-/* -----------------------------------------------------------------------------
- *  Traverse all static objects for which we compute retainer sets,
- *  and reset their rs fields to NULL, which is accomplished by
- *  invoking maybeInitRetainerSet(). This function must be called
- *  before zeroing all objects reachable from scavenged_static_objects
- *  in the case of major gabage collections. See GarbageCollect() in
- *  GC.c.
- *  Note:
- *    The mut_once_list of the oldest generation must also be traversed?
- *    Why? Because if the evacuation of an object pointed to by a static
- *    indirection object fails, it is put back to the mut_once_list of
- *    the oldest generation.
- *    However, this is not necessary because any static indirection objects
- *    are just traversed through to reach dynamic objects. In other words,
- *    they are not taken into consideration in computing retainer sets.
- * -------------------------------------------------------------------------- */
-void
-resetStaticObjectForRetainerProfiling( void )
-{
-#ifdef DEBUG_RETAINER
-    nat count;
-#endif
-    StgClosure *p;
-
-#ifdef DEBUG_RETAINER
-    count = 0;
-#endif
-    p = scavenged_static_objects;
-    while (p != END_OF_STATIC_LIST) {
-#ifdef DEBUG_RETAINER
-       count++;
-#endif
-       switch (get_itbl(p)->type) {
-       case IND_STATIC:
-           // Since we do not compute the retainer set of any
-           // IND_STATIC object, we don't have to reset its retainer
-           // field.
-           p = (StgClosure*)*IND_STATIC_LINK(p);
-           break;
-       case THUNK_STATIC:
-           maybeInitRetainerSet(p);
-           p = (StgClosure*)*THUNK_STATIC_LINK(p);
-           break;
-       case FUN_STATIC:
-           maybeInitRetainerSet(p);
-           p = (StgClosure*)*FUN_STATIC_LINK(p);
-           break;
-       case CONSTR_STATIC:
-           maybeInitRetainerSet(p);
-           p = (StgClosure*)*STATIC_LINK(get_itbl(p), p);
-           break;
-       default:
-           barf("resetStaticObjectForRetainerProfiling: %p (%s)",
-                p, get_itbl(p)->type);
-           break;
-       }
-    }
-#ifdef DEBUG_RETAINER
-    // debugBelch("count in scavenged_static_objects = %d\n", count);
-#endif
-}
-
-/* -----------------------------------------------------------------------------
- * Perform retainer profiling.
- * N is the oldest generation being profilied, where the generations are
- * numbered starting at 0.
- * Invariants:
- * Note:
- *   This function should be called only immediately after major garbage
- *   collection.
- * ------------------------------------------------------------------------- */
-void
-retainerProfile(void)
-{
-#ifdef DEBUG_RETAINER
-  nat i;
-  nat totalHeapSize;        // total raw heap size (computed by linear scanning)
-#endif
-
-#ifdef DEBUG_RETAINER
-  debugBelch(" < retainerProfile() invoked : %d>\n", retainerGeneration);
-#endif
-
-  stat_startRP();
-
-  // We haven't flipped the bit yet.
-#ifdef DEBUG_RETAINER
-  debugBelch("Before traversing:\n");
-  sumOfCostLinear = 0;
-  for (i = 0;i < N_CLOSURE_TYPES; i++)
-    costArrayLinear[i] = 0;
-  totalHeapSize = checkHeapSanityForRetainerProfiling();
-
-  debugBelch("\tsumOfCostLinear = %d, totalHeapSize = %d\n", sumOfCostLinear, totalHeapSize);
-  /*
-  debugBelch("costArrayLinear[] = ");
-  for (i = 0;i < N_CLOSURE_TYPES; i++)
-    debugBelch("[%u:%u] ", i, costArrayLinear[i]);
-  debugBelch("\n");
-  */
-
-  ASSERT(sumOfCostLinear == totalHeapSize);
-
-/*
-#define pcostArrayLinear(index) \
-  if (costArrayLinear[index] > 0) \
-    debugBelch("costArrayLinear[" #index "] = %u\n", costArrayLinear[index])
-  pcostArrayLinear(THUNK_STATIC);
-  pcostArrayLinear(FUN_STATIC);
-  pcostArrayLinear(CONSTR_STATIC);
-  pcostArrayLinear(CONSTR_NOCAF_STATIC);
-  pcostArrayLinear(CONSTR_INTLIKE);
-  pcostArrayLinear(CONSTR_CHARLIKE);
-*/
-#endif
-
-  // Now we flips flip.
-  flip = flip ^ 1;
-
-#ifdef DEBUG_RETAINER
-  stackSize = 0;
-  maxStackSize = 0;
-  cStackSize = 0;
-  maxCStackSize = 0;
-#endif
-  numObjectVisited = 0;
-  timesAnyObjectVisited = 0;
-
-#ifdef DEBUG_RETAINER
-  debugBelch("During traversing:\n");
-  sumOfNewCost = 0;
-  sumOfNewCostExtra = 0;
-  for (i = 0;i < N_CLOSURE_TYPES; i++)
-    costArray[i] = 0;
-#endif
-
-  /*
-    We initialize the traverse stack each time the retainer profiling is
-    performed (because the traverse stack size varies on each retainer profiling
-    and this operation is not costly anyhow). However, we just refresh the
-    retainer sets.
-   */
-  initializeTraverseStack();
-#ifdef DEBUG_RETAINER
-  initializeAllRetainerSet();
-#else
-  refreshAllRetainerSet();
-#endif
-  computeRetainerSet();
-
-#ifdef DEBUG_RETAINER
-  debugBelch("After traversing:\n");
-  sumOfCostLinear = 0;
-  for (i = 0;i < N_CLOSURE_TYPES; i++)
-    costArrayLinear[i] = 0;
-  totalHeapSize = checkHeapSanityForRetainerProfiling();
-
-  debugBelch("\tsumOfCostLinear = %d, totalHeapSize = %d\n", sumOfCostLinear, totalHeapSize);
-  ASSERT(sumOfCostLinear == totalHeapSize);
-
-  // now, compare the two results
-  /*
-    Note:
-      costArray[] must be exactly the same as costArrayLinear[].
-      Known exceptions:
-        1) Dead weak pointers, whose type is CONSTR. These objects are not
-           reachable from any roots.
-  */
-  debugBelch("Comparison:\n");
-  debugBelch("\tcostArrayLinear[] (must be empty) = ");
-  for (i = 0;i < N_CLOSURE_TYPES; i++)
-    if (costArray[i] != costArrayLinear[i])
-      // nothing should be printed except MUT_VAR after major GCs
-      debugBelch("[%u:%u] ", i, costArrayLinear[i]);
-  debugBelch("\n");
-
-  debugBelch("\tsumOfNewCost = %u\n", sumOfNewCost);
-  debugBelch("\tsumOfNewCostExtra = %u\n", sumOfNewCostExtra);
-  debugBelch("\tcostArray[] (must be empty) = ");
-  for (i = 0;i < N_CLOSURE_TYPES; i++)
-    if (costArray[i] != costArrayLinear[i])
-      // nothing should be printed except MUT_VAR after major GCs
-      debugBelch("[%u:%u] ", i, costArray[i]);
-  debugBelch("\n");
-
-  // only for major garbage collection
-  ASSERT(sumOfNewCost + sumOfNewCostExtra == sumOfCostLinear);
-#endif
-
-  // post-processing
-  closeTraverseStack();
-#ifdef DEBUG_RETAINER
-  closeAllRetainerSet();
-#else
-  // Note that there is no post-processing for the retainer sets.
-#endif
-  retainerGeneration++;
-
-  stat_endRP(
-    retainerGeneration - 1,   // retainerGeneration has just been incremented!
-#ifdef DEBUG_RETAINER
-    maxCStackSize, maxStackSize,
-#endif
-    (double)timesAnyObjectVisited / numObjectVisited);
-}
-
-/* -----------------------------------------------------------------------------
- * DEBUGGING CODE
- * -------------------------------------------------------------------------- */
-
-#ifdef DEBUG_RETAINER
-
-#define LOOKS_LIKE_PTR(r) ((LOOKS_LIKE_STATIC_CLOSURE(r) || \
-        ((HEAP_ALLOCED(r) && ((Bdescr((P_)r)->flags & BF_FREE) == 0)))) && \
-        ((StgWord)(*(StgPtr)r)!=0xaaaaaaaa))
-
-static nat
-sanityCheckHeapClosure( StgClosure *c )
-{
-    StgInfoTable *info;
-
-    ASSERT(LOOKS_LIKE_GHC_INFO(c->header.info));
-    ASSERT(!closure_STATIC(c));
-    ASSERT(LOOKS_LIKE_PTR(c));
-
-    if ((((StgWord)RSET(c) & 1) ^ flip) != 0) {
-       if (get_itbl(c)->type == CONSTR &&
-           !strcmp(get_itbl(c)->prof.closure_type, "DEAD_WEAK") &&
-           !strcmp(get_itbl(c)->prof.closure_desc, "DEAD_WEAK")) {
-           debugBelch("\tUnvisited dead weak pointer object found: c = %p\n", c);
-           costArray[get_itbl(c)->type] += cost(c);
-           sumOfNewCost += cost(c);
-       } else
-           debugBelch(
-                   "Unvisited object: flip = %d, c = %p(%d, %s, %s), rs = %p\n",
-                   flip, c, get_itbl(c)->type,
-                   get_itbl(c)->prof.closure_type, get_itbl(c)->prof.closure_desc,
-                   RSET(c));
-    } else {
-       // debugBelch("sanityCheckHeapClosure) S: flip = %d, c = %p(%d), rs = %p\n", flip, c, get_itbl(c)->type, RSET(c));
-    }
-
-    return closure_sizeW(c);
-}
-
-static nat
-heapCheck( bdescr *bd )
-{
-    StgPtr p;
-    static nat costSum, size;
-
-    costSum = 0;
-    while (bd != NULL) {
-       p = bd->start;
-       while (p < bd->free) {
-           size = sanityCheckHeapClosure((StgClosure *)p);
-           sumOfCostLinear += size;
-           costArrayLinear[get_itbl((StgClosure *)p)->type] += size;
-           p += size;
-           // no need for slop check; I think slops are not used currently.
-       }
-       ASSERT(p == bd->free);
-       costSum += bd->free - bd->start;
-       bd = bd->link;
-    }
-
-    return costSum;
-}
-
-static nat
-smallObjectPoolCheck(void)
-{
-    bdescr *bd;
-    StgPtr p;
-    static nat costSum, size;
-
-    bd = small_alloc_list;
-    costSum = 0;
-
-    // first block
-    if (bd == NULL)
-       return costSum;
-
-    p = bd->start;
-    while (p < alloc_Hp) {
-       size = sanityCheckHeapClosure((StgClosure *)p);
-       sumOfCostLinear += size;
-       costArrayLinear[get_itbl((StgClosure *)p)->type] += size;
-       p += size;
-    }
-    ASSERT(p == alloc_Hp);
-    costSum += alloc_Hp - bd->start;
-
-    bd = bd->link;
-    while (bd != NULL) {
-       p = bd->start;
-       while (p < bd->free) {
-           size = sanityCheckHeapClosure((StgClosure *)p);
-           sumOfCostLinear += size;
-           costArrayLinear[get_itbl((StgClosure *)p)->type] += size;
-           p += size;
-       }
-       ASSERT(p == bd->free);
-       costSum += bd->free - bd->start;
-       bd = bd->link;
-    }
-
-    return costSum;
-}
-
-static nat
-chainCheck(bdescr *bd)
-{
-    nat costSum, size;
-
-    costSum = 0;
-    while (bd != NULL) {
-       // bd->free - bd->start is not an accurate measurement of the
-       // object size.  Actually it is always zero, so we compute its
-       // size explicitly.
-       size = sanityCheckHeapClosure((StgClosure *)bd->start);
-       sumOfCostLinear += size;
-       costArrayLinear[get_itbl((StgClosure *)bd->start)->type] += size;
-       costSum += size;
-       bd = bd->link;
-    }
-
-    return costSum;
-}
-
-static nat
-checkHeapSanityForRetainerProfiling( void )
-{
-    nat costSum, g, s;
-
-    costSum = 0;
-    debugBelch("START: sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-    if (RtsFlags.GcFlags.generations == 1) {
-       costSum += heapCheck(g0s0->to_blocks);
-       debugBelch("heapCheck: sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-       costSum += chainCheck(g0s0->large_objects);
-       debugBelch("chainCheck: sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-    } else {
-       for (g = 0; g < RtsFlags.GcFlags.generations; g++)
-       for (s = 0; s < generations[g].n_steps; s++) {
-           /*
-             After all live objects have been scavenged, the garbage
-             collector may create some objects in
-             scheduleFinalizers(). These objects are created throught
-             allocate(), so the small object pool or the large object
-             pool of the g0s0 may not be empty.
-           */
-           if (g == 0 && s == 0) {
-               costSum += smallObjectPoolCheck();
-               debugBelch("smallObjectPoolCheck(): sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-               costSum += chainCheck(generations[g].steps[s].large_objects);
-               debugBelch("chainCheck(): sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-           } else {
-               costSum += heapCheck(generations[g].steps[s].blocks);
-               debugBelch("heapCheck(): sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-               costSum += chainCheck(generations[g].steps[s].large_objects);
-               debugBelch("chainCheck(): sumOfCostLinear = %d, costSum = %d\n", sumOfCostLinear, costSum);
-           }
-       }
-    }
-
-    return costSum;
-}
-
-void
-findPointer(StgPtr p)
-{
-    StgPtr q, r, e;
-    bdescr *bd;
-    nat g, s;
-
-    for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
-       for (s = 0; s < generations[g].n_steps; s++) {
-           // if (g == 0 && s == 0) continue;
-           bd = generations[g].steps[s].blocks;
-           for (; bd; bd = bd->link) {
-               for (q = bd->start; q < bd->free; q++) {
-                   if (*q == (StgWord)p) {
-                       r = q;
-                       while (!LOOKS_LIKE_GHC_INFO(*r)) r--;
-                       debugBelch("Found in gen[%d], step[%d]: q = %p, r = %p\n", g, s, q, r);
-                       // return;
-                   }
-               }
-           }
-           bd = generations[g].steps[s].large_objects;
-           for (; bd; bd = bd->link) {
-               e = bd->start + cost((StgClosure *)bd->start);
-               for (q = bd->start; q < e; q++) {
-                   if (*q == (StgWord)p) {
-                       r = q;
-                       while (*r == 0 || !LOOKS_LIKE_GHC_INFO(*r)) r--;
-                       debugBelch("Found in gen[%d], large_objects: %p\n", g, r);
-                       // return;
-                   }
-               }
-           }
-       }
-    }
-}
-
-static void
-belongToHeap(StgPtr p)
-{
-    bdescr *bd;
-    nat g, s;
-
-    for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
-       for (s = 0; s < generations[g].n_steps; s++) {
-           // if (g == 0 && s == 0) continue;
-           bd = generations[g].steps[s].blocks;
-           for (; bd; bd = bd->link) {
-               if (bd->start <= p && p < bd->free) {
-                   debugBelch("Belongs to gen[%d], step[%d]", g, s);
-                   return;
-               }
-           }
-           bd = generations[g].steps[s].large_objects;
-           for (; bd; bd = bd->link) {
-               if (bd->start <= p && p < bd->start + getHeapClosureSize((StgClosure *)bd->start)) {
-                   debugBelch("Found in gen[%d], large_objects: %p\n", g, bd->start);
-                   return;
-               }
-           }
-       }
-    }
-}
-#endif /* DEBUG_RETAINER */
-
-#endif /* PROFILING */