8000 Add new PyFrame_GetLasti C-API function (GH-32413) · python/cpython@5b4a4b6 · GitHub
[go: up one dir, main page]

Skip to content

Commit < 10000 span class="text-mono bgColor-muted rounded p-1">5b4a4b6

Browse files
authored
Add new PyFrame_GetLasti C-API function (GH-32413)
1 parent f4b328e commit 5b4a4b6

File tree

7 files changed

+45
-4
lines changed

7 files changed

+45
-4
lines changed

Doc/c-api/frame.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ See also :ref:`Reflection <reflection>`.
7878
.. versionadded:: 3.11
7979
8080
81+
.. c:function:: int PyFrame_GetLasti(PyFrameObject *frame)
82+
83+
Get the *frame*'s ``f_lasti`` attribute (:class:`dict`).
84+
85+
Returns -1 if ``frame.f_lasti`` is ``None``.
86+
87+
*frame* must not be ``NULL``.
88+
89+
.. versionadded:: 3.11
90+
91+
8192
.. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame)
8293
8394
Get the *frame*'s ``f_locals`` attribute (:class:`dict`).

Doc/whatsnew/3.11.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,7 @@ New Features
11211121

11221122
* Add new functions to get frame object attributes:
11231123
:c:func:`PyFrame_GetBuiltins`, :c:func:`PyFrame_GetGenerator`,
1124-
:c:func:`PyFrame_GetGlobals`.
1124+
:c:func:`PyFrame_GetGlobals`, :c:func:`PyFrame_GetLasti`.
11251125

11261126
Porting to Python 3.11
11271127
----------------------
@@ -1246,9 +1246,9 @@ Porting to Python 3.11
12461246
* ``f_gen``: use :c:func:`PyFrame_GetGenerator`.
12471247
* ``f_globals``: use :c:func:`PyFrame_GetGlobals`.
12481248
* ``f_iblock``: removed.
1249-
* ``f_lasti``: use ``PyObject_GetAttrString((PyObject*)frame, "f_lasti")``.
1249+
* ``f_lasti``: use :c:func:`PyFrame_GetLasti`.
12501250
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` should use
1251-
:c:func:`PyFrame_GetLineNumber` instead.
1251+
:c:func:`PyFrame_GetLineNumber` instead; it may be faster.
12521252
* ``f_lineno``: use :c:func:`PyFrame_GetLineNumber`
12531253
* ``f_locals``: use :c:func:`PyFrame_GetLocals`.
12541254
* ``f_stackdepth``: removed.

Include/cpython/frameobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ PyAPI_FUNC(PyObject *) PyFrame_GetGlobals(PyFrameObject *frame);
2929
PyAPI_FUNC(PyObject *) PyFrame_GetBuiltins(PyFrameObject *frame);
3030

3131
PyAPI_FUNC(PyObject *) PyFrame_GetGenerator(PyFrameObject *frame);
32+
PyAPI_FUNC(int) PyFrame_GetLasti(PyFrameObject *frame);

Lib/test/test_capi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,7 @@ def test_frame_getters(self):
11021102
self.assertEqual(frame.f_locals, _testcapi.frame_getlocals(frame))
11031103
self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame))
11041104
self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame))
1105+
self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame))
11051106

11061107
def test_frame_get_generator(self):
11071108
gen = self.getgenframe()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add ``PyFrame_GetLasti`` C-API function to access frame object's ``lasti``
2+
attribute safely from C code.

Modules/_testcapimodule.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5893,6 +5893,21 @@ frame_getbuiltins(PyObject *self, PyObject *frame)
58935893
return PyFrame_GetBuiltins((PyFrameObject *)frame);
58945894
}
58955895

5896+
static PyObject *
5897+
frame_getlasti(PyObject *self, PyObject *frame)
5898+
{
5899+
if (!PyFrame_Check(frame)) {
5900+
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
5901+
return NULL;
5902+
}
5903+
int lasti = PyFrame_GetLasti((PyFrameObject *)frame);
5904+
if (lasti < 0) {
5905+
assert(lasti == -1);
5906+
Py_RETURN_NONE;
5907+
}
5908+
return PyLong_FromLong(lasti);
5909+
}
5910+
58965911

58975912
static PyObject *negative_dictoffset(PyObject *, PyObject *);
58985913
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
@@ -6186,6 +6201,7 @@ static PyMethodDef TestMethods[] = {
61866201
{"frame_getglobals", frame_getglobals, METH_O, NULL},
61876202
{"frame_getgenerator", frame_getgenerator, METH_O, NULL},
61886203
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
6204+
{"frame_getlasti", frame_getlasti, METH_O, NULL},
61896205
{NULL, NULL} /* sentinel */
61906206
};
61916207

Objects/frameobject.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
880880
// This only works when opcode is a non-quickened form:
881881
assert(_PyOpcode_Deopt[opcode] == opcode);
882882
int check_oparg = 0;
883-
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code);
883+
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code);
884884
instruction < frame->prev_instr; instruction++)
885885
{
886886
int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)];
@@ -1135,6 +1135,16 @@ PyFrame_GetBuiltins(PyFrameObject *frame)
11351135
return frame_getbuiltins(frame, NULL);
11361136
}
11371137

1138+
int
1139+
PyFrame_GetLasti(PyFrameObject *frame)
1140+
{
1141+
int lasti = _PyInterpreterFrame_LASTI(frame->f_frame);
1142+
if (lasti < 0) {
1143+
return -1;
1144+
}
1145+
return lasti*2;
1146+
}
1147+
11381148
PyObject *
11391149
PyFrame_GetGenerator(PyFrameObject *frame)
11401150
{

0 commit comments

Comments
 (0)
0