]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40421: Add pyframe.h header file (GH-19755)
authorVictor Stinner <vstinner@python.org>
Tue, 28 Apr 2020 14:32:48 +0000 (16:32 +0200)
committerGitHub <noreply@github.com>
Tue, 28 Apr 2020 14:32:48 +0000 (16:32 +0200)
Add a new separated pyframe.h header file of the PyFrame public C
API: it is included by Python.h.

Add PyFrame_GetLineNumber() to the limited C API.

Replace "struct _frame" with "PyFrameObject" in header files.
PyFrameObject is now defined as struct _frame by pyframe.h which is
included early enough in Python.h.

19 files changed:
Doc/c-api/reflection.rst
Doc/whatsnew/3.9.rst
Include/Python.h
Include/ceval.h
Include/cpython/ceval.h
Include/cpython/frameobject.h
Include/cpython/pystate.h
Include/cpython/traceback.h
Include/frameobject.h
Include/genobject.h
Include/internal/pycore_ceval.h
Include/internal/pycore_traceback.h
Include/pyframe.h [new file with mode: 0644]
Include/pystate.h
Include/traceback.h
Makefile.pre.in
Objects/frameobject.c
PCbuild/pythoncore.vcxproj
PCbuild/pythoncore.vcxproj.filters

index 4d3d25e6621b21fa06bd550b5a2c6904c32cfabd..498219fd9aa84372755d2925b5fbee8977d2d977 100644 (file)
@@ -35,6 +35,8 @@ Reflection
 
    Return the line number that *frame* is currently executing.
 
+   *frame* must not be ``NULL``.
+
 
 .. c:function:: const char* PyEval_GetFuncName(PyObject *func)
 
index 13cd09b0b8be5aa8df5ca2eebbcb5e1cdd48315d..8b8aa9a514c6820a0c90ab145661dd13ce65972a 100644 (file)
@@ -537,6 +537,9 @@ Optimizations
 Build and C API Changes
 =======================
 
+* Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
+  (Contributed by Victor Stinner in :issue:`40421`.)
+
 * New :c:func:`PyThreadState_GetInterpreter` and
   :c:func:`PyInterpreterState_Get` functions to get the interpreter.
   New :c:func:`PyThreadState_GetFrame` function to get the current frame of a
index 7fdb9df7065de1fa0f8979194b5f78241d0a7e2a..868e31bfa4e38381736d4886b55405d06a217bef 100644 (file)
 #include "classobject.h"
 #include "fileobject.h"
 #include "pycapsule.h"
+#include "pyframe.h"
 #include "traceback.h"
 #include "sliceobject.h"
 #include "cellobject.h"
index a70c421c18d02dc391886743d48cab725182bd37..df5253900eea71af789d7d40354e0df3d6c1933d 100644 (file)
@@ -28,12 +28,10 @@ Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallFunction(
 Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyEval_CallMethod(
     PyObject *obj, const char *name, const char *format, ...);
 
-struct _frame; /* Avoid including frameobject.h */
-
 PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void);
 PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void);
 PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
-PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void);
+PyAPI_FUNC(PyFrameObject *) PyEval_GetFrame(void);
 
 PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg);
 PyAPI_FUNC(int) Py_MakePendingCalls(void);
@@ -80,8 +78,8 @@ PyAPI_FUNC(void) Py_LeaveRecursiveCall(void);
 PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *);
 PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *);
 
-PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *);
-PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc);
+PyAPI_FUNC(PyObject *) PyEval_EvalFrame(PyFrameObject *);
+PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(PyFrameObject *f, int exc);
 
 /* Interface for threads.
 
index 020f78712ff50f1cbeff16ed5e1e012db52a13f2..e1922a677bd38c0563cc491c4e2969fdd872f812 100644 (file)
@@ -23,7 +23,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(PyThreadState *tstate, struct _frame *f, int exc);
+PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int exc);
 
 PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
 PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);
index 4ced96746aa39b0e79184ce4d1495a4bde96e329..e819cefd13cbeb18972f6df595cef4deea21347d 100644 (file)
@@ -14,7 +14,7 @@ typedef struct {
     int b_level;                /* value stack level to pop to */
 } PyTryBlock;
 
