From ce233949c1bb5843ca59dc30cb2f5ff613b533b7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Sep 2022 15:22:08 +0100 Subject: [PATCH 1/8] Add three C-API functions to make _PyInterpreterFrame more usable for users of PEP 523. --- Include/cpython/frameobject.h | 15 +++++++++++++++ .../2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst | 9 +++++++++ Python/frame.c | 14 ++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index 4e19535c656f2c..6a0ed7abc34be6 100644 --- a/Include/cpython/frameobject.h +++ b/Include/cpython/frameobject.h @@ -27,3 +27,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. + * Does not raise an exception. */ +PyAPI_FUNC(PyCodeObject *) _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); + +/* Returns a byte ofsset into the last executed instruction. + * Does not raise an exception. */ +PyAPI_FUNC(int) _PyInterpreterFrame_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) _PyInterpreterFrame_GetLine(struct _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 00000000000000..7f4a1c6cf68dc1 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst @@ -0,0 +1,9 @@ +Expose C-API functions to get the code object, lasti and line number from +the internal ``_PyInterpreterFrame`` in the limited API. The functions are: + +``PyCodeObject * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame +*frame);`` + +``int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame);`` + +``int _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame);`` diff --git a/Python/frame.c b/Python/frame.c index 14464df0a8d506..1b4459b607321c 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -118,6 +118,20 @@ _PyFrame_Clear(_PyInterpreterFrame *frame) Py_DECREF(frame->f_code); } +/* Limited API functions */ + +PyCodeObject *_PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) +{ + PyCodeObject *code = frame->f_code; + Py_INCREF(code); + return code; +} + +int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame) +{ + return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); +} + int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame) { From 6ff2f4d15d0d0b97ad6fd1147fcfda984575ab71 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Sep 2022 16:06:05 +0100 Subject: [PATCH 2/8] Remove duplicate definition. --- Include/internal/pycore_frame.h | 2 -- Modules/_tracemalloc.c | 1 + Objects/genobject.c | 1 + Python/ceval.c | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 5bd0a7f2f517ef..180ab19bf1500c 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -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) { diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 44a1f7b673c0eb..13dfd55ed614ea 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -6,6 +6,7 @@ #include "pycore_runtime.h" // _Py_ID() #include "pycore_traceback.h" #include +#include "frameobject.h" // _PyInterpreterFrame_GetLine #include // malloc() diff --git a/Objects/genobject.c b/Objects/genobject.c index da4afecc69c8c1..cd4e33889128b8 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -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 *); diff --git a/Python/ceval.c b/Python/ceval.c index b61cc0852ed96a..0381bd00b3e121 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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" From 821de76c9201fa6f72eb655dc04819b2a7c18efa Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Sep 2022 17:02:01 +0100 Subject: [PATCH 3/8] Update Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst Co-authored-by: Victor Stinner --- .../2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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 index 7f4a1c6cf68dc1..be5373f53cc992 100644 --- 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 @@ -1,9 +1,7 @@ Expose C-API functions to get the code object, lasti and line number from the internal ``_PyInterpreterFrame`` in the limited API. The functions are: -``PyCodeObject * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame -*frame);`` - -``int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame);`` - -``int _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame);`` +* ``PyCodeObject * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame +*frame)`` +* ``int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` +* ``int _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` From 5aed2cbd5be66b896b66fa177f54a5220d3d1fb4 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Sep 2022 17:02:23 +0100 Subject: [PATCH 4/8] Update Include/cpython/frameobject.h Co-authored-by: Victor Stinner --- Include/cpython/frameobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index 6a0ed7abc34be6..93a67081ce5098 100644 --- a/Include/cpython/frameobject.h +++ b/Include/cpython/frameobject.h @@ -31,7 +31,7 @@ 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. +/* Returns the code object of the frame (strong reference). * Does not raise an exception. */ PyAPI_FUNC(PyCodeObject *) _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); From fea57fbd53a15bbeb9a76def776a383a03188a71 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Sep 2022 17:40:04 +0100 Subject: [PATCH 5/8] Attempt to fix rst formatting. --- .../next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index be5373f53cc992..874ad505e54e80 100644 --- 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 @@ -1,7 +1,6 @@ Expose C-API functions to get the code object, lasti and line number from the internal ``_PyInterpreterFrame`` in the limited API. The functions are: -* ``PyCodeObject * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame -*frame)`` +* ``PyCodeObject * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` * ``int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` * ``int _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` From a6a6662dd73c8547f6ed611c844ff76d146a9693 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 4 May 2023 18:45:14 +0100 Subject: [PATCH 6/8] Make new function part of unstable API. --- Include/cpython/frameobject.h | 8 +++++--- Modules/_tracemalloc.c | 2 +- Objects/frameobject.c | 2 +- Objects/genobject.c | 2 +- Python/ceval.c | 6 +++--- Python/frame.c | 10 ++++++---- Python/traceback.c | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index 93a67081ce5098..6f3efe36ede5d8 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 *, @@ -33,12 +35,12 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); /* Returns the code object of the frame (strong reference). * Does not raise an exception. */ -PyAPI_FUNC(PyCodeObject *) _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); +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) _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame); +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) _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame); +PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame); diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 13dfd55ed614ea..67d26d8305473a 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -309,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; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 2e377794312612..f9993d3bf38228 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -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); } } diff --git a/Objects/genobject.c b/Objects/genobject.c index cd4e33889128b8..229760837d8af1 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1328,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) { diff --git a/Python/ceval.c b/Python/ceval.c index 0381bd00b3e121..c658eebd208d8a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5047,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; @@ -7277,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); } @@ -7292,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); } diff --git a/Python/frame.c b/Python/frame.c index 1b4459b607321c..62b8ef61c7f9b8 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -118,22 +118,24 @@ _PyFrame_Clear(_PyInterpreterFrame *frame) Py_DECREF(frame->f_code); } -/* Limited API functions */ +/* Unstable API functions */ -PyCodeObject *_PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) +PyCodeObject * +PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) { PyCodeObject *code = frame->f_code; Py_INCREF(code); return code; } -int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame) +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 de658b9103180e..719288ed706e23 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -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); From 19bc82e62efb4572893bb1c46af56552e248a150 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 4 May 2023 18:52:29 +0100 Subject: [PATCH 7/8] Update news item --- .../C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 874ad505e54e80..6fc56d2249f581 100644 --- 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 @@ -1,6 +1,6 @@ -Expose C-API functions to get the code object, lasti and line number from +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 * _PyInterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` -* ``int _PyInterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` -* ``int _PyInterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` +* ``PyCodeObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` +* ``int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` +* ``int PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` From 7fbece8a1c728b5c08b6b40d1352c64202c1b770 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 4 May 2023 23:16:03 +0100 Subject: [PATCH 8/8] Fix merge. --- Python/ceval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/ceval.c b/Python/ceval.c index 7bc6d524a80d9e..56a3b123f46331 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -784,7 +784,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int next_instr points the current instruction without TARGET(). */ opcode = next_instr->op.code; _PyErr_Format(tstate, PyExc_SystemError, - PyUnstable_InterpreterFrame_GetLine(frame), opcode); + "%U:%d: unknown opcode %d", frame->f_code->co_filename, PyUnstable_InterpreterFrame_GetLine(frame), opcode);