Skip to content

Commit a42ca74

Browse files
authored
bpo-40421: Add PyFrame_GetCode() function (GH-19757)
PyFrame_GetCode(frame): return a borrowed reference to the frame code. Replace frame->f_code with PyFrame_GetCode(frame) in most code, except in frameobject.c, genobject.c and ceval.c. Also add PyFrame_GetLineNumber() to the limited C API.
1 parent b8f704d commit a42ca74

File tree

12 files changed

+58
-25
lines changed

12 files changed

+58
-25
lines changed

‎Doc/c-api/init.rst‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,8 +1074,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
10741074

10751075
.. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
10761076

1077-
Get the current frame of the Python thread state *tstate*. It can be
1078-
``NULL`` if no frame is currently executing.
1077+
Get a borrowed reference to the current frame of the Python thread state
1078+
*tstate*.
1079+
1080+
Return ``NULL`` if no frame is currently executing.
10791081

10801082
See also :c:func:`PyEval_GetFrame`.
10811083

‎Doc/c-api/reflection.rst‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ Reflection
3131
See also :c:func:`PyThreadState_GetFrame`.
3232

3333

34+
.. c:function:: int PyFrame_GetCode(PyFrameObject *frame)
35+
36+
Return a borrowed reference to the *frame* code.
37+
38+
*frame* must not be ``NULL``.
39+
40+
.. versionadded:: 3.9
41+
42+
3443
.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
3544

3645
Return the line number that *frame* is currently executing.

‎Doc/whatsnew/3.9.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,10 @@ Optimizations
537537
Build and C API Changes
538538
=======================
539539

540+
* New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
541+
frame code.
542+
(Contributed by Victor Stinner in :issue:`40421`.)
543+
540544
* Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
541545
(Contributed by Victor Stinner in :issue:`40421`.)
542546

‎Include/pyframe.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ typedef struct _frame PyFrameObject;
1414
/* Return the line of code the frame is currently executing. */
1515
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
1616

17+
PyAPI_FUNC(PyCodeObject *) PyFrame_GetCode(PyFrameObject *frame);
18+
1719
#ifdef __cplusplus
1820
}
1921
#endif
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
2+
frame code.

‎Modules/_lsprof.c‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "Python.h"
2-
#include "frameobject.h"
32
#include "rotatingtree.h"
43

54
/************************************************************/
@@ -388,14 +387,16 @@ profiler_callback(PyObject *self, PyFrameObject *frame, int what,
388387

389388
/* the 'frame' of a called function is about to start its execution */
390389
case PyTrace_CALL:
391-
ptrace_enter_call(self, (void *)frame->f_code,
392-
(PyObject *)frame->f_code);
390+
{
391+
PyCodeObject *code = PyFrame_GetCode(frame);
392+
ptrace_enter_call(self, (void *)code, (PyObject *)code);
393393
break;
394+
}
394395

395396
/* the 'frame' of a called function is about to finish
396397
(either normally or with an exception) */
397398
case PyTrace_RETURN:
398-
ptrace_leave_call(self, (void *)frame->f_code);
399+
ptrace_leave_call(self, (void *)PyFrame_GetCode(frame));
399400
break;
400401

401402
/* case PyTrace_EXCEPTION:

‎Modules/_tracemalloc.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
346346
lineno = 0;
347347
frame->lineno = (unsigned int)lineno;
348348

349-
code = pyframe->f_code;
349+
code = PyFrame_GetCode(pyframe);
350350
if (code == NULL) {
351351
#ifdef TRACE_DEBUG
352352
tracemalloc_error("failed to get the code object of the frame");

‎Objects/frameobject.c‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,3 +1222,10 @@ _PyFrame_DebugMallocStats(FILE *out)
12221222
numfree, sizeof(PyFrameObject));
12231223
}
12241224

1225+
1226+
PyCodeObject *
1227+
PyFrame_GetCode(PyFrameObject *frame)
1228+
{
1229+
assert(frame != NULL);
1230+
return frame->f_code;
1231+
}

‎Objects/typeobject.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8033,13 +8033,13 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
80338033
PyFrameObject *f;
80348034
PyCodeObject *co;
80358035
Py_ssize_t i, n;
8036-
f = _PyThreadState_GET()->frame;
8036+
f = PyThreadState_GetFrame(_PyThreadState_GET());
80378037
if (f == NULL) {
80388038
PyErr_SetString(PyExc_RuntimeError,
80398039
"super(): no current frame");
80408040
return -1;
80418041
}
8042-
co = f->f_code;
8042+
co = PyFrame_GetCode(f);
80438043
if (co == NULL) {
80448044
PyErr_SetString(PyExc_RuntimeError,
80458045
"super(): no code object");

‎Python/_warnings.c‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,6 @@ is_internal_frame(PyFrameObject *frame)
762762
{
763763
static PyObject *importlib_string = NULL;
764764
static PyObject *bootstrap_string = NULL;
765-
PyObject *filename;
766765
int contains;
767766

768767
if (importlib_string == NULL) {
@@ -780,14 +779,23 @@ is_internal_frame(PyFrameObject *frame)
780779
Py_INCREF(bootstrap_string);
781780
}
782781

783-
if (frame == NULL || frame->f_code == NULL ||
784-
frame->f_code->co_filename == NULL) {
782+
if (frame == NULL) {
783+
return 0;
784+
}
785+
786+
PyCodeObject *code = PyFrame_GetCode(frame);
787+
if (code == NULL) {
788+
return 0;
789+
}
790+
791+
PyObject *filename = code->co_filename;
792+
if (filename == NULL) {
785793
return 0;
786794
}
787-
filename = frame->f_code->co_filename;
788795
if (!PyUnicode_Check(filename)) {
789796
return 0;
790797
}
798+
791799
contains = PyUnicode_Contains(filename, importlib_string);
792800
if (contains < 0) {
793801
return 0;
@@ -846,7 +854,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
846854
}
847855
else {
848856
globals = f->f_globals;
849-
*filename = f->f_code->co_filename;
857+
*filename = PyFrame_GetCode(f)->co_filename;
850858
Py_INCREF(*filename);
851859
*lineno = PyFrame_GetLineNumber(f);
852860
}

0 commit comments

Comments
 (0)