@@ -205,10 +205,6 @@ def generate_class_reuse(
205205 TODO: Generalize to support a free list with up to N objects.
206206 """
207207 assert cl .reuse_freed_instance
208-
209- # The free list implementation doesn't support class hierarchies
210- assert cl .is_final_class or cl .children == []
211-
212208 context = c_emitter .context
213209 name = cl .name_prefix (c_emitter .names ) + "_free_instance"
214210 struct_name = cl .struct_name (c_emitter .names )
@@ -889,8 +885,21 @@ def generate_dealloc_for_class(
889885 emitter .emit_line (f"{ dealloc_func_name } ({ cl .struct_name (emitter .names )} *self)" )
890886 emitter .emit_line ("{" )
891887 if has_tp_finalize :
892- emitter .emit_line ("if (!PyObject_GC_IsFinalized((PyObject *)self)) {" )
893- emitter .emit_line ("Py_TYPE(self)->tp_finalize((PyObject *)self);" )
888+ emitter .emit_line ("PyObject *type, *value, *traceback;" )
889+ emitter .emit_line ("PyErr_Fetch(&type, &value, &traceback);" )
890+ emitter .emit_line ("int res = PyObject_CallFinalizerFromDealloc((PyObject *)self);" )
891+ # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
892+ # However, the message is slightly different due to the way mypyc compiles classes.
893+ # CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
894+ # mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
895+ emitter .emit_line ("if (PyErr_Occurred() != NULL) {" )
896+ # Don't untrack instance if error occurred
897+ emitter .emit_line ("PyErr_WriteUnraisable((PyObject *)self);" )
898+ emitter .emit_line ("res = -1;" )
899+ emitter .emit_line ("}" )
900+ emitter .emit_line ("PyErr_Restore(type, value, traceback);" )
901+ emitter .emit_line ("if (res < 0) {" )
902+ emitter .emit_line ("goto done;" )
894903 emitter .emit_line ("}" )
895904 emitter .emit_line ("PyObject_GC_UnTrack(self);" )
896905 if cl .reuse_freed_instance :
@@ -900,6 +909,7 @@ def generate_dealloc_for_class(
900909 emitter .emit_line (f"{ clear_func_name } (self);" )
901910 emitter .emit_line ("Py_TYPE(self)->tp_free((PyObject *)self);" )
902911 emitter .emit_line ("CPy_TRASHCAN_END(self)" )
912+ emitter .emit_line ("done: ;" )
903913 emitter .emit_line ("}" )
904914
905915
@@ -930,30 +940,13 @@ def generate_finalize_for_class(
930940 emitter .emit_line ("static void" )
931941 emitter .emit_line (f"{ finalize_func_name } (PyObject *self)" )
932942 emitter .emit_line ("{" )
933- emitter .emit_line ("PyObject *type, *value, *traceback;" )
934- emitter .emit_line ("PyErr_Fetch(&type, &value, &traceback);" )
935943 emitter .emit_line (
936944 "{}{}{}(self);" .format (
937945 emitter .get_group_prefix (del_method .decl ),
938946 NATIVE_PREFIX ,
939947 del_method .cname (emitter .names ),
940948 )
941949 )
942- emitter .emit_line ("if (PyErr_Occurred() != NULL) {" )
943- emitter .emit_line ('PyObject *del_str = PyUnicode_FromString("__del__");' )
944- emitter .emit_line (
945- "PyObject *del_method = (del_str == NULL) ? NULL : _PyType_Lookup(Py_TYPE(self), del_str);"
946- )
947- # CPython interpreter uses PyErr_WriteUnraisable: https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable
948- # However, the message is slightly different due to the way mypyc compiles classes.
949- # CPython interpreter prints: Exception ignored in: <function F.__del__ at 0x100aed940>
950- # mypyc prints: Exception ignored in: <slot wrapper '__del__' of 'F' objects>
951- emitter .emit_line ("PyErr_WriteUnraisable(del_method);" )
952- emitter .emit_line ("Py_XDECREF(del_method);" )
953- emitter .emit_line ("Py_XDECREF(del_str);" )
954- emitter .emit_line ("}" )
955- # PyErr_Restore also clears exception raised in __del__.
956- emitter .emit_line ("PyErr_Restore(type, value, traceback);" )
957950 emitter .emit_line ("}" )
958951
959952
0 commit comments