-typedef struct _frame {
+struct _frame {
     PyObject_VAR_HEAD
     struct _frame *f_back;      /* previous frame, or NULL */
     PyCodeObject *f_code;       /* code segment */
@@ -44,7 +44,7 @@ typedef struct _frame {
     char f_executing;           /* whether the frame is still executing */
     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
     PyObject *f_localsplus[1];  /* locals+stack, dynamically sized */
-} PyFrameObject;
+};
 
 
 /* Standard object interface */
@@ -79,9 +79,6 @@ PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
 
 PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
 
-/* Return the line of code the frame is currently executing. */
-PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
-
 #ifdef __cplusplus
 }
 #endif
index 9b28f66fdba582363e497fb3b0e6a3f4c136429c..f292da1d3c6c5ee48ceaad0639b9cb42d4414d9f 100644 (file)
@@ -16,7 +16,7 @@ PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *);
 /* State unique per thread */
 
 /* Py_tracefunc return -1 when raising an exception, or 0 for success. */
-typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *);
+typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
 
 /* The following values are used for 'what' for tracefunc functions
  *
@@ -56,7 +56,7 @@ struct _ts {
     PyInterpreterState *interp;
 
     /* Borrowed reference to the current frame (it can be NULL) */
-    struct _frame *frame;
+    PyFrameObject *frame;
     int recursion_depth;
     char overflowed; /* The stack has overflowed. Allow 50 more calls
                         to handle the runtime error. */
@@ -184,7 +184,7 @@ PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void);
 
 /* Frame evaluation API */
 
-typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, struct _frame *, int);
+typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *, int);
 
 PyAPI_FUNC(_PyFrameEvalFunction) _PyInterpreterState_GetEvalFrameFunc(
     PyInterpreterState *interp);
