[Python-checkins] GH-96803: Add three C-API functions to make _PyInterpreterFrame less opaque for users of PEP 523. (GH-96849)

markshannon webhook-mailer at python.org
Fri May 5 12:53:18 EDT 2023


https://github.com/python/cpython/commit/a0df9ee8fc77443510ab7e9ba8fd830f255a8fec
commit: a0df9ee8fc77443510ab7e9ba8fd830f255a8fec
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2023-05-05T17:53:07+01:00
summary:

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

files:
A Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst
M Include/cpython/frameobject.h
M Include/internal/pycore_frame.h
M Modules/_tracemalloc.c
M Objects/frameobject.c
M Objects/genobject.c
M Python/ceval.c
M Python/frame.c
M Python/traceback.c

diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index 4e19535c656f..6f3efe36ede5 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -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 *,
@@ -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. */
+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);
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index d8d7fe9ef2eb..3d3cbbff7aae 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -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)
 {
diff --git a/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst b/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst
new file mode 100644
index 000000000000..6fc56d2249f5
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst	
@@ -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)``
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index d69c5636486d..c5714d5e7d5a 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -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()
 
@@ -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;
     }
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index ef0070199ab2..d0eca447c012 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -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);
     }
 }
 
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 6316fa9865fe..937d497753e9 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -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 *);
@@ -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) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 958689debc87..56a3b123f463 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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"
@@ -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;
 
diff --git a/Python/frame.c b/Python/frame.c
index c2c0be301139..d792b92fa575 100644
--- a/Python/frame.c
+++ b/Python/frame.c
@@ -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);
diff --git a/Python/traceback.c b/Python/traceback.c
index 097f69c76abf..b24795420473 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -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);



More information about the Python-checkins mailing list