summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/frame.rst11
-rw-r--r--Doc/whatsnew/3.11.rst8
-rw-r--r--Include/cpython/frameobject.h1
-rw-r--r--Include/internal/pycore_frame.h1
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-03-22-15-12-28.bpo-42197.SwrrFO.rst2
-rw-r--r--Objects/frameobject.c23
-rw-r--r--Python/sysmodule.c10
7 files changed, 46 insertions, 10 deletions
diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst
index 0e36e6e..0c11bc1 100644
--- a/Doc/c-api/frame.rst
+++ b/Doc/c-api/frame.rst
@@ -41,6 +41,17 @@ See also :ref:`Reflection <reflection>`.
.. versionadded:: 3.9
+.. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame)
+
+ Get the *frame*'s ``f_locals`` attribute (:class:`dict`).
+
+ Return a :term:`strong reference`.
+
+ *frame* must not be ``NULL``.
+
+ .. versionadded:: 3.11
+
+
.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
Return the line number that *frame* is currently executing.
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index b2fdb48..8c120ec 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -969,7 +969,7 @@ Porting to Python 3.11
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` must use
:c:func:`PyFrame_GetLineNumber` instead.
* ``f_lineno``: use :c:func:`PyFrame_GetLineNumber`
- * ``f_locals``: use ``PyObject_GetAttrString((PyObject*)frame, "f_locals")``.
+ * ``f_locals``: use :c:func:`PyFrame_GetLocals`.
* ``f_stackdepth``: removed.
* ``f_state``: no public API (renamed to ``f_frame.f_state``).
* ``f_trace``: no public API.
@@ -983,6 +983,12 @@ Porting to Python 3.11
computed lazily. The :c:func:`PyFrame_GetBack` function must be called
instead.
+ Debuggers that accessed the ``f_locals`` directly *must* call
+ `:c:func:`PyFrame_GetLocals` instead. They no longer need to call
+ `:c:func:`PyFrame_FastToLocalsWithError` or :c:func:`PyFrame_LocalsToFast`,
+ in fact they should not call those functions. The necessary updating of the
+ frame is now managed by the virtual machine.
+
Code defining ``PyFrame_GetCode()`` on Python 3.8 and older::
#if PY_VERSION_HEX < 0x030900B1
diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index 9b697fb..d54d365 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -23,3 +23,4 @@ PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f);
PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
+PyAPI_FUNC(PyObject *) PyFrame_GetLocals(PyFrameObject *frame);
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index 14fba8c..211831a 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -15,6 +15,7 @@ struct _frame {
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_fast_as_locals; /* Have the fast locals of this frame been converted to a dict? */
/* The frame data, if this frame object owns the frame */
PyObject *_f_frame_data[1];
};
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-22-15-12-28.bpo-42197.SwrrFO.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-22-15-12-28.bpo-42197.SwrrFO.rst
new file mode 100644
index 0000000..d54002a
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-22-15-12-28.bpo-42197.SwrrFO.rst
@@ -0,0 +1,2 @@
+:c:func:`PyFrame_FastToLocalsWithError` and :c:func:`PyFrame_LocalsToFast` are no longer
+called during profiling nor tracing. C code can access the ``f_locals`` attribute of :c:type:`PyFrameObject` by calling :c:func:`PyFrame_GetLocals`.
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 5c6a8bc..13dfbf6 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -840,6 +840,7 @@ _PyFrame_New_NoTrack(PyCodeObject *code)
f->f_trace = NULL;
f->f_trace_lines = 1;
f->f_trace_opcodes = 0;
+ f->f_fast_as_locals = 0;
f->f_lineno = 0;
return f;
}
@@ -1004,7 +1005,11 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
PyErr_BadInternalCall();
return -1;
}
- return _PyFrame_FastToLocalsWithError(f->f_frame);
+ int err = _PyFrame_FastToLocalsWithError(f->f_frame);
+ if (err == 0) {
+ f->f_fast_as_locals = 1;
+ }
+ return err;
}
void
@@ -1028,8 +1033,9 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
PyObject *error_type, *error_value, *error_traceback;
PyCodeObject *co;
locals = frame->f_locals;
- if (locals == NULL)
+ if (locals == NULL) {
return;
+ }
fast = _PyFrame_GetLocalsArray(frame);
co = frame->f_code;
@@ -1088,13 +1094,12 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
void
PyFrame_LocalsToFast(PyFrameObject *f, int clear)
{
- if (f == NULL || _PyFrame_GetState(f) == FRAME_CLEARED) {
- return;
+ if (f && f->f_fast_as_locals && _PyFrame_GetState(f) != FRAME_CLEARED) {
+ _PyFrame_LocalsToFast(f->f_frame, clear);
+ f->f_fast_as_locals = 0;
}
- _PyFrame_LocalsToFast(f->f_frame, clear);
}
-
PyCodeObject *
PyFrame_GetCode(PyFrameObject *frame)
{
@@ -1119,6 +1124,12 @@ PyFrame_GetBack(PyFrameObject *frame)
}
PyObject*
+PyFrame_GetLocals(PyFrameObject *frame)
+{
+ return frame_getlocals(frame, NULL);
+}
+
+PyObject*
_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
{
PyObject *builtins = PyDict_GetItemWithError(globals, &_Py_ID(__builtins__));
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index c89f81f..6322af5 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -924,15 +924,19 @@ static PyObject *
call_trampoline(PyThreadState *tstate, PyObject* callback,
PyFrameObject *frame, int what, PyObject *arg)
{
- if (PyFrame_FastToLocalsWithError(frame) < 0) {
- return NULL;
- }
PyObject *stack[3];
stack[0] = (PyObject *)frame;
stack[1] = whatstrings[what];
stack[2] = (arg != NULL) ? arg : Py_None;
+ /* Discard any previous modifications the frame's fast locals */
+ if (frame->f_fast_as_locals) {
+ if (PyFrame_FastToLocalsWithError(frame) < 0) {
+ return NULL;
+ }
+ }
+
/* call the Python-level function */
PyObject *result = _PyObject_FastCallTstate(tstate, callback, stack, 3);