diff --git a/Python/ceval.c b/Python/ceval.c index 5a9723fc27b..badfcedd77d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -39,6 +39,893 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define TRACE #endif +/* Forward declarations */ +/* XXX Need prototypes */ + +void flushline(); +static object *add(); +static object *sub(); +static object *mul(); +static object *divide(); +static object *rem(); +static object *neg(); +static object *pos(); +static object *not(); +static object *call_builtin(); +static object *call_function(); +static object *apply_subscript(); +static object *loop_subscript(); +static object *apply_slice(); +static object *cmp_outcome(); +static object *build_class(); +static int testbool(); +static int assign_subscript PROTO((object *, object *, object *)); +static int assign_slice PROTO((object *, object *, object *, object *)); +static int import_from PROTO((object *, object *, char *)); + + +static frameobject *current_frame; + + +/* Status code for main loop (reason for stack unwind) */ + +enum why_code { + WHY_NOT, /* No error */ + WHY_EXCEPTION, /* Exception occurred */ + WHY_RERAISE, /* Exception re-raised by 'finally' */ + WHY_RETURN, /* 'return' statement */ + WHY_BREAK /* 'break' statement */ +}; + + +/* Interpreter main loop */ + +object * +eval_code(co, globals, locals, arg) + codeobject *co; + object *globals; + object *locals; + object *arg; +{ + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register object **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register object *x; /* Result object -- NULL if error */ + register object *v; /* Temporary objects popped off stack */ + register object *w; + register object *u; + register object *t; + register frameobject *f; /* Current frame */ + int lineno; /* Current line number */ + object *retval; /* Return value iff why == WHY_RETURN */ + char *name; /* Name used by some instructions */ + FILE *fp; /* Used by print operations */ +#ifdef TRACE + int trace = dictlookup(globals, "__trace__") != NULL; +#endif + +/* Code access macros */ + +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define GETNAMEV(i) Getnamev(f, i) +#define FIRST_INSTR() (GETUSTRINGVALUE(f->f_code->co_code)) +#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef TRACE +#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push")) +#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP()) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#endif + + f = newframeobject( + current_frame, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals, /*locals*/ + 50, /*nvalues*/ + 20); /*nblocks*/ + if (f == NULL) + return NULL; + + current_frame = f; + + 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 */ + lineno = -1; + + for (;;) { + static ticker; + + /* Do periodic things */ + + if (--ticker < 0) { + ticker = 100; + if (intrcheck()) { + err_set(KeyboardInterrupt); + why = WHY_EXCEPTION; + tb_here(f, INSTR_OFFSET(), lineno); + goto on_error; + } + } + + /* Extract opcode and argument */ + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); + +#ifdef TRACE + /* Instruction tracing */ + + if (trace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + DECREF(v); + break; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + break; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + break; + + case DUP_TOP: + v = TOP(); + INCREF(v); + PUSH(v); + break; + + case UNARY_POSITIVE: + v = POP(); + x = pos(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_NEGATIVE: + v = POP(); + x = neg(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_NOT: + v = POP(); + x = not(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_CONVERT: + v = POP(); + x = reprobject(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_CALL: + v = POP(); + if (is_classmethodobject(v) || is_funcobject(v)) + x = call_function(v, (object *)NULL); + else + x = call_builtin(v, (object *)NULL); + DECREF(v); + PUSH(x); + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = mul(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = divide(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = rem(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + x = add(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + x = sub(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + x = apply_subscript(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_CALL: + w = POP(); + v = POP(); + if (is_classmethodobject(v) || is_funcobject(v)) + x = call_function(v, w); + else + x = call_builtin(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + DECREF(u); + XDECREF(v); + XDECREF(w); + PUSH(x); + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + DECREF(t); + DECREF(u); + XDECREF(v); + XDECREF(w); + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (object *)NULL); + /* del u[v:w] */ + DECREF(u); + XDECREF(v); + XDECREF(w); + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = assign_subscript(v, w, u); + DECREF(u); + DECREF(v); + DECREF(w); + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = assign_subscript(v, w, (object *)NULL); + DECREF(v); + DECREF(w); + break; + + case PRINT_EXPR: + v = POP(); + fp = sysgetfile("stdout", stdout); + /* Print value except if procedure result */ + if (v != None) { + flushline(); + softspace(sysget("stdout"), 1); + printobject(v, fp, 0); + flushline(); + } + DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + fp = sysgetfile("stdout", stdout); + if (softspace(sysget("stdout"), 1)) + fprintf(fp, " "); + if (is_stringobject(v)) { + char *s = getstringvalue(v); + int len = getstringsize(v); + fwrite(s, 1, len, fp); + if (len > 0 && s[len-1] == '\n') + softspace(sysget("stdout"), 0); + } + else { + printobject(v, fp, 0); + } + DECREF(v); + break; + + case PRINT_NEWLINE: + fp = sysgetfile("stdout", stdout); + fprintf(fp, "\n"); + softspace(sysget("stdout"), 0); + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_EXCEPTION: + v = POP(); + w = POP(); + if (!is_stringobject(w)) + err_setstr(TypeError, + "exceptions must be strings"); + else + err_setval(w, v); + DECREF(v); + DECREF(w); + why = WHY_EXCEPTION; + break; + + case LOAD_LOCALS: + v = f->f_locals; + INCREF(v); + PUSH(v); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case REQUIRE_ARGS: + if (EMPTY()) { + err_setstr(TypeError, + "function expects argument(s)"); + why = WHY_EXCEPTION; + } + break; + + case REFUSE_ARGS: + if (!EMPTY()) { + err_setstr(TypeError, + "function expects no argument(s)"); + why = WHY_EXCEPTION; + } + break; + + case BUILD_FUNCTION: + v = POP(); + x = newfuncobject(v, f->f_globals); + DECREF(v); + PUSH(x); + break; + + case POP_BLOCK: + { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (is_intobject(v)) { + why = (enum why_code) getintvalue(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (is_stringobject(v)) { + w = POP(); + err_setval(v, w); + DECREF(w); + w = POP(); + tb_store(w); + DECREF(w); + why = WHY_RERAISE; + } + else if (v != None) { + err_setstr(SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + DECREF(v); + break; + + case BUILD_CLASS: + w = POP(); + v = POP(); + x = build_class(v, w); + PUSH(x); + DECREF(v); + DECREF(w); + break; + + case STORE_NAME: + w = GETNAMEV(oparg); + v = POP(); + err = dict2insert(f->f_locals, w, v); + DECREF(v); + break; + + case DELETE_NAME: + name = GETNAME(oparg); + if ((err = dictremove(f->f_locals, name)) != 0) + err_setstr(NameError, name); + break; + + case UNPACK_TUPLE: + v = POP(); + if (!is_tupleobject(v)) { + err_setstr(TypeError, "unpack non-tuple"); + why = WHY_EXCEPTION; + } + else if (gettuplesize(v) != oparg) { + err_setstr(RuntimeError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = gettupleitem(v, oparg); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case UNPACK_LIST: + v = POP(); + if (!is_listobject(v)) { + err_setstr(TypeError, "unpack non-list"); + why = WHY_EXCEPTION; + } + else if (getlistsize(v) != oparg) { + err_setstr(RuntimeError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = getlistitem(v, oparg); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case STORE_ATTR: + name = GETNAME(oparg); + v = POP(); + u = POP(); + err = setattr(v, name, u); /* v.name = u */ + DECREF(v); + DECREF(u); + break; + + case DELETE_ATTR: + name = GETNAME(oparg); + v = POP(); + err = setattr(v, name, (object *)NULL); + /* del v.name */ + DECREF(v); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + name = GETNAME(oparg); + x = dictlookup(f->f_locals, name); + if (x == NULL) { + x = dictlookup(f->f_globals, name); + if (x == NULL) { + x = getbuiltin(name); + if (x == NULL) { + err_setstr(NameError, name); + break; + } + } + } + INCREF(x); + PUSH(x); + break; + + case LOAD_GLOBAL: + name = GETNAME(oparg); + x = dictlookup(f->f_globals, name); + if (x == NULL) { + x = getbuiltin(name); + if (x == NULL) { + err_setstr(NameError, name); + break; + } + } + INCREF(x); + PUSH(x); + break; + + case LOAD_LOCAL: + name = GETNAME(oparg); + x = dictlookup(f->f_locals, name); + if (x == NULL) { + err_setstr(NameError, name); + break; + } + INCREF(x); + PUSH(x); + break; + + case BUILD_TUPLE: + x = newtupleobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = settupleitem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + } + break; + + case BUILD_LIST: + x = newlistobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = setlistitem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + } + break; + + case BUILD_MAP: + x = newdictobject(); + PUSH(x); + break; + + case LOAD_ATTR: + name = GETNAME(oparg); + v = POP(); + x = getattr(v, name); + DECREF(v); + PUSH(x); + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + x = cmp_outcome((enum cmp_op)oparg, v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case IMPORT_NAME: + name = GETNAME(oparg); + x = import_module(name); + XINCREF(x); + PUSH(x); + break; + + case IMPORT_FROM: + name = GETNAME(oparg); + v = TOP(); + err = import_from(f->f_locals, v, name); + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + break; + + case JUMP_IF_FALSE: + if (!testbool(TOP())) + JUMPBY(oparg); + break; + + case JUMP_IF_TRUE: + if (testbool(TOP())) + JUMPBY(oparg); + break; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + break; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = newintobject(getintvalue(w)+1); + PUSH(x); + DECREF(w); + PUSH(u); + } + else { + DECREF(v); + DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (err_occurred()) + why = WHY_EXCEPTION; + else + JUMPBY(oparg); + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + setup_block(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + break; + + case SET_LINENO: +#ifdef TRACE + if (trace) + printf("--- Line %d ---\n", oparg); +#endif + lineno = oparg; + break; + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + lineno, opcode); + err_setstr(SystemError, "eval_code: unknown opcode"); + why = WHY_EXCEPTION; + break; + + } /* switch */ + + on_error: + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) + continue; /* Normal, fast path */ + why = WHY_EXCEPTION; + x = None; + err = 0; + } + +#ifndef NDEBUG + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!err_occurred()) { + fprintf(stderr, "XXX ghost error\n"); + err_setstr(SystemError, "ghost error"); + why = WHY_EXCEPTION; + } + } + else { + if (err_occurred()) { + fprintf(stderr, "XXX undetected error\n"); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + int lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + lasti -= 2; + tb_here(f, lasti, lineno); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION) { + if (why == WHY_EXCEPTION) { + object *exc, *val; + err_get(&exc, &val); + if (val == NULL) { + val = None; + INCREF(val); + } + v = tb_fetch(); + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { +#if 0 /* Oops, this breaks too many things */ + sysset("exc_traceback", v); +#endif + sysset("exc_value", val); + sysset("exc_type", exc); + err_clear(); + } + PUSH(v); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = newintobject((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + XDECREF(v); + } + + /* Restore previous frame and release the current one */ + + current_frame = f->f_back; + DECREF(f); + + if (why == WHY_RETURN) + return retval; + else + return NULL; +} + #ifdef TRACE static int prtrace(v, str) @@ -51,8 +938,6 @@ prtrace(v, str) } #endif -static frameobject *current_frame; - object * getlocals() { @@ -84,20 +969,11 @@ printtraceback(fp) } -/* XXX Mixing "print ...," and direct file I/O on stdin/stdout - XXX has some bad consequences. The needspace flag should - XXX really be part of the file object. */ - -static int needspace; - void flushline() { - FILE *fp = sysgetfile("stdout", stdout); - if (needspace) { - fprintf(fp, "\n"); - needspace = 0; - } + if (softspace(sysget("stdout"), 0)) + fprintf(sysgetfile("stdout", stdout), "\n"); } @@ -243,7 +1119,7 @@ call_builtin(func, arg) "classobject() allows no arguments"); return NULL; } - return newclassmemberobject(func); + return newinstanceobject(func); } err_setstr(TypeError, "call of non-function"); return NULL; @@ -540,6 +1416,8 @@ cmp_outcome(op, v, w) return v; } +/* XXX This function should use dict2 variants (change interface!) */ + static int import_from(locals, v, name) object *locals; @@ -602,836 +1480,3 @@ build_class(v, w) } return newclassobject(v, w); } - - -/* Status code for main loop (reason for stack unwind) */ - -enum why_code { - WHY_NOT, /* No error */ - WHY_EXCEPTION, /* Exception occurred */ - WHY_RERAISE, /* Exception re-raised by 'finally' */ - WHY_RETURN, /* 'return' statement */ - WHY_BREAK /* 'break' statement */ -}; - -/* Interpreter main loop */ - -object * -eval_code(co, globals, locals, arg) - codeobject *co; - object *globals; - object *locals; - object *arg; -{ - register unsigned char *next_instr; - register int opcode; /* Current opcode */ - register int oparg; /* Current opcode argument, if any */ - register object **stack_pointer; - register enum why_code why; /* Reason for block stack unwind */ - register int err; /* Error status -- nonzero if error */ - register object *x; /* Result object -- NULL if error */ - register object *v; /* Temporary objects popped off stack */ - register object *w; - register object *u; - register object *t; - register frameobject *f; /* Current frame */ - int lineno; /* Current line number */ - object *retval; /* Return value iff why == WHY_RETURN */ - char *name; /* Name used by some instructions */ - FILE *fp; /* Used by print operations */ -#ifdef TRACE - int trace = dictlookup(globals, "__trace__") != NULL; -#endif - -/* Code access macros */ - -#define GETCONST(i) Getconst(f, i) -#define GETNAME(i) Getname(f, i) -#define GETNAMEV(i) Getnamev(f, i) -#define FIRST_INSTR() (GETUSTRINGVALUE(f->f_code->co_code)) -#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) -#define NEXTOP() (*next_instr++) -#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) -#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) -#define JUMPBY(x) (next_instr += (x)) - -/* Stack manipulation macros */ - -#define STACK_LEVEL() (stack_pointer - f->f_valuestack) -#define EMPTY() (STACK_LEVEL() == 0) -#define TOP() (stack_pointer[-1]) -#define BASIC_PUSH(v) (*stack_pointer++ = (v)) -#define BASIC_POP() (*--stack_pointer) - -#ifdef TRACE -#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push")) -#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP()) -#else -#define PUSH(v) BASIC_PUSH(v) -#define POP() BASIC_POP() -#endif - - f = newframeobject( - current_frame, /*back*/ - co, /*code*/ - globals, /*globals*/ - locals, /*locals*/ - 50, /*nvalues*/ - 20); /*nblocks*/ - if (f == NULL) - return NULL; - - current_frame = f; - - 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 */ - lineno = -1; - - for (;;) { - static ticker; - - /* Do periodic things */ - - if (--ticker < 0) { - ticker = 100; - if (intrcheck()) { - err_set(KeyboardInterrupt); - why = WHY_EXCEPTION; - tb_here(f, INSTR_OFFSET(), lineno); - break; - } - } - - /* Extract opcode and argument */ - - opcode = NEXTOP(); - if (HAS_ARG(opcode)) - oparg = NEXTARG(); - -#ifdef TRACE - /* Instruction tracing */ - - if (trace) { - if (HAS_ARG(opcode)) { - printf("%d: %d, %d\n", - (int) (INSTR_OFFSET() - 3), - opcode, oparg); - } - else { - printf("%d: %d\n", - (int) (INSTR_OFFSET() - 1), opcode); - } - } -#endif - - /* Main switch on opcode */ - - switch (opcode) { - - /* BEWARE! - It is essential that any operation that fails sets either - x to NULL, err to nonzero, or why to anything but WHY_NOT, - and that no operation that succeeds does this! */ - - /* case STOP_CODE: this is an error! */ - - case POP_TOP: - v = POP(); - DECREF(v); - break; - - case ROT_TWO: - v = POP(); - w = POP(); - PUSH(v); - PUSH(w); - break; - - case ROT_THREE: - v = POP(); - w = POP(); - x = POP(); - PUSH(v); - PUSH(x); - PUSH(w); - break; - - case DUP_TOP: - v = TOP(); - INCREF(v); - PUSH(v); - break; - - case UNARY_POSITIVE: - v = POP(); - x = pos(v); - DECREF(v); - PUSH(x); - break; - - case UNARY_NEGATIVE: - v = POP(); - x = neg(v); - DECREF(v); - PUSH(x); - break; - - case UNARY_NOT: - v = POP(); - x = not(v); - DECREF(v); - PUSH(x); - break; - - case UNARY_CONVERT: - v = POP(); - x = reprobject(v); - DECREF(v); - PUSH(x); - break; - - case UNARY_CALL: - v = POP(); - if (is_classmethodobject(v) || is_funcobject(v)) - x = call_function(v, (object *)NULL); - else - x = call_builtin(v, (object *)NULL); - DECREF(v); - PUSH(x); - break; - - case BINARY_MULTIPLY: - w = POP(); - v = POP(); - x = mul(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case BINARY_DIVIDE: - w = POP(); - v = POP(); - x = divide(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case BINARY_MODULO: - w = POP(); - v = POP(); - x = rem(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case BINARY_ADD: - w = POP(); - v = POP(); - x = add(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case BINARY_SUBTRACT: - w = POP(); - v = POP(); - x = sub(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case BINARY_SUBSCR: - w = POP(); - v = POP(); - x = apply_subscript(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case BINARY_CALL: - w = POP(); - v = POP(); - if (is_classmethodobject(v) || is_funcobject(v)) - x = call_function(v, w); - else - x = call_builtin(v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case SLICE+0: - case SLICE+1: - case SLICE+2: - case SLICE+3: - if ((opcode-SLICE) & 2) - w = POP(); - else - w = NULL; - if ((opcode-SLICE) & 1) - v = POP(); - else - v = NULL; - u = POP(); - x = apply_slice(u, v, w); - DECREF(u); - XDECREF(v); - XDECREF(w); - PUSH(x); - break; - - case STORE_SLICE+0: - case STORE_SLICE+1: - case STORE_SLICE+2: - case STORE_SLICE+3: - if ((opcode-STORE_SLICE) & 2) - w = POP(); - else - w = NULL; - if ((opcode-STORE_SLICE) & 1) - v = POP(); - else - v = NULL; - u = POP(); - t = POP(); - err = assign_slice(u, v, w, t); /* u[v:w] = t */ - DECREF(t); - DECREF(u); - XDECREF(v); - XDECREF(w); - break; - - case DELETE_SLICE+0: - case DELETE_SLICE+1: - case DELETE_SLICE+2: - case DELETE_SLICE+3: - if ((opcode-DELETE_SLICE) & 2) - w = POP(); - else - w = NULL; - if ((opcode-DELETE_SLICE) & 1) - v = POP(); - else - v = NULL; - u = POP(); - err = assign_slice(u, v, w, (object *)NULL); - /* del u[v:w] */ - DECREF(u); - XDECREF(v); - XDECREF(w); - break; - - case STORE_SUBSCR: - w = POP(); - v = POP(); - u = POP(); - /* v[w] = u */ - err = assign_subscript(v, w, u); - DECREF(u); - DECREF(v); - DECREF(w); - break; - - case DELETE_SUBSCR: - w = POP(); - v = POP(); - /* del v[w] */ - err = assign_subscript(v, w, (object *)NULL); - DECREF(v); - DECREF(w); - break; - - case PRINT_EXPR: - v = POP(); - fp = sysgetfile("stdout", stdout); - /* Print value except if procedure result */ - if (v != None) { - flushline(); - printobject(v, fp, 0); - fprintf(fp, "\n"); - } - DECREF(v); - break; - - case PRINT_ITEM: - v = POP(); - fp = sysgetfile("stdout", stdout); - if (needspace) - fprintf(fp, " "); - if (is_stringobject(v)) { - char *s = getstringvalue(v); - int len = getstringsize(v); - fwrite(s, 1, len, fp); - if (len > 0 && s[len-1] == '\n') - needspace = 0; - else - needspace = 1; - } - else { - printobject(v, fp, 0); - needspace = 1; - } - DECREF(v); - break; - - case PRINT_NEWLINE: - fp = sysgetfile("stdout", stdout); - fprintf(fp, "\n"); - needspace = 0; - break; - - case BREAK_LOOP: - why = WHY_BREAK; - break; - - case RAISE_EXCEPTION: - v = POP(); - w = POP(); - if (!is_stringobject(w)) - err_setstr(TypeError, - "exceptions must be strings"); - else - err_setval(w, v); - DECREF(v); - DECREF(w); - why = WHY_EXCEPTION; - break; - - case LOAD_LOCALS: - v = f->f_locals; - INCREF(v); - PUSH(v); - break; - - case RETURN_VALUE: - retval = POP(); - why = WHY_RETURN; - break; - - case REQUIRE_ARGS: - if (EMPTY()) { - err_setstr(TypeError, - "function expects argument(s)"); - why = WHY_EXCEPTION; - } - break; - - case REFUSE_ARGS: - if (!EMPTY()) { - err_setstr(TypeError, - "function expects no argument(s)"); - why = WHY_EXCEPTION; - } - break; - - case BUILD_FUNCTION: - v = POP(); - x = newfuncobject(v, f->f_globals); - DECREF(v); - PUSH(x); - break; - - case POP_BLOCK: - { - block *b = pop_block(f); - while (STACK_LEVEL() > b->b_level) { - v = POP(); - DECREF(v); - } - } - break; - - case END_FINALLY: - v = POP(); - if (is_intobject(v)) { - why = (enum why_code) getintvalue(v); - if (why == WHY_RETURN) - retval = POP(); - } - else if (is_stringobject(v)) { - w = POP(); - err_setval(v, w); - DECREF(w); - w = POP(); - tb_store(w); - DECREF(w); - why = WHY_RERAISE; - } - else if (v != None) { - err_setstr(SystemError, - "'finally' pops bad exception"); - why = WHY_EXCEPTION; - } - DECREF(v); - break; - - case BUILD_CLASS: - w = POP(); - v = POP(); - x = build_class(v, w); - PUSH(x); - DECREF(v); - DECREF(w); - break; - - case STORE_NAME: - w = GETNAMEV(oparg); - v = POP(); - err = dict2insert(f->f_locals, w, v); - DECREF(v); - break; - - case DELETE_NAME: - name = GETNAME(oparg); - if ((err = dictremove(f->f_locals, name)) != 0) - err_setstr(NameError, name); - break; - - case UNPACK_TUPLE: - v = POP(); - if (!is_tupleobject(v)) { - err_setstr(TypeError, "unpack non-tuple"); - why = WHY_EXCEPTION; - } - else if (gettuplesize(v) != oparg) { - err_setstr(RuntimeError, - "unpack tuple of wrong size"); - why = WHY_EXCEPTION; - } - else { - for (; --oparg >= 0; ) { - w = gettupleitem(v, oparg); - INCREF(w); - PUSH(w); - } - } - DECREF(v); - break; - - case UNPACK_LIST: - v = POP(); - if (!is_listobject(v)) { - err_setstr(TypeError, "unpack non-list"); - why = WHY_EXCEPTION; - } - else if (getlistsize(v) != oparg) { - err_setstr(RuntimeError, - "unpack list of wrong size"); - why = WHY_EXCEPTION; - } - else { - for (; --oparg >= 0; ) { - w = getlistitem(v, oparg); - INCREF(w); - PUSH(w); - } - } - DECREF(v); - break; - - case STORE_ATTR: - name = GETNAME(oparg); - v = POP(); - u = POP(); - err = setattr(v, name, u); /* v.name = u */ - DECREF(v); - DECREF(u); - break; - - case DELETE_ATTR: - name = GETNAME(oparg); - v = POP(); - err = setattr(v, name, (object *)NULL); - /* del v.name */ - DECREF(v); - break; - - case LOAD_CONST: - x = GETCONST(oparg); - INCREF(x); - PUSH(x); - break; - - case LOAD_NAME: - name = GETNAME(oparg); - x = dictlookup(f->f_locals, name); - if (x == NULL) { - x = dictlookup(f->f_globals, name); - if (x == NULL) - x = getbuiltin(name); - } - if (x == NULL) - err_setstr(NameError, name); - else - INCREF(x); - PUSH(x); - break; - - case BUILD_TUPLE: - x = newtupleobject(oparg); - if (x != NULL) { - for (; --oparg >= 0;) { - w = POP(); - err = settupleitem(x, oparg, w); - if (err != 0) - break; - } - PUSH(x); - } - break; - - case BUILD_LIST: - x = newlistobject(oparg); - if (x != NULL) { - for (; --oparg >= 0;) { - w = POP(); - err = setlistitem(x, oparg, w); - if (err != 0) - break; - } - PUSH(x); - } - break; - - case BUILD_MAP: - x = newdictobject(); - PUSH(x); - break; - - case LOAD_ATTR: - name = GETNAME(oparg); - v = POP(); - x = getattr(v, name); - DECREF(v); - PUSH(x); - break; - - case COMPARE_OP: - w = POP(); - v = POP(); - x = cmp_outcome((enum cmp_op)oparg, v, w); - DECREF(v); - DECREF(w); - PUSH(x); - break; - - case IMPORT_NAME: - name = GETNAME(oparg); - x = import_module(name); - XINCREF(x); - PUSH(x); - break; - - case IMPORT_FROM: - name = GETNAME(oparg); - v = TOP(); - err = import_from(f->f_locals, v, name); - break; - - case JUMP_FORWARD: - JUMPBY(oparg); - break; - - case JUMP_IF_FALSE: - if (!testbool(TOP())) - JUMPBY(oparg); - break; - - case JUMP_IF_TRUE: - if (testbool(TOP())) - JUMPBY(oparg); - break; - - case JUMP_ABSOLUTE: - JUMPTO(oparg); - break; - - case FOR_LOOP: - /* for v in s: ... - On entry: stack contains s, i. - On exit: stack contains s, i+1, s[i]; - but if loop exhausted: - s, i are popped, and we jump */ - w = POP(); /* Loop index */ - v = POP(); /* Sequence object */ - u = loop_subscript(v, w); - if (u != NULL) { - PUSH(v); - x = newintobject(getintvalue(w)+1); - PUSH(x); - DECREF(w); - PUSH(u); - } - else { - DECREF(v); - DECREF(w); - /* A NULL can mean "s exhausted" - but also an error: */ - if (err_occurred()) - why = WHY_EXCEPTION; - else - JUMPBY(oparg); - } - break; - - case SETUP_LOOP: - case SETUP_EXCEPT: - case SETUP_FINALLY: - setup_block(f, opcode, INSTR_OFFSET() + oparg, - STACK_LEVEL()); - break; - - case SET_LINENO: -#ifdef TRACE - if (trace) - printf("--- Line %d ---\n", oparg); -#endif - lineno = oparg; - break; - - default: - fprintf(stderr, - "XXX lineno: %d, opcode: %d\n", - lineno, opcode); - err_setstr(SystemError, "eval_code: unknown opcode"); - why = WHY_EXCEPTION; - break; - - } /* switch */ - - - /* Quickly continue if no error occurred */ - - if (why == WHY_NOT) { - if (err == 0 && x != NULL) - continue; /* Normal, fast path */ - why = WHY_EXCEPTION; - x = None; - err = 0; - } - -#ifndef NDEBUG - /* Double-check exception status */ - - if (why == WHY_EXCEPTION || why == WHY_RERAISE) { - if (!err_occurred()) { - fprintf(stderr, "XXX ghost error\n"); - err_setstr(SystemError, "ghost error"); - why = WHY_EXCEPTION; - } - } - else { - if (err_occurred()) { - fprintf(stderr, "XXX undetected error\n"); - why = WHY_EXCEPTION; - } - } -#endif - - /* Log traceback info if this is a real exception */ - - if (why == WHY_EXCEPTION) { - int lasti = INSTR_OFFSET() - 1; - if (HAS_ARG(opcode)) - lasti -= 2; - tb_here(f, lasti, lineno); - } - - /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ - - if (why == WHY_RERAISE) - why = WHY_EXCEPTION; - - /* Unwind stacks if a (pseudo) exception occurred */ - - while (why != WHY_NOT && f->f_iblock > 0) { - block *b = pop_block(f); - while (STACK_LEVEL() > b->b_level) { - v = POP(); - XDECREF(v); - } - if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { - why = WHY_NOT; - JUMPTO(b->b_handler); - break; - } - if (b->b_type == SETUP_FINALLY || - b->b_type == SETUP_EXCEPT && - why == WHY_EXCEPTION) { - if (why == WHY_EXCEPTION) { - object *exc, *val; - err_get(&exc, &val); - if (val == NULL) { - val = None; - INCREF(val); - } - v = tb_fetch(); - /* Make the raw exception data - available to the handler, - so a program can emulate the - Python main loop. Don't do - this for 'finally'. */ - if (b->b_type == SETUP_EXCEPT) { -#if 0 /* Oops, this breaks too many things */ - sysset("exc_traceback", v); -#endif - sysset("exc_value", val); - sysset("exc_type", exc); - err_clear(); - } - PUSH(v); - PUSH(val); - PUSH(exc); - } - else { - if (why == WHY_RETURN) - PUSH(retval); - v = newintobject((long)why); - PUSH(v); - } - why = WHY_NOT; - JUMPTO(b->b_handler); - break; - } - } /* unwind stack */ - - /* End the loop if we still have an error (or return) */ - - if (why != WHY_NOT) - break; - - } /* main loop */ - - /* Pop remaining stack entries */ - - while (!EMPTY()) { - v = POP(); - XDECREF(v); - } - - /* Restore previous frame and release the current one */ - - current_frame = f->f_back; - DECREF(f); - - if (why == WHY_RETURN) - return retval; - else - return NULL; -}