summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1995-07-18 14:51:37 (GMT)
committerGuido van Rossum <guido@python.org>1995-07-18 14:51:37 (GMT)
commit681d79aaf397850778608f35585d091fa7fe370a (patch)
tree3d45bd9b84777931bba732abd1dbba484e2a64c1 /Python/compile.c
parent11a3f0c2bca1a8fdea396b989559f25fbc6fe65e (diff)
downloadcpython-681d79aaf397850778608f35585d091fa7fe370a.zip
cpython-681d79aaf397850778608f35585d091fa7fe370a.tar.gz
cpython-681d79aaf397850778608f35585d091fa7fe370a.tar.bz2
keyword arguments and faster calls
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c486
1 files changed, 280 insertions, 206 deletions
diff --git a/Python/compile.c b/Python/compile.c
index df81f8f..9f15254 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -25,8 +25,14 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Compile an expression node to intermediate code */
/* XXX TO DO:
- XXX Compute maximum needed stack sizes while compiling
+ 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 Generate simple jump for break/return outside '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 other JAR tricks?
*/
#include "allobjects.h"
@@ -44,9 +50,13 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define OFF(x) offsetof(codeobject, x)
static struct memberlist code_memberlist[] = {
+ {"co_argcount", T_INT, OFF(co_argcount), READONLY},
+ {"co_nlocals", T_INT, OFF(co_nlocals), 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},
{"co_names", T_OBJECT, OFF(co_names), READONLY},
+ {"co_varnames", T_OBJECT, OFF(co_varnames), READONLY},
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
{"co_name", T_OBJECT, OFF(co_name), READONLY},
{NULL} /* Sentinel */
@@ -69,6 +79,7 @@ code_dealloc(co)
XDECREF(co->co_names);
XDECREF(co->co_filename);
XDECREF(co->co_name);
+ XDECREF(co->co_varnames);
DEL(co);
}
@@ -97,11 +108,19 @@ code_compare(co, cp)
codeobject *co, *cp;
{
int cmp;
+ cmp = cp->co_argcount - cp->co_argcount;
+ if (cmp) return cmp;
+ cmp = cp->co_nlocals - cp->co_nlocals;
+ if (cmp) return cmp;
+ cmp = cp->co_flags - cp->co_flags;
+ if (cmp) return cmp;
cmp = cmpobject((object *)co->co_code, (object *)cp->co_code);
if (cmp) return cmp;
cmp = cmpobject(co->co_consts, cp->co_consts);
if (cmp) return cmp;
cmp = cmpobject(co->co_names, cp->co_names);
+ if (cmp) return cmp;
+ cmp = cmpobject(co->co_varnames, cp->co_varnames);
return cmp;
}
@@ -109,14 +128,17 @@ static long
code_hash(co)
codeobject *co;
{
- long h, h1, h2, h3;
+ long h, h1, h2, h3, h4;
h1 = hashobject((object *)co->co_code);
if (h1 == -1) return -1;
h2 = hashobject(co->co_consts);
if (h2 == -1) return -1;
h3 = hashobject(co->co_names);
if (h3 == -1) return -1;
- h = h1 ^ h2 ^ h3;
+ h4 = hashobject(co->co_varnames);
+ if (h4 == -1) return -1;
+ h = h1 ^ h2 ^ h3 ^ h4 ^
+ co->co_argcount ^ co->co_nlocals ^ co->co_flags;
if (h == -1) h = -2;
return h;
}
@@ -140,67 +162,64 @@ typeobject Codetype = {
};
codeobject *
-newcodeobject(code, consts, names, filename, name)
+newcodeobject(argcount, nlocals, flags,
+ code, consts, names, varnames, filename, name)
+ int argcount;
+ int nlocals;
+ int flags;
object *code;
object *consts;
object *names;
+ object *varnames;
object *filename;
object *name;
{
codeobject *co;
int i;
/* Check argument types */
- if (code == NULL || !is_stringobject(code) ||
- consts == NULL ||
- names == NULL ||
- name == NULL || !(is_stringobject(name) || name == None)) {
+ if (argcount < 0 || nlocals < 0 ||
+ code == NULL || !is_stringobject(code) ||
+ consts == NULL || !is_tupleobject(consts) ||
+ names == NULL || !is_tupleobject(names) ||
+ varnames == NULL || !is_tupleobject(varnames) ||
+ name == NULL || !is_stringobject(name) ||
+ filename == NULL || !is_stringobject(filename)) {
err_badcall();
return NULL;
}
- /* Allow two lists instead of two tuples */
- if (is_listobject(consts) && is_listobject(names)) {
- consts = listtuple(consts);
- if (consts == NULL)
- return NULL;
- names = listtuple(names);
- if (names == NULL) {
- DECREF(consts);
+ /* Make sure names and varnames are all strings */
+ for (i = gettuplesize(names); --i >= 0; ) {
+ object *v = gettupleitem(names, i);
+ if (v == NULL || !is_stringobject(v)) {
+ err_badcall();
return NULL;
}
}
- else if (!is_tupleobject(consts) && !is_tupleobject(names)) {
- err_badcall();
- return NULL;
- }
- else {
- INCREF(consts);
- INCREF(names);
- }
- /* Make sure the list of names contains only strings */
- for (i = gettuplesize(names); --i >= 0; ) {
- object *v = gettupleitem(names, i);
+ for (i = gettuplesize(varnames); --i >= 0; ) {
+ object *v = gettupleitem(varnames, i);
if (v == NULL || !is_stringobject(v)) {
- DECREF(consts);
- DECREF(names);
err_badcall();
return NULL;
}
}
co = NEWOBJ(codeobject, &Codetype);
if (co != NULL) {
+ co->co_argcount = argcount;
+ co->co_nlocals = nlocals;
+ co->co_flags = flags;
INCREF(code);
co->co_code = (stringobject *)code;
+ INCREF(consts);
co->co_consts = consts;
+ INCREF(names);
co->co_names = names;
+ INCREF(varnames);
+ co->co_varnames = varnames;
INCREF(filename);
co->co_filename = filename;
INCREF(name);
co->co_name = name;
}
- else {
- DECREF(consts);
- DECREF(names);
- }
return co;
}
@@ -213,7 +232,12 @@ struct compiling {
object *c_code; /* string */
object *c_consts; /* list of objects */
object *c_names; /* list of strings (names) */
- object *c_globals; /* dictionary */
+ object *c_globals; /* dictionary (value=None) */
+ object *c_locals; /* dictionary (value=localID) */
+ object *c_varnames; /* list (inverse of c_locals) */
+ int c_nlocals; /* index of next local */
+ int c_argcount; /* number of top-level arguments */
+ int c_flags; /* same as co_flags */
int c_nexti; /* index into c_code */
int c_errors; /* counts errors occurred */
int c_infunction; /* set when compiling a function */
@@ -257,7 +281,7 @@ block_pop(c, type)
}
-/* Prototypes */
+/* Prototype forward declarations */
static int com_init PROTO((struct compiling *, char *));
static void com_free PROTO((struct compiling *));
@@ -273,7 +297,8 @@ static int com_addconst PROTO((struct compiling *, object *));
static int com_addname PROTO((struct compiling *, object *));
static void com_addopname PROTO((struct compiling *, int, node *));
static void com_list PROTO((struct compiling *, node *, int));
-static int com_argdefs PROTO((struct compiling *, node *, int *));
+static int com_argdefs PROTO((struct compiling *, node *));
+static int com_newlocal PROTO((struct compiling *, char *));
static int
com_init(c, filename)
@@ -288,6 +313,13 @@ com_init(c, filename)
goto fail_1;
if ((c->c_globals = newdictobject()) == NULL)
goto fail_0;
+ if ((c->c_locals = newdictobject()) == NULL)
+ goto fail_00;
+ if ((c->c_varnames = newlistobject(0)) == NULL)
+ goto fail_000;
+ c->c_nlocals = 0;
+ c->c_argcount = 0;
+ c->c_flags = 0;
c->c_nexti = 0;
c->c_errors = 0;
c->c_infunction = 0;
@@ -299,6 +331,10 @@ com_init(c, filename)
c->c_name = "?";
return 1;
+ fail_000:
+ DECREF(c->c_locals);
+ fail_00:
+ DECREF(c->c_globals);
fail_0:
DECREF(c->c_names);
fail_1:
@@ -317,6 +353,8 @@ com_free(c)
XDECREF(c->c_consts);
XDECREF(c->c_names);
XDECREF(c->c_globals);
+ XDECREF(c->c_locals);
+ XDECREF(c->c_varnames);
}
static void
@@ -333,6 +371,7 @@ com_addbyte(c, byte)
int byte;
{
int len;
+ /*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
if (byte < 0 || byte > 255) {
/*
fprintf(stderr, "XXX compiling bad byte: %d\n", byte);
@@ -1221,8 +1260,7 @@ com_test(c, n)
if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
object *v;
int i;
- int argcount;
- int ndefs = com_argdefs(c, CHILD(n, 0), &argcount);
+ int ndefs = com_argdefs(c, CHILD(n, 0));
v = (object *) compile(CHILD(n, 0), c->c_filename);
if (v == NULL) {
c->c_errors++;
@@ -1233,9 +1271,7 @@ com_test(c, n)
DECREF(v);
}
com_addoparg(c, LOAD_CONST, i);
- com_addbyte(c, BUILD_FUNCTION);
- if (ndefs > 0)
- com_addoparg(c, SET_FUNC_ARGS, argcount);
+ com_addoparg(c, MAKE_FUNCTION, ndefs);
}
else {
int anchor = 0;
@@ -1537,16 +1573,12 @@ com_raise_stmt(c, n)
{
REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
com_node(c, CHILD(n, 1));
- if (NCH(n) > 3)
+ if (NCH(n) > 3) {
com_node(c, CHILD(n, 3));
- else
- com_addoparg(c, LOAD_CONST, com_addconst(c, None));
- if (NCH(n) > 5) {
- com_node(c, CHILD(n, 5));
- com_addoparg(c, RAISE_VARARGS, 3);
+ if (NCH(n) > 5)
+ com_node(c, CHILD(n, 5));
}
- else
- com_addbyte(c, RAISE_EXCEPTION);
+ com_addoparg(c, RAISE_VARARGS, NCH(n)/2);
}
static void
@@ -1585,9 +1617,67 @@ com_global_stmt(c, n)
REQ(n, global_stmt);
/* 'global' NAME (',' NAME)* */
for (i = 1; i < NCH(n); i += 2) {
- if (dictinsert(c->c_globals, STR(CHILD(n, i)), None) != 0)
+ char *s = STR(CHILD(n, i));
+ if (dictlookup(c->c_locals, s) != NULL) {
+ err_setstr(SyntaxError, "name is local and global");
+ c->c_errors++;
+ }
+ else if (dictinsert(c->c_globals, s, None) != 0)
+ c->c_errors++;
+ }
+}
+
+static int
+com_newlocal_o(c, nameval)
+ struct compiling *c;
+ object *nameval;
+{
+ int i;
+ object *ival;
+ if (getlistsize(c->c_varnames) != c->c_nlocals) {
+ /* This is usually caused by an error on a previous call */
+ if (c->c_errors == 0) {
+ err_setstr(SystemError, "mixed up var name/index");
c->c_errors++;
+ }
+ return 0;
+ }
+ ival = newintobject(i = c->c_nlocals++);
+ if (ival == NULL)
+ c->c_errors++;
+ else if (mappinginsert(c->c_locals, nameval, ival) != 0)
+ c->c_errors++;
+ else if (addlistitem(c->c_varnames, nameval) != 0)
+ c->c_errors++;
+ XDECREF(ival);
+ return i;
+}
+
+static int
+com_addlocal_o(c, nameval)
+ struct compiling *c;
+ object *nameval;
+{
+ object *ival = mappinglookup(c->c_locals, nameval);
+ if (ival != NULL)
+ return getintvalue(ival);
+ return com_newlocal_o(c, nameval);
+}
+
+static int
+com_newlocal(c, name)
+ struct compiling *c;
+ char *name;
+{
+ object *nameval = newstringobject(name);
+ int i;
+ if (nameval == NULL) {
+ c->c_errors++;
+ return 0;
}
+ i = com_newlocal_o(c, nameval);
+ DECREF(nameval);
+ return i;
}
#define strequ(a, b) (strcmp((a), (b)) == 0)
@@ -2019,12 +2109,11 @@ com_continue_stmt(c, n)
}
static int
-com_argdefs(c, n, argcount_return)
+com_argdefs(c, n)
struct compiling *c;
node *n;
- int *argcount_return;
{
- int i, nch, nargs, ndefs, star;
+ int i, nch, nargs, ndefs;
if (TYPE(n) == lambdef) {
/* lambdef: 'lambda' [varargslist] ':' test */
n = CHILD(n, 1);
@@ -2036,14 +2125,13 @@ com_argdefs(c, n, argcount_return)
n = CHILD(n, 1);
}
if (TYPE(n) != varargslist)
- return -1;
+ return 0;
/* varargslist:
- (fpdef ['=' test] ',')* '*' NAME ....... |
+ (fpdef ['=' test] ',')* '*' ....... |
fpdef ['=' test] (',' fpdef ['=' test])* [','] */
nch = NCH(n);
nargs = 0;
ndefs = 0;
- star = 0;
for (i = 0; i < nch; i++) {
int t;
if (TYPE(CHILD(n, i)) == STAR)
@@ -2073,11 +2161,6 @@ com_argdefs(c, n, argcount_return)
if (t != COMMA)
break;
}
- if (star)
- nargs ^= 0x4000;
- *argcount_return = nargs;
- if (ndefs > 0)
- com_addoparg(c, BUILD_TUPLE, ndefs);
return ndefs;
}
@@ -2093,12 +2176,9 @@ com_funcdef(c, n)
c->c_errors++;
else {
int i = com_addconst(c, v);
- int argcount;
- int ndefs = com_argdefs(c, n, &argcount);
+ int ndefs = com_argdefs(c, n);
com_addoparg(c, LOAD_CONST, i);
- com_addbyte(c, BUILD_FUNCTION);
- if (ndefs > 0)
- com_addoparg(c, SET_FUNC_ARGS, argcount);
+ com_addoparg(c, MAKE_FUNCTION, ndefs);
com_addopname(c, STORE_NAME, CHILD(n, 1));
DECREF(v);
}
@@ -2145,8 +2225,8 @@ com_classdef(c, n)
else {
i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i);
- com_addbyte(c, BUILD_FUNCTION);
- com_addbyte(c, UNARY_CALL);
+ com_addoparg(c, MAKE_FUNCTION, 0);
+ com_addoparg(c, CALL_FUNCTION, 0);
com_addbyte(c, BUILD_CLASS);
com_addopname(c, STORE_NAME, CHILD(n, 1));
DECREF(v);
@@ -2312,7 +2392,7 @@ com_fpdef(c, n)
if (TYPE(CHILD(n, 0)) == LPAR)
com_fplist(c, CHILD(n, 1));
else
- com_addopname(c, STORE_NAME, CHILD(n, 0));
+ com_addoparg(c, STORE_FAST, com_newlocal(c, STR(CHILD(n, 0))));
}
static void
@@ -2337,53 +2417,87 @@ com_arglist(c, n)
struct compiling *c;
node *n;
{
- int nch, op, nargs, i, t;
+ int nch, i;
+ int complex = 0;
REQ(n, varargslist);
/* varargslist:
- (fpdef ['=' test] ',')* '*' NAME ..... |
- fpdef ['=' test] (',' fpdef ['=' test])* [','] */
+ (fpdef ['=' test] ',')* (fpdef ['=' test] | '*' .....) */
nch = NCH(n);
- op = UNPACK_ARG;
- nargs = 0;
+ /* Enter all arguments in table of locals */
for (i = 0; i < nch; i++) {
- if (TYPE(CHILD(n, i)) == STAR) {
- nch = i;
- if (TYPE(CHILD(n, i+1)) != STAR)
- op = UNPACK_VARARG;
+ node *ch = CHILD(n, i);
+ node *fp;
+ char *name;
+ if (TYPE(ch) == STAR)
break;
+ REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
+ fp = CHILD(ch, 0);
+ if (TYPE(fp) == NAME)
+ name = STR(fp);
+ else {
+ name = "";
+ complex= 1;
}
- nargs++;
- i++;
- if (i >= nch)
+ com_newlocal(c, name);
+ c->c_argcount++;
+ if (++i >= nch)
break;
- t = TYPE(CHILD(n, i));
- if (t == EQUAL) {
+ ch = CHILD(n, i);
+ if (TYPE(ch) == EQUAL)
i += 2;
- if (i >= nch)
- break;
- t = TYPE(CHILD(n, i));
+ else
+ REQ(ch, COMMA);
+ }
+ /* Handle *arguments */
+ if (i < nch) {
+ node *ch;
+ ch = CHILD(n, i);
+ REQ(ch, STAR);
+ ch = CHILD(n, i+1);
+ if (TYPE(ch) == NAME) {
+ c->c_flags |= CO_VARARGS;
+ i += 3;
+ com_newlocal(c, STR(ch));
}
- if (t != COMMA)
- break;
}
- com_addoparg(c, op, nargs);
- for (i = 0; i < nch; i++) {
- com_fpdef(c, CHILD(n, i));
- i++;
- if (i >= nch)
- break;
- t = TYPE(CHILD(n, i));
- if (t == EQUAL) {
- i += 2;
- if (i >= nch)
+ /* Handle **keywords */
+ if (i < nch) {
+ node *ch;
+ ch = CHILD(n, i);
+ REQ(ch, STAR);
+ ch = CHILD(n, i+1);
+ REQ(ch, STAR);
+ ch = CHILD(n, i+2);
+ REQ(ch, NAME);
+ c->c_flags |= CO_VARKEYWORDS;
+ com_newlocal(c, STR(ch));
+ }
+ if (complex) {
+ /* Generate code for complex arguments only after
+ having counted the simple arguments */
+ int ilocal = 0;
+ for (i = 0; i < nch; i++) {
+ node *ch = CHILD(n, i);
+ node *fp;
+ char *name;
+ if (TYPE(ch) == STAR)
break;
- t = TYPE(CHILD(n, i));
+ REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
+ fp = CHILD(ch, 0);
+ if (TYPE(fp) != NAME) {
+ com_addoparg(c, LOAD_FAST, ilocal);
+ com_fpdef(c, ch);
+ }
+ ilocal++;
+ if (++i >= nch)
+ break;
+ ch = CHILD(n, i);
+ if (TYPE(ch) == EQUAL)
+ i += 2;
+ else
+ REQ(ch, COMMA);
}
- if (t != COMMA)
- break;
}
- if (op == UNPACK_VARARG)
- com_addopname(c, STORE_NAME, CHILD(n, nch+1));
}
static void
@@ -2424,12 +2538,11 @@ compile_funcdef(c, n)
(void) com_addconst(c, doc);
DECREF(doc);
}
- com_addoparg(c, RESERVE_FAST, com_addconst(c, None)); /* Patched! */
+ else
+ (void) com_addconst(c, None); /* No docstring */
ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
ch = CHILD(ch, 1); /* ')' | varargslist */
- if (TYPE(ch) == RPAR)
- com_addoparg(c, UNPACK_ARG, 0);
- else
+ if (TYPE(ch) == varargslist)
com_arglist(c, ch);
c->c_infunction = 1;
com_node(c, CHILD(n, 4));
@@ -2444,21 +2557,18 @@ compile_lambdef(c, n)
node *n;
{
node *ch;
- REQ(n, lambdef); /* lambdef: 'lambda' [parameters] ':' test */
+ REQ(n, lambdef); /* lambdef: 'lambda' [varargslist] ':' test */
c->c_name = "<lambda>";
ch = CHILD(n, 1);
- (void) com_addconst(c, None);
- if (TYPE(ch) == COLON) {
- com_addoparg(c, UNPACK_ARG, 0);
- com_node(c, CHILD(n, 2));
- }
- else {
- com_addoparg(c, RESERVE_FAST, com_addconst(c, None));
+ (void) com_addconst(c, None); /* No docstring */
+ if (TYPE(ch) == varargslist) {
com_arglist(c, ch);
- com_node(c, CHILD(n, 3));
+ ch = CHILD(n, 3);
}
-
+ else
+ ch = CHILD(n, 2);
+ com_node(c, ch);
com_addbyte(c, RETURN_VALUE);
}
@@ -2544,34 +2654,31 @@ compile_node(c, n)
The latter instructions are much faster because they don't need to
look up the variable name in a dictionary.
- To find all local variables, we check all STORE_NAME, IMPORT_FROM and
- DELETE_NAME instructions. This yields all local variables, including
- arguments, function definitions, class definitions and import
- statements.
+ To find all local variables, we check all STORE_NAME, IMPORT_FROM
+ and DELETE_NAME instructions. This yields all local variables,
+ function definitions, class definitions and import statements.
+ Argument names have already been entered into the list by the
+ special processing for the argument list.
All remaining LOAD_NAME instructions must refer to non-local (global
or builtin) variables, so are replaced by LOAD_GLOBAL.
There are two problems: 'from foo import *' and 'exec' may introduce
local variables that we can't know while compiling. If this is the
- case, we don't optimize at all (this rarely happens, since exec is
- rare, & this form of import statement is mostly used at the module
- level).
+ case, we can still optimize bona fide locals (since those
+ statements will be surrounded by fast_2_locals() and
+ locals_2_fast()), but we can't change LOAD_NAME to LOAD_GLOBAL.
- NB: this modifies the string object co->co_code!
-*/
+ NB: this modifies the string object c->c_code! */
static void
optimize(c)
struct compiling *c;
{
unsigned char *next_instr, *cur_instr;
- object *locals;
- int nlocals;
int opcode;
int oparg;
object *name;
- int fast_reserved;
object *error_type, *error_value, *error_traceback;
#define NEXTOP() (*next_instr++)
@@ -2579,53 +2686,33 @@ optimize(c)
#define GETITEM(v, i) (getlistitem((v), (i)))
#define GETNAMEOBJ(i) (GETITEM(c->c_names, (i)))
- locals = newdictobject();
- if (locals == NULL) {
- c->c_errors++;
- return;
- }
- nlocals = 0;
-
err_fetch(&error_type, &error_value, &error_traceback);
+
+ c->c_flags |= CO_OPTIMIZED;
next_instr = (unsigned char *) getstringvalue(c->c_code);
for (;;) {
opcode = NEXTOP();
if (opcode == STOP_CODE)
break;
- if (opcode == EXEC_STMT)
- goto end; /* Don't optimize if exec present */
if (HAS_ARG(opcode))
oparg = NEXTARG();
- if (opcode == STORE_NAME || opcode == DELETE_NAME ||
- opcode == IMPORT_FROM) {
- object *v;
- name = GETNAMEOBJ(oparg);
- if (dict2lookup(locals, name) != NULL)
- continue;
- err_clear();
- v = newintobject(nlocals);
- if (v == NULL) {
- c->c_errors++;
- goto err;
- }
- nlocals++;
- if (dict2insert(locals, name, v) != 0) {
- DECREF(v);
- c->c_errors++;
- goto err;
- }
- DECREF(v);
+ switch (opcode) {
+ case STORE_NAME:
+ case DELETE_NAME:
+ case IMPORT_FROM:
+ com_addlocal_o(c, GETNAMEOBJ(oparg));
+ break;
+ case EXEC_STMT:
+ c->c_flags &= ~CO_OPTIMIZED;
+ break;
}
}
- if (dictlookup(locals, "*") != NULL) {
- /* Don't optimize anything */
- goto end;
- }
+ if (dictlookup(c->c_locals, "*") != NULL)
+ c->c_flags &= ~CO_OPTIMIZED;
next_instr = (unsigned char *) getstringvalue(c->c_code);
- fast_reserved = 0;
for (;;) {
cur_instr = next_instr;
opcode = NEXTOP();
@@ -2633,45 +2720,17 @@ optimize(c)
break;
if (HAS_ARG(opcode))
oparg = NEXTARG();
- if (opcode == RESERVE_FAST) {
- int i;
- object *localmap = newtupleobject(nlocals);
- int pos;
- object *key, *value;
- if (localmap == NULL) { /* XXX mask error */
- err_clear();
- continue;
- }
- pos = 0;
- while (mappinggetnext(locals, &pos, &key, &value)) {
- int j;
- if (!is_intobject(value))
- continue;
- j = getintvalue(value);
- if (0 <= j && j < nlocals) {
- INCREF(key);
- settupleitem(localmap, j, key);
- }
- }
- i = com_addconst(c, localmap);
- cur_instr[1] = i & 0xff;
- cur_instr[2] = (i>>8) & 0xff;
- fast_reserved = 1;
- DECREF(localmap);
- continue;
- }
- if (!fast_reserved)
- continue;
if (opcode == LOAD_NAME ||
opcode == STORE_NAME ||
opcode == DELETE_NAME) {
object *v;
int i;
name = GETNAMEOBJ(oparg);
- v = dict2lookup(locals, name);
+ v = dict2lookup(c->c_locals, name);
if (v == NULL) {
err_clear();
- if (opcode == LOAD_NAME)
+ if (opcode == LOAD_NAME &&
+ (c->c_flags&CO_OPTIMIZED))
cur_instr[0] = LOAD_GLOBAL;
continue;
}
@@ -2686,10 +2745,8 @@ optimize(c)
}
}
- end:
- err_restore(error_type, error_value, error_traceback);
- err:
- DECREF(locals);
+ if (c->c_errors == 0)
+ err_restore(error_type, error_value, error_traceback);
}
codeobject *
@@ -2703,18 +2760,35 @@ compile(n, filename)
return NULL;
compile_node(&sc, n);
com_done(&sc);
- if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0)
+ if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0) {
optimize(&sc);
+ sc.c_flags |= CO_NEWLOCALS;
+ }
+ else if (TYPE(n) == classdef)
+ sc.c_flags |= CO_NEWLOCALS;
co = NULL;
if (sc.c_errors == 0) {
- object *v, *w;
- v = newstringobject(sc.c_filename);
- w = newstringobject(sc.c_name);
- if (v != NULL && w != NULL)
- co = newcodeobject(sc.c_code, sc.c_consts,
- sc.c_names, v, w);
- XDECREF(v);
- XDECREF(w);
+ object *consts, *names, *varnames, *filename, *name;
+ consts = listtuple(sc.c_consts);
+ names = listtuple(sc.c_names);
+ varnames = listtuple(sc.c_varnames);
+ filename = newstringobject(sc.c_filename);
+ name = newstringobject(sc.c_name);
+ if (!err_occurred())
+ co = newcodeobject(sc.c_argcount,
+ sc.c_nlocals,
+ sc.c_flags,
+ sc.c_code,
+ consts,
+ names,
+ varnames,
+ filename,
+ name);
+ XDECREF(consts);
+ XDECREF(names);
+ XDECREF(varnames);
+ XDECREF(filename);
+ XDECREF(name);
}
com_free(&sc);
return co;