[Python-checkins] bpo-38500: Add _PyInterpreterState_SetEvalFrameFunc() (GH-17340)
Victor Stinner
webhook-mailer at python.org
Thu Mar 12 18:18:43 EDT 2020
https://github.com/python/cpython/commit/0b72b23fb0c130279f65f3bcd23521acf4a98c88
commit: 0b72b23fb0c130279f65f3bcd23521acf4a98c88
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-03-12T23:18:39+01:00
summary:
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().
files:
A Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst
M Doc/c-api/init.rst
M Doc/whatsnew/3.9.rst
M Include/cpython/ceval.h
M Include/cpython/pystate.h
M Include/internal/pycore_ceval.h
M Include/internal/pycore_pystate.h
M Python/ceval.c
M Python/pystate.c
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index c34b1174a5913..badea5a01362a 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 1434a9e2143d6..0b61fb8f0deb9 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 e601304589f76..f03b53ade9298 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 d1792575c9737..fbb0899186f60 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 70ce0ee5f70d3..23d80916fde38 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 b5f509547207d..0a83546362558 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 0000000000000..f1ccfacd2c8f9
--- /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 380212a71aaf7..ccd1c06a39cfd 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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
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 504f5f456dd2a..9cf6bea1a027d 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
More information about the Python-checkins
mailing list