summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-04-28 17:01:31 (GMT)
committerGitHub <noreply@github.com>2020-04-28 17:01:31 (GMT)
commita42ca74fa30227e2f89a619332557cf093a937d5 (patch)
treea3097e76897d8f8a0f054cab0736fd3cff80f8da
parentb8f704d2190125a7750b50cd9b67267b9c20fd43 (diff)
downloadcpython-a42ca74fa30227e2f89a619332557cf093a937d5.zip
cpython-a42ca74fa30227e2f89a619332557cf093a937d5.tar.gz
cpython-a42ca74fa30227e2f89a619332557cf093a937d5.tar.bz2
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.
-rw-r--r--Doc/c-api/init.rst6
-rw-r--r--Doc/c-api/reflection.rst9
-rw-r--r--Doc/whatsnew/3.9.rst4
-rw-r--r--Include/pyframe.h2
-rw-r--r--Misc/NEWS.d/next/C API/2020-04-28-15-47-58.bpo-40421.ZIzOV0.rst2
-rw-r--r--Modules/_lsprof.c9
-rw-r--r--Modules/_tracemalloc.c2
-rw-r--r--Objects/frameobject.c7
-rw-r--r--Objects/typeobject.c4
-rw-r--r--Python/_warnings.c18
-rw-r--r--Python/import.c3
-rw-r--r--Python/traceback.c17
12 files changed, 58 insertions, 25 deletions
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 435808f..afde3db 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 498219f..b313ea3 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 8b8aa9a..e3751fa 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 d3404cd..3816224 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 0000000..11cf878
--- /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 7115fee..39cf6e1 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 dbae107..3593bae 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 d0a15e7..92206c5 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 bf95dd6..9d97f38 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 f4ef0bb..91c611c 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 a874345..9142ebb 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 85e9124..1ea6cba 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))