diff --git a/Include/cpython/slp_structs.h b/Include/cpython/slp_structs.h index 21ab38ac073def..e915565bbd784b 100644 --- a/Include/cpython/slp_structs.h +++ b/Include/cpython/slp_structs.h @@ -13,7 +13,6 @@ extern "C" { #ifdef SLP_BUILD_CORE -#include "frameobject.h" #if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) #define SLP_SEH32 #endif @@ -237,22 +236,39 @@ typedef struct _channel { PyObject *chan_weakreflist; } PyChannelObject; +struct _cframe; +typedef PyObject *(PyFrame_ExecFunc) (struct _cframe *, int, PyObject *); +/* + * How to write frame execution functions: + * + * Special rule for frame execution functions: the function owns a reference to retval! + * + * PyObject * example(PyCFrameObject *f, int exc, PyObject *retval) + * { + * PyThreadState *ts = _PyThreadState_GET(); + * + * do something .... + * If you change retval, use Py_SETREF(retval, new_value) or Py_CLEAR(retval). + * + * SLP_STORE_NEXT_FRAME(ts, f->f_back); + * return retval; + * } + * + */ /*** important stuctures: cframe ***/ typedef struct _cframe { PyObject_VAR_HEAD struct _frame *f_back; /* previous frame, or NULL */ - PyFrame_ExecFunc *f_execute; /* - * the above part is compatible with frames. - * Note that I have re-arranged some fields in the frames - * to keep cframes as small as possible. + * the above part is compatible with regular frames. */ - /* these can be used as the CFrame likes to */ + PyFrame_ExecFunc *f_execute; + /* these can be used as the CFrame likes to */ PyObject *ob1; PyObject *ob2; PyObject *ob3; diff --git a/Include/frameobject.h b/Include/frameobject.h index f7572ad6e8a003..a95baf8867a360 100644 --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -8,28 +8,6 @@ extern "C" { #endif -#ifdef STACKLESS -typedef PyObject *(PyFrame_ExecFunc) (struct _frame *, int, PyObject *); -/* - * How to write frame execution functions: - * - * Special rule for frame execution functions: the function owns a reference to retval! - * - * PyObject * example(PyFrameObject *f, int exc, PyObject *retval) - * { - * PyThreadState *ts = _PyThreadState_GET(); - * - * do something .... - * if you change retval, use Py_SETREF(retval, new_value) or - * Py_CLEAR(retval) - * - * SLP_STORE_NEXT_FRAME(ts, f->f_back); - * return retval; - * } - * - */ -#endif - typedef struct { int b_type; /* what kind of block this is */ int b_handler; /* where to jump to find handler */ @@ -39,11 +17,7 @@ typedef struct { typedef struct _frame { PyObject_VAR_HEAD struct _frame *f_back; /* previous frame, or NULL */ -#ifdef STACKLESS - PyFrame_ExecFunc *f_execute;/* support for soft stackless */ -#else PyCodeObject *f_code; /* code segment */ -#endif PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ PyObject *f_globals; /* global symbol table (PyDictObject) */ PyObject *f_locals; /* local symbol table (any mapping) */ @@ -69,9 +43,6 @@ typedef struct _frame { int f_iblock; /* index in f_blockstack */ char f_executing; /* whether the frame is still executing */ PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ -#ifdef STACKLESS - PyCodeObject *f_code; /* code segment */ -#endif PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */ } PyFrameObject; diff --git a/Include/internal/pycore_slp_prickelpit.h b/Include/internal/pycore_slp_prickelpit.h index 2b8d6bf6780059..f2d2f65d9b5fc0 100644 --- a/Include/internal/pycore_slp_prickelpit.h +++ b/Include/internal/pycore_slp_prickelpit.h @@ -19,15 +19,15 @@ int slp_find_execfuncs(PyTypeObject *type, PyObject *exec_name, PyFrame_ExecFunc **good, PyFrame_ExecFunc **bad); -PyObject * slp_find_execname(PyFrameObject *f, int *valid); +PyObject * slp_find_execname(PyCFrameObject *f, int *valid); -PyObject * slp_cannot_execute(PyFrameObject *f, const char *exec_name, PyObject *retval); +PyObject * slp_cannot_execute(PyCFrameObject *f, const char *exec_name, PyObject *retval); /* macros to define and use an invalid frame executor */ #define SLP_DEF_INVALID_EXEC(procname) \ static PyObject *\ -cannot_##procname(PyFrameObject *f, int exc, PyObject *retval) \ +cannot_##procname(PyCFrameObject *f, int exc, PyObject *retval) \ { \ return slp_cannot_execute(f, #procname, retval); \ } diff --git a/Include/internal/pycore_stackless.h b/Include/internal/pycore_stackless.h index 2cde84c3cbe580..8562d915a2ce83 100644 --- a/Include/internal/pycore_stackless.h +++ b/Include/internal/pycore_stackless.h @@ -17,6 +17,7 @@ extern "C" { #ifdef SLP_BUILD_CORE +#include "frameobject.h" #ifdef Py_BUILD_CORE #include "pycore_pystate.h" /* for _PyRuntime */ #endif @@ -39,7 +40,7 @@ extern "C" { * were created with an older Cython compiled with regular C-Python. * See Stackless issue #168 */ -#define SLP_END_OF_OLD_CYTHON_HACK_VERSION (0x030800b1) +#define SLP_END_OF_OLD_CYTHON_HACK_VERSION (0x030800a1) #endif /* @@ -325,8 +326,9 @@ PyObject * slp_wrap_call_frame(PyFrameObject *frame, int exc, PyObject *retval); } while (0) #define CALL_FRAME_FUNCTION(frame_, exc, retval) \ - (assert((frame_) && (frame_)->f_execute), \ - ((frame_)->f_execute((frame_), (exc), (retval)))) + (assert((frame_) && (!PyCFrame_Check(frame_) || ((PyCFrameObject *)(frame_))->f_execute)), \ + (PyCFrame_Check(frame_) ? (((PyCFrameObject *)(frame_))->f_execute(((PyCFrameObject *)(frame_)), (exc), (retval))) : \ + PyEval_EvalFrameEx_slp((frame_), (exc), (retval)))) #endif @@ -378,18 +380,10 @@ PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx_slp(struct _frame *, int, PyObject *); /* eval_frame with stack overflow, triggered there with a macro */ PyObject * slp_eval_frame_newstack(struct _frame *f, int throwflag, PyObject *retval); -/* the new eval_frame loop with or without value or resuming an iterator - or setting up or cleaning up a with block */ -PyObject * slp_eval_frame_value(struct _frame *f, int throwflag, PyObject *retval); -PyObject * slp_eval_frame_noval(struct _frame *f, int throwflag, PyObject *retval); -PyObject * slp_eval_frame_iter(struct _frame *f, int throwflag, PyObject *retval); -PyObject * slp_eval_frame_setup_with(struct _frame *f, int throwflag, PyObject *retval); -PyObject * slp_eval_frame_with_cleanup(struct _frame *f, int throwflag, PyObject *retval); -PyObject * slp_eval_frame_yield_from(struct _frame *f, int throwflag, PyObject *retval); /* other eval_frame functions from module/scheduling.c */ -PyObject * slp_restore_tracing(PyFrameObject *f, int exc, PyObject *retval); +PyObject * slp_restore_tracing(PyCFrameObject *cf, int exc, PyObject *retval); /* other eval_frame functions from Objects/typeobject.c */ -PyObject * slp_tp_init_callback(PyFrameObject *f, int exc, PyObject *retval); +PyObject * slp_tp_init_callback(PyCFrameObject *cf, int exc, PyObject *retval); /* functions related to pickling */ PyObject * slp_reduce_frame(PyFrameObject * frame); @@ -765,13 +759,13 @@ PyTaskletTStateStruc * slp_get_saved_tstate(PyTaskletObject *task); /* * Channel related prototypes */ -PyObject * slp_channel_seq_callback(struct _frame *f, int throwflag, PyObject *retval); +PyObject * slp_channel_seq_callback(PyCFrameObject *f, int throwflag, PyObject *retval); PyObject * slp_get_channel_callback(void); /* * contextvars related prototypes */ -PyObject* slp_context_run_callback(PyFrameObject *f, int exc, PyObject *result); +PyObject* slp_context_run_callback(PyCFrameObject *f, int exc, PyObject *result); /* macro for use when interrupting tasklets from watchdog */ #define TASKLET_NESTING_OK(task) \ @@ -788,6 +782,48 @@ void slp_head_unlock(void); long slp_parse_thread_id(PyObject *thread_id, unsigned long *id); +/* + * Symbolic names for values stored in PyFrameObject.f_executing + * + * Regular C-Python only uses two values + * 0: the frame is not executing + * 1: the frame is executing + * + * Stackless Python extends the range of values to indicate, what to do + * upon the next invocation of PyEval_EvalFrameEx_slp. + */ + +/* Frame is invalid and PyEval_EvalFrameEx_slp must raise an exception. + * Only set, if the frame was unpickled and had C-state on the stack. + */ +#define SLP_FRAME_EXECUTING_INVALID (-1) + +/* Frame is new or completely executed. */ +#define SLP_FRAME_EXECUTING_NO 0 + +/* Frame is executing, value in retval is valid and must be pushed onto the stack. */ +#define SLP_FRAME_EXECUTING_VALUE 1 + +/* Frame is executing, ignore value in retval. + * This is used at the start of a frame or after an interrupt. */ +#define SLP_FRAME_EXECUTING_NOVAL 2 + +/* Frame is executing, continue opcode ITER */ +#define SLP_FRAME_EXECUTING_ITER 3 + +/* Frame is executing, continue opcode SETUP_WITH */ +#define SLP_FRAME_EXECUTING_SETUP_WITH 4 + +/* Frame is executing, continue opcode WITH_CLEANUP */ +#define SLP_FRAME_EXECUTING_WITH_CLEANUP 5 + +/* Frame is executing, continue opcode YIELD_FROM */ +#define SLP_FRAME_EXECUTING_YIELD_FROM 6 + +/* Test, if the frame is executing */ +#define SLP_FRAME_IS_EXECUTING(frame_) \ + ((frame_)->f_executing >= SLP_FRAME_EXECUTING_VALUE && \ + (frame_)->f_executing <= SLP_FRAME_EXECUTING_YIELD_FROM) #endif /* #ifdef SLP_BUILD_CORE */ diff --git a/Objects/call.c b/Objects/call.c index 3ed5d58bbb5169..f682dcf5a89b95 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -354,7 +354,6 @@ function_code_fastcall(PyCodeObject *co, PyObject *const *args, Py_ssize_t nargs } #ifdef STACKLESS - f->f_execute = PyEval_EvalFrameEx_slp; if (stackless) { Py_INCREF(Py_None); result = Py_None; diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 2356b922a198f0..8897da3cea4f1f 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -751,9 +751,6 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code, f->f_trace_opcodes = 0; f->f_trace_lines = 1; -#ifdef STACKLESS - f->f_execute = NULL; -#endif return f; } diff --git a/Objects/genobject.c b/Objects/genobject.c index 6a86f21ae1d6b6..e135c544cf4428 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -166,7 +166,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, int exc, int closing, PyObject* ob /* callback for (async) generators and coroutines. */ static PyObject * -gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result); +gen_iternext_callback(PyCFrameObject *f, int exc, PyObject *result); /* Additional callback-code for async generators. */ static PyObject * @@ -310,8 +310,6 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, int exc, int closing, PyObject * o gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - f->f_execute = PyEval_EvalFrameEx_slp; - Py_INCREF(gen); Py_XINCREF(arg); Py_XINCREF(ob3); @@ -341,10 +339,10 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, int exc, int closing, PyObject * o } static PyObject* -gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result) +gen_iternext_callback(PyCFrameObject *cf, int exc, PyObject *result) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *cf = (PyCFrameObject *) f; + PyFrameObject *f = (PyFrameObject *) cf; PyGenObject *gen = (PyGenObject *) cf->ob1; PyObject *arg = cf->ob2; PyObject *ob3 = cf->ob3; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7f4cbf40215028..db28aec70bdfa0 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6781,10 +6781,10 @@ slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value) #ifdef STACKLESS PyObject * -slp_tp_init_callback(PyFrameObject *f, int exc, PyObject *retval) +slp_tp_init_callback(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *cf = (PyCFrameObject *) f; + PyFrameObject *f = (PyFrameObject *) cf; f = cf->f_back; if (retval != NULL) { diff --git a/Python/ceval.c b/Python/ceval.c index bc1dfd3e99cbfc..4024e5033245f3 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -600,10 +600,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) do { \ if (has_opcode) \ next_instr -= 1 + EXTENDED_ARG_OFFSET(oparg); \ - SLP_DISABLE_GCC_W_ADDRESS /* suppress warning, if frame_func is a function */ \ - if (frame_func != NULL) { \ - SLP_RESTORE_WARNINGS \ - f->f_execute = (frame_func); \ + assert(SLP_FRAME_EXECUTING_VALUE == f->f_executing); \ + if (frame_func != SLP_FRAME_EXECUTING_VALUE) { \ + f->f_executing = (frame_func); \ } \ /* keep the reference to the frame to be called. */ \ f->f_stacktop = stack_pointer; \ @@ -623,11 +622,9 @@ do { \ (retval__) = CALL_FRAME_FUNCTION(f2, 0, (retval__)); \ Py_DECREF(f2); \ if (SLP_PEEK_NEXT_FRAME(tstate) != f) { \ - assert(f->f_execute == slp_eval_frame_value || f->f_execute == slp_eval_frame_noval || \ - f->f_execute == slp_eval_frame_setup_with || f->f_execute == slp_eval_frame_with_cleanup || \ - f->f_execute == slp_eval_frame_yield_from); \ - if (f->f_execute == slp_eval_frame_noval) \ - f->f_execute = slp_eval_frame_value; \ + assert(SLP_FRAME_IS_EXECUTING(f)); \ + if (f->f_executing == SLP_FRAME_EXECUTING_NOVAL) \ + f->f_executing = SLP_FRAME_EXECUTING_VALUE; \ LLTRACE_HANDLE_UNWINDING(STACKLESS_RETVAL((tstate), (retval__)), "handle_unwinding return from next frame:");\ return (retval__); \ } \ @@ -638,15 +635,13 @@ do { \ if (STACKLESS_UNWINDING(retval__)) \ STACKLESS_UNPACK(tstate, (retval__)); \ f->f_stacktop = NULL; \ - SLP_DISABLE_GCC_W_ADDRESS /* suppress warning, if frame_func is a function */ \ - if (frame_func != NULL) { \ - SLP_RESTORE_WARNINGS \ - assert(f->f_execute == (frame_func)); \ + if (frame_func != SLP_FRAME_EXECUTING_VALUE) { \ + assert(f->f_executing == (frame_func)); \ } \ else { \ - assert(f->f_execute == slp_eval_frame_value || f->f_execute == slp_eval_frame_noval); \ + assert(f->f_executing == SLP_FRAME_EXECUTING_VALUE || f->f_executing == SLP_FRAME_EXECUTING_NOVAL); \ } \ - f->f_execute = slp_eval_frame_value; \ + f->f_executing = SLP_FRAME_EXECUTING_VALUE; \ if (has_opcode) \ next_instr += 1 + EXTENDED_ARG_OFFSET(oparg); \ LLTRACE_HANDLE_UNWINDING((retval__), "handle_unwinding end:");\ @@ -966,6 +961,8 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) /* Stackless specific defines start here.. */ #ifdef STACKLESS + int executing = f->f_executing; + #define SLP_CHECK_INTERRUPT() \ if (tstate->st.interrupt && !tstate->curexc_type) { \ if (tstate->st.tick_counter > tstate->st.tick_watermark) { \ @@ -1087,33 +1084,27 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) #ifdef STACKLESS - if (f->f_execute == slp_eval_frame_value) { - /* this is a return */ - PUSH(retval); /* we are back from a function call */ - } - else if (f->f_execute == slp_eval_frame_noval) { - f->f_execute = slp_eval_frame_value; + assert(f->f_executing == SLP_FRAME_EXECUTING_VALUE); + switch(executing){ + case SLP_FRAME_EXECUTING_NOVAL: /* don't push it, frame ignores value */ Py_XDECREF(retval); - } - else if (f->f_execute == slp_eval_frame_iter) { - f->f_execute = slp_eval_frame_value; + break; + case SLP_FRAME_EXECUTING_VALUE: + /* this is a return */ + PUSH(retval); /* we are back from a function call */ + break; + case SLP_FRAME_EXECUTING_ITER: goto slp_continue_slp_eval_frame_iter; - } - else if (f->f_execute == slp_eval_frame_setup_with) { - f->f_execute = slp_eval_frame_value; + case SLP_FRAME_EXECUTING_SETUP_WITH: goto slp_continue_slp_eval_frame_setup_with; - } - else if (f->f_execute == slp_eval_frame_with_cleanup) { - f->f_execute = slp_eval_frame_value; + case SLP_FRAME_EXECUTING_WITH_CLEANUP: goto slp_continue_slp_eval_frame_with_cleanup; - } - else if (f->f_execute == slp_eval_frame_yield_from) { - f->f_execute = slp_eval_frame_value; + case SLP_FRAME_EXECUTING_YIELD_FROM: goto slp_continue_slp_eval_frame_yield_from; + default: + Py_FatalError("invalid frame->f_executing value"); } - else - Py_FatalError("invalid frame function"); /* always check for an error flag */ if (retval == NULL) @@ -2040,7 +2031,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) Py_DECREF(v); #ifdef STACKLESS if (STACKLESS_UNWINDING(retval)) { - HANDLE_UNWINDING(slp_eval_frame_yield_from, 0, retval); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_YIELD_FROM, 0, retval); } if (0) { slp_continue_slp_eval_frame_yield_from: @@ -3129,7 +3120,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) STACKLESS_ASSERT(); } if (STACKLESS_UNWINDING(next)) { - HANDLE_UNWINDING(slp_eval_frame_iter, 1, next); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_ITER, 1, next); } if (0) { slp_continue_slp_eval_frame_iter: @@ -3231,7 +3222,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) Py_DECREF(enter); #ifdef STACKLESS if (STACKLESS_UNWINDING(res)) { - HANDLE_UNWINDING(slp_eval_frame_setup_with, 1, res); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_SETUP_WITH, 1, res); } if(0) { slp_continue_slp_eval_frame_setup_with: @@ -3320,7 +3311,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) Py_DECREF(exit_func); #ifdef STACKLESS if (STACKLESS_UNWINDING(res)) { - HANDLE_UNWINDING(slp_eval_frame_with_cleanup, 0, res); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_WITH_CLEANUP, 0, res); } if (0) { slp_continue_slp_eval_frame_with_cleanup: @@ -3460,7 +3451,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) } #ifdef STACKLESS if (STACKLESS_UNWINDING(res)) { - HANDLE_UNWINDING(NULL, 0, res); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_VALUE, 0, res); } #endif @@ -3478,7 +3469,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) stack_pointer = sp; #ifdef STACKLESS if (STACKLESS_UNWINDING(res)) { - HANDLE_UNWINDING(NULL, 0, res); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_VALUE, 0, res); } #endif PUSH(res); @@ -3499,7 +3490,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) Py_DECREF(names); #ifdef STACKLESS if (STACKLESS_UNWINDING(res)) { - HANDLE_UNWINDING(NULL, 0, res); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_VALUE, 0, res); } #endif PUSH(res); @@ -3552,7 +3543,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) #ifdef STACKLESS if (STACKLESS_UNWINDING(result)) { (void) POP(); /* top of stack causes a GC related assertion error */ - HANDLE_UNWINDING(NULL, 0, result); + HANDLE_UNWINDING(SLP_FRAME_EXECUTING_VALUE, 0, result); PUSH(result); } else #endif @@ -3821,8 +3812,8 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) stackless_interrupt_call: /* interrupted during unwinding */ - - f->f_execute = slp_eval_frame_noval; + assert(f->f_executing == SLP_FRAME_EXECUTING_VALUE); + f->f_executing = SLP_FRAME_EXECUTING_NOVAL; f->f_stacktop = stack_pointer; /* Set f->f_lasti to the instruction before the current one or to the @@ -3837,86 +3828,12 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) #ifdef STACKLESS -PyObject * _Py_HOT_FUNCTION -slp_eval_frame_noval(PyFrameObject *f, int throwflag, PyObject *retval) -{ - PyObject *r; - /* - * this function is identical to PyEval_EvalFrame_value. - * it serves as a marker whether we expect a value or - * not, and it makes debugging a little easier. - */ - SLP_DO_NOT_OPTIMIZE_AWAY((char *)1); - - r = slp_eval_frame_value(f, throwflag, retval); - return r; -} - -PyObject * -slp_eval_frame_iter(PyFrameObject *f, int throwflag, PyObject *retval) -{ - PyObject *r; - /* - * this function is identical to PyEval_EvalFrame_value. - * it serves as a marker whether we are inside of a - * for_iter operation. In this case we need to handle - * null without error as valid result. - */ - SLP_DO_NOT_OPTIMIZE_AWAY((char *)2); - r = slp_eval_frame_value(f, throwflag, retval); - return r; -} - -PyObject * -slp_eval_frame_setup_with(PyFrameObject *f, int throwflag, PyObject *retval) -{ - PyObject *r; - /* - * this function is identical to PyEval_EvalFrame_value. - * it serves as a marker whether we are inside of a - * SETUP_WITH operation. - * NOTE / XXX: see above. - */ - SLP_DO_NOT_OPTIMIZE_AWAY((char *)3); - r = slp_eval_frame_value(f, throwflag, retval); - return r; -} - -PyObject * -slp_eval_frame_with_cleanup(PyFrameObject *f, int throwflag, PyObject *retval) -{ - PyObject *r; - /* - * this function is identical to PyEval_EvalFrame_value. - * it serves as a marker whether we are inside of a - * WITH_CLEANUP operation. - * NOTE / XXX: see above. - */ - SLP_DO_NOT_OPTIMIZE_AWAY((char *)4); - r = slp_eval_frame_value(f, throwflag, retval); - return r; -} - -PyObject * -slp_eval_frame_yield_from(PyFrameObject *f, int throwflag, PyObject *retval) -{ - PyObject *r; - /* - * this function is identical to PyEval_EvalFrame_value. - * it serves as a marker whether we are inside of a - * WITH_CLEANUP operation. - * NOTE / XXX: see above. - */ - SLP_DO_NOT_OPTIMIZE_AWAY((char *)5); - r = slp_eval_frame_value(f, throwflag, retval); - return r; -} static PyObject * -run_frame_dispatch(PyFrameObject *f, int exc, PyObject *retval) +run_frame_dispatch(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *cf = (PyCFrameObject*) f; + PyFrameObject *f = (PyFrameObject*) cf; PyFrameObject *f_back; int done = cf->i; @@ -3965,75 +3882,24 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject * retval = NULL; PyFrameObject * f_back; - if (f == NULL) + if (f == NULL) { + PyErr_BadInternalCall(); return NULL; - - /* The layout of PyFrameObject differs between Stackless and C-Python. - * Stackless f->f_execute is C-Python f->f_code. Stackless f->f_code is at - * the end, just before f_localsplus. - */ - if (PyFrame_Check(f) && f->f_execute == NULL) { - /* A new frame returned from PyFrame_New() has f->f_execute == NULL. - * Set the usual execution function. - */ - f->f_execute = PyEval_EvalFrameEx_slp; - -#if PY_VERSION_HEX < SLP_END_OF_OLD_CYTHON_HACK_VERSION - /* Older versions of Cython used to create frames using C-Python layout - * of PyFrameObject. As a consequence f_code is overwritten by the first - * item of f_localsplus[]. To be able to fix it, we have a copy of - * f_code and a signature at the end of the block-stack. - * The Py_BUILD_ASSERT_EXPR checks,that our assumptions about the layout - * of PyFrameObject are true. - * See Stackless issue #168 - */ - (void) Py_BUILD_ASSERT_EXPR(offsetof(PyFrameObject, f_code) == - offsetof(PyFrameObject, f_localsplus) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus[0])); - - /* Check for an old Cython frame */ - if (f->f_iblock == 0 && f->f_lasti == -1 && /* blockstack is empty */ - f->f_blockstack[0].b_type == -31683 && /* magic is present */ - /* and f_code has been overwritten */ - f->f_code != (&(f->f_code))[-1] && - /* and (&(f->f_code))[-1] looks like a valid code object */ - (&(f->f_code))[-1] && PyCode_Check((&(f->f_code))[-1]) && - /* and there are arguments */ - (&(f->f_code))[-1]->co_argcount > 0 && - /* the last argument is NULL */ - f->f_localsplus[(&(f->f_code))[-1]->co_argcount - 1] == NULL) - { - PyCodeObject * code = (&(f->f_code))[-1]; - memmove(f->f_localsplus, f->f_localsplus-1, code->co_argcount * sizeof(f->f_localsplus[0])); - f->f_code = code; - } else -#endif - if (!(f->f_code != NULL && PyCode_Check(f->f_code))) { + } + if (PyFrame_Check(f)) { + if (!(f->f_executing == SLP_FRAME_EXECUTING_NO || + SLP_FRAME_IS_EXECUTING(f))) { PyErr_BadInternalCall(); return NULL; } - } else { - /* In order to detect a broken C-Python frame, we must compare f->f_execute - * with every valid frame function. Hard to implement completely. - * Therefore I'll check only for relevant functions. - * Amend the list as needed. - * - * If needed, we could try to fix an C-Python frame on the fly. - * - * (It is not possible to detect an C-Python frame by its size, because - * we need the code object to compute the expected size and the location - * of code objects varies between Stackless and C-Python frames). - */ - if (!PyCFrame_Check(f) && - f->f_execute != PyEval_EvalFrameEx_slp && - f->f_execute != slp_eval_frame_value && - f->f_execute != slp_eval_frame_noval && - f->f_execute != slp_eval_frame_iter && - f->f_execute != slp_eval_frame_setup_with && - f->f_execute != slp_eval_frame_with_cleanup && - f->f_execute != slp_eval_frame_yield_from) { + } else if (PyCFrame_Check(f)) { + if (((PyCFrameObject *)f)->f_execute == NULL) { PyErr_BadInternalCall(); return NULL; } + } else { + PyErr_BadInternalCall(); + return NULL; } if (!throwflag) { @@ -4079,6 +3945,14 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject * _Py_HOT_FUNCTION PyEval_EvalFrameEx_slp(PyFrameObject *f, int throwflag, PyObject *retval) { + if (f->f_executing == SLP_FRAME_EXECUTING_INVALID) { + PyThreadState *tstate = _PyThreadState_GET(); + --tstate->recursion_depth; + return slp_cannot_execute((PyCFrameObject *)f, "PyEval_EvalFrameEx_slp", retval); + } else if (f->f_executing != SLP_FRAME_EXECUTING_NO) { + return slp_eval_frame_value(f, throwflag, retval); + } + PyThreadState *tstate = _PyThreadState_GET(); /* Check, if an extension module has changed tstate->interp->eval_frame. @@ -4148,14 +4022,14 @@ PyEval_EvalFrameEx_slp(PyFrameObject *f, int throwflag, PyObject *retval) */ - f->f_execute = slp_eval_frame_noval; + f->f_executing = SLP_FRAME_EXECUTING_NOVAL; return slp_eval_frame_value(f, throwflag, retval); exit_eval_frame: Py_XDECREF(retval); if (PyDTrace_FUNCTION_RETURN_ENABLED()) dtrace_function_return(f); Py_LeaveRecursiveCall(); - f->f_executing = 0; + f->f_executing = SLP_FRAME_EXECUTING_NO; SLP_STORE_NEXT_FRAME(tstate, f->f_back); return NULL; } @@ -4356,9 +4230,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, return NULL; } -#ifdef STACKLESS - f->f_execute = PyEval_EvalFrameEx_slp; -#endif fastlocals = f->f_localsplus; freevars = f->f_localsplus + co->co_nlocals; diff --git a/Python/context.c b/Python/context.c index 3aff6c24add30b..a83844bf690eaf 100644 --- a/Python/context.c +++ b/Python/context.c @@ -620,9 +620,8 @@ _contextvars_Context_copy_impl(PyContext *self) #ifdef STACKLESS -PyObject* slp_context_run_callback(PyFrameObject *f, int exc, PyObject *result) +PyObject* slp_context_run_callback(PyCFrameObject *cf, int exc, PyObject *result) { - PyCFrameObject *cf = (PyCFrameObject *)f; PyObject *context = cf->ob1; cf->ob1 = NULL; diff --git a/Stackless/changelog.txt b/Stackless/changelog.txt index 011624defcd265..ab010f4d5f38a9 100644 --- a/Stackless/changelog.txt +++ b/Stackless/changelog.txt @@ -9,6 +9,9 @@ What's New in Stackless 3.X.X? *Release date: 20XX-XX-XX* +- https://github.com/stackless-dev/stackless/issues/270 + Stackless now uses an unmodified PyFrameObject structure. + - https://github.com/stackless-dev/stackless/issues/269 A failure to unpickle a frame could cause a NULL pointer access when deallocating the frame. This has been fixed. diff --git a/Stackless/core/cframeobject.c b/Stackless/core/cframeobject.c index 6495bb2911fd24..619b8a36d38b4d 100644 --- a/Stackless/core/cframeobject.c +++ b/Stackless/core/cframeobject.c @@ -130,7 +130,7 @@ slp_cframe_new(PyFrame_ExecFunc *exec, unsigned int linked) #define cframetuplefmt "iOOll" #define cframetuplenewfmt "iOO!ll:cframe" -static PyObject * execute_soft_switchable_func(PyFrameObject *, int, PyObject *); +static PyObject * execute_soft_switchable_func(PyCFrameObject *, int, PyObject *); SLP_DEF_INVALID_EXEC(execute_soft_switchable_func) static PyObject * @@ -153,7 +153,7 @@ cframe_reduce(PyCFrameObject *cf, PyObject *value) assert(PyStacklessFunctionDeclarationType_CheckExact(exec_name)); Py_INCREF(exec_name); valid = cf->any1 == NULL; - } else if ((exec_name = slp_find_execname((PyFrameObject *) cf, &valid)) == NULL) + } else if ((exec_name = slp_find_execname(cf, &valid)) == NULL) return NULL; obs[0] = cf->ob1; @@ -252,10 +252,10 @@ static PyMethodDef cframe_methods[] = { }; -static PyObject * run_cframe(PyFrameObject *f, int exc, PyObject *retval) +static PyObject * run_cframe(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *cf = (PyCFrameObject*) f; + PyFrameObject *f = (PyFrameObject*) cf; PyTaskletObject *task = ts->st.current; int done = cf->i; @@ -458,12 +458,11 @@ PyTypeObject PyStacklessFunctionDeclaration_Type = { static PyObject * -execute_soft_switchable_func(PyFrameObject *f, int exc, PyObject *retval) +execute_soft_switchable_func(PyCFrameObject *cf, int exc, PyObject *retval) { /* * Special rule for frame execution functions: we now own a reference to retval! */ - PyCFrameObject *cf = (PyCFrameObject *)f; PyThreadState *ts = _PyThreadState_GET(); PyObject *ob1, *ob2, *ob3; PyStacklessFunctionDeclarationObject *ssfd = diff --git a/Stackless/core/stacklesseval.c b/Stackless/core/stacklesseval.c index 01fd07daa9707f..c5f9c11d8d2bb4 100644 --- a/Stackless/core/stacklesseval.c +++ b/Stackless/core/stacklesseval.c @@ -843,12 +843,12 @@ void PyStackless_kill_tasks_with_stacks(int allthreads) /* cstack spilling for recursive calls */ static PyObject * -eval_frame_callback(PyFrameObject *f, int exc, PyObject *retval) +eval_frame_callback(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); PyTaskletObject *cur = ts->st.current; PyCStackObject *cst; - PyCFrameObject *cf = (PyCFrameObject *) f; + PyFrameObject *f = (PyFrameObject *) cf; intptr_t *saved_base; Py_ssize_t tmp; int in_transfer; diff --git a/Stackless/module/channelobject.c b/Stackless/module/channelobject.c index ba635b9493679d..81ad33673ae563 100644 --- a/Stackless/module/channelobject.c +++ b/Stackless/module/channelobject.c @@ -958,10 +958,9 @@ _channel_send_sequence(PyChannelObject *self, PyObject *v) */ PyObject * -slp_channel_seq_callback(PyFrameObject *_f, int exc, PyObject *retval) +slp_channel_seq_callback(PyCFrameObject *f, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *f = (PyCFrameObject *) _f; PyChannelObject *ch; PyObject *item; int stage = f->n; diff --git a/Stackless/module/scheduling.c b/Stackless/module/scheduling.c index c91de496fcd37d..4e466872bfa07a 100644 --- a/Stackless/module/scheduling.c +++ b/Stackless/module/scheduling.c @@ -557,10 +557,9 @@ kill_wrap_bad_guy(PyTaskletObject *prev, PyTaskletObject *bad_guy) /* non-recursive scheduling */ PyObject * -slp_restore_tracing(PyFrameObject *f, int exc, PyObject *retval) +slp_restore_tracing(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *cf = (PyCFrameObject *) f; if (NULL == cf->any1 && NULL == cf->any2) { /* frame was created by unpickling */ @@ -606,20 +605,20 @@ slp_encode_ctrace_functions(Py_tracefunc c_tracefunc, Py_tracefunc c_profilefunc /* jumping from a soft tasklet to a hard switched */ static PyObject * -jump_soft_to_hard(PyFrameObject *f, int exc, PyObject *retval) +jump_soft_to_hard(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - SLP_STORE_NEXT_FRAME(ts, f->f_back); + SLP_STORE_NEXT_FRAME(ts, cf->f_back); /* reinstate the del_post_switch */ assert(ts->st.del_post_switch == NULL); - ts->st.del_post_switch = ((PyCFrameObject*)f)->ob1; - ((PyCFrameObject*)f)->ob1 = NULL; + ts->st.del_post_switch = cf->ob1; + cf->ob1 = NULL; /* ignore retval. everything is in the tasklet. */ Py_DECREF(retval); /* consume ref according to protocol */ - SLP_FRAME_EXECFUNC_DECREF(f); + SLP_FRAME_EXECFUNC_DECREF(cf); slp_transfer_return(ts->st.current->cstate); /* We either have an error or don't come back, so bail out. * There is no way to recover, because we don't know the previous @@ -1245,7 +1244,7 @@ slp_schedule_task_prepared(PyThreadState *ts, PyObject **result, PyTaskletObject * (For now there is at most a single pending cframe.) */ if (prev->cstate->nesting_level > 0 && f && PyCFrame_Check(f) && - f->f_execute == slp_restore_tracing) { + ((PyCFrameObject *)f)->f_execute == slp_restore_tracing) { PyObject *retval; PyFrameObject *f2; @@ -1648,8 +1647,12 @@ slp_wrap_call_frame(PyFrameObject *frame, int exc, PyObject *retval) { assert(frame); assert(SLP_CURRENT_FRAME_IS_VALID(ts)); Py_INCREF(frame); - assert(frame->f_execute != NULL); - res = frame->f_execute(frame, exc, retval); + if (PyCFrame_Check(frame)) { + assert(((PyCFrameObject *)frame)->f_execute != NULL); + res = ((PyCFrameObject *)frame)->f_execute((PyCFrameObject *)frame, exc, retval); + } else { + res = PyEval_EvalFrameEx_slp(frame, exc, retval); + } assert(Py_REFCNT(frame) >= 2); Py_DECREF(frame); SLP_ASSERT_FRAME_IN_TRANSFER(ts); diff --git a/Stackless/module/stacklessmodule.c b/Stackless/module/stacklessmodule.c index 95fb3c66c1e183..16e6470d8eac9a 100644 --- a/Stackless/module/stacklessmodule.c +++ b/Stackless/module/stacklessmodule.c @@ -1031,10 +1031,9 @@ Usage: Cf. test_cframe()."); static PyObject * -_test_cframe_nr_loop(PyFrameObject *f, int exc, PyObject *retval) +_test_cframe_nr_loop(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = _PyThreadState_GET(); - PyCFrameObject *cf = (PyCFrameObject *) f; if (retval == NULL) goto exit_test_cframe_nr_loop; diff --git a/Stackless/module/taskletobject.c b/Stackless/module/taskletobject.c index 4af2afa79a782b..20bf77b54c9443 100644 --- a/Stackless/module/taskletobject.c +++ b/Stackless/module/taskletobject.c @@ -817,7 +817,7 @@ tasklet_setstate(PyObject *self, PyObject *args) /* walk frames again and calculate recursion_depth */ for (f = t->f.frame; f != NULL; f = f->f_back) { - if (PyFrame_Check(f) && f->f_execute != PyEval_EvalFrameEx_slp) { + if (PyFrame_Check(f) && f->f_executing != SLP_FRAME_EXECUTING_NO) { /* * we count running frames which *have* added * to recursion_depth diff --git a/Stackless/pickling/prickelpit.c b/Stackless/pickling/prickelpit.c index 7abeb203a2fb18..3fae868570fb0a 100644 --- a/Stackless/pickling/prickelpit.c +++ b/Stackless/pickling/prickelpit.c @@ -366,7 +366,7 @@ run_script(char *src, char *retname) */ PyObject * -slp_cannot_execute(PyFrameObject *f, const char *exec_name, PyObject *retval) +slp_cannot_execute(PyCFrameObject *f, const char *exec_name, PyObject *retval) { /* * Special rule for frame execution functions: we now own a reference to retval! @@ -388,12 +388,6 @@ slp_cannot_execute(PyFrameObject *f, const char *exec_name, PyObject *retval) SLP_STORE_NEXT_FRAME(tstate, f->f_back); - if(PyFrame_Check(f)) { - /* Only real frames contribute to the recursion count. - * C-frames don't contribute, see tasklet_setstate(...) */ - --tstate->recursion_depth; - } - return NULL; } @@ -497,13 +491,13 @@ slp_find_execfuncs(PyTypeObject *type, PyObject *exec_name, } PyObject * -slp_find_execname(PyFrameObject *f, int *valid) +slp_find_execname(PyCFrameObject *cf, int *valid) { PyObject *exec_name = NULL; proxyobject *dp = (proxyobject *) - PyDict_GetItemString(Py_TYPE(f)->tp_dict, "_exec_map"); + PyDict_GetItemString(Py_TYPE(cf)->tp_dict, "_exec_map"); PyObject *dic = dp ? dp->dict : NULL; - PyObject *exec_addr = PyLong_FromVoidPtr(f->f_execute); + PyObject *exec_addr = PyLong_FromVoidPtr(cf->f_execute); assert(valid != NULL); @@ -513,19 +507,19 @@ slp_find_execname(PyFrameObject *f, int *valid) char msg[500]; PyErr_Clear(); sprintf(msg, "frame exec function at %p is not registered!", - (void *)f->f_execute); + (void *)cf->f_execute); PyErr_SetString(PyExc_ValueError, msg); *valid = 0; } else { PyFrame_ExecFunc *good, *bad; - if (slp_find_execfuncs(Py_TYPE(f), exec_name, &good, &bad)) { + if (slp_find_execfuncs(Py_TYPE(cf), exec_name, &good, &bad)) { exec_name = NULL; goto err_exit; } - if (f->f_execute == bad) + if (cf->f_execute == bad) *valid = 0; - else if (f->f_execute != good) { + else if (cf->f_execute != good) { PyErr_SetString(PyExc_SystemError, "inconsistent c?frame function registration"); goto err_exit; @@ -831,15 +825,8 @@ static int init_functype(PyObject * mod) ******************************************************/ -#define frametuplefmt "O)(OiSOiOOiiOO" +#define frametuplefmt "O)(OibOiOOiiOO" -SLP_DEF_INVALID_EXEC(eval_frame) -SLP_DEF_INVALID_EXEC(eval_frame_value) -SLP_DEF_INVALID_EXEC(eval_frame_noval) -SLP_DEF_INVALID_EXEC(eval_frame_iter) -SLP_DEF_INVALID_EXEC(eval_frame_setup_with) -SLP_DEF_INVALID_EXEC(eval_frame_with_cleanup) -SLP_DEF_INVALID_EXEC(eval_frame_yield_from) SLP_DEF_INVALID_EXEC(slp_channel_seq_callback) SLP_DEF_INVALID_EXEC(slp_restore_tracing) SLP_DEF_INVALID_EXEC(slp_tp_init_callback) @@ -852,7 +839,7 @@ frameobject_reduce(PyFrameObject *f, PyObject *unused) int i; PyObject **f_stacktop; PyObject *blockstack_as_tuple = NULL, *localsplus_as_tuple = NULL, - *res = NULL, *exec_name = NULL; + *res = NULL; int valid = 1; int have_locals = f->f_locals != NULL; PyObject * dummy_locals = NULL; @@ -863,9 +850,6 @@ frameobject_reduce(PyFrameObject *f, PyObject *unused) if ((dummy_locals = PyDict_New()) == NULL) return NULL; - if ((exec_name = slp_find_execname(f, &valid)) == NULL) - return NULL; - blockstack_as_tuple = PyTuple_New (f->f_iblock); if (blockstack_as_tuple == NULL) goto err_exit; @@ -914,7 +898,7 @@ frameobject_reduce(PyFrameObject *f, PyObject *unused) f->f_code, f->f_code, valid, - exec_name, + f->f_executing, f->f_globals, have_locals, have_locals ? f->f_locals : dummy_locals, @@ -926,7 +910,6 @@ frameobject_reduce(PyFrameObject *f, PyObject *unused) ); err_exit: - Py_XDECREF(exec_name); Py_XDECREF(blockstack_as_tuple); Py_XDECREF(localsplus_as_tuple); Py_XDECREF(dummy_locals); @@ -935,7 +918,7 @@ frameobject_reduce(PyFrameObject *f, PyObject *unused) } #define frametuplenewfmt "O!:frame.__new__" -#define frametuplesetstatefmt "O!iUO!iO!OiiO!O:frame.__setstate__" +#define frametuplesetstatefmt "O!ibO!iO!OiiO!O:frame.__setstate__" static PyObject * frame_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -958,7 +941,6 @@ frame_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (globals == NULL) return NULL; f = PyFrame_New(ts, (PyCodeObject *) f_code, globals, globals); - assert(f->f_execute == NULL); /* frame is not executable */ if (f != NULL) Py_TYPE(f) = &wrap_PyFrame_Type; Py_DECREF(globals); @@ -973,9 +955,8 @@ frame_setstate(PyFrameObject *f, PyObject *args) Py_ssize_t i; PyObject *f_globals, *f_locals, *blockstack_as_tuple; PyObject *localsplus_as_tuple, *trace, *f_code; - PyObject *exec_name = NULL; - PyFrame_ExecFunc *good_func, *bad_func; int valid, have_locals; + char f_executing; Py_ssize_t tmp; if (is_wrong_type(Py_TYPE(f))) return NULL; @@ -983,18 +964,17 @@ frame_setstate(PyFrameObject *f, PyObject *args) Py_CLEAR(f->f_locals); if (!PyArg_ParseTuple (args, frametuplesetstatefmt, - &PyCode_Type, &f_code, - &valid, - &exec_name, - &PyDict_Type, &f_globals, - &have_locals, - &PyDict_Type, &f_locals, - &trace, - &f_lasti, - &f_lineno, - &PyTuple_Type, &blockstack_as_tuple, - &localsplus_as_tuple - )) + &PyCode_Type, &f_code, + &valid, + &f_executing, + &PyDict_Type, &f_globals, + &have_locals, + &PyDict_Type, &f_locals, + &trace, + &f_lasti, + &f_lineno, + &PyTuple_Type, &blockstack_as_tuple, + &localsplus_as_tuple)) return NULL; if (f->f_code != (PyCodeObject *) f_code) { @@ -1002,9 +982,6 @@ frame_setstate(PyFrameObject *f, PyObject *args) "invalid code object for frame_setstate"); return NULL; } - if (slp_find_execfuncs(Py_TYPE(f)->tp_base, exec_name, &good_func, - &bad_func)) - return NULL; if (have_locals) { Py_INCREF(f_locals); @@ -1097,14 +1074,12 @@ frame_setstate(PyFrameObject *f, PyObject *args) } /* See if this frame is valid to be run. */ - f->f_execute = valid ? good_func : bad_func; + f->f_executing = valid ? f_executing : SLP_FRAME_EXECUTING_INVALID; Py_TYPE(f) = &PyFrame_Type; Py_INCREF(f); return (PyObject *) f; err_exit: - /* Make sure that the frame is not executable. */ - f->f_execute = NULL; /* Clear members that could leak. */ PyFrame_Type.tp_clear((PyObject*)f); @@ -1187,21 +1162,7 @@ MAKE_WRAPPERTYPE(PyFrame_Type, frame, "frame", frameobject_reduce, frame_new, fr static int init_frametype(PyObject * mod) { - return slp_register_execute(&PyFrame_Type, "eval_frame", - PyEval_EvalFrameEx_slp, SLP_REF_INVALID_EXEC(eval_frame)) - || slp_register_execute(&PyFrame_Type, "eval_frame_value", - slp_eval_frame_value, SLP_REF_INVALID_EXEC(eval_frame_value)) - || slp_register_execute(&PyFrame_Type, "eval_frame_noval", - slp_eval_frame_noval, SLP_REF_INVALID_EXEC(eval_frame_noval)) - || slp_register_execute(&PyFrame_Type, "eval_frame_iter", - slp_eval_frame_iter, SLP_REF_INVALID_EXEC(eval_frame_iter)) - || slp_register_execute(&PyFrame_Type, "eval_frame_setup_with", - slp_eval_frame_setup_with, SLP_REF_INVALID_EXEC(eval_frame_setup_with)) - || slp_register_execute(&PyFrame_Type, "eval_frame_with_cleanup", - slp_eval_frame_with_cleanup, SLP_REF_INVALID_EXEC(eval_frame_with_cleanup)) - || slp_register_execute(&PyFrame_Type, "eval_frame_yield_from", - slp_eval_frame_yield_from, SLP_REF_INVALID_EXEC(eval_frame_yield_from)) - || slp_register_execute(&PyCFrame_Type, "channel_seq_callback", + return slp_register_execute(&PyCFrame_Type, "channel_seq_callback", slp_channel_seq_callback, SLP_REF_INVALID_EXEC(slp_channel_seq_callback)) || slp_register_execute(&PyCFrame_Type, "slp_restore_tracing", slp_restore_tracing, SLP_REF_INVALID_EXEC(slp_restore_tracing)) @@ -1838,8 +1799,9 @@ static int init_generatortype(PyObject * mod) if (gen == NULL || gen->gi_frame->f_back == NULL) return -1; cbframe = gen->gi_frame->f_back; + assert(PyCFrame_Check(cbframe)); res = slp_register_execute(Py_TYPE(cbframe), "gen_iternext_callback", - gen->gi_frame->f_back->f_execute, + ((PyCFrameObject *)cbframe)->f_execute, SLP_REF_INVALID_EXEC(gen_iternext_callback)) || init_type(&wrap_PyGen_Type, initchain, mod); diff --git a/Stackless/pickling/safe_pickle.c b/Stackless/pickling/safe_pickle.c index 118cf3dee10cbc..d8a0ac76a5afd9 100644 --- a/Stackless/pickling/safe_pickle.c +++ b/Stackless/pickling/safe_pickle.c @@ -12,12 +12,12 @@ static int(*cPickle_save)(PyObject *, PyObject *, int) = NULL; static PyObject * -pickle_callback(PyFrameObject *f, int exc, PyObject *retval) +pickle_callback(PyCFrameObject *cf, int exc, PyObject *retval) { PyThreadState *ts = PyThreadState_GET(); PyTaskletObject *cur = ts->st.current; PyCStackObject *cst; - PyCFrameObject *cf = (PyCFrameObject *) f; + PyFrameObject *f = (PyFrameObject *) cf; intptr_t *saved_base; /* store and update thread state */ @@ -108,7 +108,7 @@ static PyObject *_self, *_args; static int _pers_save; static PyObject * -pickle_runmain(PyFrameObject *f, int exc, PyObject *retval) +pickle_runmain(PyCFrameObject *f, int exc, PyObject *retval) { PyThreadState *ts = PyThreadState_GET(); Py_XDECREF(retval); diff --git a/Stackless/unittests/test_defects.py b/Stackless/unittests/test_defects.py index dd70a936bb3c97..fd5e307df994ac 100644 --- a/Stackless/unittests/test_defects.py +++ b/Stackless/unittests/test_defects.py @@ -264,7 +264,7 @@ def func(current): func, args, state = reduce_current() # state is a tuple of the form - # ('f_code', 'valid', 'exec_name', 'f_globals', 'have_locals', + # ('f_code', 'valid', 'f_executing', 'f_globals', 'have_locals', # 'f_locals', 'f_trace', 'f_lasti', 'f_lineno', # 'blockstack_as_tuple', 'localsplus_as_tuple') self.assertEqual(len(state), 11) diff --git a/Stackless/unittests/test_pickle.py b/Stackless/unittests/test_pickle.py index b47e56a5f66078..601d7ff55788ab 100644 --- a/Stackless/unittests/test_pickle.py +++ b/Stackless/unittests/test_pickle.py @@ -569,7 +569,7 @@ def f2(): # r is a tuple (frame_type, (f_code), (state)) # state is a tuple of the form - # ('f_code', 'valid', 'exec_name', 'f_globals', 'have_locals', + # ('f_code', 'valid', 'f_executing', 'f_globals', 'have_locals', # 'f_locals', 'f_trace', 'f_lasti', 'f_lineno', # 'blockstack_as_tuple', 'localsplus_as_tuple') return r