Skip to content

Commit ebad413

Browse files
committed
Update generator logic
1 parent ead5d4f commit ebad413

8 files changed

Lines changed: 19 additions & 12 deletions

File tree

Include/cpython/funcobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ typedef struct {
4343
PyObject *func_annotations; /* Annotations, a dict or NULL */
4444
PyObject *func_annotate; /* Callable to fill the annotations dictionary */
4545
PyObject *func_typeparams; /* Tuple of active type variables or NULL */
46-
PyObject *func_old_codes;
46+
PyObject *func_old_codes; /* NULL or list of past code objects */
4747
vectorcallfunc vectorcall;
4848
/* Version number for use by specializer.
4949
* Can set to non-zero when we want to specialize.

Include/internal/pycore_interpframe.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
160160
}
161161
}
162162

163+
/* Generator frames need a strong reference to the code object */
164+
static inline void _PyFrame_CopyForGenerators(_PyInterpreterFrame *old_frame, _PyInterpreterFrame *gen_frame) {
165+
_PyFrame_Copy(old_frame, gen_frame);
166+
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
167+
gen_frame->f_executable = PyStackRef_MakeHeapSafe(gen_frame->f_executable);
168+
}
169+
163170
#ifdef Py_GIL_DISABLED
164171
static inline void
165172
_PyFrame_InitializeTLBC(PyThreadState *tstate, _PyInterpreterFrame *frame,

Include/internal/pycore_interpframe_structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ enum _frameowner {
2727
};
2828

2929
struct _PyInterpreterFrame {
30-
_PyStackRef f_executable; /* Deferred or strong reference (code object or None) */
30+
_PyStackRef f_executable; /* Borrowed reference (code object or None) */
3131
struct _PyInterpreterFrame *previous;
3232
_PyStackRef f_funcobj; /* Deferred or strong reference. Only valid if not on C stack */
3333
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */

Modules/_testinternalcapi/test_cases.c.h

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/genobject.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ gen_traverse(PyObject *self, visitproc visit, void *arg)
9393
return err;
9494
}
9595
}
96+
else {
97+
// We still need to visit the code object when the frame is cleared to
98+
// ensure that it's kept alive if the reference is deferred.
99+
_Py_VISIT_STACKREF(gen->gi_iframe.f_executable);
100+
}
96101
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
97102
participate in a reference cycle. */
98103
Py_VISIT(gen->gi_exc_state.exc_value);
@@ -1171,11 +1176,10 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
11711176
assert(f->f_frame->frame_obj == NULL);
11721177
assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT);
11731178
_PyInterpreterFrame *frame = &gen->gi_iframe;
1174-
_PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame);
1179+
_PyFrame_CopyForGenerators((_PyInterpreterFrame *)f->_f_frame_data, frame);
11751180
gen->gi_frame_state = FRAME_CREATED;
11761181
assert(frame->frame_obj == f);
11771182
f->f_frame = frame;
1178-
frame->owner = FRAME_OWNED_BY_GENERATOR;
11791183
assert(PyObject_GC_IsTracked((PyObject *)f));
11801184
Py_DECREF(f);
11811185
gen->gi_weakreflist = NULL;

Python/bytecodes.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5854,10 +5854,9 @@ dummy_func(
58545854
SAVE_STACK();
58555855
_PyInterpreterFrame *gen_frame = &gen->gi_iframe;
58565856
frame->instr_ptr++;
5857-
_PyFrame_Copy(frame, gen_frame);
5857+
_PyFrame_CopyForGenerators(frame, gen_frame);
58585858
assert(frame->frame_obj == NULL);
58595859
gen->gi_frame_state = FRAME_CREATED;
5860-
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
58615860
_Py_LeaveRecursiveCallPy(tstate);
58625861
_PyInterpreterFrame *prev = frame->previous;
58635862
_PyThreadState_UpdateLastProfiledFrame(tstate, frame, prev);

Python/executor_cases.c.h

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)