mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
object.h special-build macro minefield: renamed all the new lexical
helper macros to something saner, and used them appropriately in other files too, to reduce #ifdef blocks. classobject.c, instance_dealloc(): One of my worst Python Memories is trying to fix this routine a few years ago when COUNT_ALLOCS was defined but Py_TRACE_REFS wasn't. The special-build code here is way too complicated. Now it's much simpler. Difference: in a Py_TRACE_REFS build, the instance is no longer in the doubly-linked list of live objects while its __del__ method is executing, and that may be visible via sys.getobjects() called from a __del__ method. Tough -- the object is presumed dead while its __del__ is executing anyway, and not calling _Py_NewReference() at the start allows enormous code simplification. typeobject.c, call_finalizer(): The special-build instance_dealloc() pain apparently spread to here too via cut-'n-paste, and this is much simpler now too. In addition, I didn't understand why this routine was calling _PyObject_GC_TRACK() after a resurrection, since there's no plausible way _PyObject_GC_UNTRACK() could have been called on the object by this point. I suspect it was left over from pasting the instance_delloc() code. Instead asserted that the object is still tracked. Caution: I suspect we don't have a test that actually exercises the subtype_dealloc() __del__-resurrected-me code.
This commit is contained in:
parent
dc1e70987f
commit
3459251d5a
6 changed files with 114 additions and 159 deletions
|
@ -51,35 +51,10 @@ A standard interface exists for objects that contain an array of items
|
||||||
whose size is determined when the object is allocated.
|
whose size is determined when the object is allocated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef Py_DEBUG
|
/* Py_DEBUG implies Py_TRACE_REFS. */
|
||||||
/* Turn on aggregate reference counting. This arranges that extern
|
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
|
||||||
* _Py_RefTotal hold a count of all references, the sum of ob_refcnt
|
|
||||||
* across all objects. The value can be gotten programatically via
|
|
||||||
* sys.gettotalrefcount() (which exists only if Py_REF_DEBUG is enabled).
|
|
||||||
* In a debug-mode build, this is where the "8288" comes from in
|
|
||||||
*
|
|
||||||
* >>> 23
|
|
||||||
* 23
|
|
||||||
* [8288 refs]
|
|
||||||
* >>>
|
|
||||||
*
|
|
||||||
* Note that if this count increases when you're not storing away new objects,
|
|
||||||
* there's probably a leak. Remember, though, that in interactive mode the
|
|
||||||
* special name "_" holds a reference to the last result displayed!
|
|
||||||
* Py_REF_DEBUG also checks after every decref to verify that the refcount
|
|
||||||
* hasn't gone negative, and causes an immediate fatal error if it has.
|
|
||||||
*/
|
|
||||||
#define Py_REF_DEBUG
|
|
||||||
|
|
||||||
/* Turn on heavy reference debugging. This is major surgery. Every PyObject
|
|
||||||
* grows two more pointers, to maintain a doubly-linked list of all live
|
|
||||||
* heap-allocated objects (note that, e.g., most builtin type objects are
|
|
||||||
* not in this list, as they're statically allocated). This list can be
|
|
||||||
* materialized into a Python list via sys.getobjects() (which exists only
|
|
||||||
* if Py_TRACE_REFS is enabled). Py_TRACE_REFS implies Py_REF_DEBUG.
|
|
||||||
*/
|
|
||||||
#define Py_TRACE_REFS
|
#define Py_TRACE_REFS
|
||||||
#endif /* Py_DEBUG */
|
#endif
|
||||||
|
|
||||||
/* Py_TRACE_REFS implies Py_REF_DEBUG. */
|
/* Py_TRACE_REFS implies Py_REF_DEBUG. */
|
||||||
#if defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
|
#if defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
|
||||||
|
@ -536,40 +511,45 @@ variable first, both of which are slower; and in a multi-threaded
|
||||||
environment the global variable trick is not safe.)
|
environment the global variable trick is not safe.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* First define a pile of simple helper macros, one set per special
|
||||||
|
* build symbol. These either expand to the obvious things, or to
|
||||||
|
* nothing at all when the special mode isn't in effect. The main
|
||||||
|
* macros can later be defined just once then, yet expand to different
|
||||||
|
* things depending on which special build options are and aren't in effect.
|
||||||
|
* Trust me <wink>: while painful, this is 20x easier to understand than,
|
||||||
|
* e.g, defining _Py_NewReference five different times in a maze of nested
|
||||||
|
* #ifdefs (we used to do that -- it was impenetrable).
|
||||||
|
*/
|
||||||
#ifdef Py_REF_DEBUG
|
#ifdef Py_REF_DEBUG
|
||||||
extern DL_IMPORT(long) _Py_RefTotal;
|
extern DL_IMPORT(long) _Py_RefTotal;
|
||||||
extern DL_IMPORT(void) _Py_NegativeRefcount(const char *fname,
|
extern DL_IMPORT(void) _Py_NegativeRefcount(const char *fname,
|
||||||
int lineno, PyObject *op);
|
int lineno, PyObject *op);
|
||||||
#define _PyMAYBE_BUMP_REFTOTAL _Py_RefTotal++
|
#define _Py_INC_REFTOTAL _Py_RefTotal++
|
||||||
#define _PyMAYBE_DROP_REFTOTAL _Py_RefTotal--
|
#define _Py_DEC_REFTOTAL _Py_RefTotal--
|
||||||
#define _PyMAYBE_BUMP_REFTOTAL_COMMA _PyMAYBE_BUMP_REFTOTAL ,
|
#define _Py_REF_DEBUG_COMMA ,
|
||||||
#define _PyMAYBE_DROP_REFTOTAL_COMMA _PyMAYBE_DROP_REFTOTAL ,
|
#define _Py_CHECK_REFCNT(OP) \
|
||||||
#define _PyMAYBE_CHECK_REFCNT(OP) \
|
|
||||||
{ if ((OP)->ob_refcnt < 0) \
|
{ if ((OP)->ob_refcnt < 0) \
|
||||||
_Py_NegativeRefcount(__FILE__, __LINE__, \
|
_Py_NegativeRefcount(__FILE__, __LINE__, \
|
||||||
(PyObject *)(OP)); \
|
(PyObject *)(OP)); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define _PyMAYBE_BUMP_REFTOTAL
|
#define _Py_INC_REFTOTAL
|
||||||
#define _PyMAYBE_DROP_REFTOTAL
|
#define _Py_DEC_REFTOTAL
|
||||||
#define _PyMAYBE_BUMP_REFTOTAL_COMMA
|
#define _Py_REF_DEBUG_COMMA
|
||||||
#define _PyMAYBE_DROP_REFTOTAL_COMMA
|
#define _Py_CHECK_REFCNT(OP) /* a semicolon */;
|
||||||
#define _PyMAYBE_CHECK_REFCNT(OP) /* a semicolon */;
|
|
||||||
#endif /* Py_REF_DEBUG */
|
#endif /* Py_REF_DEBUG */
|
||||||
|
|
||||||
#ifdef COUNT_ALLOCS
|
#ifdef COUNT_ALLOCS
|
||||||
extern DL_IMPORT(void) inc_count(PyTypeObject *);
|
extern DL_IMPORT(void) inc_count(PyTypeObject *);
|
||||||
#define _PyMAYBE_BUMP_COUNT(OP) inc_count((OP)->ob_type)
|
#define _Py_INC_TPALLOCS(OP) inc_count((OP)->ob_type)
|
||||||
#define _PyMAYBE_BUMP_FREECOUNT(OP) (OP)->ob_type->tp_frees++
|
#define _Py_INC_TPFREES(OP) (OP)->ob_type->tp_frees++
|
||||||
#define _PyMAYBE_DROP_FREECOUNT(OP) (OP)->ob_type->tp_frees--
|
#define _Py_DEC_TPFREES(OP) (OP)->ob_type->tp_frees--
|
||||||
#define _PyMAYBE_BUMP_COUNT_COMMA(OP) _PyMAYBE_BUMP_COUNT(OP) ,
|
#define _Py_COUNT_ALLOCS_COMMA ,
|
||||||
#define _PyMAYBE_BUMP_FREECOUNT_COMMA(OP) _PyMAYBE_BUMP_FREECOUNT(OP) ,
|
|
||||||
#else
|
#else
|
||||||
#define _PyMAYBE_BUMP_COUNT(OP)
|
#define _Py_INC_TPALLOCS(OP)
|
||||||
#define _PyMAYBE_BUMP_FREECOUNT(OP)
|
#define _Py_INC_TPFREES(OP)
|
||||||
#define _PyMAYBE_DROP_FREECOUNT(OP)
|
#define _Py_DEC_TPFREES(OP)
|
||||||
#define _PyMAYBE_BUMP_COUNT_COMMA(OP)
|
#define _Py_COUNT_ALLOCS_COMMA
|
||||||
#define _PyMAYBE_BUMP_FREECOUNT_COMMA(OP)
|
|
||||||
#endif /* COUNT_ALLOCS */
|
#endif /* COUNT_ALLOCS */
|
||||||
|
|
||||||
#ifdef Py_TRACE_REFS
|
#ifdef Py_TRACE_REFS
|
||||||
|
@ -585,25 +565,25 @@ extern DL_IMPORT(void) _Py_ResetReferences(void);
|
||||||
* inline.
|
* inline.
|
||||||
*/
|
*/
|
||||||
#define _Py_NewReference(op) ( \
|
#define _Py_NewReference(op) ( \
|
||||||
_PyMAYBE_BUMP_COUNT_COMMA(op) \
|
_Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \
|
||||||
_PyMAYBE_BUMP_REFTOTAL_COMMA \
|
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
|
||||||
(op)->ob_refcnt = 1)
|
(op)->ob_refcnt = 1)
|
||||||
|
|
||||||
#define _Py_ForgetReference(op) _PyMAYBE_BUMP_FREECOUNT(op)
|
#define _Py_ForgetReference(op) _Py_INC_TPFREES(op)
|
||||||
|
|
||||||
#define _Py_Dealloc(op) ( \
|
#define _Py_Dealloc(op) ( \
|
||||||
_PyMAYBE_BUMP_FREECOUNT_COMMA(op) \
|
_Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \
|
||||||
(*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
|
(*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
|
||||||
#endif /* !Py_TRACE_REFS */
|
#endif /* !Py_TRACE_REFS */
|
||||||
|
|
||||||
#define Py_INCREF(op) ( \
|
#define Py_INCREF(op) ( \
|
||||||
_PyMAYBE_BUMP_REFTOTAL_COMMA \
|
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
|
||||||
(op)->ob_refcnt++)
|
(op)->ob_refcnt++)
|
||||||
|
|
||||||
#define Py_DECREF(op) \
|
#define Py_DECREF(op) \
|
||||||
if (_PyMAYBE_DROP_REFTOTAL_COMMA \
|
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
|
||||||
--(op)->ob_refcnt != 0) \
|
--(op)->ob_refcnt != 0) \
|
||||||
_PyMAYBE_CHECK_REFCNT(op) \
|
_Py_CHECK_REFCNT(op) \
|
||||||
else \
|
else \
|
||||||
_Py_Dealloc((PyObject *)(op))
|
_Py_Dealloc((PyObject *)(op))
|
||||||
|
|
||||||
|
|
|
@ -615,31 +615,15 @@ instance_dealloc(register PyInstanceObject *inst)
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
PyObject *error_type, *error_value, *error_traceback;
|
||||||
PyObject *del;
|
PyObject *del;
|
||||||
static PyObject *delstr;
|
static PyObject *delstr;
|
||||||
#ifdef Py_REF_DEBUG
|
|
||||||
extern long _Py_RefTotal;
|
|
||||||
#endif
|
|
||||||
_PyObject_GC_UNTRACK(inst);
|
_PyObject_GC_UNTRACK(inst);
|
||||||
if (inst->in_weakreflist != NULL)
|
if (inst->in_weakreflist != NULL)
|
||||||
PyObject_ClearWeakRefs((PyObject *) inst);
|
PyObject_ClearWeakRefs((PyObject *) inst);
|
||||||
|
|
||||||
/* Temporarily resurrect the object. */
|
/* Temporarily resurrect the object. */
|
||||||
#ifdef Py_TRACE_REFS
|
assert(inst->ob_type == &PyInstance_Type);
|
||||||
#ifndef Py_REF_DEBUG
|
assert(inst->ob_refcnt == 0);
|
||||||
# error "Py_TRACE_REFS defined but Py_REF_DEBUG not."
|
inst->ob_refcnt = 1;
|
||||||
#endif
|
|
||||||
/* much too complicated if Py_TRACE_REFS defined */
|
|
||||||
inst->ob_type = &PyInstance_Type;
|
|
||||||
_Py_NewReference((PyObject *)inst);
|
|
||||||
#ifdef COUNT_ALLOCS
|
|
||||||
/* compensate for boost in _Py_NewReference; note that
|
|
||||||
* _Py_RefTotal was also boosted; we'll knock that down later.
|
|
||||||
*/
|
|
||||||
inst->ob_type->tp_allocs--;
|
|
||||||
#endif
|
|
||||||
#else /* !Py_TRACE_REFS */
|
|
||||||
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
|
|
||||||
Py_INCREF(inst);
|
|
||||||
#endif /* !Py_TRACE_REFS */
|
|
||||||
|
|
||||||
/* Save the current exception, if any. */
|
/* Save the current exception, if any. */
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
||||||
|
@ -656,32 +640,37 @@ instance_dealloc(register PyInstanceObject *inst)
|
||||||
}
|
}
|
||||||
/* Restore the saved exception. */
|
/* Restore the saved exception. */
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_Restore(error_type, error_value, error_traceback);
|
||||||
|
|
||||||
/* Undo the temporary resurrection; can't use DECREF here, it would
|
/* Undo the temporary resurrection; can't use DECREF here, it would
|
||||||
* cause a recursive call.
|
* cause a recursive call.
|
||||||
*/
|
*/
|
||||||
#ifdef Py_REF_DEBUG
|
assert(inst->ob_refcnt > 0);
|
||||||
/* _Py_RefTotal was boosted either by _Py_NewReference or
|
if (--inst->ob_refcnt == 0) {
|
||||||
* Py_INCREF above.
|
|
||||||
*/
|
|
||||||
_Py_RefTotal--;
|
|
||||||
#endif
|
|
||||||
if (--inst->ob_refcnt > 0) {
|
|
||||||
#ifdef COUNT_ALLOCS
|
|
||||||
inst->ob_type->tp_frees--;
|
|
||||||
#endif
|
|
||||||
_PyObject_GC_TRACK(inst);
|
|
||||||
return; /* __del__ added a reference; don't delete now */
|
|
||||||
}
|
|
||||||
#ifdef Py_TRACE_REFS
|
|
||||||
_Py_ForgetReference((PyObject *)inst);
|
|
||||||
#ifdef COUNT_ALLOCS
|
|
||||||
/* compensate for increment in _Py_ForgetReference */
|
|
||||||
inst->ob_type->tp_frees--;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
Py_DECREF(inst->in_class);
|
Py_DECREF(inst->in_class);
|
||||||
Py_XDECREF(inst->in_dict);
|
Py_XDECREF(inst->in_dict);
|
||||||
PyObject_GC_Del(inst);
|
PyObject_GC_Del(inst);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int refcnt = inst->ob_refcnt;
|
||||||
|
/* __del__ resurrected it! Make it look like the original
|
||||||
|
* Py_DECREF never happened.
|
||||||
|
*/
|
||||||
|
_Py_NewReference((PyObject *)inst);
|
||||||
|
inst->ob_refcnt = refcnt;
|
||||||
|
_PyObject_GC_TRACK(inst);
|
||||||
|
/* If Py_REF_DEBUG, the original decref dropped _Py_RefTotal,
|
||||||
|
* but _Py_NewReference bumped it again, so that's a wash.
|
||||||
|
* If Py_TRACE_REFS, _Py_NewReference re-added self to the
|
||||||
|
* object chain, so no more to do there either.
|
||||||
|
* 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
|
||||||
|
--inst->ob_type->tp_frees;
|
||||||
|
--inst->ob_type->tp_allocs;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "macglue.h"
|
#include "macglue.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined( Py_TRACE_REFS ) || defined( Py_REF_DEBUG )
|
#ifdef Py_REF_DEBUG
|
||||||
DL_IMPORT(long) _Py_RefTotal;
|
DL_IMPORT(long) _Py_RefTotal;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1876,13 +1876,13 @@ _Py_ResetReferences(void)
|
||||||
void
|
void
|
||||||
_Py_NewReference(PyObject *op)
|
_Py_NewReference(PyObject *op)
|
||||||
{
|
{
|
||||||
_Py_RefTotal++;
|
_Py_INC_REFTOTAL;
|
||||||
op->ob_refcnt = 1;
|
op->ob_refcnt = 1;
|
||||||
op->_ob_next = refchain._ob_next;
|
op->_ob_next = refchain._ob_next;
|
||||||
op->_ob_prev = &refchain;
|
op->_ob_prev = &refchain;
|
||||||
refchain._ob_next->_ob_prev = op;
|
refchain._ob_next->_ob_prev = op;
|
||||||
refchain._ob_next = op;
|
refchain._ob_next = op;
|
||||||
_PyMAYBE_BUMP_COUNT(op);
|
_Py_INC_TPALLOCS(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1907,7 +1907,7 @@ _Py_ForgetReference(register PyObject *op)
|
||||||
op->_ob_next->_ob_prev = op->_ob_prev;
|
op->_ob_next->_ob_prev = op->_ob_prev;
|
||||||
op->_ob_prev->_ob_next = op->_ob_next;
|
op->_ob_prev->_ob_next = op->_ob_next;
|
||||||
op->_ob_next = op->_ob_prev = NULL;
|
op->_ob_next = op->_ob_prev = NULL;
|
||||||
_PyMAYBE_BUMP_FREECOUNT(op);
|
_Py_INC_TPFREES(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -3060,9 +3060,7 @@ _PyString_Resize(PyObject **pv, int newsize)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* XXX UNREF/NEWREF interface should be more symmetrical */
|
/* XXX UNREF/NEWREF interface should be more symmetrical */
|
||||||
#ifdef Py_REF_DEBUG
|
_Py_DEC_REFTOTAL;
|
||||||
--_Py_RefTotal;
|
|
||||||
#endif
|
|
||||||
_Py_ForgetReference(v);
|
_Py_ForgetReference(v);
|
||||||
*pv = (PyObject *)
|
*pv = (PyObject *)
|
||||||
PyObject_REALLOC((char *)v,
|
PyObject_REALLOC((char *)v,
|
||||||
|
|
|
@ -677,9 +677,7 @@ _PyTuple_Resize(PyObject **pv, int newsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX UNREF/NEWREF interface should be more symmetrical */
|
/* XXX UNREF/NEWREF interface should be more symmetrical */
|
||||||
#ifdef Py_REF_DEBUG
|
_Py_DEC_REFTOTAL;
|
||||||
--_Py_RefTotal;
|
|
||||||
#endif
|
|
||||||
_PyObject_GC_UNTRACK(v);
|
_PyObject_GC_UNTRACK(v);
|
||||||
_Py_ForgetReference((PyObject *) v);
|
_Py_ForgetReference((PyObject *) v);
|
||||||
/* DECREF items deleted by shrinkage */
|
/* DECREF items deleted by shrinkage */
|
||||||
|
|
|
@ -365,22 +365,8 @@ call_finalizer(PyObject *self)
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
PyObject *error_type, *error_value, *error_traceback;
|
||||||
|
|
||||||
/* Temporarily resurrect the object. */
|
/* Temporarily resurrect the object. */
|
||||||
#ifdef Py_TRACE_REFS
|
assert(self->ob_refcnt == 0);
|
||||||
#ifndef Py_REF_DEBUG
|
self->ob_refcnt = 1;
|
||||||
# error "Py_TRACE_REFS defined but Py_REF_DEBUG not."
|
|
||||||
#endif
|
|
||||||
/* much too complicated if Py_TRACE_REFS defined */
|
|
||||||
_Py_NewReference((PyObject *)self);
|
|
||||||
#ifdef COUNT_ALLOCS
|
|
||||||
/* compensate for boost in _Py_NewReference; note that
|
|
||||||
* _Py_RefTotal was also boosted; we'll knock that down later.
|
|
||||||
*/
|
|
||||||
self->ob_type->tp_allocs--;
|
|
||||||
#endif
|
|
||||||
#else /* !Py_TRACE_REFS */
|
|
||||||
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
|
|
||||||
Py_INCREF(self);
|
|
||||||
#endif /* !Py_TRACE_REFS */
|
|
||||||
|
|
||||||
/* Save the current exception, if any. */
|
/* Save the current exception, if any. */
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
||||||
|
@ -402,28 +388,32 @@ call_finalizer(PyObject *self)
|
||||||
/* Undo the temporary resurrection; can't use DECREF here, it would
|
/* Undo the temporary resurrection; can't use DECREF here, it would
|
||||||
* cause a recursive call.
|
* cause a recursive call.
|
||||||
*/
|
*/
|
||||||
#ifdef Py_REF_DEBUG
|
assert(self->ob_refcnt > 0);
|
||||||
/* _Py_RefTotal was boosted either by _Py_NewReference or
|
if (--self->ob_refcnt == 0)
|
||||||
* Py_INCREF above.
|
return 0; /* this is the normal path out */
|
||||||
*/
|
|
||||||
_Py_RefTotal--;
|
|
||||||
#endif
|
|
||||||
if (--self->ob_refcnt > 0) {
|
|
||||||
#ifdef COUNT_ALLOCS
|
|
||||||
self->ob_type->tp_frees--;
|
|
||||||
#endif
|
|
||||||
_PyObject_GC_TRACK(self);
|
|
||||||
return -1; /* __del__ added a reference; don't delete now */
|
|
||||||
}
|
|
||||||
#ifdef Py_TRACE_REFS
|
|
||||||
_Py_ForgetReference((PyObject *)self);
|
|
||||||
#ifdef COUNT_ALLOCS
|
|
||||||
/* compensate for increment in _Py_ForgetReference */
|
|
||||||
self->ob_type->tp_frees--;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
/* __del__ resurrected it! Make it look like the original Py_DECREF
|
||||||
|
* never happened.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int refcnt = self->ob_refcnt;
|
||||||
|
_Py_NewReference(self);
|
||||||
|
self->ob_refcnt = refcnt;
|
||||||
|
}
|
||||||
|
assert(_Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
|
||||||
|
/* If Py_REF_DEBUG, the original decref dropped _Py_RefTotal, but
|
||||||
|
* _Py_NewReference bumped it again, so that's a wash.
|
||||||
|
* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
|
||||||
|
* chain, so no more to do there either.
|
||||||
|
* 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
|
||||||
|
return -1; /* __del__ added a reference; don't delete now */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue