diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 86bf7f9eec65e7..f7297999c08204 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1083,6 +1083,35 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.8 +.. c:type:: PyObject* (*PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *frame, int throwflag) + + Type of a frame evaluation function. + + The *throwflag* parameter is used by the ``throw()`` method of generators: + if non-zero, handle the current exception. + + .. versionadded:: 3.8.1 + + .. versionchanged:: 3.8.1 + Add *tstate* parameter. + + +.. c:function:: PyFrameEvalFunction PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) + + Get the frame evaluation function. + + See the :pep:`523` "Adding a frame evaluation API to CPython". + + .. versionadded:: 3.8.1 + +.. c:function:: void PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, PyFrameEvalFunction eval_frame); + + Set the frame evaluation function. + + See the :pep:`523` "Adding a frame evaluation API to CPython". + + .. versionadded:: 3.8.1 + .. c:function:: PyObject* PyThreadState_GetDict() diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index a3ad98d020642e..3c49082c11f312 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -239,6 +239,10 @@ Build and C API Changes removed in Python 3.3. (Contributed by Victor Stinner in :issue:`38896`.) +* ``PyInterpreterState.eval_frame`` (:pep:`523`) now requires a new mandatory + *tstate* parameter (``PyThreadState*``). + (Contributed by Victor Stinner in :issue:`38818`.) + Deprecated ========== diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index e601304589f762..0a88d479a317cf 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -21,7 +21,10 @@ PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *); flag was set, else return 0. */ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); -PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(struct _frame *f, int exc); +PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault( + PyThreadState *tstate, + struct _frame *f, + int exc); PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index d1792575c97378..569e715b6c2f0b 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -186,6 +186,16 @@ PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); +/* Frame evaluation API */ + +typedef PyObject* (*PyFrameEvalFunction)(PyThreadState *tstate, struct _frame *, int); + +PyAPI_FUNC(PyFrameEvalFunction) PyInterpreterState_GetEvalFrameFunc( + PyInterpreterState *interp); +PyAPI_FUNC(void) PyInterpreterState_SetEvalFrameFunc( + PyInterpreterState *interp, + PyFrameEvalFunction eval_frame); + /* cross-interpreter data */ struct _xid; diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 857fc0b2524fe8..26abb61aad0053 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -40,7 +40,7 @@ void _PyEval_Fini(void); static inline PyObject* _PyEval_EvalFrame(PyThreadState *tstate, struct _frame *f, int throwflag) { - return tstate->interp->eval_frame(f, throwflag); + return tstate->interp->eval_frame(tstate, f, throwflag); } extern PyObject *_PyEval_EvalCode( diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index aa2103f07c795b..3c21f58c9ccf65 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -54,8 +54,6 @@ struct _ceval_runtime_state { /* interpreter state */ -typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int); - // The PyInterpreterState typedef is in Include/pystate.h. struct _is { @@ -113,7 +111,7 @@ struct _is { PyObject *builtins_copy; PyObject *import_func; /* Initialized to PyEval_EvalFrameDefault(). */ - _PyFrameEvalFunction eval_frame; + PyFrameEvalFunction eval_frame; Py_ssize_t co_extra_user_count; freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS]; diff --git a/Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst b/Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst new file mode 100644 index 00000000000000..a5b1ef47f8b61f --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst @@ -0,0 +1,2 @@ +``PyInterpreterState.eval_frame`` (:pep:`523`) now requires a new mandatory +*tstate* parameter (``PyThreadState*``). diff --git a/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst new file mode 100644 index 00000000000000..3cca07aaba00bb --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst @@ -0,0 +1,3 @@ +Add a public API to get and set the frame evaluation function: add +:c:func:`PyInterpreterState_GetEvalFrameFunc` and +:c:func:`PyInterpreterState_SetEvalFrameFunc` C functions diff --git a/Python/ceval.c b/Python/ceval.c index 96ed329b0d9952..237dbd4681e144 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -743,7 +743,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } PyObject* _Py_HOT_FUNCTION -_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) +_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) { #ifdef DXPAIRS int lastopcode = 0; @@ -755,7 +755,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject **fastlocals, **freevars; PyObject *retval = NULL; /* Return value */ _PyRuntimeState * const runtime = &_PyRuntime; - PyThreadState * const tstate = _PyRuntimeState_GetThreadState(runtime); struct _ceval_runtime_state * const ceval = &runtime->ceval; _Py_atomic_int * const eval_breaker = &ceval->eval_breaker; PyCodeObject *co; diff --git a/Python/pystate.c b/Python/pystate.c index d792380de46498..067de50151a49f 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1721,6 +1721,20 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) } +PyFrameEvalFunction +PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) +{ + return interp->eval_frame; +} + + +void +PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, + PyFrameEvalFunction eval_frame) +{ + interp->eval_frame = eval_frame; +} + #ifdef __cplusplus } #endif