Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Stackless issue #270: Remove field PyFrameObject.f_execute #271

Merged
merged 4 commits into from
Jun 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions Include/cpython/slp_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
29 changes: 0 additions & 29 deletions Include/frameobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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) */
Expand All @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions Include/internal/pycore_slp_prickelpit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); \
}
Expand Down
66 changes: 51 additions & 15 deletions Include/internal/pycore_stackless.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extern "C" {

#ifdef SLP_BUILD_CORE

#include "frameobject.h"
#ifdef Py_BUILD_CORE
#include "pycore_pystate.h" /* for _PyRuntime */
#endif
Expand All @@ -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

/*
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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) \
Expand All @@ -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 */
Expand Down
1 change: 0 additions & 1 deletion Objects/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 0 additions & 3 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
8 changes: 3 additions & 5 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading