From 681d79aaf397850778608f35585d091fa7fe370a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 18 Jul 1995 14:51:37 +0000 Subject: [PATCH] keyword arguments and faster calls --- Python/bltinmodule.c | 16 +- Python/ceval.c | 839 ++++++++++++++++++++++++------------------- Python/compile.c | 492 ++++++++++++++----------- Python/import.c | 4 +- Python/marshal.c | 16 +- Python/pythonrun.c | 13 +- Python/traceback.c | 7 +- 7 files changed, 782 insertions(+), 605 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 5103622d6c6..0be037397ab 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -80,15 +80,20 @@ builtin_apply(self, args) object *self; 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; - if (!is_tupleobject(alist)) { + if (alist != NULL && !is_tupleobject(alist)) { err_setstr(TypeError, "apply() 2nd argument must be tuple"); 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 * @@ -373,8 +378,7 @@ builtin_eval(self, args) return NULL; } if (is_codeobject(cmd)) - return eval_code((codeobject *) cmd, globals, locals, - (object *)NULL, (object *)NULL); + return eval_code((codeobject *) cmd, globals, locals); if (!is_stringobject(cmd)) { err_setstr(TypeError, "eval() argument 1 must be string or code object"); diff --git a/Python/ceval.c b/Python/ceval.c index a55451c3e46..2b501c79e39 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -24,6 +24,16 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Execute compiled code */ +/* XXX TO DO: + XXX how to pass arguments to call_trace? + XXX access stuff can probably dereference NULL locals? + XXX need to extend apply() to be able to pass keyword args + XXX need to be able to call built-in functions with keyword args + XXX speed up searching for keywords by using a dictionary + XXX unknown keyword shouldn't raise KeyError? + XXX document it! + */ + #include "allobjects.h" #include "import.h" @@ -58,6 +68,12 @@ extern int suppress_print; /* Declared in pythonrun.c, set in pythonmain.c */ /* Forward declarations */ +static object *eval_code2 PROTO((codeobject *, + object *, object *, + object **, int, + object **, int, + object **, int, + object *)); #ifdef LLTRACE static int prtrace PROTO((object *, char *)); #endif @@ -78,8 +94,8 @@ static object *rshift PROTO((object *, object *)); static object *and PROTO((object *, object *)); static object *xor PROTO((object *, object *)); static object *or PROTO((object *, object *)); -static object *call_builtin PROTO((object *, object *)); -static object *call_function PROTO((object *, object *)); +static object *call_builtin PROTO((object *, object *, object *)); +static object *call_function PROTO((object *, object *, object *)); static object *apply_subscript PROTO((object *, object *)); static object *loop_subscript PROTO((object *, object *)); static int slice_index PROTO((object *, int, int *)); @@ -259,15 +275,38 @@ enum why_code { }; -/* Interpreter main loop */ +/* Backward compatible interface */ object * -eval_code(co, globals, locals, owner, arg) +eval_code(co, globals, locals) codeobject *co; object *globals; object *locals; +{ + return eval_code2(co, + globals, locals, + (object **)NULL, 0, + (object **)NULL, 0, + (object **)NULL, 0, + (object *)NULL); +} + + +/* Interpreter main loop */ + +static object * +eval_code2(co, globals, locals, + args, argcount, kws, kwcount, defs, defcount, owner) + codeobject *co; + object *globals; + object *locals; + object **args; + int argcount; + object **kws; /* length: 2*kwcount */ + int kwcount; + object **defs; + int defcount; object *owner; - object *arg; { register unsigned char *next_instr; register int opcode; /* Current opcode */ @@ -281,15 +320,14 @@ eval_code(co, globals, locals, owner, arg) register object *u; register object *t; register frameobject *f; /* Current frame */ - register listobject *fastlocals = NULL; - object *retval; /* Return value iff why == WHY_RETURN */ - int needmerge = 0; /* Set if need to merge locals back at end */ + register object **fastlocals; + object *retval; /* Return value */ int defmode = 0; /* Default access mode for new variables */ #ifdef LLTRACE int lltrace; #endif -#if defined( DEBUG ) || defined( LLTRACE ) - /* Make it easier to find out where we are with dbx */ +#if defined(DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ char *filename = getstringvalue(co->co_filename); #endif @@ -324,8 +362,14 @@ eval_code(co, globals, locals, owner, arg) #define POP() BASIC_POP() #endif - if (globals == NULL || locals == NULL) { - err_setstr(SystemError, "eval_code: NULL globals or locals"); +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) +#define SETLOCAL(i, value) do { XDECREF(GETLOCAL(i)); \ + GETLOCAL(i) = value; } while (0) + + if (globals == NULL) { + err_setstr(SystemError, "eval_code2: NULL globals"); return NULL; } @@ -343,9 +387,113 @@ eval_code(co, globals, locals, owner, arg) 20); /*nblocks*/ if (f == NULL) return NULL; - + current_frame = f; + if (co->co_nlocals > 0) + fastlocals = ((listobject *)f->f_fastlocals)->ob_item; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + object *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = newmappingobject(); + if (kwdict == NULL) + goto fail; + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + err_setstr(TypeError, "too many arguments"); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = newtupleobject(argcount - n); + for (i = n; i < argcount; i++) { + x = args[i]; + INCREF(x); + SETTUPLEITEM(u, i-n, x); + } + SETLOCAL(co->co_argcount, u); + } + for (i = 0; i < kwcount; i++) { + object *keyword = kws[2*i]; + object *value = kws[2*i + 1]; + int j; + /* XXX slow -- speed up using dictionary? */ + for (j = 0; j < co->co_argcount; j++) { + object *nm = GETTUPLEITEM(co->co_varnames, j); + if (cmpobject(keyword, nm) == 0) + break; + } + if (j >= co->co_argcount) { + if (kwdict == NULL) { + err_setval(KeyError/*XXX*/, keyword); + goto fail; + } + mappinginsert(kwdict, keyword, value); + } + else { + if (GETLOCAL(j) != NULL) { + err_setstr(TypeError, + "keyword parameter redefined"); + goto fail; + } + INCREF(value); + SETLOCAL(j, value); + } + } + if (argcount < co->co_argcount) { + int m = co->co_argcount - defcount; + for (i = argcount; i < m; i++) { + if (GETLOCAL(i) == NULL) { + err_setstr(TypeError, + "not enough arguments"); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + object *def = defs[i]; + INCREF(def); + SETLOCAL(m+i, def); + } + } + } + if (kwdict != NULL) { + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (0) { + fail: + XDECREF(kwdict); + goto fail2; + } + } + else { + if (argcount > 0 || kwcount > 0) { + err_setstr(TypeError, "no arguments expected"); + fail2: + current_frame = f->f_back; + DECREF(f); + return NULL; + } + } + if (sys_trace != NULL) { /* sys_trace, if defined, is a function that will be called on *every* entry to a code block. @@ -359,7 +507,8 @@ eval_code(co, globals, locals, owner, arg) depends on the situation. The global trace function (sys.trace) is also called whenever an exception is detected. */ - if (call_trace(&sys_trace, &f->f_trace, f, "call", arg)) { + if (call_trace(&sys_trace, &f->f_trace, f, "call", + None/*XXX how to compute arguments now?*/)) { /* Trace function raised an error */ current_frame = f->f_back; DECREF(f); @@ -370,7 +519,8 @@ eval_code(co, globals, locals, owner, arg) if (sys_profile != NULL) { /* Similar for sys_profile, except it needn't return itself and isn't called for "line" events */ - if (call_trace(&sys_profile, (object**)0, f, "call", arg)) { + if (call_trace(&sys_profile, (object**)0, f, "call", + None/*XXX*/)) { current_frame = f->f_back; DECREF(f); return NULL; @@ -380,11 +530,6 @@ eval_code(co, globals, locals, owner, arg) next_instr = GETUSTRINGVALUE(f->f_code->co_code); stack_pointer = f->f_valuestack; - if (arg != NULL) { - INCREF(arg); - PUSH(arg); - } - why = WHY_NOT; err = 0; x = None; /* Not a reference, just anything non-NULL */ @@ -522,14 +667,6 @@ eval_code(co, globals, locals, owner, arg) DECREF(v); PUSH(x); break; - - case UNARY_CALL: - v = POP(); - f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */ - x = call_object(v, (object *)NULL); - DECREF(v); - PUSH(x); - break; case UNARY_INVERT: v = POP(); @@ -592,16 +729,6 @@ eval_code(co, globals, locals, owner, arg) PUSH(x); break; - case BINARY_CALL: - w = POP(); - v = POP(); - f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */ - x = call_object(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - case BINARY_LSHIFT: w = POP(); v = POP(); @@ -776,9 +903,6 @@ eval_code(co, globals, locals, owner, arg) why = WHY_BREAK; break; - case RAISE_EXCEPTION: - oparg = 2; - /* Fallthrough */ case RAISE_VARARGS: u = v = w = NULL; switch (oparg) { @@ -788,10 +912,7 @@ eval_code(co, globals, locals, owner, arg) DECREF(u); u = NULL; } - else if (strcmp(u->ob_type->tp_name, - "traceback") != 0) { - /* XXX traceback.h needs to define - is_traceback() */ + else if (!PyTraceback_Check(u)) { err_setstr(TypeError, "raise 3rd arg must be traceback or None"); goto raise_error; @@ -814,8 +935,8 @@ eval_code(co, globals, locals, owner, arg) } /* A tuple is equivalent to its first element here */ while (is_tupleobject(w) && gettuplesize(w) > 0) { - object *t = w; - w = GETTUPLEITEM(t, 0); + t = w; + w = GETTUPLEITEM(w, 0); INCREF(w); DECREF(t); } @@ -861,9 +982,12 @@ eval_code(co, globals, locals, owner, arg) break; case LOAD_LOCALS: - v = f->f_locals; - INCREF(v); - PUSH(v); + if ((x = f->f_locals) == NULL) { + err_setstr(SystemError, "no locals"); + break; + } + INCREF(x); + PUSH(x); break; case RETURN_VALUE: @@ -871,12 +995,6 @@ eval_code(co, globals, locals, owner, arg) why = WHY_RETURN; break; - case LOAD_GLOBALS: - v = f->f_locals; - INCREF(v); - PUSH(v); - break; - case EXEC_STMT: w = POP(); v = POP(); @@ -887,21 +1005,6 @@ eval_code(co, globals, locals, owner, arg) DECREF(w); break; - case BUILD_FUNCTION: - v = POP(); - x = newfuncobject(v, f->f_globals); - DECREF(v); - PUSH(x); - break; - - case SET_FUNC_ARGS: - v = POP(); /* The function */ - w = POP(); /* The argument list */ - err = setfuncargstuff(v, oparg, w); - PUSH(v); - DECREF(w); - break; - case POP_BLOCK: { block *b = pop_block(f); @@ -947,14 +1050,18 @@ eval_code(co, globals, locals, owner, arg) case STORE_NAME: w = GETNAMEV(oparg); v = POP(); - u = dict2lookup(f->f_locals, w); + if ((x = f->f_locals) == NULL) { + err_setstr(SystemError, "no locals"); + break; + } + u = dict2lookup(x, w); if (u == NULL) { if (defmode != 0) { if (v != None) u = (object *)v->ob_type; else u = NULL; - x = newaccessobject(v, f->f_locals, + x = newaccessobject(v, x, (typeobject *)u, defmode); DECREF(v); @@ -964,23 +1071,27 @@ eval_code(co, globals, locals, owner, arg) } } else if (is_accessobject(u)) { - err = setaccessvalue(u, f->f_locals, v); + err = setaccessvalue(u, x, v); DECREF(v); break; } - err = dict2insert(f->f_locals, w, v); + err = dict2insert(x, w, v); DECREF(v); break; case DELETE_NAME: w = GETNAMEV(oparg); - u = dict2lookup(f->f_locals, w); + if ((x = f->f_locals) == NULL) { + err_setstr(SystemError, "no locals"); + break; + } + u = dict2lookup(x, w); if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, f->f_locals, + err = setaccessvalue(u, x, (object *)NULL); break; } - if ((err = dict2remove(f->f_locals, w)) != 0) + if ((err = dict2remove(x, w)) != 0) err_setval(NameError, w); break; @@ -988,74 +1099,6 @@ eval_code(co, globals, locals, owner, arg) default: switch (opcode) { #endif - case UNPACK_VARARG: - if (EMPTY()) { - err_setstr(TypeError, - "no argument list"); - why = WHY_EXCEPTION; - break; - } - v = POP(); - if (!is_tupleobject(v)) { - err_setstr(TypeError, - "bad argument list"); - why = WHY_EXCEPTION; - } - else if (gettuplesize(v) < oparg) { - err_setstr(TypeError, - "not enough arguments"); - why = WHY_EXCEPTION; - } - else if (oparg == 0) { - PUSH(v); - break; - } - else { - x = gettupleslice(v, oparg, gettuplesize(v)); - if (x != NULL) { - PUSH(x); - if (!CHECK_STACK(oparg)) { - x = NULL; - break; - } - for (; --oparg >= 0; ) { - w = GETTUPLEITEM(v, oparg); - INCREF(w); - PUSH(w); - } - } - } - DECREF(v); - break; - - case UNPACK_ARG: - { - int n; - if (EMPTY()) { - err_setstr(TypeError, - "no argument list"); - why = WHY_EXCEPTION; - break; - } - v = POP(); - if (!is_tupleobject(v)) { - err_setstr(TypeError, - "bad argument list"); - why = WHY_EXCEPTION; - DECREF(v); - break; - } - n = gettuplesize(v); - if (n != oparg) { - err_setstr(TypeError, - "arg count mismatch"); - why = WHY_EXCEPTION; - DECREF(v); - break; - } - PUSH(v); - } - /* Fall through */ case UNPACK_TUPLE: v = POP(); if (!is_tupleobject(v)) { @@ -1125,11 +1168,14 @@ eval_code(co, globals, locals, owner, arg) case STORE_GLOBAL: w = GETNAMEV(oparg); v = POP(); - u = dict2lookup(f->f_locals, w); - if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, f->f_globals, v); - DECREF(v); - break; + if (f->f_locals != NULL) { + u = dict2lookup(f->f_locals, w); + if (u != NULL && is_accessobject(u)) { + err = setaccessvalue(u, f->f_globals, + v); + DECREF(v); + break; + } } err = dict2insert(f->f_globals, w, v); DECREF(v); @@ -1137,11 +1183,13 @@ eval_code(co, globals, locals, owner, arg) case DELETE_GLOBAL: w = GETNAMEV(oparg); - u = dict2lookup(f->f_locals, w); - if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, f->f_globals, - (object *)NULL); - break; + if (f->f_locals != NULL) { + u = dict2lookup(f->f_locals, w); + if (u != NULL && is_accessobject(u)) { + err = setaccessvalue(u, f->f_globals, + (object *)NULL); + break; + } } if ((err = dict2remove(f->f_globals, w)) != 0) err_setval(NameError, w); @@ -1155,7 +1203,11 @@ eval_code(co, globals, locals, owner, arg) case LOAD_NAME: w = GETNAMEV(oparg); - x = dict2lookup(f->f_locals, w); + if ((x = f->f_locals) == NULL) { + err_setstr(SystemError, "no locals"); + break; + } + x = dict2lookup(x, w); if (x == NULL) { err_clear(); x = dict2lookup(f->f_globals, w); @@ -1198,10 +1250,15 @@ eval_code(co, globals, locals, owner, arg) INCREF(x); PUSH(x); break; - + +#if 0 case LOAD_LOCAL: w = GETNAMEV(oparg); - x = dict2lookup(f->f_locals, w); + if ((x = f->f_locals) == NULL) { + err_setstr(SystemError, "no locals"); + break; + } + x = dict2lookup(x, w); if (x == NULL) { err_setval(NameError, w); break; @@ -1215,29 +1272,14 @@ eval_code(co, globals, locals, owner, arg) INCREF(x); PUSH(x); break; - - case RESERVE_FAST: - x = GETCONST(oparg); - if (x == None) - break; - if (x == NULL || !is_tupleobject(x)) { - err_setstr(SystemError, "bad RESERVE_FAST"); - x = NULL; - break; - } - XDECREF(f->f_fastlocals); - XDECREF(f->f_localmap); - INCREF(x); - f->f_localmap = x; - f->f_fastlocals = x = newlistobject(gettuplesize(x)); - fastlocals = (listobject *) x; - break; +#endif case LOAD_FAST: - x = GETLISTITEM(fastlocals, oparg); + x = GETLOCAL(oparg); if (x == NULL) { err_setval(NameError, - gettupleitem(f->f_localmap, oparg)); + gettupleitem(co->co_varnames, + oparg)); break; } if (is_accessobject(x)) { @@ -1252,30 +1294,29 @@ eval_code(co, globals, locals, owner, arg) case STORE_FAST: v = POP(); - w = GETLISTITEM(fastlocals, oparg); + w = GETLOCAL(oparg); if (w != NULL && is_accessobject(w)) { err = setaccessvalue(w, f->f_locals, v); DECREF(v); break; } - GETLISTITEM(fastlocals, oparg) = v; - XDECREF(w); + SETLOCAL(oparg, v); break; case DELETE_FAST: - x = GETLISTITEM(fastlocals, oparg); + x = GETLOCAL(oparg); if (x == NULL) { err_setval(NameError, - gettupleitem(f->f_localmap, oparg)); + gettupleitem(co->co_varnames, + oparg)); break; } - if (x != NULL && is_accessobject(x)) { + if (is_accessobject(x)) { err = setaccessvalue(x, f->f_locals, (object *)NULL); break; } - GETLISTITEM(fastlocals, oparg) = NULL; - DECREF(x); + SETLOCAL(oparg, NULL); break; case BUILD_TUPLE: @@ -1343,7 +1384,11 @@ eval_code(co, globals, locals, owner, arg) break; } } - w = mkvalue("(OOOO)", w, f->f_globals, f->f_locals, u); + w = mkvalue("(OOOO)", + w, + f->f_globals, + f->f_locals == NULL ? None : f->f_locals, + u); DECREF(u); if (w == NULL) { x = NULL; @@ -1358,7 +1403,11 @@ eval_code(co, globals, locals, owner, arg) w = GETNAMEV(oparg); v = TOP(); fast_2_locals(f); - err = import_from(f->f_locals, v, w); + if ((x = f->f_locals) == NULL) { + err_setstr(SystemError, "no locals"); + break; + } + err = import_from(x, v, w); locals_2_fast(f, 0); break; @@ -1447,12 +1496,6 @@ eval_code(co, globals, locals, owner, arg) case CALL_FUNCTION: { - /* XXX To do: - - fill in default arguments here - - proper handling of keyword parameters - - change eval_code interface to take an - array of arguments instead of a tuple - */ int na = oparg & 0xff; int nk = (oparg>>8) & 0xff; int n = na + 2*nk; @@ -1460,75 +1503,120 @@ eval_code(co, globals, locals, owner, arg) object *func = *pfunc; object *self = NULL; object *class = NULL; - object *args; f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */ - INCREF(func); if (is_instancemethodobject(func)) { self = instancemethodgetself(func); + class = instancemethodgetclass(func); + func = instancemethodgetfunc(func); + INCREF(func); if (self != NULL) { - class = instancemethodgetclass(func); - DECREF(func); - func = instancemethodgetfunc(func); - INCREF(func); INCREF(self); DECREF(*pfunc); *pfunc = self; na++; n++; } - } - args = newtupleobject(n); - if (args == NULL) - x = NULL; - else { - while (--n >= 0) { - w = POP(); - SETTUPLEITEM(args, n, w); - } - if (self == NULL) - POP(); - if (is_funcobject(func)) { - int argcount; - object *argdefs = - getfuncargstuff(func, &argcount); - if (argdefs == NULL) { /* Fast path */ - object *co, *loc, *glob; - co = getfunccode(func); - loc = newdictobject(); - if (loc == NULL) { - x = NULL; - DECREF(func); - break; - } - glob = getfuncglobals(func); - INCREF(glob); - x = eval_code( - (codeobject *)co, - glob, - loc, - class, - args); - DECREF(glob); - DECREF(loc); - DECREF(args); - DECREF(func); - PUSH(x); - break; + else { + /* Unbound methods must be + called with an instance of + the class (or a derived + class) as first argument */ + if (na > 0 && + (self = stack_pointer[-n]) + != NULL && + is_instanceobject(self) && + issubclass( + (object *) + (((instanceobject *)self) + ->in_class), + class)) + /* Handy-dandy */ ; + else { + err_setstr(TypeError, + "unbound method must be called with class instance 1st argument"); + return NULL; } } - x = call_object(func, args); - DECREF(args); - PUSH(x); + } + else + INCREF(func); + if (is_funcobject(func)) { + object *co = getfunccode(func); + object *globals = getfuncglobals(func); + object *argdefs = PyFunction_GetDefaults(func); + object **d; + int nd; + if (argdefs != NULL) { + d = &GETTUPLEITEM(argdefs, 0); + nd = ((tupleobject *)argdefs)->ob_size; + } + else { + d = NULL; + nd = 0; + } + x = eval_code2( + (codeobject *)co, + globals, (object *)NULL, + stack_pointer-n, na, + stack_pointer-2*nk, nk, + d, nd, + class); + } + else { + object *args = newtupleobject(na); + object *kwdict = NULL; + if (args == NULL) + x = NULL; + else if (nk > 0) { + err_setstr(SystemError, + "calling built-in with keywords not yet implemented"); + x = NULL; + } + else { + while (--na >= 0) { + w = POP(); + SETTUPLEITEM(args, na, w); + } + x = call_object(func, args); + DECREF(args); + } } DECREF(func); + while (stack_pointer > pfunc) { + w = POP(); + DECREF(w); + } + PUSH(x); break; } + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = newfuncobject(v, f->f_globals); + DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = newtupleobject(oparg); + if (v == NULL) { + DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + SETTUPLEITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + DECREF(v); + } + PUSH(x); + break; + default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", f->f_lineno, opcode); - err_setstr(SystemError, "eval_code: unknown opcode"); + err_setstr(SystemError, "unknown opcode"); why = WHY_EXCEPTION; break; @@ -1543,8 +1631,15 @@ eval_code(co, globals, locals, owner, arg) /* Quickly continue if no error occurred */ if (why == WHY_NOT) { - if (err == 0 && x != NULL) - continue; /* Normal, fast path */ + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + if (err_occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else +#endif + continue; /* Normal, fast path */ + } why = WHY_EXCEPTION; x = None; err = 0; @@ -1561,8 +1656,12 @@ eval_code(co, globals, locals, owner, arg) } } else { - if (err_occurred()) - fatal("XXX undetected error"); + if (err_occurred()) { + fprintf(stderr, + "XXX undetected error (why=%d)\n", + why); + why = WHY_EXCEPTION; + } } #endif @@ -1672,12 +1771,9 @@ eval_code(co, globals, locals, owner, arg) } /* Restore previous frame and release the current one */ - + current_frame = f->f_back; DECREF(f); - - if (needmerge) - locals_2_fast(current_frame, 1); return retval; } @@ -2134,38 +2230,66 @@ not(v) } -/* External interface to call any callable object. The arg may be NULL. */ +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ object * call_object(func, arg) object *func; object *arg; { - binaryfunc call; - object *result; - - if (call = func->ob_type->tp_call) - result = (*call)(func, arg); - else if (is_instancemethodobject(func) || is_funcobject(func)) - result = call_function(func, arg); - else - result = call_builtin(func, arg); + return PyEval_CallObjectWithKeywords(func, arg, (object *)NULL); +} +object * +PyEval_CallObjectWithKeywords(func, arg, kw) + object *func; + object *arg; + object *kw; +{ + ternaryfunc call; + object *result; + + if (arg == NULL) + arg = newtupleobject(0); + else if (!is_tupleobject(arg)) { + err_setstr(TypeError, "argument list must be a tuple"); + return NULL; + } + else + INCREF(arg); + + if (call = func->ob_type->tp_call) + result = (*call)(func, arg, kw); + else if (is_instancemethodobject(func) || is_funcobject(func)) + result = call_function(func, arg, kw); + else + result = call_builtin(func, arg, kw); + + DECREF(arg); + if (result == NULL && !err_occurred()) - fatal("null result without error in call_object"); + err_setstr(SystemError, + "NULL result without error in call_object"); return result; } static object * -call_builtin(func, arg) +call_builtin(func, arg, kw) object *func; object *arg; + object *kw; { + if (kw != NULL) { + err_setstr(SystemError, + "calling built-in with keywords not yet implemented"); + return NULL; + } if (is_methodobject(func)) { method meth = getmethod(func); object *self = getself(func); - if (!getvarargs(func) && arg != NULL && is_tupleobject(arg)) { + if (!getvarargs(func)) { int size = gettuplesize(arg); if (size == 1) arg = GETTUPLEITEM(arg, 0); @@ -2181,7 +2305,8 @@ call_builtin(func, arg) object *res, *call = getattr(func,"__call__"); if (call == NULL) { err_clear(); - err_setstr(AttributeError, "no __call__ method defined"); + err_setstr(AttributeError, + "no __call__ method defined"); return NULL; } res = call_object(call, arg); @@ -2193,16 +2318,21 @@ call_builtin(func, arg) } static object * -call_function(func, arg) +call_function(func, arg, kw) object *func; object *arg; + object *kw; { - object *newarg = NULL; - object *newlocals, *newglobals; - object *class = NULL; - object *co, *v; + object *class = NULL; /* == owner */ object *argdefs; - int argcount; + object **d, **k; + int nk, nd; + object *result; + + if (kw != NULL && !is_dictobject(kw)) { + err_badcall(); + return NULL; + } if (is_instancemethodobject(func)) { object *self = instancemethodgetself(func); @@ -2211,48 +2341,36 @@ call_function(func, arg) if (self == NULL) { /* Unbound methods must be called with an instance of the class (or a derived class) as first argument */ - if (arg != NULL && is_tupleobject(arg) && - gettuplesize(arg) >= 1) { + if (gettuplesize(arg) >= 1) { self = GETTUPLEITEM(arg, 0); if (self != NULL && is_instanceobject(self) && issubclass((object *) (((instanceobject *)self)->in_class), class)) - /* self = self */ ; + /* Handy-dandy */ ; else self = NULL; } if (self == NULL) { err_setstr(TypeError, - "unbound method must be called with class instance argument"); + "unbound method must be called with class instance 1st argument"); return NULL; } + INCREF(arg); } else { - if (arg == NULL) - argcount = 0; - else if (is_tupleobject(arg)) - argcount = gettuplesize(arg); - else - argcount = 1; - newarg = newtupleobject(argcount + 1); + int argcount = gettuplesize(arg); + object *newarg = newtupleobject(argcount + 1); + int i; if (newarg == NULL) return NULL; INCREF(self); SETTUPLEITEM(newarg, 0, self); - if (arg != NULL && !is_tupleobject(arg)) { - INCREF(arg); - SETTUPLEITEM(newarg, 1, arg); - } - else { - int i; - object *v; - for (i = 0; i < argcount; i++) { - v = GETTUPLEITEM(arg, i); - XINCREF(v); - SETTUPLEITEM(newarg, i+1, v); - } + for (i = 0; i < argcount; i++) { + object *v = GETTUPLEITEM(arg, i); + XINCREF(v); + SETTUPLEITEM(newarg, i+1, v); } arg = newarg; } @@ -2262,65 +2380,51 @@ call_function(func, arg) err_setstr(TypeError, "call of non-function"); return NULL; } + INCREF(arg); } - - argdefs = getfuncargstuff(func, &argcount); - if (argdefs != NULL && arg != NULL && is_tupleobject(arg)) { - int actualcount, j; - /* Process default arguments */ - if (argcount & 0x4000) - argcount ^= 0x4000; - actualcount = gettuplesize(arg); - j = gettuplesize(argdefs) - (argcount - actualcount); - if (actualcount < argcount && j >= 0) { - int i; - object *v; - if (newarg == NULL) - INCREF(arg); - newarg = newtupleobject(argcount); - if (newarg == NULL) { - DECREF(arg); - return NULL; - } - for (i = 0; i < actualcount; i++) { - v = GETTUPLEITEM(arg, i); - XINCREF(v); - SETTUPLEITEM(newarg, i, v); - } - for (; i < argcount; i++, j++) { - v = GETTUPLEITEM(argdefs, j); - XINCREF(v); - SETTUPLEITEM(newarg, i, v); - } + + argdefs = PyFunction_GetDefaults(func); + if (argdefs != NULL && is_tupleobject(argdefs)) { + d = &GETTUPLEITEM((tupleobject *)argdefs, 0); + nd = gettuplesize(argdefs); + } + else { + d = NULL; + nd = 0; + } + + if (kw != NULL) { + int pos, i; + nk = getmappingsize(kw); + k = NEW(object *, 2*nk); + if (k == NULL) { + err_nomem(); DECREF(arg); - arg = newarg; + return NULL; } + pos = i = 0; + while (mappinggetnext(kw, &pos, &k[i], &k[i+1])) + i += 2; + nk = i/2; + /* XXX This is broken if the caller deletes dict items! */ + } + else { + k = NULL; + nk = 0; } - co = getfunccode(func); - if (co == NULL) { - XDECREF(newarg); - return NULL; - } - if (!is_codeobject(co)) - fatal("XXX Bad code"); - newlocals = newdictobject(); - if (newlocals == NULL) { - XDECREF(newarg); - return NULL; - } + result = eval_code2( + (codeobject *)getfunccode(func), + getfuncglobals(func), (object *)NULL, + &GETTUPLEITEM(arg, 0), gettuplesize(arg), + k, nk, + d, nd, + class); - newglobals = getfuncglobals(func); - INCREF(newglobals); + DECREF(arg); + XDEL(k); - v = eval_code((codeobject *)co, newglobals, newlocals, class, arg); - - DECREF(newlocals); - DECREF(newglobals); - - XDECREF(newarg); - - return v; + return result; } static object * @@ -2690,21 +2794,9 @@ access_statement(name, vmode, f) int mode = getintvalue(vmode); object *value, *ac; typeobject *type; - int fastind, ret; - fastind = -1; - if (f->f_localmap == NULL) - value = dict2lookup(f->f_locals, name); - else { - object *map = f->f_localmap; - value = NULL; - for (fastind = gettuplesize(map); --fastind >= 0; ) { - object *fname = GETTUPLEITEM(map, fastind); - if (cmpobject(name, fname) == 0) { - value = getlistitem(f->f_fastlocals, fastind); - break; - } - } - } + int ret; + fast_2_locals(f); + value = dict2lookup(f->f_locals, name); if (value && is_accessobject(value)) { err_setstr(AccessError, "can't override access"); return -1; @@ -2717,12 +2809,9 @@ access_statement(name, vmode, f) ac = newaccessobject(value, f->f_locals, type, mode); if (ac == NULL) return -1; - if (fastind >= 0) - ret = setlistitem(f->f_fastlocals, fastind, ac); - else { - ret = dict2insert(f->f_locals, name, ac); - DECREF(ac); - } + ret = mappinginsert(f->f_locals, name, ac); + DECREF(ac); + locals_2_fast(f, 0); return ret; } @@ -2735,6 +2824,7 @@ exec_statement(prog, globals, locals) char *s; int n; object *v; + int plain = 0; if (is_tupleobject(prog) && globals == None && locals == None && ((n = gettuplesize(prog)) == 2 || n == 3)) { @@ -2746,8 +2836,10 @@ exec_statement(prog, globals, locals) } if (globals == None) { globals = getglobals(); - if (locals == None) + if (locals == None) { locals = getlocals(); + plain = 1; + } } else if (locals == None) locals = globals; @@ -2766,8 +2858,7 @@ exec_statement(prog, globals, locals) if (dictlookup(globals, "__builtins__") == NULL) dictinsert(globals, "__builtins__", current_frame->f_builtins); if (is_codeobject(prog)) { - if (eval_code((codeobject *) prog, globals, locals, - (object *)NULL, (object *)NULL) == NULL) + if (eval_code((codeobject *) prog, globals, locals) == NULL) return -1; return 0; } @@ -2783,13 +2874,16 @@ exec_statement(prog, globals, locals) err_setstr(ValueError, "embedded '\\0' in exec string"); return -1; } - if ((v = run_string(s, file_input, globals, locals)) == NULL) + v = run_string(s, file_input, globals, locals); + if (v == NULL) return -1; DECREF(v); + if (plain) + locals_2_fast(current_frame, 0); return 0; } -/* Hack for Ken Manheimer */ +/* Hack for newimp.py */ static object * find_from_args(f, nexti) frameobject *f; @@ -2812,7 +2906,8 @@ find_from_args(f, nexti) return NULL; do { - oparg = (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]); + oparg = (next_instr[1]<<8) + next_instr[0]; + next_instr += 2; name = Getnamev(f, oparg); if (addlistitem(list, name) < 0) { DECREF(list); diff --git a/Python/compile.c b/Python/compile.c index df81f8f86fb..9f15254aab0 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); - 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 */ + /* 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)) { - DECREF(consts); - DECREF(names); + err_badcall(); + return NULL; + } + } + for (i = gettuplesize(varnames); --i >= 0; ) { + object *v = gettupleitem(varnames, i); + if (v == NULL || !is_stringobject(v)) { 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,11 +1617,69 @@ 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) static void @@ -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)); - } - if (t != COMMA) - break; + else + REQ(ch, COMMA); } - 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) - break; - t = TYPE(CHILD(n, i)); + /* 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)); + } + } + /* 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 @@ -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 = ""; 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; diff --git a/Python/import.c b/Python/import.c index 4239e1230f7..4a4c3d4fa72 100644 --- a/Python/import.c +++ b/Python/import.c @@ -54,7 +54,7 @@ extern long getmtime(); /* In getmtime.c */ Apple MPW compiler swaps their values, botching string constants */ /* XXX Perhaps the magic number should be frozen and a version field 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 */ @@ -159,7 +159,7 @@ exec_code_module(name, co) if (dictinsert(d, "__builtins__", getbuiltins()) != 0) return NULL; } - v = eval_code((codeobject *)co, d, d, d, (object *)NULL); + v = eval_code((codeobject *)co, d, d); /* XXX owner? */ if (v == NULL) return NULL; DECREF(v); diff --git a/Python/marshal.c b/Python/marshal.c index 8c01020ddca..05265f58fee 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -44,7 +44,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define TYPE_TUPLE '(' #define TYPE_LIST '[' #define TYPE_DICT '{' -#define TYPE_CODE 'C' +#define TYPE_CODE 'c' #define TYPE_UNKNOWN '?' typedef struct { @@ -187,9 +187,13 @@ w_object(v, p) else if (is_codeobject(v)) { codeobject *co = (codeobject *)v; 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(co->co_consts, p); w_object(co->co_names, p); + w_object(co->co_varnames, p); w_object(co->co_filename, p); w_object(co->co_name, p); } @@ -374,14 +378,20 @@ r_object(p) case TYPE_CODE: { + int argcount = r_short(p); + int nlocals = r_short(p); + int flags = r_short(p); object *code = r_object(p); object *consts = r_object(p); object *names = r_object(p); + object *varnames = r_object(p); object *filename = r_object(p); object *name = r_object(p); if (!err_occurred()) { - v = (object *) newcodeobject(code, - consts, names, filename, name); + v = (object *) newcodeobject( + argcount, nlocals, flags, + code, consts, names, varnames, + filename, name); } else v = NULL; diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 2268c71ad48..f0875454e26 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -430,7 +430,7 @@ run_node(n, filename, globals, locals) freetree(n); if (co == NULL) return NULL; - v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL); + v = eval_code(co, globals, locals); DECREF(co); return v; } @@ -462,7 +462,7 @@ run_pyc_file(fp, filename, globals, locals) return NULL; } co = (codeobject *)v; - v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL); + v = eval_code(co, globals, locals); DECREF(co); return v; } @@ -603,16 +603,9 @@ cleanup() object *exitfunc = sysget("exitfunc"); if (exitfunc) { - object *arg; object *res; sysset("exitfunc", (object *)NULL); - arg = newtupleobject(0); - if (arg == NULL) - res = NULL; - else { - res = call_object(exitfunc, arg); - DECREF(arg); - } + res = call_object(exitfunc, (object *)NULL); if (res == NULL) { fprintf(stderr, "Error in sys.exitfunc:\n"); print_error(); diff --git a/Python/traceback.c b/Python/traceback.c index 1ab880a91e2..1f803da43b2 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -68,7 +68,10 @@ tb_dealloc(tb) DEL(tb); } -static typeobject Tracebacktype = { +#define Tracebacktype PyTraceback_Type +#define is_tracebackobject PyTraceback_Check + +typeobject Tracebacktype = { OB_HEAD_INIT(&Typetype) 0, "traceback", @@ -85,8 +88,6 @@ static typeobject Tracebacktype = { 0, /*tp_as_mapping*/ }; -#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype) - static tracebackobject * newtracebackobject(next, frame, lasti, lineno) tracebackobject *next;