#include <stdio.h>
#include "gprof.h"
#define DFN_DEPTH 100
struct dfnstruct {
nltype *nlentryp;
int cycletop;
};
typedef struct dfnstruct dfntype;
dfntype *dfn_stack = NULL;
int dfn_depth = 0;
int dfn_sz = 0;
int dfn_counter = DFN_NAN;
void
dfn(nltype *parentp)
{
arctype *arcp;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn] dfn(");
printname(parentp);
(void) printf(")\n");
}
#endif
if (!dfn_stack) {
dfn_sz = DFN_DEPTH;
dfn_stack = (dfntype *) malloc(dfn_sz * sizeof (dfntype));
if (!dfn_stack) {
(void) fprintf(stderr,
"fatal: can't malloc %d objects\n", dfn_sz);
exit(1);
}
}
if (dfn_numbered(parentp))
return;
if (dfn_busy(parentp)) {
dfn_findcycle(parentp);
return;
}
dfn_pre_visit(parentp);
for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist)
dfn(arcp->arc_childp);
dfn_post_visit(parentp);
}
void
dfn_pre_visit(nltype *parentp)
{
if (!dfn_stack) {
dfn_sz = DFN_DEPTH;
dfn_stack = (dfntype *) malloc(dfn_sz * sizeof (dfntype));
if (!dfn_stack) {
(void) printf("fatal: can't malloc %d objects\n",
dfn_sz);
exit(1);
}
}
dfn_depth += 1;
if (dfn_depth >= dfn_sz) {
dfn_sz += DFN_DEPTH;
dfn_stack = (dfntype *) realloc(dfn_stack,
dfn_sz * sizeof (dfntype));
if (!dfn_stack) {
(void) fprintf(stderr,
"fatal: can't realloc %d objects\n", dfn_sz);
exit(1);
}
}
dfn_stack[dfn_depth].nlentryp = parentp;
dfn_stack[dfn_depth].cycletop = dfn_depth;
parentp->toporder = DFN_BUSY;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_pre_visit]\t\t%d:", dfn_depth);
printname(parentp);
(void) printf("\n");
}
#endif
}
bool
dfn_numbered(nltype *childp)
{
return (childp->toporder != DFN_NAN && childp->toporder != DFN_BUSY);
}
bool
dfn_busy(nltype *childp)
{
if (childp->toporder == DFN_NAN)
return (FALSE);
return (TRUE);
}
void
dfn_findcycle(nltype *childp)
{
int cycletop;
nltype *cycleheadp = NULL;
nltype *tailp;
int index;
for (cycletop = dfn_depth; cycletop > 0; cycletop -= 1) {
cycleheadp = dfn_stack[cycletop].nlentryp;
if (childp == cycleheadp)
break;
if (childp->cyclehead != childp &&
childp->cyclehead == cycleheadp)
break;
}
if (cycletop <= 0) {
if (childp->value) {
(void) fprintf(stderr,
"[dfn_findcycle] couldn't find head "
"of cycle for %s\n", childp->name);
return;
}
}
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_findcycle] dfn_depth %d cycletop %d ",
dfn_depth, cycletop);
printname(cycleheadp);
(void) printf("\n");
}
#endif
if (cycletop == dfn_depth) {
dfn_self_cycle(childp);
} else {
for (tailp = cycleheadp; tailp->cnext; tailp = tailp->cnext) {
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_findcycle] tail ");
printname(tailp);
(void) printf("\n");
}
#endif
}
if (cycleheadp->cyclehead != cycleheadp) {
cycleheadp = cycleheadp->cyclehead;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_findcycle] new cyclehead ");
printname(cycleheadp);
(void) printf("\n");
}
#endif
}
for (index = cycletop + 1; index <= dfn_depth; index += 1) {
childp = dfn_stack[index].nlentryp;
if (childp->cyclehead == childp) {
tailp->cnext = childp;
childp->cyclehead = cycleheadp;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf(
"[dfn_findcycle] glomming ");
printname(childp);
(void) printf(" onto ");
printname(cycleheadp);
(void) printf("\n");
}
#endif
for (tailp = childp; tailp->cnext;
tailp = tailp->cnext) {
tailp->cnext->cyclehead = cycleheadp;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_findcycle]"
" and its tail ");
printname(tailp->cnext);
(void) printf(" onto ");
printname(cycleheadp);
(void) printf("\n");
}
#endif
}
} else if (childp->cyclehead != cycleheadp) {
(void) fprintf(stderr, "[dfn_busy] glommed,"
" but not to cyclehead\n");
}
}
}
}
void
dfn_self_cycle(nltype *parentp)
{
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_self_cycle] ");
printname(parentp);
(void) printf("\n");
}
#endif
}
void
dfn_post_visit(nltype *parentp)
{
nltype *memberp;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_post_visit]\t%d: ", dfn_depth);
printname(parentp);
(void) printf("\n");
}
#endif
if (parentp->cyclehead == parentp) {
dfn_counter += 1;
for (memberp = parentp; memberp; memberp = memberp->cnext) {
memberp->toporder = dfn_counter;
#ifdef DEBUG
if (debug & DFNDEBUG) {
(void) printf("[dfn_post_visit]\t\tmember ");
printname(memberp);
(void) printf(" -> toporder = %d\n",
dfn_counter);
}
#endif
}
#ifdef DEBUG
} else {
if (debug & DFNDEBUG)
(void) printf(
"[dfn_post_visit]\t\tis part of a cycle\n");
#endif
}
dfn_depth -= 1;
}