]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-38500: Add _PyInterpreterState_SetEvalFrameFunc() (GH-17340)
authorVictor Stinner <vstinner@python.org>
Thu, 12 Mar 2020 22:18:39 +0000 (23:18 +0100)
committerGitHub <noreply@github.com>
Thu, 12 Mar 2020 22:18:39 +0000 (23:18 +0100)
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().

Doc/c-api/init.rst
Doc/whatsnew/3.9.rst
Include/cpython/ceval.h
Include/cpython/pystate.h
Include/internal/pycore_ceval.h
Include/internal/pycore_pystate.h
Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst [new file with mode: 0644]
Python/ceval.c
Python/pystate.c

index c34b1174a5913d6493c5264280d9b35e6b15f1f6..badea5a01362a5e065124c0b56a9639c283407fd 100644 (file)
@@ -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()
 
index 1434a9e2143d639be40d3fc077e9a7bb88c8dadd..0b61fb8f0deb9562996b9a84cef9a491d7969828 100644 (file)
@@ -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
 ==========
index e601304589f7623880d59e8db198ea6bdcfda5a3..f03b53ade92983f23100adf2823632759d4c2610 100644 (file)
@@ -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);
index d1792575c9737899bfd6f4252c0a00a8ed9e590a..fbb0899186f6070a03ce7c190fcfddbb90b1730f 100644 (file)
@@ -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;
index 70ce0ee5f70d3412ad263f1175f6cc631b9f8dbf..23d80916fde389095d3213789e9d023512fffbf7 100644 (file)
@@ -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(
index b5f509547207dd8e3f9aecf5410750d467f58859..0a8354636255808c55faa86096c12a1267773ec4 100644 (file)
@@ -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 (file)
index 0000000..f1ccfac
--- /dev/null
@@ -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.
index 380212a71aaf75205adbec8b61ed49afc4172437..ccd1c06a39cfd9b124dfa969b271a336a4f07d76 100644 (file)
@@ -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
index 504f5f456dd2a5e01ab61b63551f04cbbb100639..9cf6bea1a027d1bad7c767eaf78813f491d263aa 100644 (file)
@@ -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