Skip to content

Commit 8ef7647

Browse files
committed
generators borrowed reference code objects
1 parent 5262271 commit 8ef7647

10 files changed

Lines changed: 17 additions & 23 deletions

File tree

Include/internal/pycore_interpframe.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,6 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
159159
}
160160
}
161161

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

Include/internal/pycore_interpframe_structs.h

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

2929
struct _PyInterpreterFrame {
30-
/* Borrowed reference (code object or None) */
31-
/* Strong reference for generators */
32-
PyObject *f_executable;
30+
PyObject *f_executable; /* Borrowed reference (code object or None) */
3331
struct _PyInterpreterFrame *previous;
3432
_PyStackRef f_funcobj; /* Deferred or strong reference. Only valid if not on C stack */
3533
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
Avoid reference counting of :class:`code` objects when creating and destroying
22
frames by having functions retain a list of all past :class:`code` objects.
3-

Modules/_testinternalcapi/test_cases.c.h

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

Objects/genobject.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ gen_traverse(PyObject *self, visitproc visit, void *arg)
9494
}
9595
}
9696
else {
97-
// We still need to visit the code object when the frame is cleared to
97+
// We still need to visit the function object when the frame is cleared to
9898
// ensure that it's kept alive if the reference is deferred.
99-
Py_VISIT(gen->gi_iframe.f_executable);
99+
_Py_VISIT_STACKREF(gen->gi_iframe.f_funcobj);
100100
}
101101
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
102102
participate in a reference cycle. */
@@ -231,7 +231,7 @@ gen_dealloc(PyObject *self)
231231
gen_clear_frame(gen);
232232
}
233233
assert(gen->gi_exc_state.exc_value == NULL);
234-
Py_CLEAR(gen->gi_iframe.f_executable);
234+
gen->gi_iframe.f_executable = NULL;
235235
Py_CLEAR(gen->gi_name);
236236
Py_CLEAR(gen->gi_qualname);
237237

@@ -1176,10 +1176,11 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
11761176
assert(f->f_frame->frame_obj == NULL);
11771177
assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT);
11781178
_PyInterpreterFrame *frame = &gen->gi_iframe;
1179-
_PyFrame_CopyForGenerators((_PyInterpreterFrame *)f->_f_frame_data, frame);
1179+
_PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame);
11801180
gen->gi_frame_state = FRAME_CREATED;
11811181
assert(frame->frame_obj == f);
11821182
f->f_frame = frame;
1183+
frame->owner = FRAME_OWNED_BY_GENERATOR;
11831184
assert(PyObject_GC_IsTracked((PyObject *)f));
11841185
Py_DECREF(f);
11851186
gen->gi_weakreflist = NULL;

Python/bytecodes.c

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

Python/ceval.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,9 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
19971997
gen->gi_exc_state.previous_item = NULL;
19981998
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
19991999
frame->previous = NULL;
2000+
if (PyGen_Check(gen)) {
2001+
frame->f_funcobj = PyStackRef_DUP(frame->f_funcobj);
2002+
}
20002003
_PyFrame_ClearExceptCode(frame);
20012004
_PyErr_ClearExcState(&gen->gi_exc_state);
20022005
// gh-143939: There must not be any escaping calls between setting

Python/executor_cases.c.h

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

Python/frame.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
5151
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
5252
_PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)f->_f_frame_data;
5353
_PyFrame_Copy(frame, new_frame);
54-
// _PyFrame_Copy takes the reference to the executable,
55-
// so we need to restore it.
5654
f->f_frame = new_frame;
5755
new_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
5856
if (_PyFrame_IsIncomplete(new_frame)) {

Python/generated_cases.c.h

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

0 commit comments

Comments
 (0)