Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-46836: Move PyFrameObject to pycore_frame.h #31530

Merged
merged 1 commit into from
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Doc/c-api/veryhigh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
68 changes: 34 additions & 34 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -832,40 +832,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
Expand All @@ -892,9 +892,9 @@ Porting to Python 3.11
}
#endif

Or use `the pythoncapi_compat project
<https://github.com/pythoncapi/pythoncapi_compat>`__ to get these APIs
on older Python versions.
Or use the `pythoncapi_compat project
<https://github.com/pythoncapi/pythoncapi_compat>`__ to get these two
functions on older Python versions.

* Changes of the :c:type:`PyThreadState` structure members:

Expand Down
13 changes: 0 additions & 13 deletions Include/cpython/frameobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ extern "C" {

#include <stdbool.h>

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 */

Expand Down
Original file line number Diff line number Diff line change
@@ -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.