1212#include " cinderx/Jit/deopt.h"
1313#include " cinderx/Jit/frame.h"
1414#include " cinderx/Jit/generators_borrowed.h"
15+ #include " cinderx/Jit/generators_mm.h"
16+ #include " cinderx/Jit/generators_rt.h"
1517#include " cinderx/Jit/runtime.h"
18+ #include " cinderx/UpstreamBorrow/borrowed.h"
1619#include " cinderx/module_state.h"
1720
1821#include < string_view>
@@ -32,11 +35,57 @@ PyObject* JitGenObject::yieldFrom() {
3235
3336namespace {
3437
35- void jitgen_dealloc (PyObject* obj) {
36- if (!deopt_jit_gen (obj)) {
38+ const destructor original_gen_dealloc = PyGen_Type.tp_dealloc;
39+ const destructor original_coro_dealloc = PyCoro_Type.tp_dealloc;
40+
41+ // This is mostly a copy of gen_dealloc from genobject.c but with a deopt at the
42+ // start, using our own memory manager for free at the end, some minor
43+ // tweaks for C++, and to use public APIs.
44+ void jitgen_dealloc (PyObject* self) {
45+ if (!deopt_jit_gen (self)) {
3746 JIT_ABORT (" Tried to dealloc a running JIT generator" );
3847 }
39- return Py_TYPE (obj)->tp_dealloc (obj);
48+
49+ PyGenObject* gen = reinterpret_cast <PyGenObject*>(self);
50+
51+ PyObject_GC_UnTrack (gen);
52+
53+ if (gen->gi_weakreflist != nullptr ) {
54+ PyObject_ClearWeakRefs (self);
55+ }
56+
57+ PyObject_GC_Track (self);
58+
59+ if (PyObject_CallFinalizerFromDealloc (self)) {
60+ return ; /* resurrected. :( */
61+ }
62+
63+ PyObject_GC_UnTrack (self);
64+ if (PyAsyncGen_CheckExact (gen)) {
65+ /* We have to handle this case for asynchronous generators
66+ right here, because this code has to be between UNTRACK
67+ and GC_Del. */
68+ Py_CLEAR (reinterpret_cast <PyAsyncGenObject*>(gen)->ag_origin_or_finalizer );
69+ }
70+ if (gen->gi_frame_state < FRAME_CLEARED ) {
71+ _PyInterpreterFrame* frame = generatorFrame (gen);
72+ gen->gi_frame_state = FRAME_CLEARED ;
73+ frame->previous = nullptr ;
74+ _PyFrame_ClearExceptCode (frame);
75+ }
76+ PyCodeObject* code = frameCode (generatorFrame (gen));
77+ if (code->co_flags & CO_COROUTINE ) {
78+ Py_CLEAR (reinterpret_cast <PyCoroObject*>(gen)->cr_origin_or_finalizer );
79+ }
80+ Py_DECREF (code);
81+ Py_CLEAR (gen->gi_name );
82+ Py_CLEAR (gen->gi_qualname );
83+ _PyErr_ClearExcState (&gen->gi_exc_state );
84+ #if PY_VERSION_HEX < 0x030E0000
85+ Py_CLEAR (gen->gi_ci_awaiter );
86+ #endif
87+
88+ cinderx::getModuleState ()->jitGenFreeList ()->free (self);
4089}
4190
4291int jitgen_traverse (PyObject* obj, visitproc visit, void * arg) {
@@ -715,6 +764,10 @@ void init_jit_genobject_type() {
715764 auto copy_getset = [](PyGetSetDef* src, PyGetSetDef* target) {
716765 int i;
717766 for (i = 0 ; src[i].name != nullptr ; ++i) {
767+ JIT_CHECK (
768+ target[i].name != nullptr ,
769+ " Missing getter/setter on JIT generator: {}" ,
770+ src[i].name );
718771 JIT_CHECK (
719772 std::string_view (target[i].name ) == src[i].name ,
720773 " Name mismatch: {} != {}" ,
@@ -744,6 +797,10 @@ void init_jit_genobject_type() {
744797 auto copy_methods = [](PyMethodDef* src, PyMethodDef* target) {
745798 int i;
746799 for (i = 0 ; src[i].ml_name != nullptr ; ++i) {
800+ JIT_CHECK (
801+ target[i].ml_name != nullptr ,
802+ " Missing method on JIT generator: {}" ,
803+ src[i].ml_name );
747804 JIT_CHECK (
748805 std::string_view (target[i].ml_name ) == src[i].ml_name ,
749806 " Name mismatch: {} != {}" ,
@@ -766,6 +823,16 @@ void init_jit_genobject_type() {
766823 copy_methods (PyGen_Type.tp_methods , gen_type->tp_methods );
767824 copy_methods (PyCoro_Type.tp_methods , coro_type->tp_methods );
768825
826+ cinderx::getModuleState ()->setJitGenFreeList (new JitGenFreeList ());
827+
828+ // Override dealloc so we can use a "free-list" for our objects.
829+ JIT_CHECK (
830+ PyGen_Type.tp_dealloc == original_gen_dealloc &&
831+ PyCoro_Type.tp_dealloc == original_coro_dealloc,
832+ " PyGen/Coro_Type already overridden" );
833+ PyGen_Type.tp_dealloc = reinterpret_cast <destructor>(jitgen_dealloc);
834+ PyCoro_Type.tp_dealloc = reinterpret_cast <destructor>(jitgen_dealloc);
835+
769836#ifdef ENABLE_GENERATOR_AWAITER
770837 JIT_CHECK (
771838 PyCoro_Type.tp_flags & Ci_TPFLAGS_HAVE_AM_EXTRA,
@@ -776,6 +843,11 @@ void init_jit_genobject_type() {
776843#endif
777844}
778845
846+ void shutdown_jit_genobject_type () {
847+ PyGen_Type.tp_dealloc = original_gen_dealloc;
848+ PyCoro_Type.tp_dealloc = original_coro_dealloc;
849+ }
850+
779851static PyMethodDef anextawaitable_methods[] = {
780852 {" send" , (PyCFunction)Ci_anextawaitable_send, METH_O , " " },
781853 {" throw" , (PyCFunction)Ci_anextawaitable_throw, METH_VARARGS , " " },
0 commit comments