MCPcopy Index your code
hub / github.com/python/mypy / generate_dealloc_for_class

Function generate_dealloc_for_class

mypyc/codegen/emitclass.py:922–971  ·  view source on GitHub ↗
(
    cl: ClassIR,
    dealloc_func_name: str,
    clear_func_name: str,
    has_tp_finalize: bool,
    emitter: Emitter,
)

Source from the content-addressed store, hash-verified

920
921
922def generate_dealloc_for_class(
923 cl: ClassIR,
924 dealloc_func_name: str,
925 clear_func_name: str,
926 has_tp_finalize: bool,
927 emitter: Emitter,
928) -> None:
929 emitter.emit_line("static void")
930 emitter.emit_line(f"{dealloc_func_name}({cl.struct_name(emitter.names)} *self)")
931 emitter.emit_line("{")
932 if has_tp_finalize:
933 emitter.emit_line("PyObject *type, *value, *traceback;")
934 emitter.emit_line("PyErr_Fetch(&type, &value, &traceback);")
935 emitter.emit_line("int res = PyObject_CallFinalizerFromDealloc((PyObject *)self);")
936 # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
937 # However, the message is slightly different due to the way mypyc compiles classes.
938 # CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
939 # mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
940 emitter.emit_line("if (PyErr_Occurred() != NULL) {")
941 # Don't untrack instance if error occurred
942 emitter.emit_line("PyErr_WriteUnraisable((PyObject *)self);")
943 emitter.emit_line("res = -1;")
944 emitter.emit_line("}")
945 emitter.emit_line("PyErr_Restore(type, value, traceback);")
946 emitter.emit_line("if (res < 0) {")
947 emitter.emit_line("goto done;")
948 emitter.emit_line("}")
949 if not cl.is_acyclic:
950 emitter.emit_line("PyObject_GC_UnTrack(self);")
951 if cl.builtin_base:
952 emitter.emit_line(f"{clear_func_name}(self);")
953 # For native subclasses of builtins such as dict, the base deallocator
954 # is responsible for tearing down base-owned storage and freeing memory.
955 # Re-track self if base is GC-aware to match cpython's subtype_dealloc.
956 base = f"{emitter.type_struct_name(cl)}->tp_base"
957 base_arg = "(PyObject *)self"
958 emitter.emit_line(f"if (PyType_IS_GC({base})) PyObject_GC_Track({base_arg});")
959 emitter.emit_base_tp_function_call(cl, "tp_dealloc", base_arg)
960 emitter.emit_line("done: ;")
961 emitter.emit_line("}")
962 return
963 if cl.reuse_freed_instance:
964 emit_reuse_dealloc(cl, emitter)
965 # The trashcan is needed to handle deep recursive deallocations
966 emitter.emit_line(f"CPy_TRASHCAN_BEGIN(self, {dealloc_func_name})")
967 emitter.emit_line(f"{clear_func_name}(self);")
968 emitter.emit_line("Py_TYPE(self)->tp_free((PyObject *)self);")
969 emitter.emit_line("CPy_TRASHCAN_END(self)")
970 emitter.emit_line("done: ;")
971 emitter.emit_line("}")
972
973
974def emit_reuse_dealloc(cl: ClassIR, emitter: Emitter) -> None:

Callers 1

generate_classFunction · 0.85

Calls 5

emit_reuse_deallocFunction · 0.85
type_struct_nameMethod · 0.80
emit_lineMethod · 0.45
struct_nameMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…