Commit bd78b696 authored by Daniel Gröber (dxld)'s avatar Daniel Gröber (dxld)

rts: retainer: Cleanup comments and strings for traversal extraction

A lot of comments and strings are still talking about old names, fix
that.
parent 64ec45a7
......@@ -158,8 +158,10 @@ typedef union {
} srt;
} nextPos;
// Tagged stack element, that keeps information how to process
// the next element in the traverse stack.
/**
* Position pointer into a closure. Determines what the next element to return
* for a stackElement is.
*/
typedef struct {
nextPosType type;
nextPos next;
......@@ -172,29 +174,48 @@ typedef union {
retainer c_child_r;
} stackData;
// Element in the traverse stack, keeps the element, information
// how to continue processing the element, and it's retainer set.
/**
* An element of the traversal work-stack. Besides the closure itself this also
* stores it's parent and associated data.
*
* When 'info.type == posTypeFresh' a 'stackElement' represents just one
* closure, namely 'c' and 'cp' being it's parent. Otherwise 'info' specifies an
* offset into the children of 'c'. This is to support returning a closure's
* children one-by-one without pushing one element per child onto the stack. See
* traversePushChildren() and traversePop().
*
*/
typedef struct {
stackPos info;
StgClosure *c;
StgClosure *cp; // parent of 'c'
StgClosure *cp; // parent of 'c'. Only used when info.type == posTypeFresh.
stackData data;
} stackElement;
typedef struct {
/*
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()).
is empty that stackTop == stackLimit (not during the execution of
pushStackElement() and popStackElement()).
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.
......@@ -226,7 +247,8 @@ typedef struct {
int stackSize, maxStackSize;
} traverseState;
/* Callback called when heap traversal visits a closure.
/**
* Callback called when heap traversal visits a closure.
*
* Before this callback is called the profiling header of the visited closure
* 'c' is zero'd with 'setTravDataToZero' if this closure hasn't been visited in
......@@ -298,9 +320,9 @@ returnToOldStack( traverseState *ts, bdescr *bd )
bd->free = (StgPtr)ts->stackLimit;
}
/* -----------------------------------------------------------------------------
* Initializes the traverse stack.
* -------------------------------------------------------------------------- */
/**
* Initializes the traversal work-stack.
*/
static void
initializeTraverseStack( traverseState *ts )
{
......@@ -315,11 +337,12 @@ initializeTraverseStack( traverseState *ts )
newStackBlock(ts, ts->firstStack);
}
/* -----------------------------------------------------------------------------
* Frees all the block groups in the traverse stack.
/**
* Frees all the block groups in the traversal works-stack.
*
* Invariants:
* firstStack != NULL
* -------------------------------------------------------------------------- */
*/
static void
closeTraverseStack( traverseState *ts )
{
......@@ -433,15 +456,17 @@ find_srt( stackPos *info )
}
}
/* -----------------------------------------------------------------------------
* Pushes an element onto traverse stack
* -------------------------------------------------------------------------- */
/**
* Push a set of closures, represented by a single 'stackElement', onto the
* traversal work-stack.
*/
static void
pushStackElement(traverseState *ts, stackElement *se)
{
bdescr *nbd; // Next Block Descriptor
if (ts->stackTop - 1 < ts->stackBottom) {
debug("pop() to the next stack.\n");
debug("pushStackElement() to the next stack.\n");
// currentStack->free is updated when the active stack is switched
// to the next stack.
ts->currentStack->free = (StgPtr)ts->stackTop;
......@@ -471,13 +496,12 @@ pushStackElement(traverseState *ts, stackElement *se)
debug("stackSize = %d\n", ts->stackSize);
}
/* Push an object onto traverse stack. This method can be used anytime
* instead of calling retainClosure(), it exists in order to use an
* explicit stack instead of direct recursion.
/**
* Push a single closure onto the traversal work-stack.
*
* *cp - object's parent
* *c - closure
* c_child_r - closure retainer.
* cp - object's parent
* c - closure
* data - data associated with closure.
*/
static INLINE void
traversePushClosure(traverseState *ts, StgClosure *c, StgClosure *cp, stackData data) {
......@@ -491,28 +515,34 @@ traversePushClosure(traverseState *ts, StgClosure *c, StgClosure *cp, stackData
pushStackElement(ts, &se);
};
/* -----------------------------------------------------------------------------
* 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_child 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.
* -------------------------------------------------------------------------- */
/**
* traversePushChildren() extracts the first child of 'c' in 'first_child' and
* conceptually pushes all remaining children of 'c' onto the traversal stack
* while associating 'data' with the pushed elements to be returned upon poping.
*
* If 'c' has no children, 'first_child' is set to NULL and nothing is pushed
* onto the stack.
*
* If 'c' has only one child, 'first_child' is set to that child and nothing is
* pushed onto the stack.
*
* Invariants:
*
* - '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.
*
* Note: When pushing onto the stack we only really push one 'stackElement'
* representing all children onto the stack. See traversePop()
*/
static INLINE void
traversePushChildren(traverseState *ts, StgClosure *c, stackData data, StgClosure **first_child)
{
stackElement se;
bdescr *nbd; // Next Block Descriptor
debug("push(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary);
debug("traversePushChildren(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary);
ASSERT(get_itbl(c)->type != TSO);
ASSERT(get_itbl(c)->type != AP_STACK);
......@@ -523,7 +553,7 @@ traversePushChildren(traverseState *ts, StgClosure *c, stackData data, StgClosur
se.c = c;
se.data = data;
// Note: se.cp ommitted on purpose, only retainPushClosure uses that.
// Note: se.cp ommitted on purpose, only traversePushClosure uses that.
// fill in se.info
switch (get_itbl(c)->type) {
......@@ -712,19 +742,14 @@ traversePushChildren(traverseState *ts, StgClosure *c, stackData data, StgClosur
pushStackElement(ts, &se);
}
/* -----------------------------------------------------------------------------
* popOff() and popOffReal(): Pop a stackElement off the traverse stack.
/**
* popStackElement(): Remove a depleted stackElement from the top of the
* traversal work-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.
* -------------------------------------------------------------------------- */
* empty, in which case popStackElement() is not allowed.
*/
static void
popStackElement(traverseState *ts) {
debug("popStackElement(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary);
......@@ -746,7 +771,7 @@ popStackElement(traverseState *ts) {
bdescr *pbd; // Previous Block Descriptor
debug("pop() to the previous stack.\n");
debug("popStackElement() to the previous stack.\n");
ASSERT(ts->stackTop + 1 == ts->stackLimit);
ASSERT(ts->stackBottom == (stackElement *)ts->currentStack->start);
......@@ -780,9 +805,10 @@ popStackElement(traverseState *ts) {
debug("stackSize = %d\n", ts->stackSize);
}
/* -----------------------------------------------------------------------------
/**
* Finds the next object to be considered for retainer profiling and store
* its pointer to *c.
*
* If the unprocessed object was stored in the stack (posTypeFresh), the
* this object is returned as-is. Otherwise Test if the topmost stack
* element indicates that more objects are left,
......@@ -790,20 +816,23 @@ popStackElement(traverseState *ts) {
* set *cp and *data 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 true 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
traversePop(traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data)
{
stackElement *se;
debug("pop(): stackTop = 0x%x currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary);
debug("traversePop(): stackTop = 0x%x currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary);
// Is this the last internal element? If so instead of modifying the current
// stackElement in place we actually remove it from the stack.
......@@ -816,7 +845,8 @@ traversePop(traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data)
}
// Note: Below every `break`, where the loop condition is true, must be
// accompanied by a popOff() otherwise this is an infinite loop.
// accompanied by a popStackElement() otherwise this is an infinite
// loop.
se = ts->stackTop;
// If this is a top-level element, you should pop that out.
......@@ -845,7 +875,7 @@ traversePop(traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data)
if (se->info.next.step == 2) {
*c = (StgClosure *)((StgMVar *)se->c)->tail;
se->info.next.step++; // move to the next step
// no popOff
// no popStackElement
} else {
*c = ((StgMVar *)se->c)->value;
last = true;
......@@ -857,7 +887,7 @@ traversePop(traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data)
if (se->info.next.step == 2) {
*c = ((StgWeak *)se->c)->value;
se->info.next.step++;
// no popOff
// no popStackElement
} else {
*c = ((StgWeak *)se->c)->finalizer;
last = true;
......@@ -982,7 +1012,7 @@ traversePop(traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data)
case IND:
case INVALID_OBJECT:
default:
barf("Invalid object *c in pop(): %d", get_itbl(se->c)->type);
barf("Invalid object *c in traversePop(): %d", get_itbl(se->c)->type);
return;
}
} while (*c == NULL);
......@@ -1194,7 +1224,7 @@ associate( StgClosure *c, RetainerSet *s )
}
/* -----------------------------------------------------------------------------
Call retainPushClosure for each of the closures covered by a large bitmap.
Call traversePushClosure for each of the closures covered by a large bitmap.
-------------------------------------------------------------------------- */
static void
......@@ -1236,24 +1266,32 @@ traverseSmallBitmap (traverseState *ts, StgPtr p, uint32_t size, StgWord bitmap,
return p;
}
/* -----------------------------------------------------------------------------
* 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.
/**
* traversePushStack(ts, cp, data, stackStart, stackEnd) pushes all the objects
* in the STG stack-chunk from stackStart to stackEnd onto the traversal
* work-stack with 'c' and 'data' being their parent and associated data,
* respectively.
*
* Invariants:
* *c is one of the following: TSO, AP_STACK.
* If *c is TSO, c == c_child_r.
*
* *cp is one of the following: TSO, AP_STACK.
*
* If *cp 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 ThreadComplete,or ThreadKilled,
* which means that its stack is ready to process.
*
* Note:
*
* This code was almost plagiarzied from GC.c! For each pointer,
* retainPushClosure() is invoked instead of evacuate().
* -------------------------------------------------------------------------- */
* traversePushClosure() is invoked instead of evacuate().
*/
static void
traversePushStack(traverseState *ts, StgClosure *cp, stackData data,
StgPtr stackStart, StgPtr stackEnd)
......@@ -1265,7 +1303,7 @@ traversePushStack(traverseState *ts, StgClosure *cp, stackData data,
uint32_t size;
/*
Each invocation of retainStack() creates a new virtual
Each invocation of traversePushStack() 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.
......@@ -1273,7 +1311,7 @@ traversePushStack(traverseState *ts, StgClosure *cp, stackData data,
oldStackBoundary = ts->currentStackBoundary;
ts->currentStackBoundary = ts->stackTop;
debug("retainStack() called: oldStackBoundary = 0x%x, currentStackBoundary = 0x%x\n",
debug("traversePushStack() called: oldStackBoundary = 0x%x, currentStackBoundary = 0x%x\n",
oldStackBoundary, ts->currentStackBoundary);
ASSERT(get_itbl(cp)->type == STACK);
......@@ -1360,19 +1398,19 @@ traversePushStack(traverseState *ts, StgClosure *cp, stackData data,
}
default:
barf("Invalid object found in retainStack(): %d",
barf("Invalid object found in traversePushStack(): %d",
(int)(info->i.type));
}
}
// restore currentStackBoundary
ts->currentStackBoundary = oldStackBoundary;
debug("retainStack() finished: currentStackBoundary = 0x%x\n",
debug("traversePushStack() finished: currentStackBoundary = 0x%x\n",
ts->currentStackBoundary);
}
/* ----------------------------------------------------------------------------
* Call retainPushClosure for each of the children of a PAP/AP
* Call traversePushClosure for each of the children of a PAP/AP
* ------------------------------------------------------------------------- */
static INLINE StgPtr
......@@ -1495,22 +1533,10 @@ retainVisitClosure( const StgClosure *c, const StgClosure *cp, const stackData d
return 0;
}
/* -----------------------------------------------------------------------------
* 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).
* -------------------------------------------------------------------------- */
/**
* Traverse all closures on the traversal work-stack, calling 'visit_cb'
* on each closure. See 'visitClosure_cb' for details.
*/
static void
traverseWorkStack(traverseState *ts, visitClosure_cb visit_cb)
{
......@@ -1541,7 +1567,7 @@ inner_loop:
case TSO:
if (((StgTSO *)c)->what_next == ThreadComplete ||
((StgTSO *)c)->what_next == ThreadKilled) {
debug("ThreadComplete or ThreadKilled encountered in retainClosure()\n");
debug("ThreadComplete or ThreadKilled encountered in traverseWorkStack()\n");
goto loop;
}
break;
......@@ -1673,7 +1699,8 @@ inner_loop:
// 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.
// object. traversePushChildren() may or may not push a stackElement on the
// stack.
if (first_child == NULL)
goto loop;
......@@ -1684,9 +1711,24 @@ inner_loop:
goto inner_loop;
}
/* -----------------------------------------------------------------------------
/**
* Compute the retainer set for every object reachable from *tl.
* -------------------------------------------------------------------------- */
*
* 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
retainRoot(void *user, StgClosure **tl)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment