/* Add op to the _PyTrash_delete_later list. Called when the current * call-stack depth gets large. op must be a currently untracked gc'ed * object, with refcount 0. Py_DECREF must already have been called on it. */ void _PyTrash_deposit_object(PyObject *op) { assert(PyObject_IS_GC(op)); assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); assert(op->ob_refcnt == 0); _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; _PyTrash_delete_later = op; }
static void gen_del(PyObject *self) { PyObject *res; PyObject *error_type, *error_value, *error_traceback; PyGenObject *gen = (PyGenObject *)self; if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) /* Generator isn't paused, so no need to close */ return; /* Temporarily resurrect the object. */ assert(self->ob_refcnt == 0); self->ob_refcnt = 1; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); res = gen_close(gen, NULL); if (res == NULL) PyErr_WriteUnraisable(self); else Py_DECREF(res); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); /* Undo the temporary resurrection; can't use DECREF here, it would * cause a recursive call. */ assert(self->ob_refcnt > 0); if (--self->ob_refcnt == 0) return; /* this is the normal path out */ /* close() resurrected it! Make it look like the original Py_DECREF * never happened. */ { Py_ssize_t refcnt = self->ob_refcnt; _Py_NewReference(self); self->ob_refcnt = refcnt; } assert(PyType_IS_GC(self->ob_type) && _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so * we need to undo that. */ _Py_DEC_REFTOTAL; /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object * chain, so no more to do there. * If COUNT_ALLOCS, the original decref bumped tp_frees, and * _Py_NewReference bumped tp_allocs: both of those need to be * undone. */ #ifdef COUNT_ALLOCS --self->ob_type->tp_frees; --self->ob_type->tp_allocs; #endif }
/* Dealloccate all the objects in the _PyTrash_delete_later list. Called when * the call-stack unwinds again. */ void _PyTrash_destroy_chain(void) { while (_PyTrash_delete_later) { PyObject *op = _PyTrash_delete_later; destructor dealloc = op->ob_type->tp_dealloc; _PyTrash_delete_later = (PyObject*) _Py_AS_GC(op)->gc.gc_prev; /* Call the deallocator directly. This used to try to * fool Py_DECREF into calling it indirectly, but * Py_DECREF was already called on this object, and in * assorted non-release builds calling Py_DECREF again ends * up distorting allocation statistics. */ assert(op->ob_refcnt == 0); ++_PyTrash_delete_nesting; (*dealloc)(op); --_PyTrash_delete_nesting; } }
/* For debugging convenience. */ void _Node_Dump(char *msg, NodeObject *self) { fprintf(stderr, "%s\n" " node : ", msg); if (self == NULL) { fprintf(stderr, "NULL\n"); } else { PyObject_Print((PyObject *) self, stderr, 0); fprintf(stderr, "\n" " type : %s\n" " refcount: %" PY_FORMAT_SIZE_T "d\n" " GC refs: %" PY_FORMAT_SIZE_T "d\n" " parent : %p\n", self->ob_type == NULL ? "NULL" : self->ob_type->tp_name, self->ob_refcnt, PyObject_IS_GC((PyObject *)self) ? _Py_AS_GC(self)->gc.gc_refs : 0, Node_GET_PARENT(self)); if (Container_Check(self)) { fprintf(stderr, " children: %" PY_FORMAT_SIZE_T "d\n", Container_GET_COUNT(self)); } } fprintf(stderr, "----------------------\n"); }
static void __Pyx_Generator_del(PyObject *self) { PyObject *res; PyObject *error_type, *error_value, *error_traceback; __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self; if (gen->resume_label <= 0) return ; #if PY_VERSION_HEX < 0x030400a1 /* Temporarily resurrect the object. */ assert(self->ob_refcnt == 0); self->ob_refcnt = 1; #endif /* Save the current exception, if any. */ __Pyx_ErrFetch(&error_type, &error_value, &error_traceback); res = __Pyx_Generator_Close(self); if (res == NULL) PyErr_WriteUnraisable(self); else Py_DECREF(res); /* Restore the saved exception. */ __Pyx_ErrRestore(error_type, error_value, error_traceback); #if PY_VERSION_HEX < 0x030400a1 /* Undo the temporary resurrection; can't use DECREF here, it would * cause a recursive call. */ assert(self->ob_refcnt > 0); if (--self->ob_refcnt == 0) return; /* this is the normal path out */ /* close() resurrected it! Make it look like the original Py_DECREF * never happened. */ { Py_ssize_t refcnt = self->ob_refcnt; _Py_NewReference(self); self->ob_refcnt = refcnt; } #if CYTHON_COMPILING_IN_CPYTHON assert(PyType_IS_GC(self->ob_type) && _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so * we need to undo that. */ _Py_DEC_REFTOTAL; #endif /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object * chain, so no more to do there. * If COUNT_ALLOCS, the original decref bumped tp_frees, and * _Py_NewReference bumped tp_allocs: both of those need to be * undone. */ #ifdef COUNT_ALLOCS --Py_TYPE(self)->tp_frees; --Py_TYPE(self)->tp_allocs; #endif #endif }