Skip to content

GH-96803: Add three C-API functions to make _PyInterpreterFrame less opaque for users of PEP 523. #96849

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

Merged
merged 9 commits into from
May 5, 2023
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
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.
* 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 @@ -265,8 +265,6 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l
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 @@
Add unstable C-API functions to get the code object, lasti and line number from
the internal ``_PyInterpreterFrame`` in the limited API. The functions are:

* ``PyCodeObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)``
* ``int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)``
* ``int PyUnstable_InterpreterFrame_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 @@ -7,6 +7,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 @@ -257,7 +258,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 @@ -38,7 +38,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 @@ -12,6 +12,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 @@ -1322,7 +1323,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
3 changes: 2 additions & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,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 @@ -785,7 +786,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
_PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d",
frame->f_code->co_filename,
_PyInterpreterFrame_GetLine(frame),
PyUnstable_InterpreterFrame_GetLine(frame),
opcode);
goto error;

Expand Down
18 changes: 17 additions & 1 deletion Python/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,24 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
Py_DECREF(frame->f_funcobj);
}

/* Unstable API functions */

PyCodeObject *
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
{
PyCodeObject *code = frame->f_code;
Py_INCREF(code);
return code;
}

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 @@ -1180,7 +1180,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