parent
1027df054a
commit
2fadf887e6
|
@ -359,6 +359,7 @@ void show_help()
|
|||
printf("\t-o<name> set base name of output file\n");
|
||||
printf("\t-p<name> set name of \"prefix\" file\n");
|
||||
printf("\t-r[name] write cross reference report to console or to specified file\n");
|
||||
printf("\t-sui[+/-] show stack usage info\n");
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
|
|
@ -812,6 +812,7 @@ SC_VDECL int rational_digits; /* number of fractional digits */
|
|||
SC_VDECL int sc_allowproccall;/* allow/detect tagnames in lex() */
|
||||
SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecated */
|
||||
SC_VDECL int sc_warnings_are_errors;
|
||||
SC_VDECL int sc_stkusageinfo; /* show stack usage info? */
|
||||
|
||||
SC_VDECL constvalue sc_automaton_tab; /* automaton table */
|
||||
SC_VDECL constvalue sc_state_tab; /* state table */
|
||||
|
|
|
@ -756,14 +756,55 @@ cleanup:
|
|||
|
||||
#if !defined SC_LIGHT
|
||||
if (errnum==0 && strlen(errfname)==0) {
|
||||
int flag_exceed=0;
|
||||
if (sc_amxlimit > 0 && (long)(hdrsize+code_idx+glb_declared*sizeof(cell)+sc_stksize*sizeof(cell)) >= sc_amxlimit)
|
||||
flag_exceed=1;
|
||||
if ((sc_debug & sSYMBOLIC)!=0 || verbosity>=2 || flag_exceed) {
|
||||
int recursion = 0, flag_exceed = 0;
|
||||
long stacksize = 0L;
|
||||
unsigned long maxStackUsage = 0L;
|
||||
unsigned long dynamicStackSizeLimit = (long)sc_stksize * sizeof(cell);
|
||||
|
||||
if (sc_amxlimit > 0) {
|
||||
long totalsize = hdrsize + code_idx + glb_declared * sizeof(cell) + dynamicStackSizeLimit;
|
||||
if (totalsize >= sc_amxlimit)
|
||||
flag_exceed = 1;
|
||||
} /* if */
|
||||
|
||||
/* if */
|
||||
if(sc_stkusageinfo) {
|
||||
stacksize = max_stacksize(&glbtab, &recursion);
|
||||
maxStackUsage = stacksize * sizeof(cell);
|
||||
|
||||
if (recursion) {
|
||||
pc_printf("Note: estimated max. usage: unknown, due to recursion\n");
|
||||
} /* if */
|
||||
else if (maxStackUsage >= dynamicStackSizeLimit) {
|
||||
pc_printf("Note: estimated max. stack usage is %ld cells %ld bytes, limit %ld bytes\n", stacksize, maxStackUsage, dynamicStackSizeLimit);
|
||||
}
|
||||
} /* if */
|
||||
|
||||
/* if */
|
||||
/* Note: Seems like `stacksize + 32 >= (long)sc_stksize` condition in original compiler invented to show stack usage warning if it's exceeded, that's why it's defined */
|
||||
if ((sc_debug & sSYMBOLIC)!=0 || verbosity>=2 || /* stacksize + 32 >= (long)sc_stksize || */ flag_exceed) {
|
||||
pc_printf("Header size: %8ld bytes\n", (long)hdrsize);
|
||||
pc_printf("Code size: %8ld bytes\n", (long)code_idx);
|
||||
pc_printf("Data size: %8ld bytes\n", (long)glb_declared*sizeof(cell));
|
||||
pc_printf("Stack/heap size: %8ld bytes\n", (long)sc_stksize*sizeof(cell));
|
||||
pc_printf("Stack/heap size: %8ld bytes", dynamicStackSizeLimit);
|
||||
|
||||
if(sc_stkusageinfo) {
|
||||
pc_printf(" | estimated max. usage");
|
||||
|
||||
/* if */
|
||||
if (recursion) {
|
||||
pc_printf(": unknown, due to recursion\n");
|
||||
}
|
||||
/* else if ((pc_memflags & suSLEEP_INSTR) != 0)
|
||||
pc_printf(": unknown, due to the \"sleep\" instruction\n");*/
|
||||
else {
|
||||
pc_printf("=%ld cells (%ld bytes)\n", stacksize, maxStackUsage);
|
||||
} /* if */
|
||||
}
|
||||
else {
|
||||
pc_printf("\n");
|
||||
} /* if */
|
||||
|
||||
pc_printf("Total requirements:%8ld bytes\n", (long)hdrsize+(long)code_idx+(long)glb_declared*sizeof(cell)+(long)sc_stksize*sizeof(cell));
|
||||
} /* if */
|
||||
if (flag_exceed)
|
||||
|
@ -962,6 +1003,8 @@ static void initglobals(void)
|
|||
sc_documentation=NULL;
|
||||
sc_makereport=FALSE; /* do not generate a cross-reference report */
|
||||
#endif
|
||||
|
||||
sc_stkusageinfo=FALSE;/* stack usage info disabled by default */
|
||||
}
|
||||
|
||||
/* set_extension
|
||||
|
@ -1024,6 +1067,8 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
|
|||
const char *ptr;
|
||||
int arg,i,isoption;
|
||||
|
||||
static const char stackusageinfo[4] = { 's', 'u', 'i', '\0' };
|
||||
|
||||
for (arg=1; arg<argc; arg++) {
|
||||
#if DIRSEP_CHAR=='/'
|
||||
isoption= argv[arg][0]=='-';
|
||||
|
@ -1152,9 +1197,18 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
|
|||
else
|
||||
about();
|
||||
break;
|
||||
case 's':
|
||||
case 's': {
|
||||
if(strlen(ptr) >= (sizeof(stackusageinfo) - 1)) {
|
||||
if(*(ptr+1) == stackusageinfo[1] && *(ptr+2) == stackusageinfo[2]) {
|
||||
ptr += 2;
|
||||
sc_stkusageinfo = toggle_option(ptr, sc_stkusageinfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
skipinput=atoi(option_value(ptr));
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
i=atoi(option_value(ptr));
|
||||
if (i>0)
|
||||
|
@ -1434,6 +1488,7 @@ static void about(void)
|
|||
#endif
|
||||
pc_printf(" -S<num> stack/heap size in cells (default=%d)\n",(int)sc_stksize);
|
||||
pc_printf(" -s<num> skip lines from the input file\n");
|
||||
pc_printf(" -sui[+/-] show stack usage info\n");
|
||||
pc_printf(" -t<num> TAB indent size (in character positions, default=%d)\n",sc_tabsize);
|
||||
pc_printf(" -v<num> verbosity level; 0=quiet, 1=normal, 2=verbose (default=%d)\n",verbosity);
|
||||
pc_printf(" -w<num> disable a specific warning by its number\n");
|
||||
|
@ -5734,3 +5789,137 @@ static int *readwhile(void)
|
|||
return (wqptr-wqSIZE);
|
||||
} /* if */
|
||||
}
|
||||
|
||||
#if !defined SC_LIGHT
|
||||
static long max_stacksize_recurse(symbol** sourcesym, symbol* sym, symbol** rsourcesym, long basesize, int* pubfuncparams, int* recursion)
|
||||
{
|
||||
long size, maxsize;
|
||||
int i, stkpos;
|
||||
|
||||
assert(sourcesym != NULL);
|
||||
assert(sym != NULL);
|
||||
assert(sym->ident == iFUNCTN);
|
||||
assert((sym->usage & uNATIVE) == 0);
|
||||
assert(recursion != NULL);
|
||||
|
||||
maxsize = sym->x.stacksize;
|
||||
for (i = 0; i < sym->numrefers; i++) {
|
||||
if (sym->refer[i] != NULL) {
|
||||
assert(sym->refer[i]->ident == iFUNCTN);
|
||||
assert((sym->refer[i]->usage & uNATIVE) == 0); /* a native function cannot refer to a user-function */
|
||||
*(rsourcesym) = sym;
|
||||
*(rsourcesym + 1) = NULL;
|
||||
for (stkpos = 0; sourcesym[stkpos] != NULL; stkpos++) {
|
||||
if (sym->refer[i] == sourcesym[stkpos]) { /* recursion detection */
|
||||
*recursion = 1;
|
||||
goto break_recursion; /* recursion was detected, quit loop */
|
||||
} /* if */
|
||||
} /* for */
|
||||
/* add this symbol to the stack */
|
||||
sourcesym[stkpos] = sym;
|
||||
sourcesym[stkpos + 1] = NULL;
|
||||
/* check size of callee */
|
||||
size = max_stacksize_recurse(sourcesym, sym->refer[i], rsourcesym + 1, sym->x.stacksize, pubfuncparams, recursion);
|
||||
if (maxsize < size)
|
||||
maxsize = size;
|
||||
/* remove this symbol from the stack */
|
||||
sourcesym[stkpos] = NULL;
|
||||
} /* if */
|
||||
} /* for */
|
||||
break_recursion:
|
||||
|
||||
if ((sym->usage & uPUBLIC) != 0) {
|
||||
/* Find out how many parameters a public function has, then see if this
|
||||
* is bigger than some maximum
|
||||
*/
|
||||
arginfo* arg = sym->dim.arglist;
|
||||
int count = 0;
|
||||
assert(arg != 0);
|
||||
while (arg->ident != 0) {
|
||||
count++;
|
||||
arg++;
|
||||
} /* while */
|
||||
assert(pubfuncparams != 0);
|
||||
if (count > * pubfuncparams)
|
||||
*pubfuncparams = count;
|
||||
} /* if */
|
||||
|
||||
return maxsize + basesize;
|
||||
}
|
||||
|
||||
static long max_stacksize(symbol* root, int* recursion)
|
||||
{
|
||||
/* Loop over all non-native functions. For each function, loop
|
||||
* over all of its referrers, accumulating the stack requirements.
|
||||
* Detect (indirect) recursion with a "mark-and-sweep" algorithm.
|
||||
* I (mis-)use the "compound" field of the symbol structure for
|
||||
* the marker, as this field is unused for functions.
|
||||
*
|
||||
* Note that the stack is shared with the heap. A host application
|
||||
* may "eat" cells from the heap as well, through amx_Allot(). The
|
||||
* stack requirements are thus only an estimate.
|
||||
*/
|
||||
long size, maxsize;
|
||||
int maxparams, numfunctions;
|
||||
symbol* sym;
|
||||
symbol** symstack, ** rsymstack;
|
||||
|
||||
assert(root != NULL);
|
||||
assert(recursion != NULL);
|
||||
/* count number of functions (for allocating the stack for recursion detection) */
|
||||
numfunctions = 0;
|
||||
for (sym = root->next; sym != NULL; sym = sym->next) {
|
||||
if (sym->ident == iFUNCTN) {
|
||||
assert(sym->compound == 0);
|
||||
if ((sym->usage & uNATIVE) == 0)
|
||||
numfunctions++;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/* allocate function symbol stack */
|
||||
symstack = (symbol**)malloc((numfunctions + 1) * sizeof(symbol*));
|
||||
rsymstack = (symbol**)malloc((numfunctions + 1) * sizeof(symbol*));
|
||||
if (symstack == NULL || rsymstack == NULL)
|
||||
error(103); /* insufficient memory (fatal error) */
|
||||
memset(symstack, 0, (numfunctions + 1) * sizeof(symbol*));
|
||||
memset(rsymstack, 0, (numfunctions + 1) * sizeof(symbol*));
|
||||
|
||||
maxsize = 0;
|
||||
maxparams = 0;
|
||||
*recursion = 0; /* assume no recursion */
|
||||
for (sym = root->next; sym != NULL; sym = sym->next) {
|
||||
int recursion_detected;
|
||||
/* drop out if this is not a user-implemented function */
|
||||
if (sym->ident != iFUNCTN || (sym->usage & uNATIVE) != 0)
|
||||
continue;
|
||||
/* accumulate stack size for this symbol */
|
||||
symstack[0] = sym;
|
||||
assert(symstack[1] == NULL);
|
||||
recursion_detected = 0;
|
||||
size = max_stacksize_recurse(symstack, sym, rsymstack, 0L, &maxparams, &recursion_detected);
|
||||
if (recursion_detected) {
|
||||
if (rsymstack[1] == NULL) {
|
||||
pc_printf("recursion detected: function %s directly calls itself\n", sym->name);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
pc_printf("recursion detected: function %s indirectly calls itself:\n", sym->name);
|
||||
pc_printf("%s ", sym->name);
|
||||
for (i = 1; rsymstack[i] != NULL; i++) {
|
||||
pc_printf("<- %s ", rsymstack[i]->name);
|
||||
}
|
||||
pc_printf("<- %s\n", sym->name);
|
||||
}
|
||||
*recursion = recursion_detected;
|
||||
}
|
||||
assert(size >= 0);
|
||||
if (maxsize < size)
|
||||
maxsize = size;
|
||||
} /* for */
|
||||
|
||||
free((void*)symstack);
|
||||
free((void*)rsymstack);
|
||||
maxsize++; /* +1 because a zero cell is always pushed on top
|
||||
* of the stack to catch stack overwrites */
|
||||
return maxsize + (maxparams + 1);/* +1 because # of parameters is always pushed on entry */
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1190,6 +1190,8 @@ static int command(void)
|
|||
if (comma)
|
||||
lptr++;
|
||||
} while (comma);
|
||||
} else if (strcmp(str, "showstackusageinfo")==0) {
|
||||
sc_stkusageinfo=TRUE;
|
||||
} else {
|
||||
error(207); /* unknown #pragma */
|
||||
} /* if */
|
||||
|
|
|
@ -87,6 +87,7 @@ SC_VDEFINE int sc_allowproccall=0; /* allow/detect tagnames in lex() */
|
|||
SC_VDEFINE char *pc_deprecate = NULL;/* if non-null, mark next declaration as deprecated */
|
||||
SC_VDEFINE int sc_showincludes=0; /* show include files */
|
||||
SC_VDEFINE int sc_warnings_are_errors=0;
|
||||
SC_VDEFINE int sc_stkusageinfo = FALSE; /* show stack usage info? */
|
||||
|
||||
SC_VDEFINE constvalue sc_automaton_tab = { NULL, "", 0, 0}; /* automaton table */
|
||||
SC_VDEFINE constvalue sc_state_tab = { NULL, "", 0, 0}; /* state table */
|
||||
|
|
Loading…
Reference in New Issue
Block a user