index 746097daaf9400cfb783eba79d73d70d32217c69..837470c3ba2bca9491901e7d8cf14557fde27130 100644 (file)
@@ -9,7 +9,7 @@ extern "C" {
 typedef struct _traceback {
     PyObject_HEAD
     struct _traceback *tb_next;
-    struct _frame *tb_frame;
+    PyFrameObject *tb_frame;
     int tb_lasti;
     int tb_lineno;
 } PyTracebackObject;
index 1460e2210e3173dfed15252a243a1463bba2da7e..c118af1201a4c854ab899e17ca9148ae21a72991 100644 (file)
@@ -6,9 +6,7 @@
 extern "C" {
 #endif
 
-/* There are currently no frame related APIs in the stable ABI
- * (they're all in the full CPython-specific API)
- */
+#include "pyframe.h"
 
 #ifndef Py_LIMITED_API
 #  define Py_CPYTHON_FRAMEOBJECT_H
index b87a6485631c0140e655bb7d1e22a3ab71ba8766..a7393a9a8359232a76883232946f3dedc03276b0 100644 (file)
@@ -10,14 +10,12 @@ extern "C" {
 
 #include "pystate.h"   /* _PyErr_StackItem */
 
-struct _frame; /* Avoid including frameobject.h */
-
 /* _PyGenObject_HEAD defines the initial segment of generator
    and coroutine objects. */
 #define _PyGenObject_HEAD(prefix)                                           \
     PyObject_HEAD                                                           \
     /* Note: gi_frame can be NULL if the generator is "finished" */         \
-    struct _frame *prefix##_frame;                                          \
+    PyFrameObject *prefix##_frame;                                          \
     /* True if generator is being executed. */                              \
     char prefix##_running;                                                  \
     /* The code object backing the generator */                             \
@@ -40,8 +38,8 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
 #define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type)
 #define PyGen_CheckExact(op) Py_IS_TYPE(op, &PyGen_Type)
 
-PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *);
-PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(struct _frame *,
+PyAPI_FUNC(PyObject *) PyGen_New(PyFrameObject *);
+PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(PyFrameObject *,
     PyObject *name, PyObject *qualname);
 PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *);
 PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **);
@@ -60,7 +58,7 @@ PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type;
 
 #define PyCoro_CheckExact(op) Py_IS_TYPE(op, &PyCoro_Type)
 PyObject *_PyCoro_GetAwaitableIter(PyObject *o);
-PyAPI_FUNC(PyObject *) PyCoro_New(struct _frame *,
+PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *,
     PyObject *name, PyObject *qualname);
 
 /* Asynchronous Generators */
@@ -86,7 +84,7 @@ PyAPI_DATA(PyTypeObject) _PyAsyncGenASend_Type;
 PyAPI_DATA(PyTypeObject) _PyAsyncGenWrappedValue_Type;
 PyAPI_DATA(PyTypeObject) _PyAsyncGenAThrow_Type;
 
-PyAPI_FUNC(PyObject *) PyAsyncGen_New(struct _frame *,
+PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *,
     PyObject *name, PyObject *qualname);
 
 #define PyAsyncGen_CheckExact(op) Py_IS_TYPE(op, &PyAsyncGen_Type)
index 050dd59ed15f0be7b487b509ec24ce765beed495..2df796deade3a9602598327836340369ebbfab29 100644 (file)
@@ -11,7 +11,6 @@ extern "C" {
 /* Forward declarations */
 struct pyruntimestate;
 struct _ceval_runtime_state;
-struct _frame;
 
 #include "pycore_interp.h"   /* PyInterpreterState.eval_frame */
 
@@ -36,7 +35,7 @@ PyAPI_FUNC(void) _PyEval_SetCoroutineOriginTrackingDepth(
 void _PyEval_Fini(void);
 
 static inline PyObject*
-_PyEval_EvalFrame(PyThreadState *tstate, struct _frame *f, int throwflag)
+_PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
 {
     return tstate->interp->eval_frame(tstate, f, throwflag);
 }
index 99443d7ba2706fb9c2aad3d9907c1e2afb61b0b2..1f092411a72ba5c975d11a00cdd9e81ab5ab2f77 100644 (file)
@@ -89,7 +89,7 @@ PyAPI_FUNC(void) _Py_DumpHexadecimal(
 
 PyAPI_FUNC(PyObject*) _PyTraceBack_FromFrame(
     PyObject *tb_next,
-    struct _frame *frame);
+    PyFrameObject *frame);
 
 #ifdef __cplusplus
 }
diff --git a/Include/pyframe.h b/Include/pyframe.h
new file mode 100644 (file)
index 0000000..d3404cd
--- /dev/null
@@ -0,0 +1,20 @@
+/* Limited C API of PyFrame API
+ *
+ * Include "frameobject.h" to get the PyFrameObject structure.
+ */
+
+#ifndef Py_PYFRAME_H
+#define Py_PYFRAME_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _frame PyFrameObject;
+
+/* Return the line of code the frame is currently executing. */
+PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_PYFRAME_H */
index 65b0a24e87f86b5fdf38bbd0c3b461b0c816387a..34cad02c3a930d9a75a4738a91474fcbc0e5960e 100644 (file)
@@ -13,7 +13,6 @@ removed (with effort). */
 
 /* Forward declarations for PyFrameObject, PyThreadState
    and PyInterpreterState */
-struct _frame;
 struct _ts;
 struct _is;
 
@@ -88,7 +87,7 @@ PyAPI_FUNC(int) PyThreadState_SetAsyncExc(unsigned long, PyObject *);
 #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
 /* New in 3.9 */
 PyAPI_FUNC(PyInterpreterState*) PyThreadState_GetInterpreter(PyThreadState *tstate);
-PyAPI_FUNC(struct _frame*) PyThreadState_GetFrame(PyThreadState *tstate);
+PyAPI_FUNC(PyFrameObject*) PyThreadState_GetFrame(PyThreadState *tstate);
 PyAPI_FUNC(uint64_t) PyThreadState_GetID(PyThreadState *tstate);
 #endif
 
index 0efbae8a76a2f2983967a8b57c25c0045f6018eb..781e5a6eec4edd4c199079aa9f25d8c05082b3f2 100644 (file)
@@ -4,11 +4,9 @@
 extern "C" {
 #endif
 
-struct _frame;
-
 /* Traceback interface */
 
-PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
+PyAPI_FUNC(int) PyTraceBack_Here(PyFrameObject *);
 PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
 
 /* Reveal traceback type so we can typecheck traceback objects */
index 200fd319ebb0663bf258dff422674e85288bb8f9..5db381f90f98c761d32b22257f4075400a1e3c82 100644 (file)
@@ -1047,6 +1047,7 @@ PYTHON_HEADERS= \
                $(srcdir)/Include/pydtrace.h \
                $(srcdir)/Include/pyerrors.h \
                $(srcdir)/Include/pyfpe.h \
+               $(srcdir)/Include/pyframe.h \
                $(srcdir)/Include/pyhash.h \
                $(srcdir)/Include/pylifecycle.h \
                $(srcdir)/Include/pymacconfig.h \
index bdd7862b3c9d2a6fcce1d9e5351db562496d8598..d0a15e77512c67271c70b7bdcf8566b25284a806 100644 (file)
@@ -34,10 +34,13 @@ frame_getlocals(PyFrameObject *f, void *closure)
 int
 PyFrame_GetLineNumber(PyFrameObject *f)
 {
-    if (f->f_trace)
+    assert(f != NULL);
+    if (f->f_trace) {
         return f->f_lineno;
-    else
+    }
+    else {
         return PyCode_Addr2Line(f->f_code, f->f_lasti);
+    }
 }
 
 static PyObject *
index d20e749b051a58311e565265b533d7892af253a8..f54f155413038294f42ba430f2fe9d8b4e350a0b 100644 (file)
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\Include\Python-ast.h" />
+    <ClInclude Include="..\Include\Python.h" />
     <ClInclude Include="..\Include\abstract.h" />
     <ClInclude Include="..\Include\asdl.h" />
     <ClInclude Include="..\Include\ast.h" />
     <ClInclude Include="..\Include\internal\pycore_abstract.h" />
     <ClInclude Include="..\Include\internal\pycore_accu.h" />
     <ClInclude Include="..\Include\internal\pycore_atomic.h" />
-    <ClInclude Include="..\Include\internal\pycore_byteswap.h" />
     <ClInclude Include="..\Include\internal\pycore_bytes_methods.h" />
+    <ClInclude Include="..\Include\internal\pycore_byteswap.h" />
     <ClInclude Include="..\Include\internal\pycore_call.h" />
     <ClInclude Include="..\Include\internal\pycore_ceval.h" />
     <ClInclude Include="..\Include\internal\pycore_code.h" />
     <ClInclude Include="..\Include\parsetok.h" />
     <ClInclude Include="..\Include\patchlevel.h" />
     <ClInclude Include="..\Include\picklebufobject.h" />
-    <ClInclude Include="..\Include\pyhash.h" />
     <ClInclude Include="..\Include\py_curses.h" />
     <ClInclude Include="..\Include\pyarena.h" />
     <ClInclude Include="..\Include\pycapsule.h" />
     <ClInclude Include="..\Include\pyerrors.h" />
     <ClInclude Include="..\Include\pyexpat.h" />
     <ClInclude Include="..\Include\pyfpe.h" />
+    <ClInclude Include="..\Include\pyframe.h" />
+    <ClInclude Include="..\Include\pyhash.h" />
     <ClInclude Include="..\Include\pylifecycle.h" />
-    <ClInclude Include="..\Include\pymath.h" />
-    <ClInclude Include="..\Include\pytime.h" />
     <ClInclude Include="..\Include\pymacro.h" />
+    <ClInclude Include="..\Include\pymath.h" />
     <ClInclude Include="..\Include\pymem.h" />
     <ClInclude Include="..\Include\pyport.h" />
     <ClInclude Include="..\Include\pystate.h" />
     <ClInclude Include="..\Include\pystrcmp.h" />
-    <ClInclude Include="..\Include\pystrtod.h" />
     <ClInclude Include="..\Include\pystrhex.h" />
-    <ClInclude Include="..\Include\Python-ast.h" />
-    <ClInclude Include="..\Include\Python.h" />
+    <ClInclude Include="..\Include\pystrtod.h" />
     <ClInclude Include="..\Include\pythonrun.h" />
     <ClInclude Include="..\Include\pythread.h" />
+    <ClInclude Include="..\Include\pytime.h" />
     <ClInclude Include="..\Include\rangeobject.h" />
     <ClInclude Include="..\Include\setobject.h" />
     <ClInclude Include="..\Include\sliceobject.h" />
index 8c02622fd552d6fd29d349841207539e545eac46..c8758dab3b348e3836f516e7615491a497d33271 100644 (file)
     <ClInclude Include="..\Include\internal\pycore_pyerrors.h">
       <Filter>Include</Filter>
     </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_pyframe.h">
+      <Filter>Include</Filter>
+    </ClInclude>
     <ClInclude Include="..\Include\internal\pycore_pyhash.h">
       <Filter>Include</Filter>
     </ClInclude>