This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: High memory consumption compiling syntax.c
> Date: Mon, 1 Oct 2001 09:00:51 -0700
> From: Zack Weinberg <zack@codesourcery.com>
>
> You can try -fmem-report (in 3.x). This will dump statistics on the
> data remaining allocated in the garbage collection arena at the end of
> compilation. However, from what you report below, it rather sounds
> like the runaway memory allocation is not through the garbage
> collector, so this may not help.
I'm attaching the output of -fmem-report below anyway, in the hope
that it will give some clue.
> Based on previous similar reports, I'm inclined to suspect the basic
> block tree. Is the control flow in scan_sexps_forward unusually
> complex? Does it make use of computed GOTO?
I attach the entire function scan_sexps_forward below. As far as I
could see, it's a large case inside a loop. (If it helps, I can post
the preprocessed source of that function.)
Thanks for your help.
gcc -c -Demacs -DHAVE_CONFIG_H -I. -I. -O2 -gcoff -fmem-report syntax.c
Tree Number Bytes % Total
error_mark 1 16 0.003
identifier_node 2914 182k 29.629
tree_list 1706 33k 5.421
block 8 256 0.041
void_type 3 312 0.050
integer_type 85 8840 1.404
real_type 3 312 0.050
complex_type 4 416 0.066
vector_type 5 520 0.083
enumeral_type 15 1560 0.248
boolean_type 1 104 0.017
pointer_type 173 17k 2.858
reference_type 1 104 0.017
array_type 84 8736 1.388
record_type 87 9048 1.437
union_type 5 520 0.083
function_type 349 35k 5.766
integer_cst 927 28k 4.713
string_cst 25 800 0.127
function_decl 1462 148k 24.156
const_decl 126 12k 2.082
type_decl 149 15k 2.462
var_decl 359 36k 5.932
parm_decl 3 312 0.050
result_decl 38 3952 0.628
field_decl 656 66k 10.839
component_ref 6 192 0.031
indirect_ref 6 120 0.019
constructor 22 704 0.112
compound_expr 1 32 0.005
cond_expr 1 32 0.005
plus_expr 4 128 0.020
minus_expr 2 64 0.010
ge_expr 1 32 0.005
eq_expr 1 32 0.005
convert_expr 1 20 0.003
nop_expr 25 500 0.079
non_lvalue_expr 2 40 0.006
save_expr 1 32 0.005
addr_expr 45 900 0.143
postdecrement_expr 1 32 0.005
Total 9308 614k
RTX Number Bytes % Total
const_int 363 2904 17.494
const_double 21 672 4.048
pc 1 4 0.024
reg 58 928 5.590
mem 438 7008 42.217
symbol_ref 605 4840 29.157
cc0 1 4 0.024
plus 14 224 1.349
eq 1 16 0.096
Total 1502 16k
Log Allocated Used Overhead
2 4096 8 160
3 180k 8048 4320
4 312k 8192 4992
5 212k 31k 2544
6 252k 182k 2520
32 832k 366k 7488
33 552k 34k 7728
Total 5376k 631k 29k
String pool
entries 3328
identifiers 2914 (87.56%)
slots 16384
bytes 43k (4367 overhead)
table size 192k
coll/search 0.1183
ins/search 0.0827
avg. entry 13.37 bytes (+/- 7.98)
longest entry 57
static void
scan_sexps_forward (stateptr, from, from_byte, end, targetdepth,
stopbefore, oldstate, commentstop)
struct lisp_parse_state *stateptr;
register int from;
int end, targetdepth, stopbefore;
Lisp_Object oldstate;
int commentstop;
{
struct lisp_parse_state state;
register enum syntaxcode code;
int c1;
int comnested;
struct level { int last, prev; };
struct level levelstart[100];
register struct level *curlevel = levelstart;
struct level *endlevel = levelstart + 100;
register int depth; /* Paren depth of current scanning location.
level - levelstart equals this except
when the depth becomes negative. */
int mindepth; /* Lowest DEPTH value seen. */
int start_quoted = 0; /* Nonzero means starting after a char quote */
Lisp_Object tem;
int prev_from; /* Keep one character before FROM. */
int prev_from_byte;
int prev_from_syntax;
int boundary_stop = commentstop == -1;
int nofence;
int found;
int out_bytepos, out_charpos;
int temp;
prev_from = from;
prev_from_byte = from_byte;
if (from != BEGV)
DEC_BOTH (prev_from, prev_from_byte);
/* Use this macro instead of `from++'. */
#define INC_FROM \
do { prev_from = from; \
prev_from_byte = from_byte; \
prev_from_syntax \
= SYNTAX_WITH_FLAGS (FETCH_CHAR (prev_from_byte)); \
INC_BOTH (from, from_byte); \
UPDATE_SYNTAX_TABLE_FORWARD (from); \
} while (0)
immediate_quit = 1;
QUIT;
if (NILP (oldstate))
{
depth = 0;
state.instring = -1;
state.incomment = 0;
state.comstyle = 0; /* comment style a by default. */
state.comstr_start = -1; /* no comment/string seen. */
}
else
{
tem = Fcar (oldstate);
if (!NILP (tem))
depth = XINT (tem);
else
depth = 0;
oldstate = Fcdr (oldstate);
oldstate = Fcdr (oldstate);
oldstate = Fcdr (oldstate);
tem = Fcar (oldstate);
/* Check whether we are inside string_fence-style string: */
state.instring = (!NILP (tem)
? (INTEGERP (tem) ? XINT (tem) : ST_STRING_STYLE)
: -1);
oldstate = Fcdr (oldstate);
tem = Fcar (oldstate);
state.incomment = (!NILP (tem)
? (INTEGERP (tem) ? XINT (tem) : -1)
: 0);
oldstate = Fcdr (oldstate);
tem = Fcar (oldstate);
start_quoted = !NILP (tem);
/* if the eighth element of the list is nil, we are in comment
style a. If it is non-nil, we are in comment style b */
oldstate = Fcdr (oldstate);
oldstate = Fcdr (oldstate);
tem = Fcar (oldstate);
state.comstyle = NILP (tem) ? 0 : (EQ (tem, Qsyntax_table)
? ST_COMMENT_STYLE : 1);
oldstate = Fcdr (oldstate);
tem = Fcar (oldstate);
state.comstr_start = NILP (tem) ? -1 : XINT (tem) ;
oldstate = Fcdr (oldstate);
tem = Fcar (oldstate);
while (!NILP (tem)) /* >= second enclosing sexps. */
{
/* curlevel++->last ran into compiler bug on Apollo */
curlevel->last = XINT (Fcar (tem));
if (++curlevel == endlevel)
curlevel--; /* error ("Nesting too deep for parser"); */
curlevel->prev = -1;
curlevel->last = -1;
tem = Fcdr (tem);
}
}
state.quoted = 0;
mindepth = depth;
curlevel->prev = -1;
curlevel->last = -1;
SETUP_SYNTAX_TABLE (prev_from, 1);
prev_from_syntax = SYNTAX_WITH_FLAGS (FETCH_CHAR (prev_from_byte));
UPDATE_SYNTAX_TABLE_FORWARD (from);
/* Enter the loop at a place appropriate for initial state. */
if (state.incomment)
goto startincomment;
if (state.instring >= 0)
{
nofence = state.instring != ST_STRING_STYLE;
if (start_quoted)
goto startquotedinstring;
goto startinstring;
}
else if (start_quoted)
goto startquoted;
#if 0 /* This seems to be redundant with the identical code above. */
SETUP_SYNTAX_TABLE (prev_from, 1);
prev_from_syntax = SYNTAX_WITH_FLAGS (FETCH_CHAR (prev_from_byte));
UPDATE_SYNTAX_TABLE_FORWARD (from);
#endif
while (from < end)
{
INC_FROM;
code = prev_from_syntax & 0xff;
if (code == Scomment)
{
state.comstyle = SYNTAX_FLAGS_COMMENT_STYLE (prev_from_syntax);
state.incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
1 : -1);
state.comstr_start = prev_from;
}
else if (code == Scomment_fence)
{
/* Record the comment style we have entered so that only
the comment-end sequence of the same style actually
terminates the comment section. */
state.comstyle = ST_COMMENT_STYLE;
state.incomment = -1;
state.comstr_start = prev_from;
code = Scomment;
}
else if (from < end)
if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax))
if (c1 = FETCH_CHAR (from_byte),
SYNTAX_COMSTART_SECOND (c1))
/* Duplicate code to avoid a complex if-expression
which causes trouble for the SGI compiler. */
{
/* Record the comment style we have entered so that only
the comment-end sequence of the same style actually
terminates the comment section. */
state.comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from_byte));
comnested = SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax);
comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
state.incomment = comnested ? 1 : -1;
state.comstr_start = prev_from;
INC_FROM;
code = Scomment;
}
if (SYNTAX_FLAGS_PREFIX (prev_from_syntax))
continue;
switch (SWITCH_ENUM_CAST (code))
{
case Sescape:
case Scharquote:
if (stopbefore) goto stop; /* this arg means stop at sexp start */
curlevel->last = prev_from;
startquoted:
if (from == end) goto endquoted;
INC_FROM;
goto symstarted;
/* treat following character as a word constituent */
case Sword:
case Ssymbol:
if (stopbefore) goto stop; /* this arg means stop at sexp start */
curlevel->last = prev_from;
symstarted:
while (from < end)
{
/* Some compilers can't handle this inside the switch. */
temp = SYNTAX (FETCH_CHAR (from_byte));
switch (temp)
{
case Scharquote:
case Sescape:
INC_FROM;
if (from == end) goto endquoted;
break;
case Sword:
case Ssymbol:
case Squote:
break;
default:
goto symdone;
}
INC_FROM;
}
symdone:
curlevel->prev = curlevel->last;
break;
case Scomment:
if (commentstop || boundary_stop) goto done;
startincomment:
/* The (from == BEGV) test was to enter the loop in the middle so
that we find a 2-char comment ender even if we start in the
middle of it. We don't want to do that if we're just at the
beginning of the comment (think of (*) ... (*)). */
found = forw_comment (from, from_byte, end,
state.incomment, state.comstyle,
(from == BEGV || from < state.comstr_start + 3)
? 0 : prev_from_syntax,
&out_charpos, &out_bytepos, &state.incomment);
from = out_charpos; from_byte = out_bytepos;
/* Beware! prev_from and friends are invalid now.
Luckily, the `done' doesn't use them and the INC_FROM
sets them to a sane value without looking at them. */
if (!found) goto done;
INC_FROM;
state.incomment = 0;
state.comstyle = 0; /* reset the comment style */
if (boundary_stop) goto done;
break;
case Sopen:
if (stopbefore) goto stop; /* this arg means stop at sexp start */
depth++;
/* curlevel++->last ran into compiler bug on Apollo */
curlevel->last = prev_from;
if (++curlevel == endlevel)
curlevel--; /* error ("Nesting too deep for parser"); */
curlevel->prev = -1;
curlevel->last = -1;
if (targetdepth == depth) goto done;
break;
case Sclose:
depth--;
if (depth < mindepth)
mindepth = depth;
if (curlevel != levelstart)
curlevel--;
curlevel->prev = curlevel->last;
if (targetdepth == depth) goto done;
break;
case Sstring:
case Sstring_fence:
state.comstr_start = from - 1;
if (stopbefore) goto stop; /* this arg means stop at sexp start */
curlevel->last = prev_from;
state.instring = (code == Sstring
? (FETCH_CHAR (prev_from_byte))
: ST_STRING_STYLE);
if (boundary_stop) goto done;
startinstring:
{
nofence = state.instring != ST_STRING_STYLE;
while (1)
{
int c;
if (from >= end) goto done;
c = FETCH_CHAR (from_byte);
/* Some compilers can't handle this inside the switch. */
temp = SYNTAX (c);
/* Check TEMP here so that if the char has
a syntax-table property which says it is NOT
a string character, it does not end the string. */
if (nofence && c == state.instring && temp == Sstring)
break;
switch (temp)
{
case Sstring_fence:
if (!nofence) goto string_end;
break;
case Scharquote:
case Sescape:
INC_FROM;
startquotedinstring:
if (from >= end) goto endquoted;
}
INC_FROM;
}
}
string_end:
state.instring = -1;
curlevel->prev = curlevel->last;
INC_FROM;
if (boundary_stop) goto done;
break;
case Smath:
break;
}
}
goto done;
stop: /* Here if stopping before start of sexp. */
from = prev_from; /* We have just fetched the char that starts it; */
goto done; /* but return the position before it. */
endquoted:
state.quoted = 1;
done:
state.depth = depth;
state.mindepth = mindepth;
state.thislevelstart = curlevel->prev;
state.prevlevelstart
= (curlevel == levelstart) ? -1 : (curlevel - 1)->last;
state.location = from;
state.levelstarts = Qnil;
while (--curlevel >= levelstart)
state.levelstarts = Fcons (make_number (curlevel->last),
state.levelstarts);
immediate_quit = 0;
*stateptr = state;
}