summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-01-17 21:04:03 (GMT)
committerGuido van Rossum <guido@python.org>1997-01-17 21:04:03 (GMT)
commit8b993a98db507cc3a75067af4c865ffc8afbada1 (patch)
treebe3fd639a280cf39bc3827babdd4bd10b5eb4e59
parent3f6e408a31208d29cf867bb30496bdb1f863d310 (diff)
downloadcpython-8b993a98db507cc3a75067af4c865ffc8afbada1.zip
cpython-8b993a98db507cc3a75067af4c865ffc8afbada1.tar.gz
cpython-8b993a98db507cc3a75067af4c865ffc8afbada1.tar.bz2
Add co_stacksize field to codeobject structure, and stacksize argument
to PyCode_New() argument list. Move MAXBLOCKS constant to conpile.h. Added accurate calculation of the actual stack size needed by the generated code. Also commented out all fprintf statements (except for a new one to diagnose stack underflow, and one in #ifdef'ed out code), and added some new TO DO suggestions (now that the stacksize is taken of the TO DO list).
-rw-r--r--Python/compile.c315
1 files changed, 253 insertions, 62 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 5429e80..5562751 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -32,13 +32,14 @@ PERFORMANCE OF THIS SOFTWARE.
/* Compile an expression node to intermediate code */
/* XXX TO DO:
- XXX Compute maximum needed stack sizes while compiling;
- XXX then frame object can be one malloc and no stack checks are needed
- XXX add __doc__ attribute == co_doc to code object attributes
- XXX don't execute doc string
+ XXX add __doc__ attribute == co_doc to code object attributes?
+ XXX (it's currently the first item of the co_const tuple)
XXX Generate simple jump for break/return outside 'try...finally'
+ XXX Allow 'continue' inside try-finally
XXX get rid of SET_LINENO instructions, use JAR's table trick
XXX (need an option to put them back in, for debugger!)
+ XXX New 1-byte opcode for loading None
+ XXX New opcode for loading the initial index for a for loop
XXX other JAR tricks?
*/
@@ -67,6 +68,7 @@ PERFORMANCE OF THIS SOFTWARE.
static struct memberlist code_memberlist[] = {
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
{"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
+ {"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
{"co_flags", T_INT, OFF(co_flags), READONLY},
{"co_code", T_OBJECT, OFF(co_code), READONLY},
{"co_consts", T_OBJECT, OFF(co_consts), READONLY},
@@ -177,10 +179,11 @@ typeobject Codetype = {
};
codeobject *
-newcodeobject(argcount, nlocals, flags,
+newcodeobject(argcount, nlocals, stacksize, flags,
code, consts, names, varnames, filename, name)
int argcount;
int nlocals;
+ int stacksize;
int flags;
object *code;
object *consts;
@@ -221,6 +224,7 @@ newcodeobject(argcount, nlocals, flags,
if (co != NULL) {
co->co_argcount = argcount;
co->co_nlocals = nlocals;
+ co->co_stacksize = stacksize;
co->co_flags = flags;
INCREF(code);
co->co_code = (stringobject *)code;
@@ -241,8 +245,6 @@ newcodeobject(argcount, nlocals, flags,
/* Data structure used internally */
-#define MAXBLOCKS 20 /* Max static block nesting within a function */
-
struct compiling {
object *c_code; /* string */
object *c_consts; /* list of objects */
@@ -259,11 +261,13 @@ struct compiling {
int c_interactive; /* generating code for interactive command */
int c_loops; /* counts nested loops */
int c_begin; /* begin of current loop, for 'continue' */
- int c_block[MAXBLOCKS]; /* stack of block types */
+ int c_block[CO_MAXBLOCKS]; /* stack of block types */
int c_nblocks; /* current block stack level */
char *c_filename; /* filename of current node */
char *c_name; /* name of object (e.g. function) */
int c_lineno; /* Current line number */
+ int c_stacklevel; /* Current stack level */
+ int c_maxstacklevel; /* Maximum stack level */
#ifdef PRIVATE_NAME_MANGLING
char *c_private; /* for private name mangling */
#endif
@@ -307,7 +311,7 @@ block_push(c, type)
struct compiling *c;
int type;
{
- if (c->c_nblocks >= MAXBLOCKS) {
+ if (c->c_nblocks >= CO_MAXBLOCKS) {
com_error(c, SystemError, "too many statically nested blocks");
}
else {
@@ -332,6 +336,8 @@ block_pop(c, type)
static int com_init PROTO((struct compiling *, char *));
static void com_free PROTO((struct compiling *));
+static void com_push PROTO((struct compiling *, int));
+static void com_pop PROTO((struct compiling *, int));
static void com_done PROTO((struct compiling *));
static void com_node PROTO((struct compiling *, struct _node *));
static void com_factor PROTO((struct compiling *, struct _node *));
@@ -380,6 +386,8 @@ com_init(c, filename)
c->c_filename = filename;
c->c_name = "?";
c->c_lineno = 0;
+ c->c_stacklevel = 0;
+ c->c_maxstacklevel = 0;
return 1;
fail_000:
@@ -409,6 +417,32 @@ com_free(c)
}
static void
+com_push(c, n)
+ struct compiling *c;
+ int n;
+{
+ c->c_stacklevel += n;
+ if (c->c_stacklevel > c->c_maxstacklevel)
+ c->c_maxstacklevel = c->c_stacklevel;
+}
+
+static void
+com_pop(c, n)
+ struct compiling *c;
+ int n;
+{
+ if (c->c_stacklevel < n) {
+ fprintf(stderr,
+ "%s:%d: underflow! nexti=%d, level=%d, n=%d\n",
+ c->c_filename, c->c_lineno,
+ c->c_nexti, c->c_stacklevel, n);
+ c->c_stacklevel = 0;
+ }
+ else
+ c->c_stacklevel -= n;
+}
+
+static void
com_done(c)
struct compiling *c;
{
@@ -804,6 +838,7 @@ com_list_constructor(c, n)
for (i = 0; i < NCH(n); i += 2)
com_node(c, CHILD(n, i));
com_addoparg(c, BUILD_LIST, len);
+ com_pop(c, len-1);
}
static void
@@ -817,10 +852,12 @@ com_dictmaker(c, n)
/* We must arrange things just right for STORE_SUBSCR.
It wants the stack to look like (value) (dict) (key) */
com_addbyte(c, DUP_TOP);
+ com_push(c, 1);
com_node(c, CHILD(n, i+2)); /* value */
com_addbyte(c, ROT_TWO);
com_node(c, CHILD(n, i)); /* key */
com_addbyte(c, STORE_SUBSCR);
+ com_pop(c, 3);
}
}
@@ -836,19 +873,24 @@ com_atom(c, n)
ch = CHILD(n, 0);
switch (TYPE(ch)) {
case LPAR:
- if (TYPE(CHILD(n, 1)) == RPAR)
+ if (TYPE(CHILD(n, 1)) == RPAR) {
com_addoparg(c, BUILD_TUPLE, 0);
+ com_push(c, 1);
+ }
else
com_node(c, CHILD(n, 1));
break;
case LSQB:
- if (TYPE(CHILD(n, 1)) == RSQB)
+ if (TYPE(CHILD(n, 1)) == RSQB) {
com_addoparg(c, BUILD_LIST, 0);
+ com_push(c, 1);
+ }
else
com_list_constructor(c, CHILD(n, 1));
break;
case LBRACE: /* '{' [dictmaker] '}' */
com_addoparg(c, BUILD_MAP, 0);
+ com_push(c, 1);
if (TYPE(CHILD(n, 1)) != RBRACE)
com_dictmaker(c, CHILD(n, 1));
break;
@@ -865,6 +907,7 @@ com_atom(c, n)
DECREF(v);
}
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
break;
case STRING:
v = parsestrplus(n);
@@ -877,12 +920,14 @@ com_atom(c, n)
DECREF(v);
}
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
break;
case NAME:
com_addopname(c, LOAD_NAME, ch);
+ com_push(c, 1);
break;
default:
- fprintf(stderr, "node type %d\n", TYPE(ch));
+ /* XXX fprintf(stderr, "node type %d\n", TYPE(ch)); */
com_error(c, SystemError, "com_atom: unexpected node type");
}
}
@@ -905,11 +950,13 @@ com_slice(c, n, op)
com_node(c, CHILD(n, 1));
com_addbyte(c, op+2);
}
+ com_pop(c, 1);
}
else {
com_node(c, CHILD(n, 0));
com_node(c, CHILD(n, 2));
com_addbyte(c, op+3);
+ com_pop(c, 2);
}
}
@@ -920,7 +967,7 @@ com_argument(c, n, pkeywords)
object **pkeywords;
{
node *m;
- REQ(n, argument); /* [test '='] test; really [ keyword '='] keyword */
+ REQ(n, argument); /* [test '='] test; really [keyword '='] test */
if (NCH(n) == 1) {
if (*pkeywords != NULL) {
com_error(c, SyntaxError,
@@ -952,6 +999,7 @@ com_argument(c, n, pkeywords)
if (dict2insert(*pkeywords, v, v) != 0)
c->c_errors++;
com_addoparg(c, LOAD_CONST, com_addconst(c, v));
+ com_push(c, 1);
DECREF(v);
}
}
@@ -984,6 +1032,7 @@ com_call_function(c, n)
com_error(c, SyntaxError, "more than 255 arguments");
}
com_addoparg(c, CALL_FUNCTION, na | (nk << 8));
+ com_pop(c, na + 2*nk);
}
}
@@ -1007,6 +1056,7 @@ com_sliceobj(c, n)
/* first argument */
if (TYPE(CHILD(n,i)) == COLON) {
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
i++;
}
else {
@@ -1020,7 +1070,10 @@ com_sliceobj(c, n)
com_node(c, CHILD(n,i));
i++;
}
- else com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ else {
+ com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
+ }
/* remaining arguments */
for (; i < NCH(n); i++) {
ns++;
@@ -1029,11 +1082,13 @@ com_sliceobj(c, n)
if (NCH(ch) == 1) {
/* right argument of ':' missing */
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
}
else
com_node(c, CHILD(ch,1));
}
com_addoparg(c, BUILD_SLICE, ns);
+ com_pop(c, 1 + (ns == 3));
}
static void
@@ -1045,8 +1100,10 @@ com_subscript(c, n)
REQ(n, subscript);
ch = CHILD(n,0);
/* check for rubber index */
- if (TYPE(ch) == DOT && TYPE(CHILD(n,1)) == DOT)
+ if (TYPE(ch) == DOT && TYPE(CHILD(n,1)) == DOT) {
com_addoparg(c, LOAD_CONST, com_addconst(c, Py_Ellipsis));
+ com_push(c, 1);
+ }
else {
/* check for slice */
if ((TYPE(ch) == COLON || NCH(n) > 1))
@@ -1070,15 +1127,20 @@ com_subscriptlist(c, n, assigning)
if (NCH(n) == 1) {
node *sub = CHILD(n, 0); /* subscript */
/* Make it is a simple slice.
- should have exactly one colon. */
+ Should have exactly one colon. */
if ((TYPE(CHILD(sub, 0)) == COLON
|| (NCH(sub) > 1 && TYPE(CHILD(sub, 1)) == COLON))
- && (TYPE(CHILD(sub,NCH(sub)-1)) != sliceop)) {
+ && (TYPE(CHILD(sub,NCH(sub)-1)) != sliceop))
+ {
if (assigning == OP_APPLY)
op = SLICE;
else
op = ((assigning == OP_ASSIGN) ? STORE_SLICE : DELETE_SLICE);
com_slice(c, sub, op);
+ if (op == STORE_SLICE)
+ com_pop(c, 2);
+ else if (op == DELETE_SLICE)
+ com_pop(c, 1);
return;
}
}
@@ -1086,13 +1148,25 @@ com_subscriptlist(c, n, assigning)
for (i = 0; i < NCH(n); i += 2)
com_subscript(c, CHILD(n, i));
/* Put multiple subscripts into a tuple */
- if (NCH(n) > 1)
- com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 2);
- if (assigning == OP_APPLY)
+ if (NCH(n) > 1) {
+ i = (NCH(n)+1) / 2;
+ com_addoparg(c, BUILD_TUPLE, i);
+ com_pop(c, i-1);
+ }
+ if (assigning == OP_APPLY) {
op = BINARY_SUBSCR;
- else
- op = ((assigning == OP_ASSIGN) ? STORE_SUBSCR : DELETE_SUBSCR);
+ i = 1;
+ }
+ else if (assigning == OP_ASSIGN) {
+ op = STORE_SUBSCR;
+ i = 3;
+ }
+ else {
+ op = DELETE_SUBSCR;
+ i = 2;
+ }
com_addbyte(c, op);
+ com_pop(c, i);
}
static void
@@ -1129,6 +1203,7 @@ com_power(c, n)
if (TYPE(CHILD(n, i)) == DOUBLESTAR) {
com_factor(c, CHILD(n, i+1));
com_addbyte(c, BINARY_POWER);
+ com_pop(c, 1);
break;
}
else
@@ -1186,6 +1261,7 @@ com_term(c, n)
op = 255;
}
com_addbyte(c, op);
+ com_pop(c, 1);
}
}
@@ -1213,6 +1289,7 @@ com_arith_expr(c, n)
op = 255;
}
com_addbyte(c, op);
+ com_pop(c, 1);
}
}
@@ -1240,6 +1317,7 @@ com_shift_expr(c, n)
op = 255;
}
com_addbyte(c, op);
+ com_pop(c, 1);
}
}
@@ -1263,6 +1341,7 @@ com_and_expr(c, n)
op = 255;
}
com_addbyte(c, op);
+ com_pop(c, 1);
}
}
@@ -1286,6 +1365,7 @@ com_xor_expr(c, n)
op = 255;
}
com_addbyte(c, op);
+ com_pop(c, 1);
}
}
@@ -1309,6 +1389,7 @@ com_expr(c, n)
op = 255;
}
com_addbyte(c, op);
+ com_pop(c, 1);
}
}
@@ -1387,7 +1468,7 @@ com_comparison(c, n)
L1: b, 0 ROT_TWO
0, b POP_TOP
0
- L2:
+ L2: 0-or-1
****************************************************************/
anchor = 0;
@@ -1396,6 +1477,7 @@ com_comparison(c, n)
com_expr(c, CHILD(n, i));
if (i+2 < NCH(n)) {
com_addbyte(c, DUP_TOP);
+ com_push(c, 1);
com_addbyte(c, ROT_THREE);
}
op = cmp_type(CHILD(n, i-1));
@@ -1404,9 +1486,11 @@ com_comparison(c, n)
"com_comparison: unknown comparison op");
}
com_addoparg(c, COMPARE_OP, op);
+ com_pop(c, 1);
if (i+2 < NCH(n)) {
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
}
}
@@ -1451,6 +1535,7 @@ com_and_test(c, n)
break;
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
}
if (anchor)
com_backpatch(c, anchor);
@@ -1461,7 +1546,7 @@ com_test(c, n)
struct compiling *c;
node *n;
{
- REQ(n, test); /* and_test ('and' and_test)* | lambdef */
+ REQ(n, test); /* and_test ('or' and_test)* | lambdef */
if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
object *v;
int i;
@@ -1476,7 +1561,9 @@ com_test(c, n)
DECREF(v);
}
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
com_addoparg(c, MAKE_FUNCTION, ndefs);
+ com_pop(c, ndefs);
}
else {
int anchor = 0;
@@ -1487,6 +1574,7 @@ com_test(c, n)
break;
com_addfwref(c, JUMP_IF_TRUE, &anchor);
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
}
if (anchor)
com_backpatch(c, anchor);
@@ -1510,6 +1598,7 @@ com_list(c, n, toplevel)
for (i = 0; i < NCH(n); i += 2)
com_node(c, CHILD(n, i));
com_addoparg(c, BUILD_TUPLE, len);
+ com_pop(c, len-1);
}
}
@@ -1526,6 +1615,7 @@ com_assign_attr(c, n, assigning)
int assigning;
{
com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n);
+ com_pop(c, assigning ? 2 : 1);
}
static void
@@ -1559,8 +1649,11 @@ com_assign_tuple(c, n, assigning)
int i;
if (TYPE(n) != testlist)
REQ(n, exprlist);
- if (assigning)
- com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2);
+ if (assigning) {
+ i = (NCH(n)+1)/2;
+ com_addoparg(c, UNPACK_TUPLE, i);
+ com_push(c, i-1);
+ }
for (i = 0; i < NCH(n); i += 2)
com_assign(c, CHILD(n, i), assigning);
}
@@ -1572,8 +1665,11 @@ com_assign_list(c, n, assigning)
int assigning;
{
int i;
- if (assigning)
- com_addoparg(c, UNPACK_LIST, (NCH(n)+1)/2);
+ if (assigning) {
+ i = (NCH(n)+1)/2;
+ com_addoparg(c, UNPACK_LIST, i);
+ com_push(c, i-1);
+ }
for (i = 0; i < NCH(n); i += 2)
com_assign(c, CHILD(n, i), assigning);
}
@@ -1586,6 +1682,8 @@ com_assign_name(c, n, assigning)
{
REQ(n, NAME);
com_addopname(c, assigning ? STORE_NAME : DELETE_NAME, n);
+ if (assigning)
+ com_pop(c, 1);
}
static void
@@ -1686,13 +1784,14 @@ com_assign(c, n, assigning)
return;
default:
- fprintf(stderr, "node type %d\n", TYPE(n));
+ /* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
com_error(c, SystemError, "com_assign: bad node");
return;
}
}
}
+/* Forward */ static node *get_rawdocstring PROTO((node *));
static void
com_expr_stmt(c, n)
@@ -1700,18 +1799,24 @@ com_expr_stmt(c, n)
node *n;
{
REQ(n, expr_stmt); /* testlist ('=' testlist)* */
+ /* Forget it if we have just a doc string here */
+ if (NCH(n) == 1 && get_rawdocstring(n) != NULL)
+ return;
com_node(c, CHILD(n, NCH(n)-1));
if (NCH(n) == 1) {
if (c->c_interactive)
com_addbyte(c, PRINT_EXPR);
else
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
}
else {
int i;
for (i = 0; i < NCH(n)-2; i+=2) {
- if (i+2 < NCH(n)-2)
+ if (i+2 < NCH(n)-2) {
com_addbyte(c, DUP_TOP);
+ com_push(c, 1);
+ }
com_assign(c, CHILD(n, i), OP_ASSIGN);
}
}
@@ -1727,6 +1832,7 @@ com_print_stmt(c, n)
for (i = 1; i < NCH(n); i += 2) {
com_node(c, CHILD(n, i));
com_addbyte(c, PRINT_ITEM);
+ com_pop(c, 1);
}
if (TYPE(CHILD(n, NCH(n)-1)) != COMMA)
com_addbyte(c, PRINT_NEWLINE);
@@ -1742,11 +1848,14 @@ com_return_stmt(c, n)
if (!c->c_infunction) {
com_error(c, SyntaxError, "'return' outside function");
}
- if (NCH(n) < 2)
+ if (NCH(n) < 2) {
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
+ }
else
com_node(c, CHILD(n, 1));
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
}
static void
@@ -1754,6 +1863,7 @@ com_raise_stmt(c, n)
struct compiling *c;
node *n;
{
+ int i;
REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
com_node(c, CHILD(n, 1));
if (NCH(n) > 3) {
@@ -1761,7 +1871,9 @@ com_raise_stmt(c, n)
if (NCH(n) > 5)
com_node(c, CHILD(n, 5));
}
- com_addoparg(c, RAISE_VARARGS, NCH(n)/2);
+ i = NCH(n)/2;
+ com_addoparg(c, RAISE_VARARGS, i);
+ com_pop(c, i);
}
static void
@@ -1777,16 +1889,20 @@ com_import_stmt(c, n)
/* 'from' dotted_name 'import' ... */
REQ(CHILD(n, 1), dotted_name);
com_addopname(c, IMPORT_NAME, CHILD(n, 1));
+ com_push(c, 1);
for (i = 3; i < NCH(n); i += 2)
com_addopname(c, IMPORT_FROM, CHILD(n, i));
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
}
else {
/* 'import' ... */
for (i = 1; i < NCH(n); i += 2) {
REQ(CHILD(n, i), dotted_name);
com_addopname(c, IMPORT_NAME, CHILD(n, i));
+ com_push(c, 1);
com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0));
+ com_pop(c, 1);
}
}
}
@@ -1868,9 +1984,10 @@ com_newlocal(c, name)
return i;
}
+#ifdef SUPPORT_OBSOLETE_ACCESS
+
#define strequ(a, b) (strcmp((a), (b)) == 0)
-#ifdef SUPPORT_OBSOLETE_ACCESS
static void
com_access_stmt(c, n)
struct compiling *c;
@@ -1939,13 +2056,18 @@ com_exec_stmt(c, n)
com_node(c, CHILD(n, 1));
if (NCH(n) >= 4)
com_node(c, CHILD(n, 3));
- else
+ else {
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
+ }
if (NCH(n) >= 6)
com_node(c, CHILD(n, 5));
- else
+ else {
com_addbyte(c, DUP_TOP);
+ com_push(c, 1);
+ }
com_addbyte(c, EXEC_STMT);
+ com_pop(c, 3);
}
static void
@@ -1965,9 +2087,11 @@ com_if_stmt(c, n)
com_node(c, CHILD(n, i+1));
com_addfwref(c, JUMP_IF_FALSE, &a);
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
com_node(c, CHILD(n, i+3));
com_addfwref(c, JUMP_FORWARD, &anchor);
com_backpatch(c, a);
+ /* We jump here with an extra entry which we now pop */
com_addbyte(c, POP_TOP);
}
if (i+2 < NCH(n))
@@ -1991,12 +2115,14 @@ com_while_stmt(c, n)
com_node(c, CHILD(n, 1));
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
c->c_loops++;
com_node(c, CHILD(n, 3));
c->c_loops--;
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
com_backpatch(c, anchor);
+ /* We jump here with one entry more on the stack */
com_addbyte(c, POP_TOP);
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_LOOP);
@@ -2023,10 +2149,12 @@ com_for_stmt(c, n)
if (v == NULL)
c->c_errors++;
com_addoparg(c, LOAD_CONST, com_addconst(c, v));
+ com_push(c, 1);
XDECREF(v);
c->c_begin = c->c_nexti;
com_addoparg(c, SET_LINENO, n->n_lineno);
com_addfwref(c, FOR_LOOP, &anchor);
+ com_push(c, 1);
com_assign(c, CHILD(n, 1), OP_ASSIGN);
c->c_loops++;
com_node(c, CHILD(n, 5));
@@ -2034,6 +2162,7 @@ com_for_stmt(c, n)
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
com_backpatch(c, anchor);
+ com_pop(c, 2); /* FOR_LOOP has popped these */
com_addbyte(c, POP_BLOCK);
block_pop(c, SETUP_LOOP);
if (NCH(n) > 8)
@@ -2128,34 +2257,49 @@ com_try_except(c, n)
for (i = 3;
i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
i += 3) {
- /* except_clause: 'except' [expr [',' expr]] */
+ /* except_clause: 'except' [expr [',' var]] */
if (except_anchor == 0) {
com_error(c, SyntaxError,
"default 'except:' must be last");
break;
}
except_anchor = 0;
+ com_push(c, 3); /* tb, val, exc pushed by exception */
com_addoparg(c, SET_LINENO, ch->n_lineno);
if (NCH(ch) > 1) {
com_addbyte(c, DUP_TOP);
+ com_push(c, 1);
com_node(c, CHILD(ch, 1));
com_addoparg(c, COMPARE_OP, EXC_MATCH);
+ com_pop(c, 1);
com_addfwref(c, JUMP_IF_FALSE, &except_anchor);
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
}
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
if (NCH(ch) > 3)
com_assign(c, CHILD(ch, 3), OP_ASSIGN);
- else
+ else {
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
+ }
com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
com_node(c, CHILD(n, i+2));
com_addfwref(c, JUMP_FORWARD, &end_anchor);
if (except_anchor) {
com_backpatch(c, except_anchor);
+ /* We come in with [tb, val, exc, 0] on the
+ stack; one pop and it's the same as
+ expected at the start of the loop */
com_addbyte(c, POP_TOP);
}
}
+ /* We actually come in here with [tb, val, exc] but the
+ END_FINALLY will zap those and jump around.
+ The c_stacklevel does not reflect them so we need not pop
+ anything. */
com_addbyte(c, END_FINALLY);
com_backpatch(c, else_anchor);
if (i < NCH(n))
@@ -2178,12 +2322,18 @@ com_try_finally(c, n)
block_pop(c, SETUP_FINALLY);
block_push(c, END_FINALLY);
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ /* While the generated code pushes only one item,
+ the try-finally handling can enter here with
+ up to three items. OK, here are the details:
+ 3 for an exception, 2 for RETURN, 1 for BREAK. */
+ com_push(c, 3);
com_backpatch(c, finally_anchor);
ch = CHILD(n, NCH(n)-1);
com_addoparg(c, SET_LINENO, ch->n_lineno);
com_node(c, ch);
com_addbyte(c, END_FINALLY);
block_pop(c, END_FINALLY);
+ com_pop(c, 3); /* Matches the com_push above */
}
static void
@@ -2200,38 +2350,37 @@ com_try_stmt(c, n)
com_try_except(c, n);
}
-static object *
-get_docstring(n)
+static node *
+get_rawdocstring(n)
node *n;
{
int i;
+ /* Label to avoid tail recursion */
+ next:
switch (TYPE(n)) {
case suite:
- if (NCH(n) == 1)
- return get_docstring(CHILD(n, 0));
- else {
- for (i = 0; i < NCH(n); i++) {
- node *ch = CHILD(n, i);
- if (TYPE(ch) == stmt)
- return get_docstring(ch);
- }
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto next;
}
- break;
-
+ /* Fall through */
case file_input:
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
- if (TYPE(ch) == stmt)
- return get_docstring(ch);
+ if (TYPE(ch) == stmt) {
+ n = ch;
+ goto next;
+ }
}
break;
case stmt:
case simple_stmt:
case small_stmt:
- return get_docstring(CHILD(n, 0));
+ n = CHILD(n, 0);
+ goto next;
case expr_stmt:
case testlist:
@@ -2247,19 +2396,31 @@ get_docstring(n)
case term:
case factor:
case power:
- if (NCH(n) == 1)
- return get_docstring(CHILD(n, 0));
+ if (NCH(n) == 1) {
+ n = CHILD(n, 0);
+ goto next;
+ }
break;
case atom:
if (TYPE(CHILD(n, 0)) == STRING)
- return parsestrplus(n);
+ return n;
break;
}
return NULL;
}
+static object *
+get_docstring(n)
+ node *n;
+{
+ n = get_rawdocstring(n);
+ if (n == NULL)
+ return NULL;
+ return parsestrplus(n);
+}
+
static void
com_suite(c, n)
struct compiling *c;
@@ -2345,6 +2506,7 @@ com_argdefs(c, n)
if (ndefs) {
com_addoparg(c, LOAD_CONST,
com_addconst(c, None));
+ com_push(c, 1);
ndefs++;
}
}
@@ -2368,8 +2530,11 @@ com_funcdef(c, n)
int i = com_addconst(c, v);
int ndefs = com_argdefs(c, n);
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
com_addoparg(c, MAKE_FUNCTION, ndefs);
+ com_pop(c, ndefs);
com_addopname(c, STORE_NAME, CHILD(n, 1));
+ com_pop(c, 1);
DECREF(v);
}
}
@@ -2384,7 +2549,9 @@ com_bases(c, n)
/* testlist: test (',' test)* [','] */
for (i = 0; i < NCH(n); i += 2)
com_node(c, CHILD(n, i));
- com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 2);
+ i = (NCH(n)+1) / 2;
+ com_addoparg(c, BUILD_TUPLE, i);
+ com_pop(c, i-1);
}
static void
@@ -2403,10 +2570,13 @@ com_classdef(c, n)
/* Push the class name on the stack */
i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
DECREF(v);
/* Push the tuple of base classes on the stack */
- if (TYPE(CHILD(n, 2)) != LPAR)
+ if (TYPE(CHILD(n, 2)) != LPAR) {
com_addoparg(c, BUILD_TUPLE, 0);
+ com_push(c, 1);
+ }
else
com_bases(c, CHILD(n, 3));
v = (object *)icompile(n, c);
@@ -2415,9 +2585,11 @@ com_classdef(c, n)
else {
i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
com_addoparg(c, MAKE_FUNCTION, 0);
com_addoparg(c, CALL_FUNCTION, 0);
com_addbyte(c, BUILD_CLASS);
+ com_pop(c, 2);
com_addopname(c, STORE_NAME, CHILD(n, 1));
DECREF(v);
}
@@ -2569,7 +2741,7 @@ com_node(c, n)
break;
default:
- fprintf(stderr, "node type %d\n", TYPE(n));
+ /* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
com_error(c, SystemError, "com_node: unexpected node type");
}
}
@@ -2584,8 +2756,10 @@ com_fpdef(c, n)
REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */
if (TYPE(CHILD(n, 0)) == LPAR)
com_fplist(c, CHILD(n, 1));
- else
+ else {
com_addoparg(c, STORE_FAST, com_newlocal(c, STR(CHILD(n, 0))));
+ com_pop(c, 1);
+ }
}
static void
@@ -2598,8 +2772,9 @@ com_fplist(c, n)
com_fpdef(c, CHILD(n, 0));
}
else {
- int i;
- com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2);
+ int i = (NCH(n)+1)/2;
+ com_addoparg(c, UNPACK_TUPLE, i);
+ com_push(c, i-1);
for (i = 0; i < NCH(n); i += 2)
com_fpdef(c, CHILD(n, i));
}
@@ -2684,6 +2859,7 @@ com_arglist(c, n)
fp = CHILD(ch, 0);
if (TYPE(fp) != NAME) {
com_addoparg(c, LOAD_FAST, ilocal);
+ com_push(c, 1);
com_fpdef(c, ch);
}
ilocal++;
@@ -2711,7 +2887,9 @@ com_file_input(c, n)
int i = com_addconst(c, doc);
DECREF(doc);
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
com_addopnamestr(c, STORE_NAME, "__doc__");
+ com_pop(c, 1);
}
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
@@ -2746,7 +2924,9 @@ compile_funcdef(c, n)
com_node(c, CHILD(n, 4));
c->c_infunction = 0;
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
}
static void
@@ -2768,6 +2948,7 @@ compile_lambdef(c, n)
ch = CHILD(n, 2);
com_node(c, ch);
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
}
static void
@@ -2789,13 +2970,17 @@ compile_classdef(c, n)
int i = com_addconst(c, doc);
DECREF(doc);
com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
com_addopnamestr(c, STORE_NAME, "__doc__");
+ com_pop(c, 1);
}
else
(void) com_addconst(c, None);
com_node(c, ch);
com_addbyte(c, LOAD_LOCALS);
+ com_push(c, 1);
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
}
static void
@@ -2814,19 +2999,24 @@ compile_node(c, n)
if (TYPE(n) != NEWLINE)
com_node(c, n);
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
c->c_interactive--;
break;
case file_input: /* A whole file, or built-in function exec() */
com_file_input(c, n);
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+ com_push(c, 1);
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
break;
case eval_input: /* Built-in function input() */
com_node(c, CHILD(n, 0));
com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
break;
case lambdef: /* anonymous function definition */
@@ -2842,7 +3032,7 @@ compile_node(c, n)
break;
default:
- fprintf(stderr, "node type %d\n", TYPE(n));
+ /* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
com_error(c, SystemError,
"compile_node: unexpected node type");
}
@@ -3001,6 +3191,7 @@ jcompile(n, filename, base)
if (!err_occurred())
co = newcodeobject(sc.c_argcount,
sc.c_nlocals,
+ sc.c_maxstacklevel,
sc.c_flags,
sc.c_code,
consts,