Skip to content
17 changes: 17 additions & 0 deletions Include/cpython/frameobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
# error "this header file must not be included directly"
#endif

struct _PyInterpreterFrame;

/* Standard object interface */

PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
Expand All @@ -27,3 +29,18 @@ PyAPI_FUNC(int) _PyFrame_IsEntryFrame(PyFrameObject *frame);

PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f);
PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);

/* The following functions are for use by debuggers and other tools
* implementing custom frame evaluators with PEP 523. */

/* Returns the code object of the frame (strong reference).
* Does not raise an exception. */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhere I saw the expression: "This function cannot fail" but I can no longer find it in the doc.

PyAPI_FUNC(PyCodeObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame);

/* Returns a byte ofsset into the last executed instruction.
Comment thread
markshannon marked this conversation as resolved.
* Does not raise an exception. */
PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame);

/* Returns the currently executing line number, or -1 if there is no line number.
* Does not raise an exception. */
PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame);
2 changes: 0 additions & 2 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,6 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func)
return new_frame;
}

int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame);

static inline
PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Expose C-API functions to get the code object, lasti and line number from
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this needs a news entry since the functions are exposed technically on a private header.

the internal ``_PyInterpreterFrame`` in the limited API. The functions are:
Comment thread
markshannon marked this conversation as resolved.

* ``PyCodeObject * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)``
* ``int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)``
* ``int _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)``
3 changes: 2 additions & 1 deletion Modules/_tracemalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "pycore_runtime.h" // _Py_ID()
#include "pycore_traceback.h"
#include <pycore_frame.h>
#include "frameobject.h" // _PyInterpreterFrame_GetLine

#include <stdlib.h> // malloc()

Expand Down Expand Up @@ -308,7 +309,7 @@ static void
tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
{
frame->filename = &_Py_STR(anon_unknown);
int lineno = _PyInterpreterFrame_GetLine(pyframe);
int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe);
if (lineno < 0) {
lineno = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ PyFrame_GetLineNumber(PyFrameObject *f)
return f->f_lineno;
}
else {
return _PyInterpreterFrame_GetLine(f->f_frame);
return PyUnstable_InterpreterFrame_GetLine(f->f_frame);
}
}

Expand Down
3 changes: 2 additions & 1 deletion Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "structmember.h" // PyMemberDef
#include "opcode.h" // SEND
#include "frameobject.h" // _PyInterpreterFrame_GetLine
#include "pystats.h"

static PyObject *gen_close(PyGenObject *, PyObject *);
Expand Down Expand Up @@ -1327,7 +1328,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame)
frame = current_frame;
for (int i = 0; i < frame_count; ++i) {
PyCodeObject *code = frame->f_code;
int line = _PyInterpreterFrame_GetLine(frame);
int line = PyUnstable_InterpreterFrame_GetLine(frame);
PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line,
code->co_name);
if (!frameinfo) {
Expand Down
7 changes: 4 additions & 3 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "pycore_dict.h"
#include "dictobject.h"
#include "pycore_frame.h"
#include "frameobject.h" // _PyInterpreterFrame_GetLine
#include "opcode.h"
#include "pydtrace.h"
#include "setobject.h"
Expand Down Expand Up @@ -5046,7 +5047,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
next_instr points the current instruction without TARGET(). */
opcode = _Py_OPCODE(*next_instr);
fprintf(stderr, "XXX lineno: %d, opcode: %d\n",
_PyInterpreterFrame_GetLine(frame), opcode);
PyUnstable_InterpreterFrame_GetLine(frame), opcode);
_PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode");
goto error;

Expand Down Expand Up @@ -7276,7 +7277,7 @@ dtrace_function_entry(_PyInterpreterFrame *frame)
PyCodeObject *code = frame->f_code;
filename = PyUnicode_AsUTF8(code->co_filename);
funcname = PyUnicode_AsUTF8(code->co_name);
lineno = _PyInterpreterFrame_GetLine(frame);
lineno = PyUnstable_InterpreterFrame_GetLine(frame);

PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
}
Expand All @@ -7291,7 +7292,7 @@ dtrace_function_return(_PyInterpreterFrame *frame)
PyCodeObject *code = frame->f_code;
filename = PyUnicode_AsUTF8(code->co_filename);
funcname = PyUnicode_AsUTF8(code->co_name);
lineno = _PyInterpreterFrame_GetLine(frame);
lineno = PyUnstable_InterpreterFrame_GetLine(frame);

PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
}
Expand Down
18 changes: 17 additions & 1 deletion Python/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,24 @@ _PyFrame_Clear(_PyInterpreterFrame *frame)
Py_DECREF(frame->f_code);
}

/* Unstable API functions */

PyCodeObject *
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
{
PyCodeObject *code = frame->f_code;
Py_INCREF(code);
return code;
Comment thread
markshannon marked this conversation as resolved.
}

int
PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)
{
return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
}

int
_PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame)
PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame)
{
int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
return PyCode_Addr2Line(frame->f_code, addr);
Expand Down
2 changes: 1 addition & 1 deletion Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,7 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
PUTS(fd, "???");
}

int lineno = _PyInterpreterFrame_GetLine(frame);
int lineno = PyUnstable_InterpreterFrame_GetLine(frame);
PUTS(fd, ", line ");
if (lineno >= 0) {
_Py_DumpDecimal(fd, (size_t)lineno);
Expand Down