diff options
author | Guido van Rossum <guido@python.org> | 1997-01-17 21:04:03 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1997-01-17 21:04:03 (GMT) |
commit | 8b993a98db507cc3a75067af4c865ffc8afbada1 (patch) | |
tree | be3fd639a280cf39bc3827babdd4bd10b5eb4e59 /Python | |
parent | 3f6e408a31208d29cf867bb30496bdb1f863d310 (diff) | |
download | cpython-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).
Diffstat (limited to 'Python')
-rw-r--r-- | Python/compile.c | 315 |
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, |