@@ -186,6 +186,16 @@ def generate_class_type_decl(
186186 )
187187
188188
189+ def generate_class_reuse (
190+ cl : ClassIR , c_emitter : Emitter , external_emitter : Emitter , emitter : Emitter
191+ ) -> None :
192+ assert cl .reuse_freed_instance
193+ context = c_emitter .context
194+ name = cl .name_prefix (c_emitter .names ) + "_free_instance"
195+ struct_name = cl .struct_name (c_emitter .names )
196+ context .declarations [name ] = HeaderDeclaration (f"{ struct_name } *{ name } ;" , needs_export = True )
197+
198+
189199def generate_class (cl : ClassIR , module : str , emitter : Emitter ) -> None :
190200 """Generate C code for a class.
191201
@@ -557,7 +567,17 @@ def generate_setup_for_class(
557567 emitter .emit_line ("static PyObject *" )
558568 emitter .emit_line (f"{ func_name } (PyTypeObject *type)" )
559569 emitter .emit_line ("{" )
560- emitter .emit_line (f"{ cl .struct_name (emitter .names )} *self;" )
570+ struct_name = cl .struct_name (emitter .names )
571+ emitter .emit_line (f"{ struct_name } *self;" )
572+
573+ prefix = cl .name_prefix (emitter .names )
574+ if cl .reuse_freed_instance :
575+ emitter .emit_line (f"if ({ prefix } _free_instance != NULL) {{" )
576+ emitter .emit_line (f"self = { prefix } _free_instance;" )
577+ emitter .emit_line (f"{ prefix } _free_instance = NULL;" )
578+ emitter .emit_line ("return (PyObject *)self;" )
579+ emitter .emit_line ("}" )
580+
561581 emitter .emit_line (f"self = ({ cl .struct_name (emitter .names )} *)type->tp_alloc(type, 0);" )
562582 emitter .emit_line ("if (self == NULL)" )
563583 emitter .emit_line (" return NULL;" )
@@ -786,6 +806,8 @@ def generate_dealloc_for_class(
786806 emitter .emit_line ("if (!PyObject_GC_IsFinalized((PyObject *)self)) {" )
787807 emitter .emit_line ("Py_TYPE(self)->tp_finalize((PyObject *)self);" )
788808 emitter .emit_line ("}" )
809+ if cl .reuse_freed_instance :
810+ emit_reuse_dealloc (cl , emitter )
789811 emitter .emit_line ("PyObject_GC_UnTrack(self);" )
790812 # The trashcan is needed to handle deep recursive deallocations
791813 emitter .emit_line (f"CPy_TRASHCAN_BEGIN(self, { dealloc_func_name } )" )
@@ -795,6 +817,22 @@ def generate_dealloc_for_class(
795817 emitter .emit_line ("}" )
796818
797819
820+ def emit_reuse_dealloc (cl : ClassIR , emitter : Emitter ) -> None :
821+ prefix = cl .name_prefix (emitter .names )
822+ emitter .emit_line (f"if ({ prefix } _free_instance == NULL) {{" )
823+ emitter .emit_line (f"{ prefix } _free_instance = self;" )
824+ emitter .emit_line ("Py_INCREF(self);" )
825+
826+ # TODO: emit_clear_bitmaps(cl, emitter)
827+
828+ for base in reversed (cl .base_mro ):
829+ for attr , rtype in base .attributes .items ():
830+ emitter .emit_reuse_clear (f"self->{ emitter .attr (attr )} " , rtype )
831+
832+ emitter .emit_line ("return;" )
833+ emitter .emit_line ("}" )
834+
835+
798836def generate_finalize_for_class (
799837 del_method : FuncIR , finalize_func_name : str , emitter : Emitter
800838) -> None :
0 commit comments