bpo-38500: Add _PyInterpreterState_SetEvalFrameFunc() (GH-17340)
PyInterpreterState.eval_frame function now requires a tstate (Python thread state) parameter. Add private functions to the C API to get and set the frame evaluation function: * Add tstate parameter to _PyFrameEvalFunction function type. * Add _PyInterpreterState_GetEvalFrameFunc() and _PyInterpreterState_SetEvalFrameFunc() functions. * Add tstate parameter to _PyEval_EvalFrameDefault().
This commit is contained in:
parent
c846ef004d
commit
0b72b23fb0
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
==========
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -54,8 +54,6 @@ struct _ceval_runtime_state {
|
|||
|
||||
/* interpreter state */
|
||||
|
||||
typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int);
|
||||
|
||||
#define _PY_NSMALLPOSINTS 257
|
||||
#define _PY_NSMALLNEGINTS 5
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue