[Python-checkins] bpo-40421: Add PyFrame_GetCode() function (GH-19757)

Victor Stinner webhook-mailer at python.org
Tue Apr 28 13:01:40 EDT 2020


https://github.com/python/cpython/commit/a42ca74fa30227e2f89a619332557cf093a937d5
commit: a42ca74fa30227e2f89a619332557cf093a937d5
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-28T19:01:31+02:00
summary:

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.

files:
A Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst
M Doc/c-api/init.rst
M Doc/c-api/reflection.rst
M Doc/whatsnew/3.9.rst
M Include/pyframe.h
M Modules/_lsprof.c
M Modules/_tracemalloc.c
M Objects/frameobject.c
M Objects/typeobject.c
M Python/_warnings.c
M Python/import.c
M Python/traceback.c

diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 435808f537b88..afde3db30385b 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -1074,8 +1074,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
 
 .. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
 
-   Get the current frame of the Python thread state *tstate*. It can be
-   ``NULL`` if no frame is currently executing.
+   Get a borrowed reference to the current frame of the Python thread state
+   *tstate*.
+
+   Return ``NULL`` if no frame is currently executing.
 
    See also :c:func:`PyEval_GetFrame`.
 
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 498219fd9aa84..b313ea302598e 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -31,6 +31,15 @@ Reflection
    See also :c:func:`PyThreadState_GetFrame`.
 
 
+.. c:function:: int PyFrame_GetCode(PyFrameObject *frame)
+
+   Return a borrowed reference to the *frame* code.
+
+   *frame* must not be ``NULL``.
+
+   .. versionadded:: 3.9
+
+
 .. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
 
    Return the line number that *frame* is currently executing.
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index 8b8aa9a514c68..e3751fa168011 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -537,6 +537,10 @@ Optimizations
 Build and C API Changes
 =======================
 
+* New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
+  frame code.
+  (Contributed by Victor Stinner in :issue:`40421`.)
+
 * Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
   (Contributed by Victor Stinner in :issue:`40421`.)
 
diff --git a/Include/pyframe.h b/Include/pyframe.h
index d3404cde4a1fb..3816224201c7e 100644
--- a/Include/pyframe.h
+++ b/Include/pyframe.h
@@ -14,6 +14,8 @@ typedef struct _frame PyFrameObject;
 /* Return the line of code the frame is currently executing. */
 PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
 
+PyAPI_FUNC(PyCodeObject *) PyFrame_GetCode(PyFrameObject *frame);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst b/Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst
new file mode 100644
index 0000000000000..11cf87872d513
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst	
@@ -0,0 +1,2 @@
+New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
+frame code.
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index 7115fee1f2eb1..39cf6e126d635 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -1,5 +1,4 @@
 #include "Python.h"
-#include "frameobject.h"
 #include "rotatingtree.h"
 
 /************************************************************/
@@ -388,14 +387,16 @@ profiler_callback(PyObject *self, PyFrameObject *frame, int what,
 
     /* the 'frame' of a called function is about to start its execution */
     case PyTrace_CALL:
-        ptrace_enter_call(self, (void *)frame->f_code,
-                                (PyObject *)frame->f_code);
+    {
+        PyCodeObject *code = PyFrame_GetCode(frame);
+        ptrace_enter_call(self, (void *)code, (PyObject *)code);
         break;
+    }
 
     /* the 'frame' of a called function is about to finish
        (either normally or with an exception) */
     case PyTrace_RETURN:
-        ptrace_leave_call(self, (void *)frame->f_code);
+        ptrace_leave_call(self, (void *)PyFrame_GetCode(frame));
         break;
 
     /* case PyTrace_EXCEPTION:
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index dbae107c2da20..3593baee51201 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -346,7 +346,7 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
         lineno = 0;
     frame->lineno = (unsigned int)lineno;
 
-    code = pyframe->f_code;
+    code = PyFrame_GetCode(pyframe);
     if (code == NULL) {
 #ifdef TRACE_DEBUG
         tracemalloc_error("failed to get the code object of the frame");
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index d0a15e77512c6..92206c5f52108 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1222,3 +1222,10 @@ _PyFrame_DebugMallocStats(FILE *out)
                            numfree, sizeof(PyFrameObject));
 }
 
+
+PyCodeObject *
+PyFrame_GetCode(PyFrameObject *frame)
+{
+    assert(frame != NULL);
+    return frame->f_code;
+}
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index bf95dd604e58e..9d97f389401d4 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8033,13 +8033,13 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
         PyFrameObject *f;
         PyCodeObject *co;
         Py_ssize_t i, n;
-        f = _PyThreadState_GET()->frame;
+        f = PyThreadState_GetFrame(_PyThreadState_GET());
         if (f == NULL) {
             PyErr_SetString(PyExc_RuntimeError,
                             "super(): no current frame");
             return -1;
         }
-        co = f->f_code;
+        co = PyFrame_GetCode(f);
         if (co == NULL) {
             PyErr_SetString(PyExc_RuntimeError,
                             "super(): no code object");
diff --git a/Python/_warnings.c b/Python/_warnings.c
index f4ef0bb4b1214..91c611c257305 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -762,7 +762,6 @@ is_internal_frame(PyFrameObject *frame)
 {
     static PyObject *importlib_string = NULL;
     static PyObject *bootstrap_string = NULL;
-    PyObject *filename;
     int contains;
 
     if (importlib_string == NULL) {
@@ -780,14 +779,23 @@ is_internal_frame(PyFrameObject *frame)
         Py_INCREF(bootstrap_string);
     }
 
-    if (frame == NULL || frame->f_code == NULL ||
-            frame->f_code->co_filename == NULL) {
+    if (frame == NULL) {
+        return 0;
+    }
+
+    PyCodeObject *code = PyFrame_GetCode(frame);
+    if (code == NULL) {
+        return 0;
+    }
+
+    PyObject *filename = code->co_filename;
+    if (filename == NULL) {
         return 0;
     }
-    filename = frame->f_code->co_filename;
     if (!PyUnicode_Check(filename)) {
         return 0;
     }
+
     contains = PyUnicode_Contains(filename, importlib_string);
     if (contains < 0) {
         return 0;
@@ -846,7 +854,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
     }
     else {
         globals = f->f_globals;
-        *filename = f->f_code->co_filename;
+        *filename = PyFrame_GetCode(f)->co_filename;
         Py_INCREF(*filename);
         *lineno = PyFrame_GetLineNumber(f);
     }
diff --git a/Python/import.c b/Python/import.c
index a8743458dd5c9..9142ebba40dfe 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -15,7 +15,6 @@
 #include "errcode.h"
 #include "marshal.h"
 #include "code.h"
-#include "frameobject.h"
 #include "importdl.h"
 #include "pydtrace.h"
 
@@ -1536,7 +1535,7 @@ remove_importlib_frames(PyThreadState *tstate)
         PyTracebackObject *traceback = (PyTracebackObject *)tb;
         PyObject *next = (PyObject *) traceback->tb_next;
         PyFrameObject *frame = traceback->tb_frame;
-        PyCodeObject *code = frame->f_code;
+        PyCodeObject *code = PyFrame_GetCode(frame);
         int now_in_importlib;
 
         assert(PyTraceBack_Check(tb));
diff --git a/Python/traceback.c b/Python/traceback.c
index 85e9124bb6a68..1ea6cbada964f 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -560,24 +560,23 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
         tb = tb->tb_next;
     }
     while (tb != NULL && err == 0) {
+        PyCodeObject *code = PyFrame_GetCode(tb->tb_frame);
         if (last_file == NULL ||
-            tb->tb_frame->f_code->co_filename != last_file ||
+            code->co_filename != last_file ||
             last_line == -1 || tb->tb_lineno != last_line ||
-            last_name == NULL || tb->tb_frame->f_code->co_name != last_name) {
+            last_name == NULL || code->co_name != last_name) {
             if (cnt > TB_RECURSIVE_CUTOFF) {
                 err = tb_print_line_repeated(f, cnt);
             }
-            last_file = tb->tb_frame->f_code->co_filename;
+            last_file = code->co_filename;
             last_line = tb->tb_lineno;
-            last_name = tb->tb_frame->f_code->co_name;
+            last_name = code->co_name;
             cnt = 0;
         }
         cnt++;
         if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) {
-            err = tb_displayline(f,
-                                 tb->tb_frame->f_code->co_filename,
-                                 tb->tb_lineno,
-                                 tb->tb_frame->f_code->co_name);
+            err = tb_displayline(f, code->co_filename, tb->tb_lineno,
+                                 code->co_name);
             if (err == 0) {
                 err = PyErr_CheckSignals();
             }
@@ -756,7 +755,7 @@ dump_frame(int fd, PyFrameObject *frame)
     PyCodeObject *code;
     int lineno;
 
-    code = frame->f_code;
+    code = PyFrame_GetCode(frame);
     PUTS(fd, "  File ");
     if (code != NULL && code->co_filename != NULL
         && PyUnicode_Check(code->co_filename))



More information about the Python-checkins mailing list