@@ -50,42 +50,25 @@ int jitgen_traverse(PyObject* obj, visitproc visit, void* arg) {
5050 JitGenObject* jit_gen = JitGenObject::cast (obj);
5151 if (jit_gen != nullptr ) {
5252 const GenDataFooter* gen_footer = jit_gen->genDataFooter ();
53- // Only visit JIT-specific live values if we have a valid yield point.
54- // If yieldPoint is null, the generator hasn't yielded yet or has completed,
55- // but we still need to call PyGen_Type.tp_traverse below to visit standard
56- // generator references (gi_code, gi_frame, etc.).
57- if (gen_footer->yieldPoint != nullptr ) {
58- size_t deopt_idx = gen_footer->yieldPoint ->deoptIdx ();
59- const DeoptMetadata& meta =
60- gen_footer->code_rt ->getDeoptMetadata (deopt_idx);
61- for (const LiveValue& value : meta.live_values ) {
62- if (value.ref_kind != hir::RefKind::kOwned ) {
63- continue ;
64- }
65- codegen::PhyLocation loc = value.location ;
66- JIT_CHECK (
67- !loc.is_register (),
68- " DeoptMetadata for Yields should not reference registers" );
69- PyObject* v = *reinterpret_cast <PyObject**>(
70- reinterpret_cast <uintptr_t >(gen_footer) + loc.loc );
71- Py_VISIT (v);
72- }
73- JIT_CHECK (JitGen_CheckAny (obj), " Deopted during GC traversal" );
53+ if (gen_footer->yieldPoint == nullptr ) {
54+ return 0 ;
7455 }
75-
76- #if PY_VERSION_HEX < 0x030E0000
77- // In lightweight frame mode, frame->f_funcobj is set to a reifier singleton
78- // rather than the actual function. The real function is stored in the
79- // FrameHeader and contains func_closure with closure cells that may
80- // participate in reference cycles. We must visit it explicitly since
81- // _PyFrame_Traverse won't see it.
82- if (getConfig ().frame_mode == FrameMode::kLightweight &&
83- jit_gen->gi_frame_state < FRAME_CLEARED ) {
84- _PyInterpreterFrame* frame = generatorFrame (jit_gen);
85- BorrowedRef<PyFunctionObject> func = jitFrameGetFunction (frame);
86- Py_VISIT (func.get ());
56+ size_t deopt_idx = gen_footer->yieldPoint ->deoptIdx ();
57+ const DeoptMetadata& meta =
58+ gen_footer->code_rt ->getDeoptMetadata (deopt_idx);
59+ for (const LiveValue& value : meta.live_values ) {
60+ if (value.ref_kind != hir::RefKind::kOwned ) {
61+ continue ;
62+ }
63+ codegen::PhyLocation loc = value.location ;
64+ JIT_CHECK (
65+ !loc.is_register (),
66+ " DeoptMetadata for Yields should not reference registers" );
67+ PyObject* v = *reinterpret_cast <PyObject**>(
68+ reinterpret_cast <uintptr_t >(gen_footer) + loc.loc );
69+ Py_VISIT (v);
8770 }
88- # endif
71+ JIT_CHECK ( JitGen_CheckAny (obj), " Deopted during GC traversal " );
8972 }
9073 // Try to use CPython traverse as much as we can as it has internals which
9174 // are hard to borrow in 3.14 (compares 'visit' to a speicifc internal
@@ -354,26 +337,6 @@ void jitgen_finalize(PyObject* obj) {
354337 PyGen_Type.tp_finalize (obj);
355338}
356339
357- int jitgen_clear (PyObject* obj) {
358- // tp_clear is called by the cyclic GC to break reference cycles.
359- // We need to deopt the JIT generator so that the standard generator
360- // tp_clear can properly clear all references.
361- //
362- // If the generator is currently executing (gi_frame_state ==
363- // FRAME_EXECUTING), we cannot deopt it. In that case, return 0 without
364- // clearing - the GC will try again later or the generator will complete and
365- // be collected normally.
366- if (!deopt_jit_gen (obj)) {
367- return 0 ;
368- }
369- // After deopting, the object is now a regular PyGenObject/PyCoroObject.
370- // Delegate to the base type's tp_clear to break cycles.
371- if (PyGen_Type.tp_clear != nullptr ) {
372- return PyGen_Type.tp_clear (obj);
373- }
374- return 0 ;
375- }
376-
377340typedef struct {
378341 PyObject_HEAD
379342 PyObject* cw_coroutine;
@@ -637,7 +600,6 @@ static PyAsyncMethods jitcoro_as_async = {
637600PyType_Slot gen_slots[] = {
638601 {Py_tp_dealloc, reinterpret_cast <void *>(jitgen_dealloc)},
639602 {Py_tp_traverse, reinterpret_cast <void *>(jitgen_traverse)},
640- {Py_tp_clear, reinterpret_cast <void *>(jitgen_clear)},
641603 {Py_tp_finalize, reinterpret_cast <void *>(jitgen_finalize)},
642604 {Py_tp_iter, reinterpret_cast <void *>(PyObject_SelfIter)},
643605 {Py_tp_iternext, reinterpret_cast <void *>(jitgen_iternext)},
@@ -673,7 +635,6 @@ static_assert(sizeof(PyGenObject) == sizeof(PyCoroObject));
673635PyType_Slot coro_slots[] = {
674636 {Py_tp_dealloc, reinterpret_cast <void *>(jitgen_dealloc)},
675637 {Py_tp_traverse, reinterpret_cast <void *>(jitgen_traverse)},
676- {Py_tp_clear, reinterpret_cast <void *>(jitgen_clear)},
677638 {Py_tp_finalize, reinterpret_cast <void *>(jitgen_finalize)},
678639 {Py_tp_methods, jitcoro_methods},
679640 {Py_tp_members, jitcoro_memberlist},
@@ -705,16 +666,7 @@ void deopt_jit_gen_object_only(JitGenObject* gen) {
705666 Py_SET_TYPE (reinterpret_cast <PyObject*>(gen), type);
706667 if (getConfig ().frame_mode == FrameMode::kLightweight ) {
707668 auto frame = generatorFrame (gen);
708- if (gen->gi_frame_state != FRAME_CLEARED ) {
709- jitFrameRemoveReifier (frame);
710- } else if constexpr (PY_VERSION_HEX < 0x030E0000 ) {
711- // Normally we'll clear the function via jitFrameClearExceptCode. But
712- // a user can call clear on a reified frame object which transfers
713- // ownership of the _PyInterpreterFrame to the PyFrameObject and marks
714- // the generator frame as cleared. In that case we still need to decref
715- // the function which is stored before the _PyInterpreterFrame in 3.12.
716- Py_XDECREF (jitFrameGetFunction (frame));
717- }
669+ jitFrameRemoveReifier (frame);
718670 }
719671}
720672
0 commit comments