diff -r ffa851df0825 -r 2fb8b9db1c86 symbian-qemu-0.9.1-12/python-2.6.1/Python/ceval.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/symbian-qemu-0.9.1-12/python-2.6.1/Python/ceval.c Fri Jul 31 15:01:17 2009 +0100 @@ -0,0 +1,4545 @@ + +/* Execute compiled code */ + +/* XXX TO DO: + XXX speed up searching for keywords by using a dictionary + XXX document it! + */ + +/* enable more aggressive intra-module optimizations, where available */ +#define PY_LOCAL_AGGRESSIVE + +#include "Python.h" + +#include "code.h" +#include "frameobject.h" +#include "eval.h" +#include "opcode.h" +#include "structmember.h" + +#include + +#ifndef WITH_TSC + +#define READ_TIMESTAMP(var) + +#else + +typedef unsigned long long uint64; + +#if defined(__ppc__) /* <- Don't know if this is the correct symbol; this + section should work for GCC on any PowerPC + platform, irrespective of OS. + POWER? Who knows :-) */ + +#define READ_TIMESTAMP(var) ppc_getcounter(&var) + +static void +ppc_getcounter(uint64 *v) +{ + register unsigned long tbu, tb, tbu2; + + loop: + asm volatile ("mftbu %0" : "=r" (tbu) ); + asm volatile ("mftb %0" : "=r" (tb) ); + asm volatile ("mftbu %0" : "=r" (tbu2)); + if (__builtin_expect(tbu != tbu2, 0)) goto loop; + + /* The slightly peculiar way of writing the next lines is + compiled better by GCC than any other way I tried. */ + ((long*)(v))[0] = tbu; + ((long*)(v))[1] = tb; +} + +#else /* this is for linux/x86 (and probably any other GCC/x86 combo) */ + +#define READ_TIMESTAMP(val) \ + __asm__ __volatile__("rdtsc" : "=A" (val)) + +#endif + +void dump_tsc(int opcode, int ticked, uint64 inst0, uint64 inst1, + uint64 loop0, uint64 loop1, uint64 intr0, uint64 intr1) +{ + uint64 intr, inst, loop; + PyThreadState *tstate = PyThreadState_Get(); + if (!tstate->interp->tscdump) + return; + intr = intr1 - intr0; + inst = inst1 - inst0 - intr; + loop = loop1 - loop0 - intr; + fprintf(stderr, "opcode=%03d t=%d inst=%06lld loop=%06lld\n", + opcode, ticked, inst, loop); +} + +#endif + +/* Turn this on if your compiler chokes on the big switch: */ +/* #define CASE_TOO_BIG 1 */ + +#ifdef Py_DEBUG +/* For debugging the interpreter: */ +#define LLTRACE 1 /* Low-level trace feature */ +#define CHECKEXC 1 /* Double-check exception checking */ +#endif + +typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *); + +/* Forward declarations */ +#ifdef WITH_TSC +static PyObject * call_function(PyObject ***, int, uint64*, uint64*); +#else +static PyObject * call_function(PyObject ***, int); +#endif +static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); +static PyObject * do_call(PyObject *, PyObject ***, int, int); +static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); +static PyObject * update_keyword_args(PyObject *, int, PyObject ***, + PyObject *); +static PyObject * update_star_args(int, int, PyObject *, PyObject ***); +static PyObject * load_args(PyObject ***, int); +#define CALL_FLAG_VAR 1 +#define CALL_FLAG_KW 2 + +#ifdef LLTRACE +static int lltrace; +static int prtrace(PyObject *, char *); +#endif +static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *, + int, PyObject *); +static int call_trace_protected(Py_tracefunc, PyObject *, + PyFrameObject *, int, PyObject *); +static void call_exc_trace(Py_tracefunc, PyObject *, PyFrameObject *); +static int maybe_call_line_trace(Py_tracefunc, PyObject *, + PyFrameObject *, int *, int *, int *); + +static PyObject * apply_slice(PyObject *, PyObject *, PyObject *); +static int assign_slice(PyObject *, PyObject *, + PyObject *, PyObject *); +static PyObject * cmp_outcome(int, PyObject *, PyObject *); +static PyObject * import_from(PyObject *, PyObject *); +static int import_all_from(PyObject *, PyObject *); +static PyObject * build_class(PyObject *, PyObject *, PyObject *); +static int exec_statement(PyFrameObject *, + PyObject *, PyObject *, PyObject *); +static void set_exc_info(PyThreadState *, PyObject *, PyObject *, PyObject *); +static void reset_exc_info(PyThreadState *); +static void format_exc_check_arg(PyObject *, char *, PyObject *); +static PyObject * string_concatenate(PyObject *, PyObject *, + PyFrameObject *, unsigned char *); + +#define NAME_ERROR_MSG \ + "name '%.200s' is not defined" +#define GLOBAL_NAME_ERROR_MSG \ + "global name '%.200s' is not defined" +#define UNBOUNDLOCAL_ERROR_MSG \ + "local variable '%.200s' referenced before assignment" +#define UNBOUNDFREE_ERROR_MSG \ + "free variable '%.200s' referenced before assignment" \ + " in enclosing scope" + +/* Dynamic execution profile */ +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS +static long dxpairs[257][256]; +#define dxp dxpairs[256] +#else +static long dxp[256]; +#endif +#endif + +/* Function call profile */ +#ifdef CALL_PROFILE +#define PCALL_NUM 11 +static int pcall[PCALL_NUM]; + +#define PCALL_ALL 0 +#define PCALL_FUNCTION 1 +#define PCALL_FAST_FUNCTION 2 +#define PCALL_FASTER_FUNCTION 3 +#define PCALL_METHOD 4 +#define PCALL_BOUND_METHOD 5 +#define PCALL_CFUNCTION 6 +#define PCALL_TYPE 7 +#define PCALL_GENERATOR 8 +#define PCALL_OTHER 9 +#define PCALL_POP 10 + +/* Notes about the statistics + + PCALL_FAST stats + + FAST_FUNCTION means no argument tuple needs to be created. + FASTER_FUNCTION means that the fast-path frame setup code is used. + + If there is a method call where the call can be optimized by changing + the argument tuple and calling the function directly, it gets recorded + twice. + + As a result, the relationship among the statistics appears to be + PCALL_ALL == PCALL_FUNCTION + PCALL_METHOD - PCALL_BOUND_METHOD + + PCALL_CFUNCTION + PCALL_TYPE + PCALL_GENERATOR + PCALL_OTHER + PCALL_FUNCTION > PCALL_FAST_FUNCTION > PCALL_FASTER_FUNCTION + PCALL_METHOD > PCALL_BOUND_METHOD +*/ + +#define PCALL(POS) pcall[POS]++ + +PyObject * +PyEval_GetCallStats(PyObject *self) +{ + return Py_BuildValue("iiiiiiiiiii", + pcall[0], pcall[1], pcall[2], pcall[3], + pcall[4], pcall[5], pcall[6], pcall[7], + pcall[8], pcall[9], pcall[10]); +} +#else +#define PCALL(O) + +PyObject * +PyEval_GetCallStats(PyObject *self) +{ + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef WITH_THREAD + +#ifdef HAVE_ERRNO_H +#include +#endif +#include "pythread.h" + +static PyThread_type_lock interpreter_lock = 0; /* This is the GIL */ +static long main_thread = 0; + +int +PyEval_ThreadsInitialized(void) +{ + return interpreter_lock != 0; +} + +void +PyEval_InitThreads(void) +{ + if (interpreter_lock) + return; + interpreter_lock = PyThread_allocate_lock(); + PyThread_acquire_lock(interpreter_lock, 1); + main_thread = PyThread_get_thread_ident(); +} + +void +PyEval_AcquireLock(void) +{ + PyThread_acquire_lock(interpreter_lock, 1); +} + +void +PyEval_ReleaseLock(void) +{ + PyThread_release_lock(interpreter_lock); +} + +void +PyEval_AcquireThread(PyThreadState *tstate) +{ + if (tstate == NULL) + Py_FatalError("PyEval_AcquireThread: NULL new thread state"); + /* Check someone has called PyEval_InitThreads() to create the lock */ + assert(interpreter_lock); + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError( + "PyEval_AcquireThread: non-NULL old thread state"); +} + +void +PyEval_ReleaseThread(PyThreadState *tstate) +{ + if (tstate == NULL) + Py_FatalError("PyEval_ReleaseThread: NULL thread state"); + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("PyEval_ReleaseThread: wrong thread state"); + PyThread_release_lock(interpreter_lock); +} + +/* This function is called from PyOS_AfterFork to ensure that newly + created child processes don't hold locks referring to threads which + are not running in the child process. (This could also be done using + pthread_atfork mechanism, at least for the pthreads implementation.) */ + +void +PyEval_ReInitThreads(void) +{ + PyObject *threading, *result; + PyThreadState *tstate; + + if (!interpreter_lock) + return; + /*XXX Can't use PyThread_free_lock here because it does too + much error-checking. Doing this cleanly would require + adding a new function to each thread_*.h. Instead, just + create a new lock and waste a little bit of memory */ + interpreter_lock = PyThread_allocate_lock(); + PyThread_acquire_lock(interpreter_lock, 1); + main_thread = PyThread_get_thread_ident(); + + /* Update the threading module with the new state. + */ + tstate = PyThreadState_GET(); + threading = PyMapping_GetItemString(tstate->interp->modules, + "threading"); + if (threading == NULL) { + /* threading not imported */ + PyErr_Clear(); + return; + } + result = PyObject_CallMethod(threading, "_after_fork", NULL); + if (result == NULL) + PyErr_WriteUnraisable(threading); + else + Py_DECREF(result); + Py_DECREF(threading); +} +#endif + +/* Functions save_thread and restore_thread are always defined so + dynamically loaded modules needn't be compiled separately for use + with and without threads: */ + +PyThreadState * +PyEval_SaveThread(void) +{ + PyThreadState *tstate = PyThreadState_Swap(NULL); + if (tstate == NULL) + Py_FatalError("PyEval_SaveThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) + PyThread_release_lock(interpreter_lock); +#endif + return tstate; +} + +void +PyEval_RestoreThread(PyThreadState *tstate) +{ + if (tstate == NULL) + Py_FatalError("PyEval_RestoreThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) { + int err = errno; + PyThread_acquire_lock(interpreter_lock, 1); + errno = err; + } +#endif + PyThreadState_Swap(tstate); +} + + +/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX + signal handlers or Mac I/O completion routines) can schedule calls + to a function to be called synchronously. + The synchronous function is called with one void* argument. + It should return 0 for success or -1 for failure -- failure should + be accompanied by an exception. + + If registry succeeds, the registry function returns 0; if it fails + (e.g. due to too many pending calls) it returns -1 (without setting + an exception condition). + + Note that because registry may occur from within signal handlers, + or other asynchronous events, calling malloc() is unsafe! + +#ifdef WITH_THREAD + Any thread can schedule pending calls, but only the main thread + will execute them. +#endif + + XXX WARNING! ASYNCHRONOUSLY EXECUTING CODE! + There are two possible race conditions: + (1) nested asynchronous registry calls; + (2) registry calls made while pending calls are being processed. + While (1) is very unlikely, (2) is a real possibility. + The current code is safe against (2), but not against (1). + The safety against (2) is derived from the fact that only one + thread (the main thread) ever takes things out of the queue. + + XXX Darn! With the advent of thread state, we should have an array + of pending calls per thread in the thread state! Later... +*/ + +#define NPENDINGCALLS 32 +static struct { + int (*func)(void *); + void *arg; +} pendingcalls[NPENDINGCALLS]; +static volatile int pendingfirst = 0; +static volatile int pendinglast = 0; +static volatile int things_to_do = 0; + +int +Py_AddPendingCall(int (*func)(void *), void *arg) +{ + static volatile int busy = 0; + int i, j; + /* XXX Begin critical section */ + /* XXX If you want this to be safe against nested + XXX asynchronous calls, you'll have to work harder! */ + if (busy) + return -1; + busy = 1; + i = pendinglast; + j = (i + 1) % NPENDINGCALLS; + if (j == pendingfirst) { + busy = 0; + return -1; /* Queue full */ + } + pendingcalls[i].func = func; + pendingcalls[i].arg = arg; + pendinglast = j; + + _Py_Ticker = 0; + things_to_do = 1; /* Signal main loop */ + busy = 0; + /* XXX End critical section */ + return 0; +} + +int +Py_MakePendingCalls(void) +{ + static int busy = 0; +#ifdef WITH_THREAD + if (main_thread && PyThread_get_thread_ident() != main_thread) + return 0; +#endif + if (busy) + return 0; + busy = 1; + things_to_do = 0; + for (;;) { + int i; + int (*func)(void *); + void *arg; + i = pendingfirst; + if (i == pendinglast) + break; /* Queue empty */ + func = pendingcalls[i].func; + arg = pendingcalls[i].arg; + pendingfirst = (i + 1) % NPENDINGCALLS; + if (func(arg) < 0) { + busy = 0; + things_to_do = 1; /* We're not done yet */ + return -1; + } + } + busy = 0; + return 0; +} + + +/* The interpreter's recursion limit */ + +#ifndef Py_DEFAULT_RECURSION_LIMIT +#define Py_DEFAULT_RECURSION_LIMIT 1000 +#endif +static int recursion_limit = Py_DEFAULT_RECURSION_LIMIT; +int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT; + +int +Py_GetRecursionLimit(void) +{ + return recursion_limit; +} + +void +Py_SetRecursionLimit(int new_limit) +{ + recursion_limit = new_limit; + _Py_CheckRecursionLimit = recursion_limit; +} + +/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall() + if the recursion_depth reaches _Py_CheckRecursionLimit. + If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit + to guarantee that _Py_CheckRecursiveCall() is regularly called. + Without USE_STACKCHECK, there is no need for this. */ +int +_Py_CheckRecursiveCall(char *where) +{ + PyThreadState *tstate = PyThreadState_GET(); + +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + --tstate->recursion_depth; + PyErr_SetString(PyExc_MemoryError, "Stack overflow"); + return -1; + } +#endif + if (tstate->recursion_depth > recursion_limit) { + --tstate->recursion_depth; + PyErr_Format(PyExc_RuntimeError, + "maximum recursion depth exceeded%s", + where); + return -1; + } + _Py_CheckRecursionLimit = recursion_limit; + return 0; +} + +/* Status code for main loop (reason for stack unwind) */ +enum why_code { + WHY_NOT = 0x0001, /* No error */ + WHY_EXCEPTION = 0x0002, /* Exception occurred */ + WHY_RERAISE = 0x0004, /* Exception re-raised by 'finally' */ + WHY_RETURN = 0x0008, /* 'return' statement */ + WHY_BREAK = 0x0010, /* 'break' statement */ + WHY_CONTINUE = 0x0020, /* 'continue' statement */ + WHY_YIELD = 0x0040 /* 'yield' operator */ +}; + +static enum why_code do_raise(PyObject *, PyObject *, PyObject *); +static int unpack_iterable(PyObject *, int, PyObject **); + +/* for manipulating the thread switch and periodic "stuff" - used to be + per thread, now just a pair o' globals */ +int _Py_CheckInterval = 100; +volatile int _Py_Ticker = 100; + +PyObject * +PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals) +{ + return PyEval_EvalCodeEx(co, + globals, locals, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + NULL); +} + + +/* Interpreter main loop */ + +PyObject * +PyEval_EvalFrame(PyFrameObject *f) { + /* This is for backward compatibility with extension modules that + used this API; core interpreter code should call + PyEval_EvalFrameEx() */ + return PyEval_EvalFrameEx(f, 0); +} + +PyObject * +PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) +{ +#ifdef DXPAIRS + int lastopcode = 0; +#endif + register PyObject **stack_pointer; /* Next free slot in value stack */ + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register PyObject *x; /* Result object -- NULL if error */ + register PyObject *v; /* Temporary objects popped off stack */ + register PyObject *w; + register PyObject *u; + register PyObject *t; + register PyObject *stream = NULL; /* for PRINT opcodes */ + register PyObject **fastlocals, **freevars; + PyObject *retval = NULL; /* Return value */ + PyThreadState *tstate = PyThreadState_GET(); + PyCodeObject *co; + + /* when tracing we set things up so that + + not (instr_lb <= current_bytecode_offset < instr_ub) + + is true when the line being executed has changed. The + initial values are such as to make this false the first + time it is tested. */ + int instr_ub = -1, instr_lb = 0, instr_prev = -1; + + unsigned char *first_instr; + PyObject *names; + PyObject *consts; +#if defined(Py_DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ + char *filename; +#endif + +/* Tuple access macros */ + +#ifndef Py_DEBUG +#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i)) +#else +#define GETITEM(v, i) PyTuple_GetItem((v), (i)) +#endif + +#ifdef WITH_TSC +/* Use Pentium timestamp counter to mark certain events: + inst0 -- beginning of switch statement for opcode dispatch + inst1 -- end of switch statement (may be skipped) + loop0 -- the top of the mainloop + loop1 -- place where control returns again to top of mainloop + (may be skipped) + intr1 -- beginning of long interruption + intr2 -- end of long interruption + + Many opcodes call out to helper C functions. In some cases, the + time in those functions should be counted towards the time for the + opcode, but not in all cases. For example, a CALL_FUNCTION opcode + calls another Python function; there's no point in charge all the + bytecode executed by the called function to the caller. + + It's hard to make a useful judgement statically. In the presence + of operator overloading, it's impossible to tell if a call will + execute new Python code or not. + + It's a case-by-case judgement. I'll use intr1 for the following + cases: + + EXEC_STMT + IMPORT_STAR + IMPORT_FROM + CALL_FUNCTION (and friends) + + */ + uint64 inst0, inst1, loop0, loop1, intr0 = 0, intr1 = 0; + int ticked = 0; + + READ_TIMESTAMP(inst0); + READ_TIMESTAMP(inst1); + READ_TIMESTAMP(loop0); + READ_TIMESTAMP(loop1); + + /* shut up the compiler */ + opcode = 0; +#endif + +/* Code access macros */ + +#define INSTR_OFFSET() ((int)(next_instr - first_instr)) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define PEEKARG() ((next_instr[2]<<8) + next_instr[1]) +#define JUMPTO(x) (next_instr = first_instr + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* OpCode prediction macros + Some opcodes tend to come in pairs thus making it possible to + predict the second code when the first is run. For example, + COMPARE_OP is often followed by JUMP_IF_FALSE or JUMP_IF_TRUE. And, + those opcodes are often followed by a POP_TOP. + + Verifying the prediction costs a single high-speed test of a register + variable against a constant. If the pairing was good, then the + processor's own internal branch predication has a high likelihood of + success, resulting in a nearly zero-overhead transition to the + next opcode. A successful prediction saves a trip through the eval-loop + including its two unpredictable branches, the HAS_ARG test and the + switch-case. Combined with the processor's internal branch prediction, + a successful PREDICT has the effect of making the two opcodes run as if + they were a single new opcode with the bodies combined. + + If collecting opcode statistics, your choices are to either keep the + predictions turned-on and interpret the results as if some opcodes + had been combined or turn-off predictions so that the opcode frequency + counter updates for both opcodes. +*/ + +#ifdef DYNAMIC_EXECUTION_PROFILE +#define PREDICT(op) if (0) goto PRED_##op +#else +#define PREDICT(op) if (*next_instr == op) goto PRED_##op +#endif + +#define PREDICTED(op) PRED_##op: next_instr++ +#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 + +/* Stack manipulation macros */ + +/* The stack can grow at most MAXINT deep, as co_nlocals and + co_stacksize are ints. */ +#define STACK_LEVEL() ((int)(stack_pointer - f->f_valuestack)) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define SECOND() (stack_pointer[-2]) +#define THIRD() (stack_pointer[-3]) +#define FOURTH() (stack_pointer[-4]) +#define SET_TOP(v) (stack_pointer[-1] = (v)) +#define SET_SECOND(v) (stack_pointer[-2] = (v)) +#define SET_THIRD(v) (stack_pointer[-3] = (v)) +#define SET_FOURTH(v) (stack_pointer[-4] = (v)) +#define BASIC_STACKADJ(n) (stack_pointer += n) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef LLTRACE +#define PUSH(v) { (void)(BASIC_PUSH(v), \ + lltrace && prtrace(TOP(), "push")); \ + assert(STACK_LEVEL() <= co->co_stacksize); } +#define POP() ((void)(lltrace && prtrace(TOP(), "pop")), \ + BASIC_POP()) +#define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \ + lltrace && prtrace(TOP(), "stackadj")); \ + assert(STACK_LEVEL() <= co->co_stacksize); } +#define EXT_POP(STACK_POINTER) ((void)(lltrace && \ + prtrace((STACK_POINTER)[-1], "ext_pop")), \ + *--(STACK_POINTER)) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#define STACKADJ(n) BASIC_STACKADJ(n) +#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER)) +#endif + +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) + +/* The SETLOCAL() macro must not DECREF the local variable in-place and + then store the new value; it must copy the old value to a temporary + value, then store the new value, and then DECREF the temporary value. + This is because it is possible that during the DECREF the frame is + accessed by other code (e.g. a __del__ method or gc.collect()) and the + variable would be pointing to already-freed memory. */ +#define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \ + GETLOCAL(i) = value; \ + Py_XDECREF(tmp); } while (0) + +/* Start of code */ + + if (f == NULL) + return NULL; + + /* push frame */ + if (Py_EnterRecursiveCall("")) + return NULL; + + tstate->frame = f; + + if (tstate->use_tracing) { + if (tstate->c_tracefunc != NULL) { + /* tstate->c_tracefunc, if defined, is a + function that will be called on *every* entry + to a code block. Its return value, if not + None, is a function that will be called at + the start of each executed line of code. + (Actually, the function must return itself + in order to continue tracing.) The trace + functions are called with three arguments: + a pointer to the current frame, a string + indicating why the function is called, and + an argument which depends on the situation. + The global trace function is also called + whenever an exception is detected. */ + if (call_trace_protected(tstate->c_tracefunc, + tstate->c_traceobj, + f, PyTrace_CALL, Py_None)) { + /* Trace function raised an error */ + goto exit_eval_frame; + } + } + if (tstate->c_profilefunc != NULL) { + /* Similar for c_profilefunc, except it needn't + return itself and isn't called for "line" events */ + if (call_trace_protected(tstate->c_profilefunc, + tstate->c_profileobj, + f, PyTrace_CALL, Py_None)) { + /* Profile function raised an error */ + goto exit_eval_frame; + } + } + } + + co = f->f_code; + names = co->co_names; + consts = co->co_consts; + fastlocals = f->f_localsplus; + freevars = f->f_localsplus + co->co_nlocals; + first_instr = (unsigned char*) PyString_AS_STRING(co->co_code); + /* An explanation is in order for the next line. + + f->f_lasti now refers to the index of the last instruction + executed. You might think this was obvious from the name, but + this wasn't always true before 2.3! PyFrame_New now sets + f->f_lasti to -1 (i.e. the index *before* the first instruction) + and YIELD_VALUE doesn't fiddle with f_lasti any more. So this + does work. Promise. + + When the PREDICT() macros are enabled, some opcode pairs follow in + direct succession without updating f->f_lasti. A successful + prediction effectively links the two codes together as if they + were a single new opcode; accordingly,f->f_lasti will point to + the first code in the pair (for instance, GET_ITER followed by + FOR_ITER is effectively a single opcode and f->f_lasti will point + at to the beginning of the combined pair.) + */ + next_instr = first_instr + f->f_lasti + 1; + stack_pointer = f->f_stacktop; + assert(stack_pointer != NULL); + f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */ + +#ifdef LLTRACE + lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL; +#endif +#if defined(Py_DEBUG) || defined(LLTRACE) + filename = PyString_AsString(co->co_filename); +#endif + + why = WHY_NOT; + err = 0; + x = Py_None; /* Not a reference, just anything non-NULL */ + w = NULL; + + if (throwflag) { /* support for generator.throw() */ + why = WHY_EXCEPTION; + goto on_error; + } + + for (;;) { +#ifdef WITH_TSC + if (inst1 == 0) { + /* Almost surely, the opcode executed a break + or a continue, preventing inst1 from being set + on the way out of the loop. + */ + READ_TIMESTAMP(inst1); + loop1 = inst1; + } + dump_tsc(opcode, ticked, inst0, inst1, loop0, loop1, + intr0, intr1); + ticked = 0; + inst1 = 0; + intr0 = 0; + intr1 = 0; + READ_TIMESTAMP(loop0); +#endif + assert(stack_pointer >= f->f_valuestack); /* else underflow */ + assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */ + + /* Do periodic things. Doing this every time through + the loop would add too much overhead, so we do it + only every Nth instruction. We also do it if + ``things_to_do'' is set, i.e. when an asynchronous + event needs attention (e.g. a signal handler or + async I/O handler); see Py_AddPendingCall() and + Py_MakePendingCalls() above. */ + + if (--_Py_Ticker < 0) { + if (*next_instr == SETUP_FINALLY) { + /* Make the last opcode before + a try: finally: block uninterruptable. */ + goto fast_next_opcode; + } + _Py_Ticker = _Py_CheckInterval; + tstate->tick_counter++; +#ifdef WITH_TSC + ticked = 1; +#endif + if (things_to_do) { + if (Py_MakePendingCalls() < 0) { + why = WHY_EXCEPTION; + goto on_error; + } + if (things_to_do) + /* MakePendingCalls() didn't succeed. + Force early re-execution of this + "periodic" code, possibly after + a thread switch */ + _Py_Ticker = 0; + } +#ifdef WITH_THREAD + if (interpreter_lock) { + /* Give another thread a chance */ + + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("ceval: tstate mix-up"); + PyThread_release_lock(interpreter_lock); + + /* Other threads may run now */ + + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError("ceval: orphan tstate"); + + /* Check for thread interrupts */ + + if (tstate->async_exc != NULL) { + x = tstate->async_exc; + tstate->async_exc = NULL; + PyErr_SetNone(x); + Py_DECREF(x); + why = WHY_EXCEPTION; + goto on_error; + } + } +#endif + } + + fast_next_opcode: + f->f_lasti = INSTR_OFFSET(); + + /* line-by-line tracing support */ + + if (tstate->c_tracefunc != NULL && !tstate->tracing) { + /* see maybe_call_line_trace + for expository comments */ + f->f_stacktop = stack_pointer; + + err = maybe_call_line_trace(tstate->c_tracefunc, + tstate->c_traceobj, + f, &instr_lb, &instr_ub, + &instr_prev); + /* Reload possibly changed frame fields */ + JUMPTO(f->f_lasti); + if (f->f_stacktop != NULL) { + stack_pointer = f->f_stacktop; + f->f_stacktop = NULL; + } + if (err) { + /* trace function raised an exception */ + goto on_error; + } + } + + /* Extract opcode and argument */ + + opcode = NEXTOP(); + oparg = 0; /* allows oparg to be stored in a register because + it doesn't have to be remembered across a full loop */ + if (HAS_ARG(opcode)) + oparg = NEXTARG(); + dispatch_opcode: +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS + dxpairs[lastopcode][opcode]++; + lastopcode = opcode; +#endif + dxp[opcode]++; +#endif + +#ifdef LLTRACE + /* Instruction tracing */ + + if (lltrace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + f->f_lasti, opcode, oparg); + } + else { + printf("%d: %d\n", + f->f_lasti, opcode); + } + } +#endif + + /* Main switch on opcode */ + READ_TIMESTAMP(inst0); + + 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 NOP: + goto fast_next_opcode; + + case LOAD_FAST: + x = GETLOCAL(oparg); + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + goto fast_next_opcode; + } + format_exc_check_arg(PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(co->co_varnames, oparg)); + break; + + case LOAD_CONST: + x = GETITEM(consts, oparg); + Py_INCREF(x); + PUSH(x); + goto fast_next_opcode; + + PREDICTED_WITH_ARG(STORE_FAST); + case STORE_FAST: + v = POP(); + SETLOCAL(oparg, v); + goto fast_next_opcode; + + PREDICTED(POP_TOP); + case POP_TOP: + v = POP(); + Py_DECREF(v); + goto fast_next_opcode; + + case ROT_TWO: + v = TOP(); + w = SECOND(); + SET_TOP(w); + SET_SECOND(v); + goto fast_next_opcode; + + case ROT_THREE: + v = TOP(); + w = SECOND(); + x = THIRD(); + SET_TOP(w); + SET_SECOND(x); + SET_THIRD(v); + goto fast_next_opcode; + + case ROT_FOUR: + u = TOP(); + v = SECOND(); + w = THIRD(); + x = FOURTH(); + SET_TOP(v); + SET_SECOND(w); + SET_THIRD(x); + SET_FOURTH(u); + goto fast_next_opcode; + + case DUP_TOP: + v = TOP(); + Py_INCREF(v); + PUSH(v); + goto fast_next_opcode; + + case DUP_TOPX: + if (oparg == 2) { + x = TOP(); + Py_INCREF(x); + w = SECOND(); + Py_INCREF(w); + STACKADJ(2); + SET_TOP(x); + SET_SECOND(w); + goto fast_next_opcode; + } else if (oparg == 3) { + x = TOP(); + Py_INCREF(x); + w = SECOND(); + Py_INCREF(w); + v = THIRD(); + Py_INCREF(v); + STACKADJ(3); + SET_TOP(x); + SET_SECOND(w); + SET_THIRD(v); + goto fast_next_opcode; + } + Py_FatalError("invalid argument to DUP_TOPX" + " (bytecode corruption?)"); + break; + + case UNARY_POSITIVE: + v = TOP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case UNARY_NEGATIVE: + v = TOP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case UNARY_NOT: + v = TOP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + SET_TOP(Py_True); + continue; + } + else if (err > 0) { + Py_INCREF(Py_False); + SET_TOP(Py_False); + err = 0; + continue; + } + STACKADJ(-1); + break; + + case UNARY_CONVERT: + v = TOP(); + x = PyObject_Repr(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case UNARY_INVERT: + v = TOP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_POWER: + w = POP(); + v = TOP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_MULTIPLY: + w = POP(); + v = TOP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_DIVIDE: + if (!_Py_QnewFlag) { + w = POP(); + v = TOP(); + x = PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + } + /* -Qnew is in effect: fall through to + BINARY_TRUE_DIVIDE */ + case BINARY_TRUE_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_TrueDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_FLOOR_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_FloorDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_MODULO: + w = POP(); + v = TOP(); + x = PyNumber_Remainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_ADD: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int + int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a + b; + if ((i^a) < 0 && (i^b) < 0) + goto slow_add; + x = PyInt_FromLong(i); + } + else if (PyString_CheckExact(v) && + PyString_CheckExact(w)) { + x = string_concatenate(v, w, f, next_instr); + /* string_concatenate consumed the ref to v */ + goto skip_decref_vx; + } + else { + slow_add: + x = PyNumber_Add(v, w); + } + Py_DECREF(v); + skip_decref_vx: + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_SUBTRACT: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int - int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a - b; + if ((i^a) < 0 && (i^~b) < 0) + goto slow_sub; + x = PyInt_FromLong(i); + } + else { + slow_sub: + x = PyNumber_Subtract(v, w); + } + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_SUBSCR: + w = POP(); + v = TOP(); + if (PyList_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: list[int] */ + Py_ssize_t i = PyInt_AsSsize_t(w); + if (i < 0) + i += PyList_GET_SIZE(v); + if (i >= 0 && i < PyList_GET_SIZE(v)) { + x = PyList_GET_ITEM(v, i); + Py_INCREF(x); + } + else + goto slow_get; + } + else + slow_get: + x = PyObject_GetItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_LSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_RSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_AND: + w = POP(); + v = TOP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_XOR: + w = POP(); + v = TOP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_OR: + w = POP(); + v = TOP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case LIST_APPEND: + w = POP(); + v = POP(); + err = PyList_Append(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) { + PREDICT(JUMP_ABSOLUTE); + continue; + } + break; + + case INPLACE_POWER: + w = POP(); + v = TOP(); + x = PyNumber_InPlacePower(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_MULTIPLY: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceMultiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_DIVIDE: + if (!_Py_QnewFlag) { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + } + /* -Qnew is in effect: fall through to + INPLACE_TRUE_DIVIDE */ + case INPLACE_TRUE_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceTrueDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_FLOOR_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceFloorDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_MODULO: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceRemainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_ADD: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int + int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a + b; + if ((i^a) < 0 && (i^b) < 0) + goto slow_iadd; + x = PyInt_FromLong(i); + } + else if (PyString_CheckExact(v) && + PyString_CheckExact(w)) { + x = string_concatenate(v, w, f, next_instr); + /* string_concatenate consumed the ref to v */ + goto skip_decref_v; + } + else { + slow_iadd: + x = PyNumber_InPlaceAdd(v, w); + } + Py_DECREF(v); + skip_decref_v: + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_SUBTRACT: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int - int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a - b; + if ((i^a) < 0 && (i^~b) < 0) + goto slow_isub; + x = PyInt_FromLong(i); + } + else { + slow_isub: + x = PyNumber_InPlaceSubtract(v, w); + } + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_LSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceLshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_RSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceRshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_AND: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceAnd(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_XOR: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceXor(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_OR: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceOr(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + 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 = TOP(); + x = apply_slice(u, v, w); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + SET_TOP(x); + if (x != NULL) continue; + 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 */ + Py_DECREF(t); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + 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, (PyObject *)NULL); + /* del u[v:w] */ + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case STORE_SUBSCR: + w = TOP(); + v = SECOND(); + u = THIRD(); + STACKADJ(-3); + /* v[w] = u */ + err = PyObject_SetItem(v, w, u); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case DELETE_SUBSCR: + w = TOP(); + v = SECOND(); + STACKADJ(-2); + /* del v[w] */ + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case PRINT_EXPR: + v = POP(); + w = PySys_GetObject("displayhook"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "lost sys.displayhook"); + err = -1; + x = NULL; + } + if (err == 0) { + x = PyTuple_Pack(1, v); + if (x == NULL) + err = -1; + } + if (err == 0) { + w = PyEval_CallObject(w, x); + Py_XDECREF(w); + if (w == NULL) + err = -1; + } + Py_DECREF(v); + Py_XDECREF(x); + break; + + case PRINT_ITEM_TO: + w = stream = POP(); + /* fall through to PRINT_ITEM */ + + case PRINT_ITEM: + v = POP(); + if (stream == NULL || stream == Py_None) { + w = PySys_GetObject("stdout"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + err = -1; + } + } + /* PyFile_SoftSpace() can exececute arbitrary code + if sys.stdout is an instance with a __getattr__. + If __getattr__ raises an exception, w will + be freed, so we need to prevent that temporarily. */ + Py_XINCREF(w); + if (w != NULL && PyFile_SoftSpace(w, 0)) + err = PyFile_WriteString(" ", w); + if (err == 0) + err = PyFile_WriteObject(v, w, Py_PRINT_RAW); + if (err == 0) { + /* XXX move into writeobject() ? */ + if (PyString_Check(v)) { + char *s = PyString_AS_STRING(v); + Py_ssize_t len = PyString_GET_SIZE(v); + if (len == 0 || + !isspace(Py_CHARMASK(s[len-1])) || + s[len-1] == ' ') + PyFile_SoftSpace(w, 1); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(v)) { + Py_UNICODE *s = PyUnicode_AS_UNICODE(v); + Py_ssize_t len = PyUnicode_GET_SIZE(v); + if (len == 0 || + !Py_UNICODE_ISSPACE(s[len-1]) || + s[len-1] == ' ') + PyFile_SoftSpace(w, 1); + } +#endif + else + PyFile_SoftSpace(w, 1); + } + Py_XDECREF(w); + Py_DECREF(v); + Py_XDECREF(stream); + stream = NULL; + if (err == 0) + continue; + break; + + case PRINT_NEWLINE_TO: + w = stream = POP(); + /* fall through to PRINT_NEWLINE */ + + case PRINT_NEWLINE: + if (stream == NULL || stream == Py_None) { + w = PySys_GetObject("stdout"); + if (w == NULL) + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + } + if (w != NULL) { + /* w.write() may replace sys.stdout, so we + * have to keep our reference to it */ + Py_INCREF(w); + err = PyFile_WriteString("\n", w); + if (err == 0) + PyFile_SoftSpace(w, 0); + Py_DECREF(w); + } + Py_XDECREF(stream); + stream = NULL; + break; + + +#ifdef CASE_TOO_BIG + default: switch (opcode) { +#endif + case RAISE_VARARGS: + u = v = w = NULL; + switch (oparg) { + case 3: + u = POP(); /* traceback */ + /* Fallthrough */ + case 2: + v = POP(); /* value */ + /* Fallthrough */ + case 1: + w = POP(); /* exc */ + case 0: /* Fallthrough */ + why = do_raise(w, v, u); + break; + default: + PyErr_SetString(PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + why = WHY_EXCEPTION; + break; + } + break; + + case LOAD_LOCALS: + if ((x = f->f_locals) != NULL) { + Py_INCREF(x); + PUSH(x); + continue; + } + PyErr_SetString(PyExc_SystemError, "no locals"); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + goto fast_block_end; + + case YIELD_VALUE: + retval = POP(); + f->f_stacktop = stack_pointer; + why = WHY_YIELD; + goto fast_yield; + + case EXEC_STMT: + w = TOP(); + v = SECOND(); + u = THIRD(); + STACKADJ(-3); + READ_TIMESTAMP(intr0); + err = exec_statement(f, u, v, w); + READ_TIMESTAMP(intr1); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case POP_BLOCK: + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_DECREF(v); + } + } + continue; + + PREDICTED(END_FINALLY); + case END_FINALLY: + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AS_LONG(v); + assert(why != WHY_YIELD); + if (why == WHY_RETURN || + why == WHY_CONTINUE) + retval = POP(); + } + else if (PyExceptionClass_Check(v) || + PyString_Check(v)) { + w = POP(); + u = POP(); + PyErr_Restore(v, w, u); + why = WHY_RERAISE; + break; + } + else if (v != Py_None) { + PyErr_SetString(PyExc_SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case BUILD_CLASS: + u = TOP(); + v = SECOND(); + w = THIRD(); + STACKADJ(-2); + x = build_class(u, v, w); + SET_TOP(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case STORE_NAME: + w = GETITEM(names, oparg); + v = POP(); + if ((x = f->f_locals) != NULL) { + if (PyDict_CheckExact(x)) + err = PyDict_SetItem(x, w, v); + else + err = PyObject_SetItem(x, w, v); + Py_DECREF(v); + if (err == 0) continue; + break; + } + PyErr_Format(PyExc_SystemError, + "no locals found when storing %s", + PyObject_REPR(w)); + break; + + case DELETE_NAME: + w = GETITEM(names, oparg); + if ((x = f->f_locals) != NULL) { + if ((err = PyObject_DelItem(x, w)) != 0) + format_exc_check_arg(PyExc_NameError, + NAME_ERROR_MSG, + w); + break; + } + PyErr_Format(PyExc_SystemError, + "no locals when deleting %s", + PyObject_REPR(w)); + break; + + PREDICTED_WITH_ARG(UNPACK_SEQUENCE); + case UNPACK_SEQUENCE: + v = POP(); + if (PyTuple_CheckExact(v) && + PyTuple_GET_SIZE(v) == oparg) { + PyObject **items = \ + ((PyTupleObject *)v)->ob_item; + while (oparg--) { + w = items[oparg]; + Py_INCREF(w); + PUSH(w); + } + Py_DECREF(v); + continue; + } else if (PyList_CheckExact(v) && + PyList_GET_SIZE(v) == oparg) { + PyObject **items = \ + ((PyListObject *)v)->ob_item; + while (oparg--) { + w = items[oparg]; + Py_INCREF(w); + PUSH(w); + } + } else if (unpack_iterable(v, oparg, + stack_pointer + oparg)) { + stack_pointer += oparg; + } else { + /* unpack_iterable() raised an exception */ + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case STORE_ATTR: + w = GETITEM(names, oparg); + v = TOP(); + u = SECOND(); + STACKADJ(-2); + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); + if (err == 0) continue; + break; + + case DELETE_ATTR: + w = GETITEM(names, oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; + + case STORE_GLOBAL: + w = GETITEM(names, oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); + if (err == 0) continue; + break; + + case DELETE_GLOBAL: + w = GETITEM(names, oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + format_exc_check_arg( + PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w); + break; + + case LOAD_NAME: + w = GETITEM(names, oparg); + if ((v = f->f_locals) == NULL) { + PyErr_Format(PyExc_SystemError, + "no locals when loading %s", + PyObject_REPR(w)); + break; + } + if (PyDict_CheckExact(v)) { + x = PyDict_GetItem(v, w); + Py_XINCREF(x); + } + else { + x = PyObject_GetItem(v, w); + if (x == NULL && PyErr_Occurred()) { + if (!PyErr_ExceptionMatches( + PyExc_KeyError)) + break; + PyErr_Clear(); + } + } + if (x == NULL) { + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + format_exc_check_arg( + PyExc_NameError, + NAME_ERROR_MSG, w); + break; + } + } + Py_INCREF(x); + } + PUSH(x); + continue; + + case LOAD_GLOBAL: + w = GETITEM(names, oparg); + if (PyString_CheckExact(w)) { + /* Inline the PyDict_GetItem() calls. + WARNING: this is an extreme speed hack. + Do not try this at home. */ + long hash = ((PyStringObject *)w)->ob_shash; + if (hash != -1) { + PyDictObject *d; + PyDictEntry *e; + d = (PyDictObject *)(f->f_globals); + e = d->ma_lookup(d, w, hash); + if (e == NULL) { + x = NULL; + break; + } + x = e->me_value; + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + continue; + } + d = (PyDictObject *)(f->f_builtins); + e = d->ma_lookup(d, w, hash); + if (e == NULL) { + x = NULL; + break; + } + x = e->me_value; + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + continue; + } + goto load_global_error; + } + } + /* This is the un-inlined version of the code above */ + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + load_global_error: + format_exc_check_arg( + PyExc_NameError, + GLOBAL_NAME_ERROR_MSG, w); + break; + } + } + Py_INCREF(x); + PUSH(x); + continue; + + case DELETE_FAST: + x = GETLOCAL(oparg); + if (x != NULL) { + SETLOCAL(oparg, NULL); + continue; + } + format_exc_check_arg( + PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(co->co_varnames, oparg) + ); + break; + + case LOAD_CLOSURE: + x = freevars[oparg]; + Py_INCREF(x); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_DEREF: + x = freevars[oparg]; + w = PyCell_Get(x); + if (w != NULL) { + PUSH(w); + continue; + } + err = -1; + /* Don't stomp existing exception */ + if (PyErr_Occurred()) + break; + if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) { + v = PyTuple_GET_ITEM(co->co_cellvars, + oparg); + format_exc_check_arg( + PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + v); + } else { + v = PyTuple_GET_ITEM(co->co_freevars, oparg - + PyTuple_GET_SIZE(co->co_cellvars)); + format_exc_check_arg(PyExc_NameError, + UNBOUNDFREE_ERROR_MSG, v); + } + break; + + case STORE_DEREF: + w = POP(); + x = freevars[oparg]; + PyCell_Set(x, w); + Py_DECREF(w); + continue; + + case BUILD_TUPLE: + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_LIST: + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyList_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_MAP: + x = _PyDict_NewPresized((Py_ssize_t)oparg); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_MAP: + w = TOP(); /* key */ + u = SECOND(); /* value */ + v = THIRD(); /* dict */ + STACKADJ(-2); + assert (PyDict_CheckExact(v)); + err = PyDict_SetItem(v, w, u); /* v[w] = u */ + Py_DECREF(u); + Py_DECREF(w); + if (err == 0) continue; + break; + + case LOAD_ATTR: + w = GETITEM(names, oparg); + v = TOP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case COMPARE_OP: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) { + /* INLINE: cmp(int, int) */ + register long a, b; + register int res; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + switch (oparg) { + case PyCmp_LT: res = a < b; break; + case PyCmp_LE: res = a <= b; break; + case PyCmp_EQ: res = a == b; break; + case PyCmp_NE: res = a != b; break; + case PyCmp_GT: res = a > b; break; + case PyCmp_GE: res = a >= b; break; + case PyCmp_IS: res = v == w; break; + case PyCmp_IS_NOT: res = v != w; break; + default: goto slow_compare; + } + x = res ? Py_True : Py_False; + Py_INCREF(x); + } + else { + slow_compare: + x = cmp_outcome(oparg, v, w); + } + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x == NULL) break; + PREDICT(JUMP_IF_FALSE); + PREDICT(JUMP_IF_TRUE); + continue; + + case IMPORT_NAME: + w = GETITEM(names, oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__import__ not found"); + break; + } + Py_INCREF(x); + v = POP(); + u = TOP(); + if (PyInt_AsLong(u) != -1 || PyErr_Occurred()) + w = PyTuple_Pack(5, + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + v, + u); + else + w = PyTuple_Pack(4, + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + v); + Py_DECREF(v); + Py_DECREF(u); + if (w == NULL) { + u = POP(); + Py_DECREF(x); + x = NULL; + break; + } + READ_TIMESTAMP(intr0); + v = x; + x = PyEval_CallObject(v, w); + Py_DECREF(v); + READ_TIMESTAMP(intr1); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case IMPORT_STAR: + v = POP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals found during 'import *'"); + break; + } + READ_TIMESTAMP(intr0); + err = import_all_from(x, v); + READ_TIMESTAMP(intr1); + PyFrame_LocalsToFast(f, 0); + Py_DECREF(v); + if (err == 0) continue; + break; + + case IMPORT_FROM: + w = GETITEM(names, oparg); + v = TOP(); + READ_TIMESTAMP(intr0); + x = import_from(v, w); + READ_TIMESTAMP(intr1); + PUSH(x); + if (x != NULL) continue; + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + goto fast_next_opcode; + + PREDICTED_WITH_ARG(JUMP_IF_FALSE); + case JUMP_IF_FALSE: + w = TOP(); + if (w == Py_True) { + PREDICT(POP_TOP); + goto fast_next_opcode; + } + if (w == Py_False) { + JUMPBY(oparg); + goto fast_next_opcode; + } + err = PyObject_IsTrue(w); + if (err > 0) + err = 0; + else if (err == 0) + JUMPBY(oparg); + else + break; + continue; + + PREDICTED_WITH_ARG(JUMP_IF_TRUE); + case JUMP_IF_TRUE: + w = TOP(); + if (w == Py_False) { + PREDICT(POP_TOP); + goto fast_next_opcode; + } + if (w == Py_True) { + JUMPBY(oparg); + goto fast_next_opcode; + } + err = PyObject_IsTrue(w); + if (err > 0) { + err = 0; + JUMPBY(oparg); + } + else if (err == 0) + ; + else + break; + continue; + + PREDICTED_WITH_ARG(JUMP_ABSOLUTE); + case JUMP_ABSOLUTE: + JUMPTO(oparg); +#if FAST_LOOPS + /* Enabling this path speeds-up all while and for-loops by bypassing + the per-loop checks for signals. By default, this should be turned-off + because it prevents detection of a control-break in tight loops like + "while 1: pass". Compile with this option turned-on when you need + the speed-up and do not need break checking inside tight loops (ones + that contain only instructions ending with goto fast_next_opcode). + */ + goto fast_next_opcode; +#else + continue; +#endif + + case GET_ITER: + /* before: [obj]; after [getiter(obj)] */ + v = TOP(); + x = PyObject_GetIter(v); + Py_DECREF(v); + if (x != NULL) { + SET_TOP(x); + PREDICT(FOR_ITER); + continue; + } + STACKADJ(-1); + break; + + PREDICTED_WITH_ARG(FOR_ITER); + case FOR_ITER: + /* before: [iter]; after: [iter, iter()] *or* [] */ + v = TOP(); + x = (*v->ob_type->tp_iternext)(v); + if (x != NULL) { + PUSH(x); + PREDICT(STORE_FAST); + PREDICT(UNPACK_SEQUENCE); + continue; + } + if (PyErr_Occurred()) { + if (!PyErr_ExceptionMatches( + PyExc_StopIteration)) + break; + PyErr_Clear(); + } + /* iterator ended normally */ + x = v = POP(); + Py_DECREF(v); + JUMPBY(oparg); + continue; + + case BREAK_LOOP: + why = WHY_BREAK; + goto fast_block_end; + + case CONTINUE_LOOP: + retval = PyInt_FromLong(oparg); + if (!retval) { + x = NULL; + break; + } + why = WHY_CONTINUE; + goto fast_block_end; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + /* NOTE: If you add any new block-setup opcodes that + are not try/except/finally handlers, you may need + to update the PyGen_NeedsFinalizing() function. + */ + + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + continue; + + case WITH_CLEANUP: + { + /* At the top of the stack are 1-3 values indicating + how/why we entered the finally clause: + - TOP = None + - (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval + - TOP = WHY_*; no retval below it + - (TOP, SECOND, THIRD) = exc_info() + Below them is EXIT, the context.__exit__ bound method. + In the last case, we must call + EXIT(TOP, SECOND, THIRD) + otherwise we must call + EXIT(None, None, None) + + In all cases, we remove EXIT from the stack, leaving + the rest in the same order. + + In addition, if the stack represents an exception, + *and* the function call returns a 'true' value, we + "zap" this information, to prevent END_FINALLY from + re-raising the exception. (But non-local gotos + should still be resumed.) + */ + + PyObject *exit_func; + + u = POP(); + if (u == Py_None) { + exit_func = TOP(); + SET_TOP(u); + v = w = Py_None; + } + else if (PyInt_Check(u)) { + switch(PyInt_AS_LONG(u)) { + case WHY_RETURN: + case WHY_CONTINUE: + /* Retval in TOP. */ + exit_func = SECOND(); + SET_SECOND(TOP()); + SET_TOP(u); + break; + default: + exit_func = TOP(); + SET_TOP(u); + break; + } + u = v = w = Py_None; + } + else { + v = TOP(); + w = SECOND(); + exit_func = THIRD(); + SET_TOP(u); + SET_SECOND(v); + SET_THIRD(w); + } + /* XXX Not the fastest way to call it... */ + x = PyObject_CallFunctionObjArgs(exit_func, u, v, w, + NULL); + if (x == NULL) { + Py_DECREF(exit_func); + break; /* Go to error exit */ + } + if (u != Py_None && PyObject_IsTrue(x)) { + /* There was an exception and a true return */ + STACKADJ(-2); + Py_INCREF(Py_None); + SET_TOP(Py_None); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + } else { + /* The stack was rearranged to remove EXIT + above. Let END_FINALLY do its thing */ + } + Py_DECREF(x); + Py_DECREF(exit_func); + PREDICT(END_FINALLY); + break; + } + + case CALL_FUNCTION: + { + PyObject **sp; + PCALL(PCALL_ALL); + sp = stack_pointer; +#ifdef WITH_TSC + x = call_function(&sp, oparg, &intr0, &intr1); +#else + x = call_function(&sp, oparg); +#endif + stack_pointer = sp; + PUSH(x); + if (x != NULL) + continue; + break; + } + + case CALL_FUNCTION_VAR: + case CALL_FUNCTION_KW: + case CALL_FUNCTION_VAR_KW: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int flags = (opcode - CALL_FUNCTION) & 3; + int n = na + 2 * nk; + PyObject **pfunc, *func, **sp; + PCALL(PCALL_ALL); + if (flags & CALL_FLAG_VAR) + n++; + if (flags & CALL_FLAG_KW) + n++; + pfunc = stack_pointer - n - 1; + func = *pfunc; + + if (PyMethod_Check(func) + && PyMethod_GET_SELF(func) != NULL) { + PyObject *self = PyMethod_GET_SELF(func); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } else + Py_INCREF(func); + sp = stack_pointer; + READ_TIMESTAMP(intr0); + x = ext_do_call(func, &sp, flags, na, nk); + READ_TIMESTAMP(intr1); + stack_pointer = sp; + Py_DECREF(func); + + while (stack_pointer > pfunc) { + w = POP(); + Py_DECREF(w); + } + PUSH(x); + if (x != NULL) + continue; + break; + } + + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + + case MAKE_CLOSURE: + { + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + if (x != NULL) { + v = POP(); + err = PyFunction_SetClosure(x, v); + Py_DECREF(v); + } + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + } + + case BUILD_SLICE: + if (oparg == 3) + w = POP(); + else + w = NULL; + v = POP(); + u = TOP(); + x = PySlice_New(u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_XDECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case EXTENDED_ARG: + opcode = NEXTOP(); + oparg = oparg<<16 | NEXTARG(); + goto dispatch_opcode; + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + PyCode_Addr2Line(f->f_code, f->f_lasti), + opcode); + PyErr_SetString(PyExc_SystemError, "unknown opcode"); + why = WHY_EXCEPTION; + break; + +#ifdef CASE_TOO_BIG + } +#endif + + } /* switch */ + + on_error: + + READ_TIMESTAMP(inst1); + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + /* This check is expensive! */ + if (PyErr_Occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else { +#endif + READ_TIMESTAMP(loop1); + continue; /* Normal, fast path */ +#ifdef CHECKEXC + } +#endif + } + why = WHY_EXCEPTION; + x = Py_None; + err = 0; + } + + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, + "error return without exception set"); + why = WHY_EXCEPTION; + } + } +#ifdef CHECKEXC + else { + /* This check is expensive! */ + if (PyErr_Occurred()) { + char buf[128]; + sprintf(buf, "Stack unwind with exception " + "set and why=%d", why); + Py_FatalError(buf); + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + PyTraceBack_Here(f); + + if (tstate->c_tracefunc != NULL) + call_exc_trace(tstate->c_tracefunc, + tstate->c_traceobj, f); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + +fast_block_end: + while (why != WHY_NOT && f->f_iblock > 0) { + PyTryBlock *b = PyFrame_BlockPop(f); + + assert(why != WHY_YIELD); + if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) { + /* For a continue inside a try block, + don't pop the block for the loop. */ + PyFrame_BlockSetup(f, b->b_type, b->b_handler, + b->b_level); + why = WHY_NOT; + JUMPTO(PyInt_AS_LONG(retval)); + Py_DECREF(retval); + break; + } + + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_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) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val == NULL) { + val = Py_None; + Py_INCREF(val); + } + /* 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) { + PyErr_NormalizeException( + &exc, &val, &tb); + set_exc_info(tstate, + exc, val, tb); + } + if (tb == NULL) { + Py_INCREF(Py_None); + PUSH(Py_None); + } else + PUSH(tb); + PUSH(val); + PUSH(exc); + } + else { + if (why & (WHY_RETURN | WHY_CONTINUE)) + PUSH(retval); + v = PyInt_FromLong((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; + READ_TIMESTAMP(loop1); + + } /* main loop */ + + assert(why != WHY_YIELD); + /* Pop remaining stack entries. */ + while (!EMPTY()) { + v = POP(); + Py_XDECREF(v); + } + + if (why != WHY_RETURN) + retval = NULL; + +fast_yield: + if (tstate->use_tracing) { + if (tstate->c_tracefunc) { + if (why == WHY_RETURN || why == WHY_YIELD) { + if (call_trace(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN, retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + else if (why == WHY_EXCEPTION) { + call_trace_protected(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN, NULL); + } + } + if (tstate->c_profilefunc) { + if (why == WHY_EXCEPTION) + call_trace_protected(tstate->c_profilefunc, + tstate->c_profileobj, f, + PyTrace_RETURN, NULL); + else if (call_trace(tstate->c_profilefunc, + tstate->c_profileobj, f, + PyTrace_RETURN, retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + } + + if (tstate->frame->f_exc_type != NULL) + reset_exc_info(tstate); + else { + assert(tstate->frame->f_exc_value == NULL); + assert(tstate->frame->f_exc_traceback == NULL); + } + + /* pop frame */ +exit_eval_frame: + Py_LeaveRecursiveCall(); + tstate->frame = f->f_back; + + return retval; +} + +/* This is gonna seem *real weird*, but if you put some other code between + PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust + the test in the if statements in Misc/gdbinit (pystack and pystackv). */ + +PyObject * +PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, + PyObject **args, int argcount, PyObject **kws, int kwcount, + PyObject **defs, int defcount, PyObject *closure) +{ + register PyFrameObject *f; + register PyObject *retval = NULL; + register PyObject **fastlocals, **freevars; + PyThreadState *tstate = PyThreadState_GET(); + PyObject *x, *u; + + if (globals == NULL) { + PyErr_SetString(PyExc_SystemError, + "PyEval_EvalCodeEx: NULL globals"); + return NULL; + } + + assert(tstate != NULL); + assert(globals != NULL); + f = PyFrame_New(tstate, co, globals, locals); + if (f == NULL) + return NULL; + + fastlocals = f->f_localsplus; + freevars = f->f_localsplus + co->co_nlocals; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + PyObject *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = PyDict_New(); + if (kwdict == NULL) + goto fail; + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes %s %d " + "%sargument%s (%d given)", + PyString_AsString(co->co_name), + defcount ? "at most" : "exactly", + co->co_argcount, + kwcount ? "non-keyword " : "", + co->co_argcount == 1 ? "" : "s", + argcount); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + Py_INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = PyTuple_New(argcount - n); + if (u == NULL) + goto fail; + SETLOCAL(co->co_argcount, u); + for (i = n; i < argcount; i++) { + x = args[i]; + Py_INCREF(x); + PyTuple_SET_ITEM(u, i-n, x); + } + } + for (i = 0; i < kwcount; i++) { + PyObject **co_varnames; + PyObject *keyword = kws[2*i]; + PyObject *value = kws[2*i + 1]; + int j; + if (keyword == NULL || !PyString_Check(keyword)) { + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", + PyString_AsString(co->co_name)); + goto fail; + } + /* Speed hack: do raw pointer compares. As names are + normally interned this should almost always hit. */ + co_varnames = PySequence_Fast_ITEMS(co->co_varnames); + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = co_varnames[j]; + if (nm == keyword) + goto kw_found; + } + /* Slow fallback, just in case */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = co_varnames[j]; + int cmp = PyObject_RichCompareBool( + keyword, nm, Py_EQ); + if (cmp > 0) + goto kw_found; + else if (cmp < 0) + goto fail; + } + /* Check errors from Compare */ + if (PyErr_Occurred()) + goto fail; + if (j >= co->co_argcount) { + if (kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected " + "keyword argument '%.400s'", + PyString_AsString(co->co_name), + PyString_AsString(keyword)); + goto fail; + } + PyDict_SetItem(kwdict, keyword, value); + continue; + } +kw_found: + if (GETLOCAL(j) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s() got multiple " + "values for keyword " + "argument '%.400s'", + PyString_AsString(co->co_name), + PyString_AsString(keyword)); + goto fail; + } + Py_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) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes %s %d " + "%sargument%s (%d given)", + PyString_AsString(co->co_name), + ((co->co_flags & CO_VARARGS) || + defcount) ? "at least" + : "exactly", + m, kwcount ? "non-keyword " : "", + m == 1 ? "" : "s", i); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + PyObject *def = defs[i]; + Py_INCREF(def); + SETLOCAL(m+i, def); + } + } + } + } + else { + if (argcount > 0 || kwcount > 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%d given)", + PyString_AsString(co->co_name), + argcount + kwcount); + goto fail; + } + } + /* Allocate and initialize storage for cell vars, and copy free + vars into frame. This isn't too efficient right now. */ + if (PyTuple_GET_SIZE(co->co_cellvars)) { + int i, j, nargs, found; + char *cellname, *argname; + PyObject *c; + + nargs = co->co_argcount; + if (co->co_flags & CO_VARARGS) + nargs++; + if (co->co_flags & CO_VARKEYWORDS) + nargs++; + + /* Initialize each cell var, taking into account + cell vars that are initialized from arguments. + + Should arrange for the compiler to put cellvars + that are arguments at the beginning of the cellvars + list so that we can march over it more efficiently? + */ + for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) { + cellname = PyString_AS_STRING( + PyTuple_GET_ITEM(co->co_cellvars, i)); + found = 0; + for (j = 0; j < nargs; j++) { + argname = PyString_AS_STRING( + PyTuple_GET_ITEM(co->co_varnames, j)); + if (strcmp(cellname, argname) == 0) { + c = PyCell_New(GETLOCAL(j)); + if (c == NULL) + goto fail; + GETLOCAL(co->co_nlocals + i) = c; + found = 1; + break; + } + } + if (found == 0) { + c = PyCell_New(NULL); + if (c == NULL) + goto fail; + SETLOCAL(co->co_nlocals + i, c); + } + } + } + if (PyTuple_GET_SIZE(co->co_freevars)) { + int i; + for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + Py_INCREF(o); + freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; + } + } + + if (co->co_flags & CO_GENERATOR) { + /* Don't need to keep the reference to f_back, it will be set + * when the generator is resumed. */ + Py_XDECREF(f->f_back); + f->f_back = NULL; + + PCALL(PCALL_GENERATOR); + + /* Create a new generator that owns the ready to run frame + * and return that as the value. */ + return PyGen_New(f); + } + + retval = PyEval_EvalFrameEx(f,0); + +fail: /* Jump here from prelude on failure */ + + /* decref'ing the frame can cause __del__ methods to get invoked, + which can call back into Python. While we're done with the + current Python frame (f), the associated C stack is still in use, + so recursion_depth must be boosted for the duration. + */ + assert(tstate != NULL); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return retval; +} + + +/* Implementation notes for set_exc_info() and reset_exc_info(): + +- Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and + 'exc_traceback'. These always travel together. + +- tstate->curexc_ZZZ is the "hot" exception that is set by + PyErr_SetString(), cleared by PyErr_Clear(), and so on. + +- Once an exception is caught by an except clause, it is transferred + from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info() + can pick it up. This is the primary task of set_exc_info(). + XXX That can't be right: set_exc_info() doesn't look at tstate->curexc_ZZZ. + +- Now let me explain the complicated dance with frame->f_exc_ZZZ. + + Long ago, when none of this existed, there were just a few globals: + one set corresponding to the "hot" exception, and one set + corresponding to sys.exc_ZZZ. (Actually, the latter weren't C + globals; they were simply stored as sys.exc_ZZZ. For backwards + compatibility, they still are!) The problem was that in code like + this: + + try: + "something that may fail" + except "some exception": + "do something else first" + "print the exception from sys.exc_ZZZ." + + if "do something else first" invoked something that raised and caught + an exception, sys.exc_ZZZ were overwritten. That was a frequent + cause of subtle bugs. I fixed this by changing the semantics as + follows: + + - Within one frame, sys.exc_ZZZ will hold the last exception caught + *in that frame*. + + - But initially, and as long as no exception is caught in a given + frame, sys.exc_ZZZ will hold the last exception caught in the + previous frame (or the frame before that, etc.). + + The first bullet fixed the bug in the above example. The second + bullet was for backwards compatibility: it was (and is) common to + have a function that is called when an exception is caught, and to + have that function access the caught exception via sys.exc_ZZZ. + (Example: traceback.print_exc()). + + At the same time I fixed the problem that sys.exc_ZZZ weren't + thread-safe, by introducing sys.exc_info() which gets it from tstate; + but that's really a separate improvement. + + The reset_exc_info() function in ceval.c restores the tstate->exc_ZZZ + variables to what they were before the current frame was called. The + set_exc_info() function saves them on the frame so that + reset_exc_info() can restore them. The invariant is that + frame->f_exc_ZZZ is NULL iff the current frame never caught an + exception (where "catching" an exception applies only to successful + except clauses); and if the current frame ever caught an exception, + frame->f_exc_ZZZ is the exception that was stored in tstate->exc_ZZZ + at the start of the current frame. + +*/ + +static void +set_exc_info(PyThreadState *tstate, + PyObject *type, PyObject *value, PyObject *tb) +{ + PyFrameObject *frame = tstate->frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + + assert(type != NULL); + assert(frame != NULL); + if (frame->f_exc_type == NULL) { + assert(frame->f_exc_value == NULL); + assert(frame->f_exc_traceback == NULL); + /* This frame didn't catch an exception before. */ + /* Save previous exception of this thread in this frame. */ + if (tstate->exc_type == NULL) { + /* XXX Why is this set to Py_None? */ + Py_INCREF(Py_None); + tstate->exc_type = Py_None; + } + Py_INCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + frame->f_exc_type = tstate->exc_type; + frame->f_exc_value = tstate->exc_value; + frame->f_exc_traceback = tstate->exc_traceback; + } + /* Set new exception for this thread. */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_INCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", type); + PySys_SetObject("exc_value", value); + PySys_SetObject("exc_traceback", tb); +} + +static void +reset_exc_info(PyThreadState *tstate) +{ + PyFrameObject *frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + + /* It's a precondition that the thread state's frame caught an + * exception -- verify in a debug build. + */ + assert(tstate != NULL); + frame = tstate->frame; + assert(frame != NULL); + assert(frame->f_exc_type != NULL); + + /* Copy the frame's exception info back to the thread state. */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_INCREF(frame->f_exc_type); + Py_XINCREF(frame->f_exc_value); + Py_XINCREF(frame->f_exc_traceback); + tstate->exc_type = frame->f_exc_type; + tstate->exc_value = frame->f_exc_value; + tstate->exc_traceback = frame->f_exc_traceback; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + + /* For b/w compatibility */ + PySys_SetObject("exc_type", frame->f_exc_type); + PySys_SetObject("exc_value", frame->f_exc_value); + PySys_SetObject("exc_traceback", frame->f_exc_traceback); + + /* Clear the frame's exception info. */ + tmp_type = frame->f_exc_type; + tmp_value = frame->f_exc_value; + tmp_tb = frame->f_exc_traceback; + frame->f_exc_type = NULL; + frame->f_exc_value = NULL; + frame->f_exc_traceback = NULL; + Py_DECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} + +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static enum why_code +do_raise(PyObject *type, PyObject *value, PyObject *tb) +{ + if (type == NULL) { + /* Reraise */ + PyThreadState *tstate = PyThreadState_GET(); + type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; + value = tstate->exc_value; + tb = tstate->exc_traceback; + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + } + + /* We support the following forms of raise: + raise , + raise , + raise , None + raise , + raise , None + raise , + raise , None + + An omitted second argument is the same as None. + + In addition, raise , is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + Py_DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { + PyObject *tmp = type; + type = PyTuple_GET_ITEM(type, 0); + Py_INCREF(type); + Py_DECREF(tmp); + } + + if (PyExceptionClass_Check(type)) + PyErr_NormalizeException(&type, &value, &tb); + + else if (PyExceptionInstance_Check(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise , */ + Py_DECREF(value); + value = type; + type = PyExceptionInstance_Class(type); + Py_INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes or instances, not %s", + type->ob_type->tp_name); + goto raise_error; + } + + assert(PyExceptionClass_Check(type)); + if (Py_Py3kWarningFlag && PyClass_Check(type)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "exceptions must derive from BaseException " + "in 3.x", 1) < 0) + goto raise_error; + } + + PyErr_Restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; +} + +/* Iterate v argcnt times and store the results on the stack (via decreasing + sp). Return 1 for success, 0 if error. */ + +static int +unpack_iterable(PyObject *v, int argcnt, PyObject **sp) +{ + int i = 0; + PyObject *it; /* iter(v) */ + PyObject *w; + + assert(v != NULL); + + it = PyObject_GetIter(v); + if (it == NULL) + goto Error; + + for (; i < argcnt; i++) { + w = PyIter_Next(it); + if (w == NULL) { + /* Iterator done, via error or exhaustion. */ + if (!PyErr_Occurred()) { + PyErr_Format(PyExc_ValueError, + "need more than %d value%s to unpack", + i, i == 1 ? "" : "s"); + } + goto Error; + } + *--sp = w; + } + + /* We better have exhausted the iterator now. */ + w = PyIter_Next(it); + if (w == NULL) { + if (PyErr_Occurred()) + goto Error; + Py_DECREF(it); + return 1; + } + Py_DECREF(w); + PyErr_SetString(PyExc_ValueError, "too many values to unpack"); + /* fall through */ +Error: + for (; i > 0; i--, sp++) + Py_DECREF(*sp); + Py_XDECREF(it); + return 0; +} + + +#ifdef LLTRACE +static int +prtrace(PyObject *v, char *str) +{ + printf("%s ", str); + if (PyObject_Print(v, stdout, 0) != 0) + PyErr_Clear(); /* Don't know what else to do */ + printf("\n"); + return 1; +} +#endif + +static void +call_exc_trace(Py_tracefunc func, PyObject *self, PyFrameObject *f) +{ + PyObject *type, *value, *traceback, *arg; + int err; + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = PyTuple_Pack(3, type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return; + } + err = call_trace(func, self, f, PyTrace_EXCEPTION, arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static int +call_trace_protected(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, + int what, PyObject *arg) +{ + PyObject *type, *value, *traceback; + int err; + PyErr_Fetch(&type, &value, &traceback); + err = call_trace(func, obj, frame, what, arg); + if (err == 0) + { + PyErr_Restore(type, value, traceback); + return 0; + } + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + return -1; + } +} + +static int +call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, + int what, PyObject *arg) +{ + register PyThreadState *tstate = frame->f_tstate; + int result; + if (tstate->tracing) + return 0; + tstate->tracing++; + tstate->use_tracing = 0; + result = func(obj, frame, what, arg); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + return result; +} + +PyObject * +_PyEval_CallTracing(PyObject *func, PyObject *args) +{ + PyFrameObject *frame = PyEval_GetFrame(); + PyThreadState *tstate = frame->f_tstate; + int save_tracing = tstate->tracing; + int save_use_tracing = tstate->use_tracing; + PyObject *result; + + tstate->tracing = 0; + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + result = PyObject_Call(func, args, NULL); + tstate->tracing = save_tracing; + tstate->use_tracing = save_use_tracing; + return result; +} + +static int +maybe_call_line_trace(Py_tracefunc func, PyObject *obj, + PyFrameObject *frame, int *instr_lb, int *instr_ub, + int *instr_prev) +{ + int result = 0; + + /* If the last instruction executed isn't in the current + instruction window, reset the window. If the last + instruction happens to fall at the start of a line or if it + represents a jump backwards, call the trace function. + */ + if ((frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub)) { + int line; + PyAddrPair bounds; + + line = PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, + &bounds); + if (line >= 0) { + frame->f_lineno = line; + result = call_trace(func, obj, frame, + PyTrace_LINE, Py_None); + } + *instr_lb = bounds.ap_lower; + *instr_ub = bounds.ap_upper; + } + else if (frame->f_lasti <= *instr_prev) { + result = call_trace(func, obj, frame, PyTrace_LINE, Py_None); + } + *instr_prev = frame->f_lasti; + return result; +} + +void +PyEval_SetProfile(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *temp = tstate->c_profileobj; + Py_XINCREF(arg); + tstate->c_profilefunc = NULL; + tstate->c_profileobj = NULL; + /* Must make sure that tracing is not ignored if 'temp' is freed */ + tstate->use_tracing = tstate->c_tracefunc != NULL; + Py_XDECREF(temp); + tstate->c_profilefunc = func; + tstate->c_profileobj = arg; + /* Flag that tracing or profiling is turned on */ + tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL); +} + +void +PyEval_SetTrace(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *temp = tstate->c_traceobj; + Py_XINCREF(arg); + tstate->c_tracefunc = NULL; + tstate->c_traceobj = NULL; + /* Must make sure that profiling is not ignored if 'temp' is freed */ + tstate->use_tracing = tstate->c_profilefunc != NULL; + Py_XDECREF(temp); + tstate->c_tracefunc = func; + tstate->c_traceobj = arg; + /* Flag that tracing or profiling is turned on */ + tstate->use_tracing = ((func != NULL) + || (tstate->c_profilefunc != NULL)); +} + +PyObject * +PyEval_GetBuiltins(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + if (current_frame == NULL) + return PyThreadState_GET()->interp->builtins; + else + return current_frame->f_builtins; +} + +PyObject * +PyEval_GetLocals(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + if (current_frame == NULL) + return NULL; + PyFrame_FastToLocals(current_frame); + return current_frame->f_locals; +} + +PyObject * +PyEval_GetGlobals(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +PyFrameObject * +PyEval_GetFrame(void) +{ + PyThreadState *tstate = PyThreadState_GET(); + return _PyThreadState_GetFrame(tstate); +} + +int +PyEval_GetRestricted(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + return current_frame == NULL ? 0 : PyFrame_IsRestricted(current_frame); +} + +int +PyEval_MergeCompilerFlags(PyCompilerFlags *cf) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + int result = cf->cf_flags != 0; + + if (current_frame != NULL) { + const int codeflags = current_frame->f_code->co_flags; + const int compilerflags = codeflags & PyCF_MASK; + if (compilerflags) { + result = 1; + cf->cf_flags |= compilerflags; + } +#if 0 /* future keyword */ + if (codeflags & CO_GENERATOR_ALLOWED) { + result = 1; + cf->cf_flags |= CO_GENERATOR_ALLOWED; + } +#endif + } + return result; +} + +int +Py_FlushLine(void) +{ + PyObject *f = PySys_GetObject("stdout"); + if (f == NULL) + return 0; + if (!PyFile_SoftSpace(f, 0)) + return 0; + return PyFile_WriteString("\n", f); +} + + +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ + +#undef PyEval_CallObject +/* for backward compatibility: export this interface */ + +PyObject * +PyEval_CallObject(PyObject *func, PyObject *arg) +{ + return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); +} +#define PyEval_CallObject(func,arg) \ + PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + +PyObject * +PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw) +{ + PyObject *result; + + if (arg == NULL) { + arg = PyTuple_New(0); + if (arg == NULL) + return NULL; + } + else if (!PyTuple_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + else + Py_INCREF(arg); + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + Py_DECREF(arg); + return NULL; + } + + result = PyObject_Call(func, arg, kw); + Py_DECREF(arg); + return result; +} + +const char * +PyEval_GetFuncName(PyObject *func) +{ + if (PyMethod_Check(func)) + return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func)); + else if (PyFunction_Check(func)) + return PyString_AsString(((PyFunctionObject*)func)->func_name); + else if (PyCFunction_Check(func)) + return ((PyCFunctionObject*)func)->m_ml->ml_name; + else if (PyClass_Check(func)) + return PyString_AsString(((PyClassObject*)func)->cl_name); + else if (PyInstance_Check(func)) { + return PyString_AsString( + ((PyInstanceObject*)func)->in_class->cl_name); + } else { + return func->ob_type->tp_name; + } +} + +const char * +PyEval_GetFuncDesc(PyObject *func) +{ + if (PyMethod_Check(func)) + return "()"; + else if (PyFunction_Check(func)) + return "()"; + else if (PyCFunction_Check(func)) + return "()"; + else if (PyClass_Check(func)) + return " constructor"; + else if (PyInstance_Check(func)) { + return " instance"; + } else { + return " object"; + } +} + +static void +err_args(PyObject *func, int flags, int nargs) +{ + if (flags & METH_NOARGS) + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%d given)", + ((PyCFunctionObject *)func)->m_ml->ml_name, + nargs); + else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%d given)", + ((PyCFunctionObject *)func)->m_ml->ml_name, + nargs); +} + +#define C_TRACE(x, call) \ +if (tstate->use_tracing && tstate->c_profilefunc) { \ + if (call_trace(tstate->c_profilefunc, \ + tstate->c_profileobj, \ + tstate->frame, PyTrace_C_CALL, \ + func)) { \ + x = NULL; \ + } \ + else { \ + x = call; \ + if (tstate->c_profilefunc != NULL) { \ + if (x == NULL) { \ + call_trace_protected(tstate->c_profilefunc, \ + tstate->c_profileobj, \ + tstate->frame, PyTrace_C_EXCEPTION, \ + func); \ + /* XXX should pass (type, value, tb) */ \ + } else { \ + if (call_trace(tstate->c_profilefunc, \ + tstate->c_profileobj, \ + tstate->frame, PyTrace_C_RETURN, \ + func)) { \ + Py_DECREF(x); \ + x = NULL; \ + } \ + } \ + } \ + } \ +} else { \ + x = call; \ + } + +static PyObject * +call_function(PyObject ***pp_stack, int oparg +#ifdef WITH_TSC + , uint64* pintr0, uint64* pintr1 +#endif + ) +{ + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int n = na + 2 * nk; + PyObject **pfunc = (*pp_stack) - n - 1; + PyObject *func = *pfunc; + PyObject *x, *w; + + /* Always dispatch PyCFunction first, because these are + presumed to be the most frequent callable object. + */ + if (PyCFunction_Check(func) && nk == 0) { + int flags = PyCFunction_GET_FLAGS(func); + PyThreadState *tstate = PyThreadState_GET(); + + PCALL(PCALL_CFUNCTION); + if (flags & (METH_NOARGS | METH_O)) { + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + if (flags & METH_NOARGS && na == 0) { + C_TRACE(x, (*meth)(self,NULL)); + } + else if (flags & METH_O && na == 1) { + PyObject *arg = EXT_POP(*pp_stack); + C_TRACE(x, (*meth)(self,arg)); + Py_DECREF(arg); + } + else { + err_args(func, flags, na); + x = NULL; + } + } + else { + PyObject *callargs; + callargs = load_args(pp_stack, na); + READ_TIMESTAMP(*pintr0); + C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); + READ_TIMESTAMP(*pintr1); + Py_XDECREF(callargs); + } + } else { + if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { + /* optimize access to bound methods */ + PyObject *self = PyMethod_GET_SELF(func); + PCALL(PCALL_METHOD); + PCALL(PCALL_BOUND_METHOD); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } else + Py_INCREF(func); + READ_TIMESTAMP(*pintr0); + if (PyFunction_Check(func)) + x = fast_function(func, pp_stack, n, na, nk); + else + x = do_call(func, pp_stack, na, nk); + READ_TIMESTAMP(*pintr1); + Py_DECREF(func); + } + + /* Clear the stack of the function object. Also removes + the arguments in case they weren't consumed already + (fast_function() and err_args() leave them on the stack). + */ + while ((*pp_stack) > pfunc) { + w = EXT_POP(*pp_stack); + Py_DECREF(w); + PCALL(PCALL_POP); + } + return x; +} + +/* The fast_function() function optimize calls for which no argument + tuple is necessary; the objects are passed directly from the stack. + For the simplest case -- a function that takes only positional + arguments and is called with only positional arguments -- it + inlines the most primitive frame setup code from + PyEval_EvalCodeEx(), which vastly reduces the checks that must be + done before evaluating the frame. +*/ + +static PyObject * +fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject **d = NULL; + int nd = 0; + + PCALL(PCALL_FUNCTION); + PCALL(PCALL_FAST_FUNCTION); + if (argdefs == NULL && co->co_argcount == n && nk==0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + PyFrameObject *f; + PyObject *retval = NULL; + PyThreadState *tstate = PyThreadState_GET(); + PyObject **fastlocals, **stack; + int i; + + PCALL(PCALL_FASTER_FUNCTION); + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) + return NULL; + + fastlocals = f->f_localsplus; + stack = (*pp_stack) - n; + + for (i = 0; i < n; i++) { + Py_INCREF(*stack); + fastlocals[i] = *stack++; + } + retval = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return retval; + } + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + return PyEval_EvalCodeEx(co, globals, + (PyObject *)NULL, (*pp_stack)-n, na, + (*pp_stack)-2*nk, nk, d, nd, + PyFunction_GET_CLOSURE(func)); +} + +static PyObject * +update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, + PyObject *func) +{ + PyObject *kwdict = NULL; + if (orig_kwdict == NULL) + kwdict = PyDict_New(); + else { + kwdict = PyDict_Copy(orig_kwdict); + Py_DECREF(orig_kwdict); + } + if (kwdict == NULL) + return NULL; + while (--nk >= 0) { + int err; + PyObject *value = EXT_POP(*pp_stack); + PyObject *key = EXT_POP(*pp_stack); + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%.200s'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + PyString_AsString(key)); + Py_DECREF(key); + Py_DECREF(value); + Py_DECREF(kwdict); + return NULL; + } + err = PyDict_SetItem(kwdict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + +static PyObject * +update_star_args(int nstack, int nstar, PyObject *stararg, + PyObject ***pp_stack) +{ + PyObject *callargs, *w; + + callargs = PyTuple_New(nstack + nstar); + if (callargs == NULL) { + return NULL; + } + if (nstar) { + int i; + for (i = 0; i < nstar; i++) { + PyObject *a = PyTuple_GET_ITEM(stararg, i); + Py_INCREF(a); + PyTuple_SET_ITEM(callargs, nstack + i, a); + } + } + while (--nstack >= 0) { + w = EXT_POP(*pp_stack); + PyTuple_SET_ITEM(callargs, nstack, w); + } + return callargs; +} + +static PyObject * +load_args(PyObject ***pp_stack, int na) +{ + PyObject *args = PyTuple_New(na); + PyObject *w; + + if (args == NULL) + return NULL; + while (--na >= 0) { + w = EXT_POP(*pp_stack); + PyTuple_SET_ITEM(args, na, w); + } + return args; +} + +static PyObject * +do_call(PyObject *func, PyObject ***pp_stack, int na, int nk) +{ + PyObject *callargs = NULL; + PyObject *kwdict = NULL; + PyObject *result = NULL; + + if (nk > 0) { + kwdict = update_keyword_args(NULL, nk, pp_stack, func); + if (kwdict == NULL) + goto call_fail; + } + callargs = load_args(pp_stack, na); + if (callargs == NULL) + goto call_fail; +#ifdef CALL_PROFILE + /* At this point, we have to look at the type of func to + update the call stats properly. Do it here so as to avoid + exposing the call stats machinery outside ceval.c + */ + if (PyFunction_Check(func)) + PCALL(PCALL_FUNCTION); + else if (PyMethod_Check(func)) + PCALL(PCALL_METHOD); + else if (PyType_Check(func)) + PCALL(PCALL_TYPE); + else + PCALL(PCALL_OTHER); +#endif + result = PyObject_Call(func, callargs, kwdict); + call_fail: + Py_XDECREF(callargs); + Py_XDECREF(kwdict); + return result; +} + +static PyObject * +ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) +{ + int nstar = 0; + PyObject *callargs = NULL; + PyObject *stararg = NULL; + PyObject *kwdict = NULL; + PyObject *result = NULL; + + if (flags & CALL_FLAG_KW) { + kwdict = EXT_POP(*pp_stack); + if (!PyDict_Check(kwdict)) { + PyObject *d; + d = PyDict_New(); + if (d == NULL) + goto ext_call_fail; + if (PyDict_Update(d, kwdict) != 0) { + Py_DECREF(d); + /* PyDict_Update raises attribute + * error (percolated from an attempt + * to get 'keys' attribute) instead of + * a type error if its second argument + * is not a mapping. + */ + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after ** " + "must be a mapping, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + kwdict->ob_type->tp_name); + } + goto ext_call_fail; + } + Py_DECREF(kwdict); + kwdict = d; + } + } + if (flags & CALL_FLAG_VAR) { + stararg = EXT_POP(*pp_stack); + if (!PyTuple_Check(stararg)) { + PyObject *t = NULL; + t = PySequence_Tuple(stararg); + if (t == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after * " + "must be a sequence, not %200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + stararg->ob_type->tp_name); + } + goto ext_call_fail; + } + Py_DECREF(stararg); + stararg = t; + } + nstar = PyTuple_GET_SIZE(stararg); + } + if (nk > 0) { + kwdict = update_keyword_args(kwdict, nk, pp_stack, func); + if (kwdict == NULL) + goto ext_call_fail; + } + callargs = update_star_args(na, nstar, stararg, pp_stack); + if (callargs == NULL) + goto ext_call_fail; +#ifdef CALL_PROFILE + /* At this point, we have to look at the type of func to + update the call stats properly. Do it here so as to avoid + exposing the call stats machinery outside ceval.c + */ + if (PyFunction_Check(func)) + PCALL(PCALL_FUNCTION); + else if (PyMethod_Check(func)) + PCALL(PCALL_METHOD); + else if (PyType_Check(func)) + PCALL(PCALL_TYPE); + else + PCALL(PCALL_OTHER); +#endif + result = PyObject_Call(func, callargs, kwdict); +ext_call_fail: + Py_XDECREF(callargs); + Py_XDECREF(kwdict); + Py_XDECREF(stararg); + return result; +} + +/* Extract a slice index from a PyInt or PyLong or an object with the + nb_index slot defined, and store in *pi. + Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, + and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1. + Return 0 on error, 1 on success. +*/ +/* Note: If v is NULL, return success without storing into *pi. This + is because_PyEval_SliceIndex() is called by apply_slice(), which can be + called by the SLICE opcode with v and/or w equal to NULL. +*/ +int +_PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi) +{ + if (v != NULL) { + Py_ssize_t x; + if (PyInt_Check(v)) { + /* XXX(nnorwitz): I think PyInt_AS_LONG is correct, + however, it looks like it should be AsSsize_t. + There should be a comment here explaining why. + */ + x = PyInt_AS_LONG(v); + } + else if (PyIndex_Check(v)) { + x = PyNumber_AsSsize_t(v, NULL); + if (x == -1 && PyErr_Occurred()) + return 0; + } + else { + PyErr_SetString(PyExc_TypeError, + "slice indices must be integers or " + "None or have an __index__ method"); + return 0; + } + *pi = x; + } + return 1; +} + +#undef ISINDEX +#define ISINDEX(x) ((x) == NULL || \ + PyInt_Check(x) || PyLong_Check(x) || PyIndex_Check(x)) + +static PyObject * +apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ +{ + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { + Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; + if (!_PyEval_SliceIndex(v, &ilow)) + return NULL; + if (!_PyEval_SliceIndex(w, &ihigh)) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); + } + else { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + PyObject *res = PyObject_GetItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return NULL; + } +} + +static int +assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) + /* u[v:w] = x */ +{ + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_ass_slice && ISINDEX(v) && ISINDEX(w)) { + Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; + if (!_PyEval_SliceIndex(v, &ilow)) + return -1; + if (!_PyEval_SliceIndex(w, &ihigh)) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); + } + else { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + int res; + if (x != NULL) + res = PyObject_SetItem(u, slice, x); + else + res = PyObject_DelItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return -1; + } +} + +#define Py3kExceptionClass_Check(x) \ + (PyType_Check((x)) && \ + PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)) + +#define CANNOT_CATCH_MSG "catching classes that don't inherit from " \ + "BaseException is not allowed in 3.x" + +static PyObject * +cmp_outcome(int op, register PyObject *v, register PyObject *w) +{ + int res = 0; + switch (op) { + case PyCmp_IS: + res = (v == w); + break; + case PyCmp_IS_NOT: + res = (v != w); + break; + case PyCmp_IN: + res = PySequence_Contains(w, v); + if (res < 0) + return NULL; + break; + case PyCmp_NOT_IN: + res = PySequence_Contains(w, v); + if (res < 0) + return NULL; + res = !res; + break; + case PyCmp_EXC_MATCH: + if (PyTuple_Check(w)) { + Py_ssize_t i, length; + length = PyTuple_Size(w); + for (i = 0; i < length; i += 1) { + PyObject *exc = PyTuple_GET_ITEM(w, i); + if (PyString_Check(exc)) { + int ret_val; + ret_val = PyErr_WarnEx( + PyExc_DeprecationWarning, + "catching of string " + "exceptions is deprecated", 1); + if (ret_val < 0) + return NULL; + } + else if (Py_Py3kWarningFlag && + !PyTuple_Check(exc) && + !Py3kExceptionClass_Check(exc)) + { + int ret_val; + ret_val = PyErr_WarnEx( + PyExc_DeprecationWarning, + CANNOT_CATCH_MSG, 1); + if (ret_val < 0) + return NULL; + } + } + } + else { + if (PyString_Check(w)) { + int ret_val; + ret_val = PyErr_WarnEx( + PyExc_DeprecationWarning, + "catching of string " + "exceptions is deprecated", 1); + if (ret_val < 0) + return NULL; + } + else if (Py_Py3kWarningFlag && + !PyTuple_Check(w) && + !Py3kExceptionClass_Check(w)) + { + int ret_val; + ret_val = PyErr_WarnEx( + PyExc_DeprecationWarning, + CANNOT_CATCH_MSG, 1); + if (ret_val < 0) + return NULL; + } + } + res = PyErr_GivenExceptionMatches(v, w); + break; + default: + return PyObject_RichCompare(v, w, op); + } + v = res ? Py_True : Py_False; + Py_INCREF(v); + return v; +} + +static PyObject * +import_from(PyObject *v, PyObject *name) +{ + PyObject *x; + + x = PyObject_GetAttr(v, name); + if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_ImportError, + "cannot import name %.230s", + PyString_AsString(name)); + } + return x; +} + +static int +import_all_from(PyObject *locals, PyObject *v) +{ + PyObject *all = PyObject_GetAttrString(v, "__all__"); + PyObject *dict, *name, *value; + int skip_leading_underscores = 0; + int pos, err; + + if (all == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; /* Unexpected error */ + PyErr_Clear(); + dict = PyObject_GetAttrString(v, "__dict__"); + if (dict == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_SetString(PyExc_ImportError, + "from-import-* object has no __dict__ and no __all__"); + return -1; + } + all = PyMapping_Keys(dict); + Py_DECREF(dict); + if (all == NULL) + return -1; + skip_leading_underscores = 1; + } + + for (pos = 0, err = 0; ; pos++) { + name = PySequence_GetItem(all, pos); + if (name == NULL) { + if (!PyErr_ExceptionMatches(PyExc_IndexError)) + err = -1; + else + PyErr_Clear(); + break; + } + if (skip_leading_underscores && + PyString_Check(name) && + PyString_AS_STRING(name)[0] == '_') + { + Py_DECREF(name); + continue; + } + value = PyObject_GetAttr(v, name); + if (value == NULL) + err = -1; + else if (PyDict_CheckExact(locals)) + err = PyDict_SetItem(locals, name, value); + else + err = PyObject_SetItem(locals, name, value); + Py_DECREF(name); + Py_XDECREF(value); + if (err != 0) + break; + } + Py_DECREF(all); + return err; +} + +static PyObject * +build_class(PyObject *methods, PyObject *bases, PyObject *name) +{ + PyObject *metaclass = NULL, *result, *base; + + if (PyDict_Check(methods)) + metaclass = PyDict_GetItemString(methods, "__metaclass__"); + if (metaclass != NULL) + Py_INCREF(metaclass); + else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { + base = PyTuple_GET_ITEM(bases, 0); + metaclass = PyObject_GetAttrString(base, "__class__"); + if (metaclass == NULL) { + PyErr_Clear(); + metaclass = (PyObject *)base->ob_type; + Py_INCREF(metaclass); + } + } + else { + PyObject *g = PyEval_GetGlobals(); + if (g != NULL && PyDict_Check(g)) + metaclass = PyDict_GetItemString(g, "__metaclass__"); + if (metaclass == NULL) + metaclass = (PyObject *) &PyClass_Type; + Py_INCREF(metaclass); + } + result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, + NULL); + Py_DECREF(metaclass); + if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + /* A type error here likely means that the user passed + in a base that was not a class (such the random module + instead of the random.random type). Help them out with + by augmenting the error message with more information.*/ + + PyObject *ptype, *pvalue, *ptraceback; + + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + if (PyString_Check(pvalue)) { + PyObject *newmsg; + newmsg = PyString_FromFormat( + "Error when calling the metaclass bases\n" + " %s", + PyString_AS_STRING(pvalue)); + if (newmsg != NULL) { + Py_DECREF(pvalue); + pvalue = newmsg; + } + } + PyErr_Restore(ptype, pvalue, ptraceback); + } + return result; +} + +static int +exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals, + PyObject *locals) +{ + int n; + PyObject *v; + int plain = 0; + + if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && + ((n = PyTuple_Size(prog)) == 2 || n == 3)) { + /* Backward compatibility hack */ + globals = PyTuple_GetItem(prog, 1); + if (n == 3) + locals = PyTuple_GetItem(prog, 2); + prog = PyTuple_GetItem(prog, 0); + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) { + locals = PyEval_GetLocals(); + plain = 1; + } + if (!globals || !locals) { + PyErr_SetString(PyExc_SystemError, + "globals and locals cannot be NULL"); + return -1; + } + } + else if (locals == Py_None) + locals = globals; + if (!PyString_Check(prog) && + !PyUnicode_Check(prog) && + !PyCode_Check(prog) && + !PyFile_Check(prog)) { + PyErr_SetString(PyExc_TypeError, + "exec: arg 1 must be a string, file, or code object"); + return -1; + } + if (!PyDict_Check(globals)) { + PyErr_SetString(PyExc_TypeError, + "exec: arg 2 must be a dictionary or None"); + return -1; + } + if (!PyMapping_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "exec: arg 3 must be a mapping or None"); + return -1; + } + if (PyDict_GetItemString(globals, "__builtins__") == NULL) + PyDict_SetItemString(globals, "__builtins__", f->f_builtins); + if (PyCode_Check(prog)) { + if (PyCode_GetNumFree((PyCodeObject *)prog) > 0) { + PyErr_SetString(PyExc_TypeError, + "code object passed to exec may not contain free variables"); + return -1; + } + v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals); + } + else if (PyFile_Check(prog)) { + FILE *fp = PyFile_AsFile(prog); + char *name = PyString_AsString(PyFile_Name(prog)); + PyCompilerFlags cf; + if (name == NULL) + return -1; + cf.cf_flags = 0; + if (PyEval_MergeCompilerFlags(&cf)) + v = PyRun_FileFlags(fp, name, Py_file_input, globals, + locals, &cf); + else + v = PyRun_File(fp, name, Py_file_input, globals, + locals); + } + else { + PyObject *tmp = NULL; + char *str; + PyCompilerFlags cf; + cf.cf_flags = 0; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(prog)) { + tmp = PyUnicode_AsUTF8String(prog); + if (tmp == NULL) + return -1; + prog = tmp; + cf.cf_flags |= PyCF_SOURCE_IS_UTF8; + } +#endif + if (PyString_AsStringAndSize(prog, &str, NULL)) + return -1; + if (PyEval_MergeCompilerFlags(&cf)) + v = PyRun_StringFlags(str, Py_file_input, globals, + locals, &cf); + else + v = PyRun_String(str, Py_file_input, globals, locals); + Py_XDECREF(tmp); + } + if (plain) + PyFrame_LocalsToFast(f, 0); + if (v == NULL) + return -1; + Py_DECREF(v); + return 0; +} + +static void +format_exc_check_arg(PyObject *exc, char *format_str, PyObject *obj) +{ + char *obj_str; + + if (!obj) + return; + + obj_str = PyString_AsString(obj); + if (!obj_str) + return; + + PyErr_Format(exc, format_str, obj_str); +} + +static PyObject * +string_concatenate(PyObject *v, PyObject *w, + PyFrameObject *f, unsigned char *next_instr) +{ + /* This function implements 'variable += expr' when both arguments + are strings. */ + Py_ssize_t v_len = PyString_GET_SIZE(v); + Py_ssize_t w_len = PyString_GET_SIZE(w); + Py_ssize_t new_len = v_len + w_len; + if (new_len < 0) { + PyErr_SetString(PyExc_OverflowError, + "strings are too large to concat"); + return NULL; + } + + if (v->ob_refcnt == 2) { + /* In the common case, there are 2 references to the value + * stored in 'variable' when the += is performed: one on the + * value stack (in 'v') and one still stored in the + * 'variable'. We try to delete the variable now to reduce + * the refcnt to 1. + */ + switch (*next_instr) { + case STORE_FAST: + { + int oparg = PEEKARG(); + PyObject **fastlocals = f->f_localsplus; + if (GETLOCAL(oparg) == v) + SETLOCAL(oparg, NULL); + break; + } + case STORE_DEREF: + { + PyObject **freevars = (f->f_localsplus + + f->f_code->co_nlocals); + PyObject *c = freevars[PEEKARG()]; + if (PyCell_GET(c) == v) + PyCell_Set(c, NULL); + break; + } + case STORE_NAME: + { + PyObject *names = f->f_code->co_names; + PyObject *name = GETITEM(names, PEEKARG()); + PyObject *locals = f->f_locals; + if (PyDict_CheckExact(locals) && + PyDict_GetItem(locals, name) == v) { + if (PyDict_DelItem(locals, name) != 0) { + PyErr_Clear(); + } + } + break; + } + } + } + + if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) { + /* Now we own the last reference to 'v', so we can resize it + * in-place. + */ + if (_PyString_Resize(&v, new_len) != 0) { + /* XXX if _PyString_Resize() fails, 'v' has been + * deallocated so it cannot be put back into + * 'variable'. The MemoryError is raised when there + * is no value in 'variable', which might (very + * remotely) be a cause of incompatibilities. + */ + return NULL; + } + /* copy 'w' into the newly allocated area of 'v' */ + memcpy(PyString_AS_STRING(v) + v_len, + PyString_AS_STRING(w), w_len); + return v; + } + else { + /* When in-place resizing is not an option. */ + PyString_Concat(&v, w); + return v; + } +} + +#ifdef DYNAMIC_EXECUTION_PROFILE + +static PyObject * +getarray(long a[256]) +{ + int i; + PyObject *l = PyList_New(256); + if (l == NULL) return NULL; + for (i = 0; i < 256; i++) { + PyObject *x = PyInt_FromLong(a[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + for (i = 0; i < 256; i++) + a[i] = 0; + return l; +} + +PyObject * +_Py_GetDXProfile(PyObject *self, PyObject *args) +{ +#ifndef DXPAIRS + return getarray(dxp); +#else + int i; + PyObject *l = PyList_New(257); + if (l == NULL) return NULL; + for (i = 0; i < 257; i++) { + PyObject *x = getarray(dxpairs[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + return l; +#endif +} + +#endif