@@ -193,7 +193,9 @@ def generate_class_reuse(
193193 context = c_emitter .context
194194 name = cl .name_prefix (c_emitter .names ) + "_free_instance"
195195 struct_name = cl .struct_name (c_emitter .names )
196- context .declarations [name ] = HeaderDeclaration (f"CPyThreadLocal { struct_name } *{ name } ;" , needs_export = True )
196+ context .declarations [name ] = HeaderDeclaration (
197+ f"CPyThreadLocal { struct_name } *{ name } ;" , needs_export = True
198+ )
197199
198200
199201def generate_class (cl : ClassIR , module : str , emitter : Emitter ) -> None :
@@ -572,11 +574,14 @@ def generate_setup_for_class(
572574
573575 prefix = cl .name_prefix (emitter .names )
574576 if cl .reuse_freed_instance :
577+ # Attempt to use a per-type free list first (a free "list" with up to one object only).
575578 emitter .emit_line (f"if ({ prefix } _free_instance != NULL) {{" )
576579 emitter .emit_line (f"self = { prefix } _free_instance;" )
577580 emitter .emit_line (f"{ prefix } _free_instance = NULL;" )
578581 emitter .emit_line ("Py_SET_REFCNT(self, 1);" )
579582 emitter .emit_line ("PyObject_GC_Track(self);" )
583+ if defaults_fn is not None :
584+ emit_attr_defaults_func_call (defaults_fn , "self" , emitter )
580585 emitter .emit_line ("return (PyObject *)self;" )
581586 emitter .emit_line ("}" )
582587
@@ -593,9 +598,7 @@ def generate_setup_for_class(
593598 else :
594599 emitter .emit_line (f"self->vtable = { vtable_name } ;" )
595600
596- for i in range (0 , len (cl .bitmap_attrs ), BITMAP_BITS ):
597- field = emitter .bitmap_field (i )
598- emitter .emit_line (f"self->{ field } = 0;" )
601+ emit_clear_bitmaps (cl , emitter )
599602
600603 if cl .has_method ("__call__" ):
601604 name = cl .method_decl ("__call__" ).cname (emitter .names )
@@ -612,19 +615,34 @@ def generate_setup_for_class(
612615
613616 # Initialize attributes to default values, if necessary
614617 if defaults_fn is not None :
615- emitter .emit_lines (
616- "if ({}{}((PyObject *)self) == 0) {{" .format (
617- NATIVE_PREFIX , defaults_fn .cname (emitter .names )
618- ),
619- "Py_DECREF(self);" ,
620- "return NULL;" ,
621- "}" ,
622- )
618+ emit_attr_defaults_func_call (defaults_fn , "self" , emitter )
623619
624620 emitter .emit_line ("return (PyObject *)self;" )
625621 emitter .emit_line ("}" )
626622
627623
624+ def emit_clear_bitmaps (cl : ClassIR , emitter : Emitter ) -> None :
625+ """Emit C code to clear bitmaps that track if attributes have an assigned value."""
626+ for i in range (0 , len (cl .bitmap_attrs ), BITMAP_BITS ):
627+ field = emitter .bitmap_field (i )
628+ emitter .emit_line (f"self->{ field } = 0;" )
629+
630+
631+ def emit_attr_defaults_func_call (defaults_fn : FuncIR , self_name : str , emitter : Emitter ) -> None :
632+ """Emit C code to initialize attribute defaults by calling defaults_fn.
633+
634+ The code returns NULL on a raised exception.
635+ """
636+ emitter .emit_lines (
637+ "if ({}{}((PyObject *){}) == 0) {{" .format (
638+ NATIVE_PREFIX , defaults_fn .cname (emitter .names ), self_name
639+ ),
640+ "Py_DECREF(self);" ,
641+ "return NULL;" ,
642+ "}" ,
643+ )
644+
645+
628646def generate_constructor_for_class (
629647 cl : ClassIR ,
630648 fn : FuncDecl ,
@@ -834,13 +852,6 @@ def emit_reuse_dealloc(cl: ClassIR, emitter: Emitter) -> None:
834852 emitter .emit_line ("}" )
835853
836854
837- def emit_clear_bitmaps (cl : ClassIR , emitter : Emitter ) -> None :
838- """Emit C code to clear bitmaps that track if attributes have an assigned value."""
839- for i in range (0 , len (cl .bitmap_attrs ), BITMAP_BITS ):
840- field = emitter .bitmap_field (i )
841- emitter .emit_line (f"self->{ field } = 0;" )
842-
843-
844855def generate_finalize_for_class (
845856 del_method : FuncIR , finalize_func_name : str , emitter : Emitter
846857) -> None :
0 commit comments