From ed1e6d63b467b0ff201684903d3ada0a0436c1a0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 25 Feb 2022 12:53:19 +0100 Subject: [PATCH] bpo-46836: Move PyFrameObject to pycore_frame.h (GH-31530) Move the PyFrameObject type definition (struct _frame) to the internal C API pycore_frame.h header file. --- Doc/c-api/veryhigh.rst | 12 +++- Doc/whatsnew/3.11.rst | 68 +++++++++---------- Include/cpython/frameobject.h | 13 ---- Include/internal/pycore_frame.h | 12 ++++ .../2022-02-23-16-13-17.bpo-46836.ZYyPF_.rst | 2 + 5 files changed, 58 insertions(+), 49 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2022-02-23-16-13-17.bpo-46836.ZYyPF_.rst diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 5b8735de75e9d0..2f5720d493d798 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -288,8 +288,16 @@ the same library that the Python runtime is using. .. c:type:: PyFrameObject - The C structure of the objects used to describe frame objects. The - fields of this type are subject to change at any time. + The C structure of the objects used to describe frame objects. + + The structure is only part of the internal C API: fields should not be + access directly. Use getter functions like :c:func:`PyFrame_GetCode` and + :c:func:`PyFrame_GetBack`. + + Debuggers and profilers can use the limited C API to access this structure. + + .. versionchanged:: 3.11 + The structure moved to the internal C API headers. .. c:function:: PyObject* PyEval_EvalFrame(PyFrameObject *f) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 0556a44d4c7d4c..3f73bdfa3020f2 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -837,40 +837,40 @@ Porting to Python 3.11 which are not available in the limited C API. (Contributed by Victor Stinner in :issue:`46007`.) -* Changes of the private :c:type:`PyFrameObject` structure members. +* The :c:type:`PyFrameObject` structure member has been moved to the internal C + API headers. - While the documentation notes that the fields of ``PyFrameObject`` are - subject to change at any time, they have been stable for a long time - and were used in several popular extensions. - In Python 3.11, the frame struct was reorganized to allow performance - optimizations. Rather than reading the fields directly, extensions should - use functions: + While the documentation notes that the :c:type:`PyFrameObject` fields are + subject to change at any time, they have been stable for a long time and were + used in several popular extensions. - * ``f_code``: removed, use :c:func:`PyFrame_GetCode` instead. - Warning: the function returns a :term:`strong reference`, need to call - :c:func:`Py_DECREF`. - * ``f_back``: changed (see below), use :c:func:`PyFrame_GetBack`. - * ``f_builtins``: removed, - use ``PyObject_GetAttrString((PyObject*)frame, "f_builtins")``. - * ``f_globals``: removed, - use ``PyObject_GetAttrString((PyObject*)frame, "f_globals")``. - * ``f_locals``: removed, - use ``PyObject_GetAttrString((PyObject*)frame, "f_locals")``. - * ``f_lasti``: removed, - use ``PyObject_GetAttrString((PyObject*)frame, "f_lasti")``. - Code using ``f_lasti`` with ``PyCode_Addr2Line()`` should use + In Python 3.11, the frame struct was reorganized to allow performance + optimizations. Some fields were removed entirely, as they were details of the + old implementation. + + :c:type:`PyFrameObject` fields: + + * ``f_back``: use :c:func:`PyFrame_GetBack`. + * ``f_blockstack``: removed. + * ``f_builtins``: use ``PyObject_GetAttrString((PyObject*)frame, "f_builtins")``. + * ``f_code``: use :c:func:`PyFrame_GetCode`. + * ``f_gen``: removed. + * ``f_globals``: use ``PyObject_GetAttrString((PyObject*)frame, "f_globals")``. + * ``f_iblock``: removed. + * ``f_lasti``: use ``PyObject_GetAttrString((PyObject*)frame, "f_lasti")``. + Code using ``f_lasti`` with ``PyCode_Addr2Line()`` must use :c:func:`PyFrame_GetLineNumber` instead. - - The following fields were removed entirely, as they were details - of the old implementation: - - * ``f_valuesstack`` - * ``f_stackdepth`` - * ``f_gen`` - * ``f_iblock`` - * ``f_state`` - * ``f_blockstack`` - * ``f_localsplus`` + * ``f_lineno``: use :c:func:`PyFrame_GetLineNumber` + * ``f_locals``: use ``PyObject_GetAttrString((PyObject*)frame, "f_locals")``. + * ``f_stackdepth``: removed. + * ``f_state``: no public API (renamed to ``f_frame.f_state``). + * ``f_trace``: no public API. + * ``f_trace_lines``: use ``PyObject_GetAttrString((PyObject*)frame, "f_trace_lines")`` + (it also be modified). + * ``f_trace_opcodes``: use ``PyObject_GetAttrString((PyObject*)frame, "f_trace_opcodes")`` + (it also be modified). + * ``f_localsplus``: no public API (renamed to ``f_frame.localsplus``). + * ``f_valuestack``: removed. The Python frame object is now created lazily. A side effect is that the ``f_back`` member must not be accessed directly, since its value is now also @@ -897,9 +897,9 @@ Porting to Python 3.11 } #endif - Or use `the pythoncapi_compat project - `__ to get these APIs - on older Python versions. + Or use the `pythoncapi_compat project + `__ to get these two + functions on older Python versions. * Changes of the :c:type:`PyThreadState` structure members: diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index 3d862d9deb000f..e69209686bee02 100644 --- a/Include/cpython/frameobject.h +++ b/Include/cpython/frameobject.h @@ -4,19 +4,6 @@ # error "this header file must not be included directly" #endif -struct _frame { - PyObject_HEAD - PyFrameObject *f_back; /* previous frame, or NULL */ - struct _interpreter_frame *f_frame; /* points to the frame data */ - PyObject *f_trace; /* Trace function */ - int f_lineno; /* Current line number. Only valid if non-zero */ - char f_trace_lines; /* Emit per-line trace events? */ - char f_trace_opcodes; /* Emit per-opcode trace events? */ - char f_owns_frame; /* This frame owns the frame */ - /* The frame data, if this frame object owns the frame */ - PyObject *_f_frame_data[1]; -}; - /* Standard object interface */ PyAPI_DATA(PyTypeObject) PyFrame_Type; diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 1ad156290a55e9..09d41222b61fc9 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -6,6 +6,18 @@ extern "C" { #include +struct _frame { + PyObject_HEAD + PyFrameObject *f_back; /* previous frame, or NULL */ + struct _interpreter_frame *f_frame; /* points to the frame data */ + PyObject *f_trace; /* Trace function */ + int f_lineno; /* Current line number. Only valid if non-zero */ + char f_trace_lines; /* Emit per-line trace events? */ + char f_trace_opcodes; /* Emit per-opcode trace events? */ + char f_owns_frame; /* This frame owns the frame */ + /* The frame data, if this frame object owns the frame */ + PyObject *_f_frame_data[1]; +}; /* runtime lifecycle */ diff --git a/Misc/NEWS.d/next/C API/2022-02-23-16-13-17.bpo-46836.ZYyPF_.rst b/Misc/NEWS.d/next/C API/2022-02-23-16-13-17.bpo-46836.ZYyPF_.rst new file mode 100644 index 00000000000000..2867bfd518c332 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-02-23-16-13-17.bpo-46836.ZYyPF_.rst @@ -0,0 +1,2 @@ +Move the :c:type:`PyFrameObject` type definition (``struct _frame``) to the +internal C API ``pycore_frame.h`` header file. Patch by Victor Stinner.