Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40421: Add PyFrame_GetCode() function #19757

Merged
merged 1 commit into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down
9 changes: 9 additions & 0 deletions Doc/c-api/reflection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.)

Expand Down
2 changes: 2 additions & 0 deletions Include/pyframe.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
frame code.
9 changes: 5 additions & 4 deletions Modules/_lsprof.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "Python.h"
#include "frameobject.h"
#include "rotatingtree.h"

/************************************************************/
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Modules/_tracemalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
7 changes: 7 additions & 0 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1222,3 +1222,10 @@ _PyFrame_DebugMallocStats(FILE *out)
numfree, sizeof(PyFrameObject));
}


PyCodeObject *
PyFrame_GetCode(PyFrameObject *frame)
{
assert(frame != NULL);
return frame->f_code;
}
4 changes: 2 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
18 changes: 13 additions & 5 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
3 changes: 1 addition & 2 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "errcode.h"
#include "marshal.h"
#include "code.h"
#include "frameobject.h"
#include "importdl.h"
#include "pydtrace.h"

Expand Down Expand Up @@ -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));
Expand Down
17 changes: 8 additions & 9 deletions Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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))
Expand Down