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.
This commit is contained in:
Victor Stinner 2020-04-28 19:01:31 +02:00 committed by GitHub
parent b8f704d219
commit a42ca74fa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 58 additions and 25 deletions

View File

@ -1074,8 +1074,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) .. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
Get the current frame of the Python thread state *tstate*. It can be Get a borrowed reference to the current frame of the Python thread state
``NULL`` if no frame is currently executing. *tstate*.
Return ``NULL`` if no frame is currently executing.
See also :c:func:`PyEval_GetFrame`. See also :c:func:`PyEval_GetFrame`.

View File

@ -31,6 +31,15 @@ Reflection
See also :c:func:`PyThreadState_GetFrame`. 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) .. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
Return the line number that *frame* is currently executing. Return the line number that *frame* is currently executing.

View File

@ -537,6 +537,10 @@ Optimizations
Build and C API Changes 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. * Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
(Contributed by Victor Stinner in :issue:`40421`.) (Contributed by Victor Stinner in :issue:`40421`.)

View File

@ -14,6 +14,8 @@ typedef struct _frame PyFrameObject;
/* Return the line of code the frame is currently executing. */ /* Return the line of code the frame is currently executing. */
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
PyAPI_FUNC(PyCodeObject *) PyFrame_GetCode(PyFrameObject *frame);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -0,0 +1,2 @@
New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
frame code.

View File

@ -1,5 +1,4 @@
#include "Python.h" #include "Python.h"
#include "frameobject.h"
#include "rotatingtree.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 */ /* the 'frame' of a called function is about to start its execution */
case PyTrace_CALL: 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; break;
}
/* the 'frame' of a called function is about to finish /* the 'frame' of a called function is about to finish
(either normally or with an exception) */ (either normally or with an exception) */
case PyTrace_RETURN: case PyTrace_RETURN:
ptrace_leave_call(self, (void *)frame->f_code); ptrace_leave_call(self, (void *)PyFrame_GetCode(frame));
break; break;
/* case PyTrace_EXCEPTION: /* case PyTrace_EXCEPTION:

View File

@ -346,7 +346,7 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
lineno = 0; lineno = 0;
frame->lineno = (unsigned int)lineno; frame->lineno = (unsigned int)lineno;
code = pyframe->f_code; code = PyFrame_GetCode(pyframe);
if (code == NULL) { if (code == NULL) {
#ifdef TRACE_DEBUG #ifdef TRACE_DEBUG
tracemalloc_error("failed to get the code object of the frame"); tracemalloc_error("failed to get the code object of the frame");

View File

@ -1222,3 +1222,10 @@ _PyFrame_DebugMallocStats(FILE *out)
numfree, sizeof(PyFrameObject)); numfree, sizeof(PyFrameObject));
} }
PyCodeObject *
PyFrame_GetCode(PyFrameObject *frame)
{
assert(frame != NULL);
return frame->f_code;
}

View File

@ -8033,13 +8033,13 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
PyFrameObject *f; PyFrameObject *f;
PyCodeObject *co; PyCodeObject *co;
Py_ssize_t i, n; Py_ssize_t i, n;
f = _PyThreadState_GET()->frame; f = PyThreadState_GetFrame(_PyThreadState_GET());
if (f == NULL) { if (f == NULL) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
"super(): no current frame"); "super(): no current frame");
return -1; return -1;
} }
co = f->f_code; co = PyFrame_GetCode(f);
if (co == NULL) { if (co == NULL) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
"super(): no code object"); "super(): no code object");

View File

@ -762,7 +762,6 @@ is_internal_frame(PyFrameObject *frame)
{ {
static PyObject *importlib_string = NULL; static PyObject *importlib_string = NULL;
static PyObject *bootstrap_string = NULL; static PyObject *bootstrap_string = NULL;
PyObject *filename;
int contains; int contains;
if (importlib_string == NULL) { if (importlib_string == NULL) {
@ -780,14 +779,23 @@ is_internal_frame(PyFrameObject *frame)
Py_INCREF(bootstrap_string); Py_INCREF(bootstrap_string);
} }
if (frame == NULL || frame->f_code == NULL || if (frame == NULL) {
frame->f_code->co_filename == NULL) { return 0;
}
PyCodeObject *code = PyFrame_GetCode(frame);
if (code == NULL) {
return 0;
}
PyObject *filename = code->co_filename;
if (filename == NULL) {
return 0; return 0;
} }
filename = frame->f_code->co_filename;
if (!PyUnicode_Check(filename)) { if (!PyUnicode_Check(filename)) {
return 0; return 0;
} }
contains = PyUnicode_Contains(filename, importlib_string); contains = PyUnicode_Contains(filename, importlib_string);
if (contains < 0) { if (contains < 0) {
return 0; return 0;
@ -846,7 +854,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
} }
else { else {
globals = f->f_globals; globals = f->f_globals;
*filename = f->f_code->co_filename; *filename = PyFrame_GetCode(f)->co_filename;
Py_INCREF(*filename); Py_INCREF(*filename);
*lineno = PyFrame_GetLineNumber(f); *lineno = PyFrame_GetLineNumber(f);
} }

View File

@ -15,7 +15,6 @@
#include "errcode.h" #include "errcode.h"
#include "marshal.h" #include "marshal.h"
#include "code.h" #include "code.h"
#include "frameobject.h"
#include "importdl.h" #include "importdl.h"
#include "pydtrace.h" #include "pydtrace.h"
@ -1536,7 +1535,7 @@ remove_importlib_frames(PyThreadState *tstate)
PyTracebackObject *traceback = (PyTracebackObject *)tb; PyTracebackObject *traceback = (PyTracebackObject *)tb;
PyObject *next = (PyObject *) traceback->tb_next; PyObject *next = (PyObject *) traceback->tb_next;
PyFrameObject *frame = traceback->tb_frame; PyFrameObject *frame = traceback->tb_frame;
PyCodeObject *code = frame->f_code; PyCodeObject *code = PyFrame_GetCode(frame);
int now_in_importlib; int now_in_importlib;
assert(PyTraceBack_Check(tb)); assert(PyTraceBack_Check(tb));

View File

@ -560,24 +560,23 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
tb = tb->tb_next; tb = tb->tb_next;
} }
while (tb != NULL && err == 0) { while (tb != NULL && err == 0) {
PyCodeObject *code = PyFrame_GetCode(tb->tb_frame);
if (last_file == NULL || 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_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) { if (cnt > TB_RECURSIVE_CUTOFF) {
err = tb_print_line_repeated(f, cnt); 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_line = tb->tb_lineno;
last_name = tb->tb_frame->f_code->co_name; last_name = code->co_name;
cnt = 0; cnt = 0;
} }
cnt++; cnt++;
if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) { if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) {
err = tb_displayline(f, err = tb_displayline(f, code->co_filename, tb->tb_lineno,
tb->tb_frame->f_code->co_filename, code->co_name);
tb->tb_lineno,
tb->tb_frame->f_code->co_name);
if (err == 0) { if (err == 0) {
err = PyErr_CheckSignals(); err = PyErr_CheckSignals();
} }
@ -756,7 +755,7 @@ dump_frame(int fd, PyFrameObject *frame)
PyCodeObject *code; PyCodeObject *code;
int lineno; int lineno;
code = frame->f_code; code = PyFrame_GetCode(frame);
PUTS(fd, " File "); PUTS(fd, " File ");
if (code != NULL && code->co_filename != NULL if (code != NULL && code->co_filename != NULL
&& PyUnicode_Check(code->co_filename)) && PyUnicode_Check(code->co_filename))