keyword arguments and faster calls

This commit is contained in:
Guido van Rossum 1995-07-18 14:51:37 +00:00
parent 11a3f0c2bc
commit 681d79aaf3
7 changed files with 782 additions and 605 deletions

View File

@ -80,15 +80,20 @@ builtin_apply(self, args)
object *self; object *self;
object *args; object *args;
{ {
object *func, *alist; object *func, *alist, *kwdict = NULL;
if (!newgetargs(args, "OO:apply", &func, &alist)) if (!newgetargs(args, "O|OO:apply", &func, &alist, &kwdict))
return NULL; return NULL;
if (!is_tupleobject(alist)) { if (alist != NULL && !is_tupleobject(alist)) {
err_setstr(TypeError, "apply() 2nd argument must be tuple"); err_setstr(TypeError, "apply() 2nd argument must be tuple");
return NULL; return NULL;
} }
return call_object(func, alist); if (kwdict != NULL && !is_dictobject(kwdict)) {
err_setstr(TypeError,
"apply() 3rd argument must be dictionary");
return NULL;
}
return PyEval_CallObjectWithKeywords(func, alist, kwdict);
} }
static object * static object *
@ -373,8 +378,7 @@ builtin_eval(self, args)
return NULL; return NULL;
} }
if (is_codeobject(cmd)) if (is_codeobject(cmd))
return eval_code((codeobject *) cmd, globals, locals, return eval_code((codeobject *) cmd, globals, locals);
(object *)NULL, (object *)NULL);
if (!is_stringobject(cmd)) { if (!is_stringobject(cmd)) {
err_setstr(TypeError, err_setstr(TypeError,
"eval() argument 1 must be string or code object"); "eval() argument 1 must be string or code object");

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,14 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Compile an expression node to intermediate code */ /* Compile an expression node to intermediate code */
/* XXX TO DO: /* 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 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" #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) #define OFF(x) offsetof(codeobject, x)
static struct memberlist code_memberlist[] = { 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_code", T_OBJECT, OFF(co_code), READONLY},
{"co_consts", T_OBJECT, OFF(co_consts), READONLY}, {"co_consts", T_OBJECT, OFF(co_consts), READONLY},
{"co_names", T_OBJECT, OFF(co_names), 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_filename", T_OBJECT, OFF(co_filename), READONLY},
{"co_name", T_OBJECT, OFF(co_name), READONLY}, {"co_name", T_OBJECT, OFF(co_name), READONLY},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
@ -69,6 +79,7 @@ code_dealloc(co)
XDECREF(co->co_names); XDECREF(co->co_names);
XDECREF(co->co_filename); XDECREF(co->co_filename);
XDECREF(co->co_name); XDECREF(co->co_name);
XDECREF(co->co_varnames);
DEL(co); DEL(co);
} }
@ -97,11 +108,19 @@ code_compare(co, cp)
codeobject *co, *cp; codeobject *co, *cp;
{ {
int cmp; 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); cmp = cmpobject((object *)co->co_code, (object *)cp->co_code);
if (cmp) return cmp; if (cmp) return cmp;
cmp = cmpobject(co->co_consts, cp->co_consts); cmp = cmpobject(co->co_consts, cp->co_consts);
if (cmp) return cmp; if (cmp) return cmp;
cmp = cmpobject(co->co_names, cp->co_names); cmp = cmpobject(co->co_names, cp->co_names);
if (cmp) return cmp;
cmp = cmpobject(co->co_varnames, cp->co_varnames);
return cmp; return cmp;
} }
@ -109,14 +128,17 @@ static long
code_hash(co) code_hash(co)
codeobject *co; codeobject *co;
{ {
long h, h1, h2, h3; long h, h1, h2, h3, h4;
h1 = hashobject((object *)co->co_code); h1 = hashobject((object *)co->co_code);
if (h1 == -1) return -1; if (h1 == -1) return -1;
h2 = hashobject(co->co_consts); h2 = hashobject(co->co_consts);
if (h2 == -1) return -1; if (h2 == -1) return -1;
h3 = hashobject(co->co_names); h3 = hashobject(co->co_names);
if (h3 == -1) return -1; 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; if (h == -1) h = -2;
return h; return h;
} }
@ -140,67 +162,64 @@ typeobject Codetype = {
}; };
codeobject * 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 *code;
object *consts; object *consts;
object *names; object *names;
object *varnames;
object *filename; object *filename;
object *name; object *name;
{ {
codeobject *co; codeobject *co;
int i; int i;
/* Check argument types */ /* Check argument types */
if (code == NULL || !is_stringobject(code) || if (argcount < 0 || nlocals < 0 ||
consts == NULL || code == NULL || !is_stringobject(code) ||
names == NULL || consts == NULL || !is_tupleobject(consts) ||
name == NULL || !(is_stringobject(name) || name == None)) { names == NULL || !is_tupleobject(names) ||
varnames == NULL || !is_tupleobject(varnames) ||
name == NULL || !is_stringobject(name) ||
filename == NULL || !is_stringobject(filename)) {
err_badcall(); err_badcall();
return NULL; return NULL;
} }
/* Allow two lists instead of two tuples */ /* Make sure names and varnames are all strings */
if (is_listobject(consts) && is_listobject(names)) {
consts = listtuple(consts);
if (consts == NULL)
return NULL;
names = listtuple(names);
if (names == NULL) {
DECREF(consts);
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; ) { for (i = gettuplesize(names); --i >= 0; ) {
object *v = gettupleitem(names, i); object *v = gettupleitem(names, i);
if (v == NULL || !is_stringobject(v)) { if (v == NULL || !is_stringobject(v)) {
DECREF(consts); err_badcall();
DECREF(names); return NULL;
}
}
for (i = gettuplesize(varnames); --i >= 0; ) {
object *v = gettupleitem(varnames, i);
if (v == NULL || !is_stringobject(v)) {
err_badcall(); err_badcall();
return NULL; return NULL;
} }
} }
co = NEWOBJ(codeobject, &Codetype); co = NEWOBJ(codeobject, &Codetype);
if (co != NULL) { if (co != NULL) {
co->co_argcount = argcount;
co->co_nlocals = nlocals;
co->co_flags = flags;
INCREF(code); INCREF(code);
co->co_code = (stringobject *)code; co->co_code = (stringobject *)code;
INCREF(consts);
co->co_consts = consts; co->co_consts = consts;
INCREF(names);
co->co_names = names; co->co_names = names;
INCREF(varnames);
co->co_varnames = varnames;
INCREF(filename); INCREF(filename);
co->co_filename = filename; co->co_filename = filename;
INCREF(name); INCREF(name);
co->co_name = name; co->co_name = name;
} }
else {
DECREF(consts);
DECREF(names);
}
return co; return co;
} }
@ -213,7 +232,12 @@ struct compiling {
object *c_code; /* string */ object *c_code; /* string */
object *c_consts; /* list of objects */ object *c_consts; /* list of objects */
object *c_names; /* list of strings (names) */ 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_nexti; /* index into c_code */
int c_errors; /* counts errors occurred */ int c_errors; /* counts errors occurred */
int c_infunction; /* set when compiling a function */ 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 int com_init PROTO((struct compiling *, char *));
static void com_free PROTO((struct compiling *)); 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 int com_addname PROTO((struct compiling *, object *));
static void com_addopname PROTO((struct compiling *, int, node *)); static void com_addopname PROTO((struct compiling *, int, node *));
static void com_list PROTO((struct compiling *, node *, int)); 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 static int
com_init(c, filename) com_init(c, filename)
@ -288,6 +313,13 @@ com_init(c, filename)
goto fail_1; goto fail_1;
if ((c->c_globals = newdictobject()) == NULL) if ((c->c_globals = newdictobject()) == NULL)
goto fail_0; 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_nexti = 0;
c->c_errors = 0; c->c_errors = 0;
c->c_infunction = 0; c->c_infunction = 0;
@ -299,6 +331,10 @@ com_init(c, filename)
c->c_name = "?"; c->c_name = "?";
return 1; return 1;
fail_000:
DECREF(c->c_locals);
fail_00:
DECREF(c->c_globals);
fail_0: fail_0:
DECREF(c->c_names); DECREF(c->c_names);
fail_1: fail_1:
@ -317,6 +353,8 @@ com_free(c)
XDECREF(c->c_consts); XDECREF(c->c_consts);
XDECREF(c->c_names); XDECREF(c->c_names);
XDECREF(c->c_globals); XDECREF(c->c_globals);
XDECREF(c->c_locals);
XDECREF(c->c_varnames);
} }
static void static void
@ -333,6 +371,7 @@ com_addbyte(c, byte)
int byte; int byte;
{ {
int len; int len;
/*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
if (byte < 0 || byte > 255) { if (byte < 0 || byte > 255) {
/* /*
fprintf(stderr, "XXX compiling bad byte: %d\n", byte); 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) { if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
object *v; object *v;
int i; int i;
int argcount; int ndefs = com_argdefs(c, CHILD(n, 0));
int ndefs = com_argdefs(c, CHILD(n, 0), &argcount);
v = (object *) compile(CHILD(n, 0), c->c_filename); v = (object *) compile(CHILD(n, 0), c->c_filename);
if (v == NULL) { if (v == NULL) {
c->c_errors++; c->c_errors++;
@ -1233,9 +1271,7 @@ com_test(c, n)
DECREF(v); DECREF(v);
} }
com_addoparg(c, LOAD_CONST, i); com_addoparg(c, LOAD_CONST, i);
com_addbyte(c, BUILD_FUNCTION); com_addoparg(c, MAKE_FUNCTION, ndefs);
if (ndefs > 0)
com_addoparg(c, SET_FUNC_ARGS, argcount);
} }
else { else {
int anchor = 0; int anchor = 0;
@ -1537,16 +1573,12 @@ com_raise_stmt(c, n)
{ {
REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */ REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
com_node(c, CHILD(n, 1)); com_node(c, CHILD(n, 1));
if (NCH(n) > 3) if (NCH(n) > 3) {
com_node(c, CHILD(n, 3)); com_node(c, CHILD(n, 3));
else if (NCH(n) > 5)
com_addoparg(c, LOAD_CONST, com_addconst(c, None)); com_node(c, CHILD(n, 5));
if (NCH(n) > 5) {
com_node(c, CHILD(n, 5));
com_addoparg(c, RAISE_VARARGS, 3);
} }
else com_addoparg(c, RAISE_VARARGS, NCH(n)/2);
com_addbyte(c, RAISE_EXCEPTION);
} }
static void static void
@ -1585,11 +1617,69 @@ com_global_stmt(c, n)
REQ(n, global_stmt); REQ(n, global_stmt);
/* 'global' NAME (',' NAME)* */ /* 'global' NAME (',' NAME)* */
for (i = 1; i < NCH(n); i += 2) { 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++; 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) #define strequ(a, b) (strcmp((a), (b)) == 0)
static void static void
@ -2019,12 +2109,11 @@ com_continue_stmt(c, n)
} }
static int static int
com_argdefs(c, n, argcount_return) com_argdefs(c, n)
struct compiling *c; struct compiling *c;
node *n; node *n;
int *argcount_return;
{ {
int i, nch, nargs, ndefs, star; int i, nch, nargs, ndefs;
if (TYPE(n) == lambdef) { if (TYPE(n) == lambdef) {
/* lambdef: 'lambda' [varargslist] ':' test */ /* lambdef: 'lambda' [varargslist] ':' test */
n = CHILD(n, 1); n = CHILD(n, 1);
@ -2036,14 +2125,13 @@ com_argdefs(c, n, argcount_return)
n = CHILD(n, 1); n = CHILD(n, 1);
} }
if (TYPE(n) != varargslist) if (TYPE(n) != varargslist)
return -1; return 0;
/* varargslist: /* varargslist:
(fpdef ['=' test] ',')* '*' NAME ....... | (fpdef ['=' test] ',')* '*' ....... |
fpdef ['=' test] (',' fpdef ['=' test])* [','] */ fpdef ['=' test] (',' fpdef ['=' test])* [','] */
nch = NCH(n); nch = NCH(n);
nargs = 0; nargs = 0;
ndefs = 0; ndefs = 0;
star = 0;
for (i = 0; i < nch; i++) { for (i = 0; i < nch; i++) {
int t; int t;
if (TYPE(CHILD(n, i)) == STAR) if (TYPE(CHILD(n, i)) == STAR)
@ -2073,11 +2161,6 @@ com_argdefs(c, n, argcount_return)
if (t != COMMA) if (t != COMMA)
break; break;
} }
if (star)
nargs ^= 0x4000;
*argcount_return = nargs;
if (ndefs > 0)
com_addoparg(c, BUILD_TUPLE, ndefs);
return ndefs; return ndefs;
} }
@ -2093,12 +2176,9 @@ com_funcdef(c, n)
c->c_errors++; c->c_errors++;
else { else {
int i = com_addconst(c, v); int i = com_addconst(c, v);
int argcount; int ndefs = com_argdefs(c, n);
int ndefs = com_argdefs(c, n, &argcount);
com_addoparg(c, LOAD_CONST, i); com_addoparg(c, LOAD_CONST, i);
com_addbyte(c, BUILD_FUNCTION); com_addoparg(c, MAKE_FUNCTION, ndefs);
if (ndefs > 0)
com_addoparg(c, SET_FUNC_ARGS, argcount);
com_addopname(c, STORE_NAME, CHILD(n, 1)); com_addopname(c, STORE_NAME, CHILD(n, 1));
DECREF(v); DECREF(v);
} }
@ -2145,8 +2225,8 @@ com_classdef(c, n)
else { else {
i = com_addconst(c, v); i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i); com_addoparg(c, LOAD_CONST, i);
com_addbyte(c, BUILD_FUNCTION); com_addoparg(c, MAKE_FUNCTION, 0);
com_addbyte(c, UNARY_CALL); com_addoparg(c, CALL_FUNCTION, 0);
com_addbyte(c, BUILD_CLASS); com_addbyte(c, BUILD_CLASS);
com_addopname(c, STORE_NAME, CHILD(n, 1)); com_addopname(c, STORE_NAME, CHILD(n, 1));
DECREF(v); DECREF(v);
@ -2312,7 +2392,7 @@ com_fpdef(c, n)
if (TYPE(CHILD(n, 0)) == LPAR) if (TYPE(CHILD(n, 0)) == LPAR)
com_fplist(c, CHILD(n, 1)); com_fplist(c, CHILD(n, 1));
else else
com_addopname(c, STORE_NAME, CHILD(n, 0)); com_addoparg(c, STORE_FAST, com_newlocal(c, STR(CHILD(n, 0))));
} }
static void static void
@ -2337,53 +2417,87 @@ com_arglist(c, n)
struct compiling *c; struct compiling *c;
node *n; node *n;
{ {
int nch, op, nargs, i, t; int nch, i;
int complex = 0;
REQ(n, varargslist); REQ(n, varargslist);
/* varargslist: /* varargslist:
(fpdef ['=' test] ',')* '*' NAME ..... | (fpdef ['=' test] ',')* (fpdef ['=' test] | '*' .....) */
fpdef ['=' test] (',' fpdef ['=' test])* [','] */
nch = NCH(n); nch = NCH(n);
op = UNPACK_ARG; /* Enter all arguments in table of locals */
nargs = 0;
for (i = 0; i < nch; i++) { for (i = 0; i < nch; i++) {
if (TYPE(CHILD(n, i)) == STAR) { node *ch = CHILD(n, i);
nch = i; node *fp;
if (TYPE(CHILD(n, i+1)) != STAR) char *name;
op = UNPACK_VARARG; if (TYPE(ch) == STAR)
break; break;
REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
fp = CHILD(ch, 0);
if (TYPE(fp) == NAME)
name = STR(fp);
else {
name = "";
complex= 1;
} }
nargs++; com_newlocal(c, name);
i++; c->c_argcount++;
if (i >= nch) if (++i >= nch)
break; break;
t = TYPE(CHILD(n, i)); ch = CHILD(n, i);
if (t == EQUAL) { if (TYPE(ch) == EQUAL)
i += 2; i += 2;
if (i >= nch) else
break; REQ(ch, COMMA);
t = TYPE(CHILD(n, i));
}
if (t != COMMA)
break;
} }
com_addoparg(c, op, nargs); /* Handle *arguments */
for (i = 0; i < nch; i++) { if (i < nch) {
com_fpdef(c, CHILD(n, i)); node *ch;
i++; ch = CHILD(n, i);
if (i >= nch) REQ(ch, STAR);
break; ch = CHILD(n, i+1);
t = TYPE(CHILD(n, i)); if (TYPE(ch) == NAME) {
if (t == EQUAL) { c->c_flags |= CO_VARARGS;
i += 2; i += 3;
if (i >= nch) com_newlocal(c, STR(ch));
break; }
t = TYPE(CHILD(n, i)); }
/* 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;
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 static void
@ -2424,12 +2538,11 @@ compile_funcdef(c, n)
(void) com_addconst(c, doc); (void) com_addconst(c, doc);
DECREF(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(n, 2); /* parameters: '(' [varargslist] ')' */
ch = CHILD(ch, 1); /* ')' | varargslist */ ch = CHILD(ch, 1); /* ')' | varargslist */
if (TYPE(ch) == RPAR) if (TYPE(ch) == varargslist)
com_addoparg(c, UNPACK_ARG, 0);
else
com_arglist(c, ch); com_arglist(c, ch);
c->c_infunction = 1; c->c_infunction = 1;
com_node(c, CHILD(n, 4)); com_node(c, CHILD(n, 4));
@ -2444,21 +2557,18 @@ compile_lambdef(c, n)
node *n; node *n;
{ {
node *ch; node *ch;
REQ(n, lambdef); /* lambdef: 'lambda' [parameters] ':' test */ REQ(n, lambdef); /* lambdef: 'lambda' [varargslist] ':' test */
c->c_name = "<lambda>"; c->c_name = "<lambda>";
ch = CHILD(n, 1); ch = CHILD(n, 1);
(void) com_addconst(c, None); (void) com_addconst(c, None); /* No docstring */
if (TYPE(ch) == COLON) { if (TYPE(ch) == varargslist) {
com_addoparg(c, UNPACK_ARG, 0);
com_node(c, CHILD(n, 2));
}
else {
com_addoparg(c, RESERVE_FAST, com_addconst(c, None));
com_arglist(c, ch); 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); 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 The latter instructions are much faster because they don't need to
look up the variable name in a dictionary. look up the variable name in a dictionary.
To find all local variables, we check all STORE_NAME, IMPORT_FROM and To find all local variables, we check all STORE_NAME, IMPORT_FROM
DELETE_NAME instructions. This yields all local variables, including and DELETE_NAME instructions. This yields all local variables,
arguments, function definitions, class definitions and import function definitions, class definitions and import statements.
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 All remaining LOAD_NAME instructions must refer to non-local (global
or builtin) variables, so are replaced by LOAD_GLOBAL. or builtin) variables, so are replaced by LOAD_GLOBAL.
There are two problems: 'from foo import *' and 'exec' may introduce There are two problems: 'from foo import *' and 'exec' may introduce
local variables that we can't know while compiling. If this is the 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 case, we can still optimize bona fide locals (since those
rare, & this form of import statement is mostly used at the module statements will be surrounded by fast_2_locals() and
level). 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 static void
optimize(c) optimize(c)
struct compiling *c; struct compiling *c;
{ {
unsigned char *next_instr, *cur_instr; unsigned char *next_instr, *cur_instr;
object *locals;
int nlocals;
int opcode; int opcode;
int oparg; int oparg;
object *name; object *name;
int fast_reserved;
object *error_type, *error_value, *error_traceback; object *error_type, *error_value, *error_traceback;
#define NEXTOP() (*next_instr++) #define NEXTOP() (*next_instr++)
@ -2579,53 +2686,33 @@ optimize(c)
#define GETITEM(v, i) (getlistitem((v), (i))) #define GETITEM(v, i) (getlistitem((v), (i)))
#define GETNAMEOBJ(i) (GETITEM(c->c_names, (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); err_fetch(&error_type, &error_value, &error_traceback);
c->c_flags |= CO_OPTIMIZED;
next_instr = (unsigned char *) getstringvalue(c->c_code); next_instr = (unsigned char *) getstringvalue(c->c_code);
for (;;) { for (;;) {
opcode = NEXTOP(); opcode = NEXTOP();
if (opcode == STOP_CODE) if (opcode == STOP_CODE)
break; break;
if (opcode == EXEC_STMT)
goto end; /* Don't optimize if exec present */
if (HAS_ARG(opcode)) if (HAS_ARG(opcode))
oparg = NEXTARG(); oparg = NEXTARG();
if (opcode == STORE_NAME || opcode == DELETE_NAME || switch (opcode) {
opcode == IMPORT_FROM) { case STORE_NAME:
object *v; case DELETE_NAME:
name = GETNAMEOBJ(oparg); case IMPORT_FROM:
if (dict2lookup(locals, name) != NULL) com_addlocal_o(c, GETNAMEOBJ(oparg));
continue; break;
err_clear(); case EXEC_STMT:
v = newintobject(nlocals); c->c_flags &= ~CO_OPTIMIZED;
if (v == NULL) { break;
c->c_errors++;
goto err;
}
nlocals++;
if (dict2insert(locals, name, v) != 0) {
DECREF(v);
c->c_errors++;
goto err;
}
DECREF(v);
} }
} }
if (dictlookup(locals, "*") != NULL) { if (dictlookup(c->c_locals, "*") != NULL)
/* Don't optimize anything */ c->c_flags &= ~CO_OPTIMIZED;
goto end;
}
next_instr = (unsigned char *) getstringvalue(c->c_code); next_instr = (unsigned char *) getstringvalue(c->c_code);
fast_reserved = 0;
for (;;) { for (;;) {
cur_instr = next_instr; cur_instr = next_instr;
opcode = NEXTOP(); opcode = NEXTOP();
@ -2633,45 +2720,17 @@ optimize(c)
break; break;
if (HAS_ARG(opcode)) if (HAS_ARG(opcode))
oparg = NEXTARG(); 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 || if (opcode == LOAD_NAME ||
opcode == STORE_NAME || opcode == STORE_NAME ||
opcode == DELETE_NAME) { opcode == DELETE_NAME) {
object *v; object *v;
int i; int i;
name = GETNAMEOBJ(oparg); name = GETNAMEOBJ(oparg);
v = dict2lookup(locals, name); v = dict2lookup(c->c_locals, name);
if (v == NULL) { if (v == NULL) {
err_clear(); err_clear();
if (opcode == LOAD_NAME) if (opcode == LOAD_NAME &&
(c->c_flags&CO_OPTIMIZED))
cur_instr[0] = LOAD_GLOBAL; cur_instr[0] = LOAD_GLOBAL;
continue; continue;
} }
@ -2686,10 +2745,8 @@ optimize(c)
} }
} }
end: if (c->c_errors == 0)
err_restore(error_type, error_value, error_traceback); err_restore(error_type, error_value, error_traceback);
err:
DECREF(locals);
} }
codeobject * codeobject *
@ -2703,18 +2760,35 @@ compile(n, filename)
return NULL; return NULL;
compile_node(&sc, n); compile_node(&sc, n);
com_done(&sc); 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); optimize(&sc);
sc.c_flags |= CO_NEWLOCALS;
}
else if (TYPE(n) == classdef)
sc.c_flags |= CO_NEWLOCALS;
co = NULL; co = NULL;
if (sc.c_errors == 0) { if (sc.c_errors == 0) {
object *v, *w; object *consts, *names, *varnames, *filename, *name;
v = newstringobject(sc.c_filename); consts = listtuple(sc.c_consts);
w = newstringobject(sc.c_name); names = listtuple(sc.c_names);
if (v != NULL && w != NULL) varnames = listtuple(sc.c_varnames);
co = newcodeobject(sc.c_code, sc.c_consts, filename = newstringobject(sc.c_filename);
sc.c_names, v, w); name = newstringobject(sc.c_name);
XDECREF(v); if (!err_occurred())
XDECREF(w); 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); com_free(&sc);
return co; return co;

View File

@ -54,7 +54,7 @@ extern long getmtime(); /* In getmtime.c */
Apple MPW compiler swaps their values, botching string constants */ Apple MPW compiler swaps their values, botching string constants */
/* XXX Perhaps the magic number should be frozen and a version field /* XXX Perhaps the magic number should be frozen and a version field
added to the .pyc file header? */ added to the .pyc file header? */
#define MAGIC (0x4127L | ((long)'\r'<<16) | ((long)'\n'<<24)) #define MAGIC (11913 | ((long)'\r'<<16) | ((long)'\n'<<24))
object *import_modules; /* This becomes sys.modules */ object *import_modules; /* This becomes sys.modules */
@ -159,7 +159,7 @@ exec_code_module(name, co)
if (dictinsert(d, "__builtins__", getbuiltins()) != 0) if (dictinsert(d, "__builtins__", getbuiltins()) != 0)
return NULL; return NULL;
} }
v = eval_code((codeobject *)co, d, d, d, (object *)NULL); v = eval_code((codeobject *)co, d, d); /* XXX owner? */
if (v == NULL) if (v == NULL)
return NULL; return NULL;
DECREF(v); DECREF(v);

View File

@ -44,7 +44,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define TYPE_TUPLE '(' #define TYPE_TUPLE '('
#define TYPE_LIST '[' #define TYPE_LIST '['
#define TYPE_DICT '{' #define TYPE_DICT '{'
#define TYPE_CODE 'C' #define TYPE_CODE 'c'
#define TYPE_UNKNOWN '?' #define TYPE_UNKNOWN '?'
typedef struct { typedef struct {
@ -187,9 +187,13 @@ w_object(v, p)
else if (is_codeobject(v)) { else if (is_codeobject(v)) {
codeobject *co = (codeobject *)v; codeobject *co = (codeobject *)v;
w_byte(TYPE_CODE, p); w_byte(TYPE_CODE, p);
w_short(co->co_argcount, p);
w_short(co->co_nlocals, p);
w_short(co->co_flags, p);
w_object((object *)co->co_code, p); w_object((object *)co->co_code, p);
w_object(co->co_consts, p); w_object(co->co_consts, p);
w_object(co->co_names, p); w_object(co->co_names, p);
w_object(co->co_varnames, p);
w_object(co->co_filename, p); w_object(co->co_filename, p);
w_object(co->co_name, p); w_object(co->co_name, p);
} }
@ -374,14 +378,20 @@ r_object(p)
case TYPE_CODE: case TYPE_CODE:
{ {
int argcount = r_short(p);
int nlocals = r_short(p);
int flags = r_short(p);
object *code = r_object(p); object *code = r_object(p);
object *consts = r_object(p); object *consts = r_object(p);
object *names = r_object(p); object *names = r_object(p);
object *varnames = r_object(p);
object *filename = r_object(p); object *filename = r_object(p);
object *name = r_object(p); object *name = r_object(p);
if (!err_occurred()) { if (!err_occurred()) {
v = (object *) newcodeobject(code, v = (object *) newcodeobject(
consts, names, filename, name); argcount, nlocals, flags,
code, consts, names, varnames,
filename, name);
} }
else else
v = NULL; v = NULL;

View File

@ -430,7 +430,7 @@ run_node(n, filename, globals, locals)
freetree(n); freetree(n);
if (co == NULL) if (co == NULL)
return NULL; return NULL;
v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL); v = eval_code(co, globals, locals);
DECREF(co); DECREF(co);
return v; return v;
} }
@ -462,7 +462,7 @@ run_pyc_file(fp, filename, globals, locals)
return NULL; return NULL;
} }
co = (codeobject *)v; co = (codeobject *)v;
v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL); v = eval_code(co, globals, locals);
DECREF(co); DECREF(co);
return v; return v;
} }
@ -603,16 +603,9 @@ cleanup()
object *exitfunc = sysget("exitfunc"); object *exitfunc = sysget("exitfunc");
if (exitfunc) { if (exitfunc) {
object *arg;
object *res; object *res;
sysset("exitfunc", (object *)NULL); sysset("exitfunc", (object *)NULL);
arg = newtupleobject(0); res = call_object(exitfunc, (object *)NULL);
if (arg == NULL)
res = NULL;
else {
res = call_object(exitfunc, arg);
DECREF(arg);
}
if (res == NULL) { if (res == NULL) {
fprintf(stderr, "Error in sys.exitfunc:\n"); fprintf(stderr, "Error in sys.exitfunc:\n");
print_error(); print_error();

View File

@ -68,7 +68,10 @@ tb_dealloc(tb)
DEL(tb); DEL(tb);
} }
static typeobject Tracebacktype = { #define Tracebacktype PyTraceback_Type
#define is_tracebackobject PyTraceback_Check
typeobject Tracebacktype = {
OB_HEAD_INIT(&Typetype) OB_HEAD_INIT(&Typetype)
0, 0,
"traceback", "traceback",
@ -85,8 +88,6 @@ static typeobject Tracebacktype = {
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
}; };
#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype)
static tracebackobject * static tracebackobject *
newtracebackobject(next, frame, lasti, lineno) newtracebackobject(next, frame, lasti, lineno)
tracebackobject *next; tracebackobject *next;