diff options
-rw-r--r-- | Doc/c-api/init.rst | 26 | ||||
-rw-r--r-- | Doc/whatsnew/3.9.rst | 4 | ||||
-rw-r--r-- | Include/cpython/ceval.h | 2 | ||||
-rw-r--r-- | Include/cpython/pystate.h | 10 | ||||
-rw-r--r-- | Include/internal/pycore_ceval.h | 2 | ||||
-rw-r--r-- | Include/internal/pycore_pystate.h | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst | 5 | ||||
-rw-r--r-- | Python/ceval.c | 15 | ||||
-rw-r--r-- | Python/pystate.c | 14 |
9 files changed, 67 insertions, 13 deletions
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index c34b117..badea5a 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1091,6 +1091,32 @@ 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. + + .. versionchanged:: 3.9 + The function now takes a *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.9 + +.. 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.9 + .. c:function:: PyObject* PyThreadState_GetDict() diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 1434a9e..0b61fb8 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -487,6 +487,10 @@ Build and C API Changes (Contributed by Victor Stinner in :issue:`38644` and :issue:`39542`.) +* ``PyInterpreterState.eval_frame`` (:pep:`523`) now requires a new mandatory + *tstate* parameter (``PyThreadState*``). + (Contributed by Victor Stinner in :issue:`38500`.) + Deprecated ========== diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index e601304..f03b53a 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -21,7 +21,7 @@ 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 d179257..fbb0899 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 70ce0ee..23d8091 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 b5f5095..0a83546 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); - #define _PY_NSMALLPOSINTS 257 #define _PY_NSMALLNEGINTS 5 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 0000000..f1ccfac --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst @@ -0,0 +1,5 @@ +Add a private API to get and set the frame evaluation function: add +:c:func:`_PyInterpreterState_GetEvalFrameFunc` and +:c:func:`_PyInterpreterState_SetEvalFrameFunc` C functions. +The :c:type:`_PyFrameEvalFunction` function type now takes a *tstate* +parameter. diff --git a/Python/ceval.c b/Python/ceval.c index 380212a..ccd1c06 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -725,9 +725,7 @@ PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) PyObject * PyEval_EvalFrame(PyFrameObject *f) { - /* This is for backward compatibility with extension modules that - used this API; core interpreter code should call - PyEval_EvalFrameEx() */ + /* Function kept for backward compatibility */ PyThreadState *tstate = _PyThreadState_GET(); return _PyEval_EvalFrame(tstate, f, 0); } @@ -740,8 +738,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } PyObject* _Py_HOT_FUNCTION -_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) +_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) { + ensure_tstate_not_null(__func__, tstate); + #ifdef DXPAIRS int lastopcode = 0; #endif @@ -756,9 +756,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) _Py_atomic_int * const eval_breaker = &ceval->eval_breaker; PyCodeObject *co; - PyThreadState * const tstate = _PyRuntimeState_GetThreadState(runtime); - ensure_tstate_not_null(__func__, tstate); - /* when tracing we set things up so that not (instr_lb <= current_bytecode_offset < instr_ub) @@ -1181,7 +1178,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) goto error; #ifdef Py_DEBUG - /* PyEval_EvalFrameEx() must not be called with an exception set, + /* _PyEval_EvalFrameDefault() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!_PyErr_Occurred(tstate)); @@ -3702,7 +3699,7 @@ exit_eval_frame: f->f_executing = 0; tstate->frame = f->f_back; - return _Py_CheckFunctionResult(tstate, NULL, retval, "PyEval_EvalFrameEx"); + return _Py_CheckFunctionResult(tstate, NULL, retval, __func__); } static void diff --git a/Python/pystate.c b/Python/pystate.c index 504f5f4..9cf6bea 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1722,6 +1722,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 |