summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-07-26 10:22:16 (GMT)
committerGitHub <noreply@github.com>2021-07-26 10:22:16 (GMT)
commitae0a2b756255629140efcbe57fc2e714f0267aa3 (patch)
tree8710e8c7a398c9ec0add227fab607f367242a7e5 /Objects
parent0363a4014d90df17a29042de008ef0b659f92505 (diff)
downloadcpython-ae0a2b756255629140efcbe57fc2e714f0267aa3.zip
cpython-ae0a2b756255629140efcbe57fc2e714f0267aa3.tar.gz
cpython-ae0a2b756255629140efcbe57fc2e714f0267aa3.tar.bz2
bpo-44590: Lazily allocate frame objects (GH-27077)
* Convert "specials" array to InterpreterFrame struct, adding f_lasti, f_state and other non-debug FrameObject fields to it. * Refactor, calls pushing the call to the interpreter upward toward _PyEval_Vector. * Compute f_back when on thread stack, only filling in value when frame object outlives stack invocation. * Move ownership of InterpreterFrame in generator from frame object to generator object. * Do not create frame objects for Python calls. * Do not create frame objects for generators.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/frameobject.c296
-rw-r--r--Objects/genobject.c265
-rw-r--r--Objects/typeobject.c8
3 files changed, 336 insertions, 233 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 813ec56..d1b8048 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -14,7 +14,6 @@
#define OFF(x) offsetof(PyFrameObject, x)
static PyMemberDef frame_memberlist[] = {
- {"f_back", T_OBJECT, OFF(f_back), READONLY},
{"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0},
{"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0},
{NULL} /* Sentinel */
@@ -33,7 +32,7 @@ frame_getlocals(PyFrameObject *f, void *closure)
{
if (PyFrame_FastToLocalsWithError(f) < 0)
return NULL;
- PyObject *locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
+ PyObject *locals = f->f_frame->f_locals;
Py_INCREF(locals);
return locals;
}
@@ -46,7 +45,7 @@ PyFrame_GetLineNumber(PyFrameObject *f)
return f->f_lineno;
}
else {
- return PyCode_Addr2Line(_PyFrame_GetCode(f), f->f_lasti*2);
+ return PyCode_Addr2Line(f->f_frame->f_code, f->f_frame->f_lasti*2);
}
}
@@ -65,16 +64,16 @@ frame_getlineno(PyFrameObject *f, void *closure)
static PyObject *
frame_getlasti(PyFrameObject *f, void *closure)
{
- if (f->f_lasti < 0) {
+ if (f->f_frame->f_lasti < 0) {
return PyLong_FromLong(-1);
}
- return PyLong_FromLong(f->f_lasti*2);
+ return PyLong_FromLong(f->f_frame->f_lasti*2);
}
static PyObject *
frame_getglobals(PyFrameObject *f, void *closure)
{
- PyObject *globals = _PyFrame_GetGlobals(f);
+ PyObject *globals = f->f_frame->f_globals;
if (globals == NULL) {
globals = Py_None;
}
@@ -85,7 +84,7 @@ frame_getglobals(PyFrameObject *f, void *closure)
static PyObject *
frame_getbuiltins(PyFrameObject *f, void *closure)
{
- PyObject *builtins = _PyFrame_GetBuiltins(f);
+ PyObject *builtins = f->f_frame->f_builtins;
if (builtins == NULL) {
builtins = Py_None;
}
@@ -102,6 +101,16 @@ frame_getcode(PyFrameObject *f, void *closure)
return (PyObject *)PyFrame_GetCode(f);
}
+static PyObject *
+frame_getback(PyFrameObject *f, void *closure)
+{
+ PyObject *res = (PyObject *)PyFrame_GetBack(f);
+ if (res == NULL) {
+ Py_RETURN_NONE;
+ }
+ return res;
+}
+
/* Given the index of the effective opcode,
scan back to construct the oparg with EXTENDED_ARG */
static unsigned int
@@ -388,9 +397,9 @@ first_line_not_before(int *lines, int len, int line)
static void
frame_stack_pop(PyFrameObject *f)
{
- assert(f->f_stackdepth > 0);
- f->f_stackdepth--;
- PyObject *v = f->f_valuestack[f->f_stackdepth];
+ assert(f->f_frame->stackdepth > 0);
+ f->f_frame->stackdepth--;
+ PyObject *v = f->f_frame->stack[f->f_frame->stackdepth];
Py_DECREF(v);
}
@@ -430,7 +439,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
* In addition, jumps are forbidden when not tracing,
* as this is a debugging feature.
*/
- switch(f->f_state) {
+ switch(f->f_frame->f_state) {
case FRAME_CREATED:
PyErr_Format(PyExc_ValueError,
"can't jump from the 'call' trace event of a new frame");
@@ -472,7 +481,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
}
new_lineno = (int)l_new_lineno;
- if (new_lineno < _PyFrame_GetCode(f)->co_firstlineno) {
+ if (new_lineno < f->f_frame->f_code->co_firstlineno) {
PyErr_Format(PyExc_ValueError,
"line %d comes before the current code block",
new_lineno);
@@ -481,8 +490,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
/* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
* should never overflow. */
- int len = (int)(PyBytes_GET_SIZE(_PyFrame_GetCode(f)->co_code) / sizeof(_Py_CODEUNIT));
- int *lines = marklines(_PyFrame_GetCode(f), len);
+ int len = (int)(PyBytes_GET_SIZE(f->f_frame->f_code->co_code) / sizeof(_Py_CODEUNIT));
+ int *lines = marklines(f->f_frame->f_code, len);
if (lines == NULL) {
return -1;
}
@@ -496,7 +505,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
return -1;
}
- int64_t *stacks = mark_stacks(_PyFrame_GetCode(f), len);
+ int64_t *stacks = mark_stacks(f->f_frame->f_code, len);
if (stacks == NULL) {
PyMem_Free(lines);
return -1;
@@ -504,7 +513,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
int64_t best_stack = OVERFLOWED;
int best_addr = -1;
- int64_t start_stack = stacks[f->f_lasti];
+ int64_t start_stack = stacks[f->f_frame->f_lasti];
int err = -1;
const char *msg = "cannot find bytecode for specified line";
for (int i = 0; i < len; i++) {
@@ -538,7 +547,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
return -1;
}
/* Unwind block stack. */
- if (f->f_state == FRAME_SUSPENDED) {
+ if (f->f_frame->f_state == FRAME_SUSPENDED) {
/* Account for value popped by yield */
start_stack = pop_value(start_stack);
}
@@ -546,9 +555,9 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
frame_stack_pop(f);
start_stack = pop_value(start_stack);
}
- /* Finally set the new f_lasti and return OK. */
+ /* Finally set the new lasti and return OK. */
f->f_lineno = 0;
- f->f_lasti = best_addr;
+ f->f_frame->f_lasti = best_addr;
return 0;
}
@@ -579,6 +588,7 @@ frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
static PyGetSetDef frame_getsetlist[] = {
+ {"f_back", (getter)frame_getback, NULL, NULL},
{"f_locals", (getter)frame_getlocals, NULL, NULL},
{"f_lineno", (getter)frame_getlineno,
(setter)frame_setlineno, NULL},
@@ -612,29 +622,27 @@ frame_dealloc(PyFrameObject *f)
Py_TRASHCAN_SAFE_BEGIN(f)
PyCodeObject *co = NULL;
- /* Kill all local variables including specials. */
- if (f->f_localsptr) {
+ /* Kill all local variables including specials, if we own them */
+ if (f->f_own_locals_memory) {
+ f->f_own_locals_memory = 0;
+ InterpreterFrame *frame = f->f_frame;
/* Don't clear code object until the end */
- co = _PyFrame_GetCode(f);
- PyObject **specials = _PyFrame_Specials(f);
- Py_CLEAR(specials[FRAME_SPECIALS_GLOBALS_OFFSET]);
- Py_CLEAR(specials[FRAME_SPECIALS_BUILTINS_OFFSET]);
- Py_CLEAR(specials[FRAME_SPECIALS_LOCALS_OFFSET]);
+ co = frame->f_code;
+ frame->f_code = NULL;
+ Py_CLEAR(frame->f_globals);
+ Py_CLEAR(frame->f_builtins);
+ Py_CLEAR(frame->f_locals);
+ PyObject **locals = _PyFrame_GetLocalsArray(frame);
for (int i = 0; i < co->co_nlocalsplus; i++) {
- Py_CLEAR(f->f_localsptr[i]);
- }
- /* Free items on stack */
- for (int i = 0; i < f->f_stackdepth; i++) {
- Py_XDECREF(f->f_valuestack[i]);
+ Py_CLEAR(locals[i]);
}
- if (f->f_own_locals_memory) {
- PyMem_Free(f->f_localsptr);
- f->f_own_locals_memory = 0;
+ /* stack */
+ for (int i = 0; i < frame->stackdepth; i++) {
+ Py_CLEAR(frame->stack[i]);
}
- f->f_localsptr = NULL;
+ PyMem_Free(locals);
}
- f->f_stackdepth = 0;
- Py_XDECREF(f->f_back);
+ Py_CLEAR(f->f_back);
Py_CLEAR(f->f_trace);
struct _Py_frame_state *state = get_frame_state();
#ifdef Py_DEBUG
@@ -654,29 +662,16 @@ frame_dealloc(PyFrameObject *f)
Py_TRASHCAN_SAFE_END(f)
}
-static inline Py_ssize_t
-frame_nslots(PyFrameObject *frame)
-{
- return frame->f_valuestack - frame->f_localsptr;
-}
-
static int
frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
{
Py_VISIT(f->f_back);
Py_VISIT(f->f_trace);
-
- /* locals */
- PyObject **localsplus = f->f_localsptr;
- for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++localsplus) {
- Py_VISIT(*localsplus);
- }
-
- /* stack */
- for (int i = 0; i < f->f_stackdepth; i++) {
- Py_VISIT(f->f_valuestack[i]);
+ if (f->f_own_locals_memory == 0) {
+ return 0;
}
- return 0;
+ assert(f->f_frame->frame_obj == NULL);
+ return _PyFrame_Traverse(f->f_frame, visit, arg);
}
static int
@@ -687,34 +682,35 @@ frame_tp_clear(PyFrameObject *f)
* frame may also point to this frame, believe itself to still be
* active, and try cleaning up this frame again.
*/
- f->f_state = FRAME_CLEARED;
+ f->f_frame->f_state = FRAME_CLEARED;
Py_CLEAR(f->f_trace);
- PyCodeObject *co = _PyFrame_GetCode(f);
+
/* locals */
- for (int i = 0; i < co->co_nlocalsplus; i++) {
- Py_CLEAR(f->f_localsptr[i]);
+ PyObject **locals = _PyFrame_GetLocalsArray(f->f_frame);
+ for (int i = 0; i < f->f_frame->nlocalsplus; i++) {
+ Py_CLEAR(locals[i]);
}
/* stack */
- for (int i = 0; i < f->f_stackdepth; i++) {
- Py_CLEAR(f->f_valuestack[i]);
+ for (int i = 0; i < f->f_frame->stackdepth; i++) {
+ Py_CLEAR(f->f_frame->stack[i]);
}
- f->f_stackdepth = 0;
+ f->f_frame->stackdepth = 0;
return 0;
}
static PyObject *
frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
{
- if (_PyFrame_IsExecuting(f)) {
+ if (_PyFrame_IsExecuting(f->f_frame)) {
PyErr_SetString(PyExc_RuntimeError,
"cannot clear an executing frame");
return NULL;
}
- if (f->f_gen) {
- _PyGen_Finalize(f->f_gen);
- assert(f->f_gen == NULL);
+ if (f->f_frame->generator) {
+ _PyGen_Finalize(f->f_frame->generator);
+ assert(f->f_frame->generator == NULL);
}
(void)frame_tp_clear(f);
Py_RETURN_NONE;
@@ -729,7 +725,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
Py_ssize_t res;
res = sizeof(PyFrameObject);
if (f->f_own_locals_memory) {
- PyCodeObject *code = _PyFrame_GetCode(f);
+ PyCodeObject *code = f->f_frame->f_code;
res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *);
}
return PyLong_FromSsize_t(res);
@@ -742,7 +738,7 @@ static PyObject *
frame_repr(PyFrameObject *f)
{
int lineno = PyFrame_GetLineNumber(f);
- PyCodeObject *code = _PyFrame_GetCode(f);
+ PyCodeObject *code = f->f_frame->f_code;
return PyUnicode_FromFormat(
"<frame at %p, file %R, line %d, code %S>",
f, code->co_filename, lineno, code->co_name);
@@ -793,33 +789,39 @@ PyTypeObject PyFrame_Type = {
_Py_IDENTIFIER(__builtins__);
-static inline PyFrameObject*
-frame_alloc(PyCodeObject *code, PyObject **localsarray)
+static InterpreterFrame *
+allocate_heap_frame(PyFrameConstructor *con, PyObject *locals)
{
- int owns;
- PyFrameObject *f;
+ PyCodeObject *code = (PyCodeObject *)con->fc_code;
+ int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
+ PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size);
if (localsarray == NULL) {
- int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
- localsarray = PyMem_Malloc(sizeof(PyObject *)*size);
- if (localsarray == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
- localsarray[i] = NULL;
- }
- owns = 1;
+ PyErr_NoMemory();
+ return NULL;
}
- else {
- owns = 0;
+ for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
+ localsarray[i] = NULL;
}
+ InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus);
+ _PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
+ return frame;
+}
+
+static inline PyFrameObject*
+frame_alloc(InterpreterFrame *frame, int owns)
+{
+ PyFrameObject *f;
struct _Py_frame_state *state = get_frame_state();
if (state->free_list == NULL)
{
f = PyObject_GC_New(PyFrameObject, &PyFrame_Type);
if (f == NULL) {
if (owns) {
- PyMem_Free(localsarray);
+ Py_XDECREF(frame->f_code);
+ Py_XDECREF(frame->f_builtins);
+ Py_XDECREF(frame->f_globals);
+ Py_XDECREF(frame->f_locals);
+ PyMem_Free(frame);
}
return NULL;
}
@@ -835,66 +837,23 @@ frame_alloc(PyCodeObject *code, PyObject **localsarray)
state->free_list = state->free_list->f_back;
_Py_NewReference((PyObject *)f);
}
- f->f_localsptr = localsarray;
+ f->f_frame = frame;
f->f_own_locals_memory = owns;
return f;
}
-int
-_PyFrame_TakeLocals(PyFrameObject *f)
-{
- assert(f->f_own_locals_memory == 0);
- assert(f->f_stackdepth == 0);
- Py_ssize_t size = frame_nslots(f);
- PyObject **copy = PyMem_Malloc(sizeof(PyObject *)*size);
- if (copy == NULL) {
- for (int i = 0; i < size; i++) {
- PyObject *o = f->f_localsptr[i];
- Py_XDECREF(o);
- }
- PyErr_NoMemory();
- return -1;
- }
- for (int i = 0; i < size; i++) {
- PyObject *o = f->f_localsptr[i];
- copy[i] = o;
- }
- f->f_own_locals_memory = 1;
- f->f_localsptr = copy;
- f->f_valuestack = copy + size;
- return 0;
-}
-
PyFrameObject* _Py_HOT_FUNCTION
-_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals, PyObject **localsarray)
+_PyFrame_New_NoTrack(InterpreterFrame *frame, int owns)
{
- assert(con != NULL);
- assert(con->fc_globals != NULL);
- assert(con->fc_builtins != NULL);
- assert(con->fc_code != NULL);
- assert(locals == NULL || PyMapping_Check(locals));
- PyCodeObject *code = (PyCodeObject *)con->fc_code;
-
- PyFrameObject *f = frame_alloc(code, localsarray);
+ PyFrameObject *f = frame_alloc(frame, owns);
if (f == NULL) {
return NULL;
}
-
- PyObject **specials = f->f_localsptr + code->co_nlocalsplus;
- f->f_valuestack = specials + FRAME_SPECIALS_SIZE;
- f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame);
- specials[FRAME_SPECIALS_CODE_OFFSET] = Py_NewRef(con->fc_code);
- specials[FRAME_SPECIALS_BUILTINS_OFFSET] = Py_NewRef(con->fc_builtins);
- specials[FRAME_SPECIALS_GLOBALS_OFFSET] = Py_NewRef(con->fc_globals);
- specials[FRAME_SPECIALS_LOCALS_OFFSET] = Py_XNewRef(locals);
+ f->f_back = NULL;
f->f_trace = NULL;
- f->f_stackdepth = 0;
f->f_trace_lines = 1;
f->f_trace_opcodes = 0;
- f->f_gen = NULL;
- f->f_lasti = -1;
f->f_lineno = 0;
- f->f_state = FRAME_CREATED;
return f;
}
@@ -917,7 +876,11 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
.fc_kwdefaults = NULL,
.fc_closure = NULL
};
- PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals, NULL);
+ InterpreterFrame *frame = allocate_heap_frame(&desc, locals);
+ if (frame == NULL) {
+ return NULL;
+ }
+ PyFrameObject *f = _PyFrame_New_NoTrack(frame, 1);
if (f) {
_PyObject_GC_TRACK(f);
}
@@ -925,11 +888,11 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
}
static int
-_PyFrame_OpAlreadyRan(PyFrameObject *f, int opcode, int oparg)
+_PyFrame_OpAlreadyRan(InterpreterFrame *frame, int opcode, int oparg)
{
const _Py_CODEUNIT *code =
- (const _Py_CODEUNIT *)PyBytes_AS_STRING(_PyFrame_GetCode(f)->co_code);
- for (int i = 0; i < f->f_lasti; i++) {
+ (const _Py_CODEUNIT *)PyBytes_AS_STRING(frame->f_code->co_code);
+ for (int i = 0; i < frame->f_lasti; i++) {
if (_Py_OPCODE(code[i]) == opcode && _Py_OPARG(code[i]) == oparg) {
return 1;
}
@@ -938,25 +901,19 @@ _PyFrame_OpAlreadyRan(PyFrameObject *f, int opcode, int oparg)
}
int
-PyFrame_FastToLocalsWithError(PyFrameObject *f)
-{
+_PyFrame_FastToLocalsWithError(InterpreterFrame *frame) {
/* Merge fast locals into f->f_locals */
PyObject *locals;
PyObject **fast;
PyCodeObject *co;
-
- if (f == NULL) {
- PyErr_BadInternalCall();
- return -1;
- }
- locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
+ locals = frame->f_locals;
if (locals == NULL) {
- locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET] = PyDict_New();
+ locals = frame->f_locals = PyDict_New();
if (locals == NULL)
return -1;
}
- co = _PyFrame_GetCode(f);
- fast = f->f_localsptr;
+ co = frame->f_code;
+ fast = _PyFrame_GetLocalsArray(frame);
for (int i = 0; i < co->co_nlocalsplus; i++) {
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
@@ -974,9 +931,9 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
PyObject *value = fast[i];
- if (f->f_state != FRAME_CLEARED) {
+ if (frame->f_state != FRAME_CLEARED) {
if (kind & CO_FAST_FREE) {
- // The cell was set by _PyEval_MakeFrameVector() from
+ // The cell was set when the frame was created from
// the function's closure.
assert(value != NULL && PyCell_Check(value));
value = PyCell_GET(value);
@@ -988,12 +945,12 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
// run yet.
if (value != NULL) {
if (PyCell_Check(value) &&
- _PyFrame_OpAlreadyRan(f, MAKE_CELL, i)) {
+ _PyFrame_OpAlreadyRan(frame, MAKE_CELL, i)) {
// (likely) MAKE_CELL must have executed already.
value = PyCell_GET(value);
}
// (likely) Otherwise it it is an arg (kind & CO_FAST_LOCAL),
- // with the initial value set by _PyEval_MakeFrameVector()...
+ // with the initial value set when the frame was created...
// (unlikely) ...or it was set to some initial value by
// an earlier call to PyFrame_LocalsToFast().
}
@@ -1021,6 +978,16 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
return 0;
}
+int
+PyFrame_FastToLocalsWithError(PyFrameObject *f)
+{
+ if (f == NULL) {
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ return _PyFrame_FastToLocalsWithError(f->f_frame);
+}
+
void
PyFrame_FastToLocals(PyFrameObject *f)
{
@@ -1034,21 +1001,18 @@ PyFrame_FastToLocals(PyFrameObject *f)
}
void
-PyFrame_LocalsToFast(PyFrameObject *f, int clear)
+_PyFrame_LocalsToFast(InterpreterFrame *frame, int clear)
{
/* Merge locals into fast locals */
PyObject *locals;
PyObject **fast;
PyObject *error_type, *error_value, *error_traceback;
PyCodeObject *co;
- if (f == NULL || f->f_state == FRAME_CLEARED) {
- return;
- }
- locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
+ locals = frame->f_locals;
if (locals == NULL)
return;
- fast = f->f_localsptr;
- co = _PyFrame_GetCode(f);
+ fast = _PyFrame_GetLocalsArray(frame);
+ co = frame->f_code;
PyErr_Fetch(&error_type, &error_value, &error_traceback);
for (int i = 0; i < co->co_nlocalsplus; i++) {
@@ -1070,7 +1034,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
PyObject *oldvalue = fast[i];
PyObject *cell = NULL;
if (kind == CO_FAST_FREE) {
- // The cell was set by _PyEval_MakeFrameVector() from
+ // The cell was set when the frame was created from
// the function's closure.
assert(oldvalue != NULL && PyCell_Check(oldvalue));
cell = oldvalue;
@@ -1078,7 +1042,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
else if (kind & CO_FAST_CELL && oldvalue != NULL) {
/* Same test as in PyFrame_FastToLocals() above. */
if (PyCell_Check(oldvalue) &&
- _PyFrame_OpAlreadyRan(f, MAKE_CELL, i)) {
+ _PyFrame_OpAlreadyRan(frame, MAKE_CELL, i)) {
// (likely) MAKE_CELL must have executed already.
cell = oldvalue;
}
@@ -1102,6 +1066,15 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
PyErr_Restore(error_type, error_value, error_traceback);
}
+void
+PyFrame_LocalsToFast(PyFrameObject *f, int clear)
+{
+ if (f == NULL || f->f_frame->f_state == FRAME_CLEARED) {
+ return;
+ }
+ _PyFrame_LocalsToFast(f->f_frame, clear);
+}
+
/* Clear out the free list */
void
_PyFrame_ClearFreeList(PyInterpreterState *interp)
@@ -1141,7 +1114,7 @@ PyCodeObject *
PyFrame_GetCode(PyFrameObject *frame)
{
assert(frame != NULL);
- PyCodeObject *code = _PyFrame_GetCode(frame);
+ PyCodeObject *code = frame->f_frame->f_code;
assert(code != NULL);
Py_INCREF(code);
return code;
@@ -1153,6 +1126,9 @@ PyFrame_GetBack(PyFrameObject *frame)
{
assert(frame != NULL);
PyFrameObject *back = frame->f_back;
+ if (back == NULL && frame->f_frame->previous != NULL) {
+ back = _PyFrame_GetFrameObject(frame->f_frame->previous);
+ }
Py_XINCREF(back);
return back;
}
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 8cc965a..86cd9cf 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -6,6 +6,7 @@
#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "frameobject.h"
+#include "pycore_frame.h"
#include "structmember.h" // PyMemberDef
#include "opcode.h"
@@ -31,10 +32,17 @@ exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
static int
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
- Py_VISIT((PyObject *)gen->gi_frame);
Py_VISIT(gen->gi_code);
Py_VISIT(gen->gi_name);
Py_VISIT(gen->gi_qualname);
+ InterpreterFrame *frame = gen->gi_xframe;
+ if (frame != NULL) {
+ assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0);
+ int err = _PyFrame_Traverse(frame, visit, arg);
+ if (err) {
+ return err;
+ }
+ }
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
participate in a reference cycle. */
return exc_state_traverse(&gen->gi_exc_state, visit, arg);
@@ -47,7 +55,7 @@ _PyGen_Finalize(PyObject *self)
PyObject *res = NULL;
PyObject *error_type, *error_value, *error_traceback;
- if (gen->gi_frame == NULL || _PyFrameHasCompleted(gen->gi_frame)) {
+ if (gen->gi_xframe == NULL || _PyFrameHasCompleted(gen->gi_xframe)) {
/* Generator isn't paused, so no need to close */
return;
}
@@ -79,7 +87,7 @@ _PyGen_Finalize(PyObject *self)
issue a RuntimeWarning. */
if (gen->gi_code != NULL &&
((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE &&
- gen->gi_frame->f_lasti == -1)
+ gen->gi_xframe->f_lasti == -1)
{
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
}
@@ -122,9 +130,11 @@ gen_dealloc(PyGenObject *gen)
and GC_Del. */
Py_CLEAR(((PyAsyncGenObject*)gen)->ag_finalizer);
}
- if (gen->gi_frame != NULL) {
- gen->gi_frame->f_gen = NULL;
- Py_CLEAR(gen->gi_frame);
+ InterpreterFrame *frame = gen->gi_xframe;
+ if (frame != NULL) {
+ gen->gi_xframe = NULL;
+ frame->previous = NULL;
+ _PyFrame_Clear(frame, 1);
}
if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) {
Py_CLEAR(((PyCoroObject *)gen)->cr_origin);
@@ -141,11 +151,11 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
int exc, int closing)
{
PyThreadState *tstate = _PyThreadState_GET();
- PyFrameObject *f = gen->gi_frame;
+ InterpreterFrame *frame = gen->gi_xframe;
PyObject *result;
*presult = NULL;
- if (f != NULL && _PyFrame_IsExecuting(f)) {
+ if (frame != NULL && _PyFrame_IsExecuting(frame)) {
const char *msg = "generator already executing";
if (PyCoro_CheckExact(gen)) {
msg = "coroutine already executing";
@@ -156,7 +166,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
PyErr_SetString(PyExc_ValueError, msg);
return PYGEN_ERROR;
}
- if (f == NULL || _PyFrameHasCompleted(f)) {
+ if (frame == NULL || _PyFrameHasCompleted(frame)) {
if (PyCoro_CheckExact(gen) && !closing) {
/* `gen` is an exhausted coroutine: raise an error,
except when called from gen_close(), which should
@@ -175,19 +185,15 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
return PYGEN_ERROR;
}
- assert(_PyFrame_IsRunnable(f));
- assert(f->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(gen->gi_code->co_code))[0] == GEN_START);
+ assert(_PyFrame_IsRunnable(frame));
+ assert(frame->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(gen->gi_code->co_code))[0] == GEN_START);
/* Push arg onto the frame's value stack */
result = arg ? arg : Py_None;
Py_INCREF(result);
- gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result;
- gen->gi_frame->f_stackdepth++;
+ frame->stack[frame->stackdepth] = result;
+ frame->stackdepth++;
- /* Generators always return to their most recent caller, not
- * necessarily their creator. */
- Py_XINCREF(tstate->frame);
- assert(f->f_back == NULL);
- f->f_back = tstate->frame;
+ frame->previous = tstate->frame;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
@@ -197,20 +203,20 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
_PyErr_ChainStackItem(NULL);
}
- result = _PyEval_EvalFrame(tstate, f, exc);
+ result = _PyEval_EvalFrame(tstate, frame, exc);
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
- /* Don't keep the reference to f_back any longer than necessary. It
+ assert(tstate->frame == frame->previous);
+ /* Don't keep the reference to previous any longer than necessary. It
* may keep a chain of frames alive or it could create a reference
* cycle. */
- assert(f->f_back == tstate->frame);
- Py_CLEAR(f->f_back);
+ frame->previous = NULL;
/* If the generator just returned (as opposed to yielding), signal
* that the generator is exhausted. */
if (result) {
- if (!_PyFrameHasCompleted(f)) {
+ if (!_PyFrameHasCompleted(frame)) {
*presult = result;
return PYGEN_NEXT;
}
@@ -245,10 +251,10 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
/* generator can't be rerun, so release the frame */
/* first clean reference cycle through stored exception traceback */
_PyErr_ClearExcState(&gen->gi_exc_state);
- gen->gi_frame->f_gen = NULL;
- gen->gi_frame = NULL;
- Py_DECREF(f);
+ frame->generator = NULL;
+ gen->gi_xframe = NULL;
+ _PyFrame_Clear(frame, 1);
*presult = result;
return result ? PYGEN_RETURN : PYGEN_ERROR;
}
@@ -328,13 +334,13 @@ PyObject *
_PyGen_yf(PyGenObject *gen)
{
PyObject *yf = NULL;
- PyFrameObject *f = gen->gi_frame;
- if (f) {
+ if (gen->gi_xframe) {
+ InterpreterFrame *frame = gen->gi_xframe;
PyObject *bytecode = gen->gi_code->co_code;
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
- if (f->f_lasti < 0) {
+ if (frame->f_lasti < 0) {
/* Return immediately if the frame didn't start yet. YIELD_FROM
always come after LOAD_CONST: a code object should not start
with YIELD_FROM */
@@ -342,10 +348,10 @@ _PyGen_yf(PyGenObject *gen)
return NULL;
}
- if (code[(f->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM)
+ if (code[(frame->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM)
return NULL;
- assert(f->f_stackdepth > 0);
- yf = f->f_valuestack[f->f_stackdepth-1];
+ assert(frame->stackdepth > 0);
+ yf = frame->stack[frame->stackdepth-1];
Py_INCREF(yf);
}
@@ -360,10 +366,10 @@ gen_close(PyGenObject *gen, PyObject *args)
int err = 0;
if (yf) {
- PyFrameState state = gen->gi_frame->f_state;
- gen->gi_frame->f_state = FRAME_EXECUTING;
+ PyFrameState state = gen->gi_xframe->f_state;
+ gen->gi_xframe->f_state = FRAME_EXECUTING;
err = gen_close_iter(yf);
- gen->gi_frame->f_state = state;
+ gen->gi_xframe->f_state = state;
Py_DECREF(yf);
}
if (err == 0)
@@ -410,10 +416,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
We have to allow some awaits to work it through, hence the
`close_on_genexit` parameter here.
*/
- PyFrameState state = gen->gi_frame->f_state;
- gen->gi_frame->f_state = FRAME_EXECUTING;
+ PyFrameState state = gen->gi_xframe->f_state;
+ gen->gi_xframe->f_state = FRAME_EXECUTING;
err = gen_close_iter(yf);
- gen->gi_frame->f_state = state;
+ gen->gi_xframe->f_state = state;
Py_DECREF(yf);
if (err < 0)
return gen_send_ex(gen, Py_None, 1, 0);
@@ -422,22 +428,26 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
if (PyGen_CheckExact(yf) || PyCoro_CheckExact(yf)) {
/* `yf` is a generator or a coroutine. */
PyThreadState *tstate = _PyThreadState_GET();
- PyFrameObject *f = tstate->frame;
+ InterpreterFrame *frame = gen->gi_xframe;
+
/* Since we are fast-tracking things by skipping the eval loop,
we need to update the current frame so the stack trace
will be reported correctly to the user. */
/* XXX We should probably be updating the current frame
somewhere in ceval.c. */
- tstate->frame = gen->gi_frame;
+ InterpreterFrame *prev = tstate->frame;
+ frame->previous = prev;
+ tstate->frame = frame;
/* Close the generator that we are currently iterating with
'yield from' or awaiting on with 'await'. */
- PyFrameState state = gen->gi_frame->f_state;
- gen->gi_frame->f_state = FRAME_EXECUTING;
+ PyFrameState state = gen->gi_xframe->f_state;
+ gen->gi_xframe->f_state = FRAME_EXECUTING;
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
typ, val, tb);
- gen->gi_frame->f_state = state;
- tstate->frame = f;
+ gen->gi_xframe->f_state = state;
+ tstate->frame = prev;
+ frame->previous = NULL;
} else {
/* `yf` is an iterator or a coroutine-like object. */
PyObject *meth;
@@ -449,24 +459,24 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
Py_DECREF(yf);
goto throw_here;
}
- PyFrameState state = gen->gi_frame->f_state;
- gen->gi_frame->f_state = FRAME_EXECUTING;
+ PyFrameState state = gen->gi_xframe->f_state;
+ gen->gi_xframe->f_state = FRAME_EXECUTING;
ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL);
- gen->gi_frame->f_state = state;
+ gen->gi_xframe->f_state = state;
Py_DECREF(meth);
}
Py_DECREF(yf);
if (!ret) {
PyObject *val;
/* Pop subiterator from stack */
- assert(gen->gi_frame->f_stackdepth > 0);
- gen->gi_frame->f_stackdepth--;
- ret = gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth];
+ assert(gen->gi_xframe->stackdepth > 0);
+ gen->gi_xframe->stackdepth--;
+ ret = gen->gi_xframe->stack[gen->gi_xframe->stackdepth];
assert(ret == yf);
Py_DECREF(ret);
/* Termination repetition of YIELD_FROM */
- assert(gen->gi_frame->f_lasti >= 0);
- gen->gi_frame->f_lasti += 1;
+ assert(gen->gi_xframe->f_lasti >= 0);
+ gen->gi_xframe->f_lasti += 1;
if (_PyGen_FetchStopIterationValue(&val) == 0) {
ret = gen_send(gen, val);
Py_DECREF(val);
@@ -723,10 +733,28 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored))
static PyObject *
gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored))
{
- if (gen->gi_frame == NULL) {
+ if (gen->gi_xframe == NULL) {
Py_RETURN_FALSE;
}
- return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_frame));
+ return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_xframe));
+}
+
+static PyObject *
+_gen_getframe(PyGenObject *gen, const char *const name)
+{
+ if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
+ return NULL;
+ }
+ if (gen->gi_xframe == NULL) {
+ Py_RETURN_NONE;
+ }
+ return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(gen->gi_xframe));
+}
+
+static PyObject *
+gen_getframe(PyGenObject *gen, void *Py_UNUSED(ignored))
+{
+ return _gen_getframe(gen, "gi_frame");
}
static PyGetSetDef gen_getsetlist[] = {
@@ -737,11 +765,11 @@ static PyGetSetDef gen_getsetlist[] = {
{"gi_yieldfrom", (getter)gen_getyieldfrom, NULL,
PyDoc_STR("object being iterated by yield from, or None")},
{"gi_running", (getter)gen_getrunning, NULL, NULL},
+ {"gi_frame", (getter)gen_getframe, NULL, NULL},
{NULL} /* Sentinel */
};
static PyMemberDef gen_memberlist[] = {
- {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|PY_AUDIT_READ},
{"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|PY_AUDIT_READ},
{NULL} /* Sentinel */
};
@@ -815,6 +843,84 @@ PyTypeObject PyGen_Type = {
};
static PyObject *
+make_gen(PyTypeObject *type, PyFrameConstructor *con, InterpreterFrame *frame)
+{
+ PyGenObject *gen = PyObject_GC_New(PyGenObject, type);
+ if (gen == NULL) {
+ assert(frame->frame_obj == NULL);
+ _PyFrame_Clear(frame, 1);
+ return NULL;
+ }
+ gen->gi_xframe = frame;
+ frame->generator = (PyObject *)gen;
+ gen->gi_code = frame->f_code;
+ Py_INCREF(gen->gi_code);
+ gen->gi_weakreflist = NULL;
+ gen->gi_exc_state.exc_type = NULL;
+ gen->gi_exc_state.exc_value = NULL;
+ gen->gi_exc_state.exc_traceback = NULL;
+ gen->gi_exc_state.previous_item = NULL;
+ if (con->fc_name != NULL)
+ gen->gi_name = con->fc_name;
+ else
+ gen->gi_name = gen->gi_code->co_name;
+ Py_INCREF(gen->gi_name);
+ if (con->fc_qualname != NULL)
+ gen->gi_qualname = con->fc_qualname;
+ else
+ gen->gi_qualname = gen->gi_name;
+ Py_INCREF(gen->gi_qualname);
+ _PyObject_GC_TRACK(gen);
+ return (PyObject *)gen;
+}
+
+static PyObject *
+compute_cr_origin(int origin_depth);
+
+PyObject *
+_Py_MakeCoro(PyFrameConstructor *con, InterpreterFrame *frame)
+{
+ int coro_flags = ((PyCodeObject *)con->fc_code)->co_flags &
+ (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
+ assert(coro_flags);
+ if (coro_flags == CO_GENERATOR) {
+ return make_gen(&PyGen_Type, con, frame);
+ }
+ if (coro_flags == CO_ASYNC_GENERATOR) {
+ PyAsyncGenObject *o;
+ o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, con, frame);
+ if (o == NULL) {
+ return NULL;
+ }
+ o->ag_finalizer = NULL;
+ o->ag_closed = 0;
+ o->ag_hooks_inited = 0;
+ o->ag_running_async = 0;
+ return (PyObject*)o;
+ }
+ assert (coro_flags == CO_COROUTINE);
+ PyObject *coro = make_gen(&PyCoro_Type, con, frame);
+ if (!coro) {
+ return NULL;
+ }
+ PyThreadState *tstate = _PyThreadState_GET();
+ int origin_depth = tstate->coroutine_origin_tracking_depth;
+
+ if (origin_depth == 0) {
+ ((PyCoroObject *)coro)->cr_origin = NULL;
+ } else {
+ PyObject *cr_origin = compute_cr_origin(origin_depth);
+ ((PyCoroObject *)coro)->cr_origin = cr_origin;
+ if (!cr_origin) {
+ Py_DECREF(coro);
+ return NULL;
+ }
+ }
+
+ return coro;
+}
+
+static PyObject *
gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
PyObject *name, PyObject *qualname)
{
@@ -823,8 +929,16 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
Py_DECREF(f);
return NULL;
}
- gen->gi_frame = f;
- f->f_gen = (PyObject *) gen;
+
+ /* Take ownership of the frame */
+ assert(f->f_frame->frame_obj == NULL);
+ assert(f->f_own_locals_memory);
+ gen->gi_xframe = f->f_frame;
+ gen->gi_xframe->frame_obj = f;
+ f->f_own_locals_memory = 0;
+ gen->gi_xframe->generator = (PyObject *) gen;
+ assert(PyObject_GC_IsTracked((PyObject *)f));
+
gen->gi_code = PyFrame_GetCode(f);
gen->gi_weakreflist = NULL;
gen->gi_exc_state.exc_type = NULL;
@@ -958,12 +1072,19 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
static PyObject *
cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored))
{
- if (coro->cr_frame == NULL) {
+ if (coro->cr_xframe == NULL) {
Py_RETURN_FALSE;
}
- return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_frame));
+ return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_xframe));
+}
+
+static PyObject *
+cr_getframe(PyCoroObject *coro, void *Py_UNUSED(ignored))
+{
+ return _gen_getframe((PyGenObject *)coro, "cr_frame");
}
+
static PyGetSetDef coro_getsetlist[] = {
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
PyDoc_STR("name of the coroutine")},
@@ -972,11 +1093,11 @@ static PyGetSetDef coro_getsetlist[] = {
{"cr_await", (getter)coro_get_cr_await, NULL,
PyDoc_STR("object being awaited on, or None")},
{"cr_running", (getter)cr_getrunning, NULL, NULL},
+ {"cr_frame", (getter)cr_getframe, NULL, NULL},
{NULL} /* Sentinel */
};
static PyMemberDef coro_memberlist[] = {
- {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|PY_AUDIT_READ},
{"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|PY_AUDIT_READ},
{"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin), READONLY},
{NULL} /* Sentinel */
@@ -1150,11 +1271,11 @@ PyTypeObject _PyCoroWrapper_Type = {
static PyObject *
compute_cr_origin(int origin_depth)
{
- PyFrameObject *frame = PyEval_GetFrame();
+ InterpreterFrame *frame = _PyEval_GetFrame();
/* First count how many frames we have */
int frame_count = 0;
for (; frame && frame_count < origin_depth; ++frame_count) {
- frame = frame->f_back;
+ frame = frame->previous;
}
/* Now collect them */
@@ -1162,20 +1283,19 @@ compute_cr_origin(int origin_depth)
if (cr_origin == NULL) {
return NULL;
}
- frame = PyEval_GetFrame();
+ frame = _PyEval_GetFrame();
for (int i = 0; i < frame_count; ++i) {
- PyCodeObject *code = PyFrame_GetCode(frame);
+ PyCodeObject *code = frame->f_code;
PyObject *frameinfo = Py_BuildValue("OiO",
code->co_filename,
- PyFrame_GetLineNumber(frame),
+ PyCode_Addr2Line(frame->f_code, frame->f_lasti*2),
code->co_name);
- Py_DECREF(code);
if (!frameinfo) {
Py_DECREF(cr_origin);
return NULL;
}
PyTuple_SET_ITEM(cr_origin, i, frameinfo);
- frame = frame->f_back;
+ frame = frame->previous;
}
return cr_origin;
@@ -1346,6 +1466,11 @@ async_gen_athrow(PyAsyncGenObject *o, PyObject *args)
return async_gen_athrow_new(o, args);
}
+static PyObject *
+ag_getframe(PyAsyncGenObject *ag, void *Py_UNUSED(ignored))
+{
+ return _gen_getframe((PyGenObject *)ag, "ag_frame");
+}
static PyGetSetDef async_gen_getsetlist[] = {
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
@@ -1354,11 +1479,11 @@ static PyGetSetDef async_gen_getsetlist[] = {
PyDoc_STR("qualified name of the async generator")},
{"ag_await", (getter)coro_get_cr_await, NULL,
PyDoc_STR("object being awaited on, or None")},
+ {"ag_frame", (getter)ag_getframe, NULL, NULL},
{NULL} /* Sentinel */
};
static PyMemberDef async_gen_memberlist[] = {
- {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), READONLY|PY_AUDIT_READ},
{"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async),
READONLY},
{"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|PY_AUDIT_READ},
@@ -1865,7 +1990,7 @@ static PyObject *
async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
{
PyGenObject *gen = (PyGenObject*)o->agt_gen;
- PyFrameObject *f = gen->gi_frame;
+ InterpreterFrame *frame = gen->gi_xframe;
PyObject *retval;
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
@@ -1875,7 +2000,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
return NULL;
}
- if (f == NULL || _PyFrameHasCompleted(f)) {
+ if (frame == NULL || _PyFrameHasCompleted(frame)) {
o->agt_state = AWAITABLE_STATE_CLOSED;
PyErr_SetNone(PyExc_StopIteration);
return NULL;
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 42a9978..43b4d07 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -11,6 +11,7 @@
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_unionobject.h" // _Py_union_type_or
#include "frameobject.h"
+#include "pycore_frame.h"
#include "opcode.h" // MAKE_CELL
#include "structmember.h" // PyMemberDef
@@ -8867,12 +8868,13 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
return -1;
}
- PyObject *firstarg = f->f_localsptr[0];
+ assert(f->f_frame->nlocalsplus > 0);
+ PyObject *firstarg = _PyFrame_GetLocalsArray(f->f_frame)[0];
// The first argument might be a cell.
if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) {
// "firstarg" is a cell here unless (very unlikely) super()
// was called from the C-API before the first MAKE_CELL op.
- if (f->f_lasti >= 0) {
+ if (f->f_frame->f_lasti >= 0) {
assert(_Py_OPCODE(*co->co_firstinstr) == MAKE_CELL);
assert(PyCell_Check(firstarg));
firstarg = PyCell_GET(firstarg);
@@ -8892,7 +8894,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
assert(PyUnicode_Check(name));
if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
- PyObject *cell = f->f_localsptr[i];
+ PyObject *cell = _PyFrame_GetLocalsArray(f->f_frame)[i];
if (cell == NULL || !PyCell_Check(cell)) {
PyErr_SetString(PyExc_RuntimeError,
"super(): bad __class__ cell");