]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
object.h special-build macro minefield: renamed all the new lexical
authorTim Peters <tim.peters@gmail.com>
Thu, 11 Jul 2002 06:23:50 +0000 (06:23 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 11 Jul 2002 06:23:50 +0000 (06:23 +0000)
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.

Include/object.h
Objects/classobject.c
Objects/object.c
Objects/stringobject.c
Objects/tupleobject.c
Objects/typeobject.c

index 1f9100e4efbde994f2e789fcccde0766e3d69366..736095a7668e868f7923bd7a430b4176b06a3c04 100644 (file)
@@ -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.
 */
 
-#ifdef Py_DEBUG
-/* Turn on aggregate reference counting.  This arranges that extern
- * _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.
- */
+/* Py_DEBUG implies Py_TRACE_REFS. */
+#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
 #define Py_TRACE_REFS
-#endif /* Py_DEBUG */
+#endif
 
 /* Py_TRACE_REFS implies 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.)
 */
 
+/* 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
 extern DL_IMPORT(long) _Py_RefTotal;
 extern DL_IMPORT(void) _Py_NegativeRefcount(const char *fname,
                                            int lineno, PyObject *op);
-#define _PyMAYBE_BUMP_REFTOTAL         _Py_RefTotal++
-#define _PyMAYBE_DROP_REFTOTAL         _Py_RefTotal--
-#define _PyMAYBE_BUMP_REFTOTAL_COMMA   _PyMAYBE_BUMP_REFTOTAL ,
-#define _PyMAYBE_DROP_REFTOTAL_COMMA   _PyMAYBE_DROP_REFTOTAL ,
-#define _PyMAYBE_CHECK_REFCNT(OP)                              \
+#define _Py_INC_REFTOTAL       _Py_RefTotal++
+#define _Py_DEC_REFTOTAL       _Py_RefTotal--
+#define _Py_REF_DEBUG_COMMA    ,
+#define _Py_CHECK_REFCNT(OP)                                   \
 {      if ((OP)->ob_refcnt < 0)                                \
                _Py_NegativeRefcount(__FILE__, __LINE__,        \
                                     (PyObject *)(OP));         \
 }
 #else
-#define _PyMAYBE_BUMP_REFTOTAL
-#define _PyMAYBE_DROP_REFTOTAL
-#define _PyMAYBE_BUMP_REFTOTAL_COMMA
-#define _PyMAYBE_DROP_REFTOTAL_COMMA
-#define _PyMAYBE_CHECK_REFCNT(OP)      /* a semicolon */;
+#define _Py_INC_REFTOTAL
+#define _Py_DEC_REFTOTAL
+#define _Py_REF_DEBUG_COMMA
+#define _Py_CHECK_REFCNT(OP)   /* a semicolon */;
 #endif /* Py_REF_DEBUG */
 
 #ifdef COUNT_ALLOCS
 extern DL_IMPORT(void) inc_count(PyTypeObject *);
-#define _PyMAYBE_BUMP_COUNT(OP)                inc_count((OP)->ob_type)
-#define _PyMAYBE_BUMP_FREECOUNT(OP)    (OP)->ob_type->tp_frees++
-#define _PyMAYBE_DROP_FREECOUNT(OP)    (OP)->ob_type->tp_frees--
-#define _PyMAYBE_BUMP_COUNT_COMMA(OP)  _PyMAYBE_BUMP_COUNT(OP) ,
-#define _PyMAYBE_BUMP_FREECOUNT_COMMA(OP) _PyMAYBE_BUMP_FREECOUNT(OP) ,
+#define _Py_INC_TPALLOCS(OP)   inc_count((OP)->ob_type)
+#define _Py_INC_TPFREES(OP)    (OP)->ob_type->tp_frees++
+#define _Py_DEC_TPFREES(OP)    (OP)->ob_type->tp_frees--
+#define _Py_COUNT_ALLOCS_COMMA ,
 #else
-#define _PyMAYBE_BUMP_COUNT(OP)
-#define _PyMAYBE_BUMP_FREECOUNT(OP)
-#define _PyMAYBE_DROP_FREECOUNT(OP)
-#define _PyMAYBE_BUMP_COUNT_COMMA(OP)
-#define _PyMAYBE_BUMP_FREECOUNT_COMMA(OP)
+#define _Py_INC_TPALLOCS(OP)
+#define _Py_INC_TPFREES(OP)
+#define _Py_DEC_TPFREES(OP)
+#define _Py_COUNT_ALLOCS_COMMA
 #endif /* COUNT_ALLOCS */
 
 #ifdef Py_TRACE_REFS
@@ -584,27 +564,27 @@ extern DL_IMPORT(void) _Py_ResetReferences(void);
 /* Without Py_TRACE_REFS, there's little enough to do that we expand code
  * inline.
  */
-#define _Py_NewReference(op) (         \
-       _PyMAYBE_BUMP_COUNT_COMMA(op)   \
-       _PyMAYBE_BUMP_REFTOTAL_COMMA    \
+#define _Py_NewReference(op) (                         \
+       _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA     \
+       _Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA           \
        (op)->ob_refcnt = 1)
 
-#define _Py_ForgetReference(op) _PyMAYBE_BUMP_FREECOUNT(op)
+#define _Py_ForgetReference(op) _Py_INC_TPFREES(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)))
 #endif /* !Py_TRACE_REFS */
 
-#define Py_INCREF(op) (                        \
-       _PyMAYBE_BUMP_REFTOTAL_COMMA    \
+#define Py_INCREF(op) (                                \
+       _Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA   \
        (op)->ob_refcnt++)
 
-#define Py_DECREF(op)                          \
-       if (_PyMAYBE_DROP_REFTOTAL_COMMA        \
-           --(op)->ob_refcnt != 0)             \
-               _PyMAYBE_CHECK_REFCNT(op)       \
-       else                                    \
+#define Py_DECREF(op)                                  \
+       if (_Py_DEC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
+           --(op)->ob_refcnt != 0)                     \
+               _Py_CHECK_REFCNT(op)                    \
+       else                                            \
                _Py_Dealloc((PyObject *)(op))
 
 /* Macros to use in case the object pointer may be NULL: */
index 90a0e22dd46fbd011801628cf7df574a49c831a0..32e8d2a8dfc1df0981fbb09401bd34b2330112f0 100644 (file)
@@ -615,31 +615,15 @@ instance_dealloc(register PyInstanceObject *inst)
        PyObject *error_type, *error_value, *error_traceback;
        PyObject *del;
        static PyObject *delstr;
-#ifdef Py_REF_DEBUG
-       extern long _Py_RefTotal;
-#endif
+
        _PyObject_GC_UNTRACK(inst);
        if (inst->in_weakreflist != NULL)
                PyObject_ClearWeakRefs((PyObject *) inst);
 
        /* Temporarily resurrect the object. */
-#ifdef Py_TRACE_REFS
-#ifndef Py_REF_DEBUG
-#   error "Py_TRACE_REFS defined but Py_REF_DEBUG not."
-#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 */
+       assert(inst->ob_type == &PyInstance_Type);
+       assert(inst->ob_refcnt == 0);
+       inst->ob_refcnt = 1;
 
        /* Save the current exception, if any. */
        PyErr_Fetch(&error_type, &error_value, &error_traceback);
@@ -656,32 +640,37 @@ instance_dealloc(register PyInstanceObject *inst)
        }
        /* 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.
         */
-#ifdef Py_REF_DEBUG
-       /* _Py_RefTotal was boosted either by _Py_NewReference or
-        * 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 */
+       assert(inst->ob_refcnt > 0);
+       if (--inst->ob_refcnt == 0) {
+               Py_DECREF(inst->in_class);
+               Py_XDECREF(inst->in_dict);
+               PyObject_GC_Del(inst);
        }
-#ifdef Py_TRACE_REFS
-       _Py_ForgetReference((PyObject *)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
-       /* compensate for increment in _Py_ForgetReference */
-       inst->ob_type->tp_frees--;
-#endif
+               --inst->ob_type->tp_frees;
+               --inst->ob_type->tp_allocs;
 #endif
-       Py_DECREF(inst->in_class);
-       Py_XDECREF(inst->in_dict);
-       PyObject_GC_Del(inst);
+       }
 }
 
 static PyObject *
@@ -1097,7 +1086,7 @@ sliceobj_from_intint(int i, int j)
        start = PyInt_FromLong((long)i);
        if (!start)
                return NULL;
-       
+
        end = PyInt_FromLong((long)j);
        if (!end) {
                Py_DECREF(start);
@@ -1131,9 +1120,9 @@ instance_slice(PyInstanceObject *inst, int i, int j)
                if (func == NULL)
                        return NULL;
                arg = Py_BuildValue("(N)", sliceobj_from_intint(i, j));
-       } else 
+       } else
                arg = Py_BuildValue("(ii)", i, j);
-               
+
        if (arg == NULL) {
                Py_DECREF(func);
                return NULL;
@@ -1266,7 +1255,7 @@ instance_contains(PyInstanceObject *inst, PyObject *member)
                res = PyEval_CallObject(func, arg);
                Py_DECREF(func);
                Py_DECREF(arg);
-               if(res == NULL) 
+               if(res == NULL)
                        return -1;
                ret = PyObject_IsTrue(res);
                Py_DECREF(res);
@@ -1339,7 +1328,7 @@ static PyObject *coerce_obj;
 
 /* Try one half of a binary operator involving a class instance. */
 static PyObject *
-half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc, 
+half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
                int swapped)
 {
        PyObject *args;
@@ -1347,7 +1336,7 @@ half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
        PyObject *coerced = NULL;
        PyObject *v1;
        PyObject *result;
-       
+
        if (!PyInstance_Check(v)) {
                Py_INCREF(Py_NotImplemented);
                return Py_NotImplemented;
@@ -1708,7 +1697,7 @@ bin_power(PyObject *v, PyObject *w)
 /* This version is for ternary calls only (z != None) */
 static PyObject *
 instance_pow(PyObject *v, PyObject *w, PyObject *z)
-{      
+{
        if (z == Py_None) {
                return do_binop(v, w, "__pow__", "__rpow__", bin_power);
        }
@@ -1777,7 +1766,7 @@ instance_ipow(PyObject *v, PyObject *w, PyObject *z)
 #define NAME_OPS 6
 static PyObject **name_op = NULL;
 
-static int 
+static int
 init_name_op(void)
 {
        int i;
@@ -1818,7 +1807,7 @@ half_richcompare(PyObject *v, PyObject *w, int op)
           instance_getattr2 directly because it will not set an
           exception on failure. */
        if (((PyInstanceObject *)v)->in_class->cl_getattr == NULL) {
-               method = instance_getattr2((PyInstanceObject *)v, 
+               method = instance_getattr2((PyInstanceObject *)v,
                                           name_op[op]);
                if (method == NULL) {
                        assert(!PyErr_Occurred());
index 4987ff301817067a6683350aa4dfe8c51a4f4cda..19f9a7add145420d226b0e0f15c0e761f28098c8 100644 (file)
@@ -7,7 +7,7 @@
 #include "macglue.h"
 #endif
 
-#if defined( Py_TRACE_REFS ) || defined( Py_REF_DEBUG )
+#ifdef Py_REF_DEBUG
 DL_IMPORT(long) _Py_RefTotal;
 #endif
 
@@ -1876,13 +1876,13 @@ _Py_ResetReferences(void)
 void
 _Py_NewReference(PyObject *op)
 {
-       _Py_RefTotal++;
+       _Py_INC_REFTOTAL;
        op->ob_refcnt = 1;
        op->_ob_next = refchain._ob_next;
        op->_ob_prev = &refchain;
        refchain._ob_next->_ob_prev = op;
        refchain._ob_next = op;
-       _PyMAYBE_BUMP_COUNT(op);
+       _Py_INC_TPALLOCS(op);
 }
 
 void
@@ -1907,7 +1907,7 @@ _Py_ForgetReference(register PyObject *op)
        op->_ob_next->_ob_prev = op->_ob_prev;
        op->_ob_prev->_ob_next = op->_ob_next;
        op->_ob_next = op->_ob_prev = NULL;
-       _PyMAYBE_BUMP_FREECOUNT(op);
+       _Py_INC_TPFREES(op);
 }
 
 void
index 5d6478b783eea7713001f62247360694c0f24373..0543f80a231c232ec703630978df7c8a0dfae763 100644 (file)
@@ -3060,9 +3060,7 @@ _PyString_Resize(PyObject **pv, int newsize)
                return -1;
        }
        /* XXX UNREF/NEWREF interface should be more symmetrical */
-#ifdef Py_REF_DEBUG
-       --_Py_RefTotal;
-#endif
+       _Py_DEC_REFTOTAL;
        _Py_ForgetReference(v);
        *pv = (PyObject *)
                PyObject_REALLOC((char *)v,
index 4c264fd46ff11c7ab38ebc865c9fab1c44d724e7..1a15bb71294f3adc0f56448403fafaeb1ee69352 100644 (file)
@@ -677,9 +677,7 @@ _PyTuple_Resize(PyObject **pv, int newsize)
        }
 
        /* XXX UNREF/NEWREF interface should be more symmetrical */
-#ifdef Py_REF_DEBUG
-       --_Py_RefTotal;
-#endif
+       _Py_DEC_REFTOTAL;
        _PyObject_GC_UNTRACK(v);
        _Py_ForgetReference((PyObject *) v);
        /* DECREF items deleted by shrinkage */
index 2beb3b32a84a47e7718a26546111699c8d07e91b..a7afa9b7f0cc30d9a03f7cd5e6abb1b961d08c35 100644 (file)
@@ -365,22 +365,8 @@ call_finalizer(PyObject *self)
        PyObject *error_type, *error_value, *error_traceback;
 
        /* Temporarily resurrect the object. */
-#ifdef Py_TRACE_REFS
-#ifndef Py_REF_DEBUG
-#   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 */
+       assert(self->ob_refcnt == 0);
+       self->ob_refcnt = 1;
 
        /* Save the current exception, if any. */
        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
         * cause a recursive call.
         */
-#ifdef Py_REF_DEBUG
-       /* _Py_RefTotal was boosted either by _Py_NewReference or
-        * Py_INCREF above.
+       assert(self->ob_refcnt > 0);
+       if (--self->ob_refcnt == 0)
+               return 0;       /* this is the normal path out */
+
+       /* __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.
         */
-       _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--;
+       --self->ob_type->tp_frees;
+       --self->ob_type->tp_allocs;
 #endif
-#endif
-
-       return 0;
+       return -1; /* __del__ added a reference; don't delete now */
 }
 
 static void
@@ -1387,13 +1377,13 @@ type_getattro(PyTypeObject *type, PyObject *name)
 
        /* No readable descriptor found yet */
        meta_get = NULL;
-               
+
        /* Look for the attribute in the metatype */
        meta_attribute = _PyType_Lookup(metatype, name);
 
        if (meta_attribute != NULL) {
                meta_get = meta_attribute->ob_type->tp_descr_get;
-                               
+
                if (meta_get != NULL && PyDescr_IsData(meta_attribute)) {
                        /* Data descriptors implement tp_descr_set to intercept
                         * writes. Assume the attribute is not overridden in
@@ -1416,7 +1406,7 @@ type_getattro(PyTypeObject *type, PyObject *name)
                        return local_get(attribute, (PyObject *)NULL,
                                         (PyObject *)type);
                }
-               
+
                Py_INCREF(attribute);
                return attribute;
        }