Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3459251

Browse files
committed
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.
1 parent dc1e709 commit 3459251

6 files changed

Lines changed: 112 additions & 157 deletions

File tree

Include/object.h

Lines changed: 40 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -51,35 +51,10 @@ A standard interface exists for objects that contain an array of items
5151
whose size is determined when the object is allocated.
5252
*/
5353

54-
#ifdef Py_DEBUG
55-
/* Turn on aggregate reference counting. This arranges that extern
56-
* _Py_RefTotal hold a count of all references, the sum of ob_refcnt
57-
* across all objects. The value can be gotten programatically via
58-
* sys.gettotalrefcount() (which exists only if Py_REF_DEBUG is enabled).
59-
* In a debug-mode build, this is where the "8288" comes from in
60-
*
61-
* >>> 23
62-
* 23
63-
* [8288 refs]
64-
* >>>
65-
*
66-
* Note that if this count increases when you're not storing away new objects,
67-
* there's probably a leak. Remember, though, that in interactive mode the
68-
* special name "_" holds a reference to the last result displayed!
69-
* Py_REF_DEBUG also checks after every decref to verify that the refcount
70-
* hasn't gone negative, and causes an immediate fatal error if it has.
71-
*/
72-
#define Py_REF_DEBUG
73-
74-
/* Turn on heavy reference debugging. This is major surgery. Every PyObject
75-
* grows two more pointers, to maintain a doubly-linked list of all live
76-
* heap-allocated objects (note that, e.g., most builtin type objects are
77-
* not in this list, as they're statically allocated). This list can be
78-
* materialized into a Python list via sys.getobjects() (which exists only
79-
* if Py_TRACE_REFS is enabled). Py_TRACE_REFS implies Py_REF_DEBUG.
80-
*/
54+
/* Py_DEBUG implies Py_TRACE_REFS. */
55+
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
8156
#define Py_TRACE_REFS
82-
#endif /* Py_DEBUG */
57+
#endif
8358

8459
/* Py_TRACE_REFS implies Py_REF_DEBUG. */
8560
#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
536511
environment the global variable trick is not safe.)
537512
*/
538513

514+
/* First define a pile of simple helper macros, one set per special
515+
* build symbol. These either expand to the obvious things, or to
516+
* nothing at all when the special mode isn't in effect. The main
517+
* macros can later be defined just once then, yet expand to different
518+
* things depending on which special build options are and aren't in effect.
519+
* Trust me <wink>: while painful, this is 20x easier to understand than,
520+
* e.g, defining _Py_NewReference five different times in a maze of nested
521+
* #ifdefs (we used to do that -- it was impenetrable).
522+
*/
539523
#ifdef Py_REF_DEBUG
540524
extern DL_IMPORT(long) _Py_RefTotal;
541525
extern DL_IMPORT(void) _Py_NegativeRefcount(const char *fname,
542526
int lineno, PyObject *op);
543-
#define _PyMAYBE_BUMP_REFTOTAL _Py_RefTotal++
544-
#define _PyMAYBE_DROP_REFTOTAL _Py_RefTotal--
545-
#define _PyMAYBE_BUMP_REFTOTAL_COMMA _PyMAYBE_BUMP_REFTOTAL ,
546-
#define _PyMAYBE_DROP_REFTOTAL_COMMA _PyMAYBE_DROP_REFTOTAL ,
547-
#define _PyMAYBE_CHECK_REFCNT(OP) \
527+
#define _Py_INC_REFTOTAL _Py_RefTotal++
528+
#define _Py_DEC_REFTOTAL _Py_RefTotal--
529+
#define _Py_REF_DEBUG_COMMA ,
530+
#define _Py_CHECK_REFCNT(OP) \
548531
{ if ((OP)->ob_refcnt < 0) \
549532
_Py_NegativeRefcount(__FILE__, __LINE__, \
550533
(PyObject *)(OP)); \
551534
}
552535
#else
553-
#define _PyMAYBE_BUMP_REFTOTAL
554-
#define _PyMAYBE_DROP_REFTOTAL
555-
#define _PyMAYBE_BUMP_REFTOTAL_COMMA
556-
#define _PyMAYBE_DROP_REFTOTAL_COMMA
557-
#define _PyMAYBE_CHECK_REFCNT(OP) /* a semicolon */;
536+
#define _Py_INC_REFTOTAL
537+
#define _Py_DEC_REFTOTAL
538+
#define _Py_REF_DEBUG_COMMA
539+
#define _Py_CHECK_REFCNT(OP) /* a semicolon */;
558540
#endif /* Py_REF_DEBUG */
559541

560542
#ifdef COUNT_ALLOCS
561543
extern DL_IMPORT(void) inc_count(PyTypeObject *);
562-
#define _PyMAYBE_BUMP_COUNT(OP) inc_count((OP)->ob_type)
563-
#define _PyMAYBE_BUMP_FREECOUNT(OP) (OP)->ob_type->tp_frees++
564-
#define _PyMAYBE_DROP_FREECOUNT(OP) (OP)->ob_type->tp_frees--
565-
#define _PyMAYBE_BUMP_COUNT_COMMA(OP) _PyMAYBE_BUMP_COUNT(OP) ,
566-
#define _PyMAYBE_BUMP_FREECOUNT_COMMA(OP) _PyMAYBE_BUMP_FREECOUNT(OP) ,
544+
#define _Py_INC_TPALLOCS(OP) inc_count((OP)->ob_type)
545+
#define _Py_INC_TPFREES(OP) (OP)->ob_type->tp_frees++
546+
#define _Py_DEC_TPFREES(OP) (OP)->ob_type->tp_frees--
547+
#define _Py_COUNT_ALLOCS_COMMA ,
567548
#else
568-
#define _PyMAYBE_BUMP_COUNT(OP)
569-
#define _PyMAYBE_BUMP_FREECOUNT(OP)
570-
#define _PyMAYBE_DROP_FREECOUNT(OP)
571-
#define _PyMAYBE_BUMP_COUNT_COMMA(OP)
572-
#define _PyMAYBE_BUMP_FREECOUNT_COMMA(OP)
549+
#define _Py_INC_TPALLOCS(OP)
550+
#define _Py_INC_TPFREES(OP)
551+
#define _Py_DEC_TPFREES(OP)
552+
#define _Py_COUNT_ALLOCS_COMMA
573553
#endif /* COUNT_ALLOCS */
574554

575555
#ifdef Py_TRACE_REFS
@@ -584,27 +564,27 @@ extern DL_IMPORT(void) _Py_ResetReferences(void);
584564
/* Without Py_TRACE_REFS, there's little enough to do that we expand code
585565
* inline.
586566
*/
587-
#define _Py_NewReference(op) ( \
588-
_PyMAYBE_BUMP_COUNT_COMMA(op) \
589-
_PyMAYBE_BUMP_REFTOTAL_COMMA \
567+
#define _Py_NewReference(op) ( \
568+
_Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \
569+
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
590570
(op)->ob_refcnt = 1)
591571

592-
#define _Py_ForgetReference(op) _PyMAYBE_BUMP_FREECOUNT(op)
572+
#define _Py_ForgetReference(op) _Py_INC_TPFREES(op)
593573

594574
#define _Py_Dealloc(op) ( \
595-
_PyMAYBE_BUMP_FREECOUNT_COMMA(op) \
575+
_Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \
596576
(*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
597577
#endif /* !Py_TRACE_REFS */
598578

599-
#define Py_INCREF(op) ( \
600-
_PyMAYBE_BUMP_REFTOTAL_COMMA \
579+
#define Py_INCREF(op) ( \
580+
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
601581
(op)->ob_refcnt++)
602582

603-
#define Py_DECREF(op) \
604-
if (_PyMAYBE_DROP_REFTOTAL_COMMA \
605-
--(op)->ob_refcnt != 0) \
606-
_PyMAYBE_CHECK_REFCNT(op) \
607-
else \
583+
#define Py_DECREF(op) \
584+
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
585+
--(op)->ob_refcnt != 0) \
586+
_Py_CHECK_REFCNT(op) \
587+
else \
608588
_Py_Dealloc((PyObject *)(op))
609589

610590
/* Macros to use in case the object pointer may be NULL: */

Objects/classobject.c

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -615,31 +615,15 @@ instance_dealloc(register PyInstanceObject *inst)
615615
PyObject *error_type, *error_value, *error_traceback;
616616
PyObject *del;
617617
static PyObject *delstr;
618-
#ifdef Py_REF_DEBUG
619-
extern long _Py_RefTotal;
620-
#endif
618+
621619
_PyObject_GC_UNTRACK(inst);
622620
if (inst->in_weakreflist != NULL)
623621
PyObject_ClearWeakRefs((PyObject *) inst);
624622

625623
/* Temporarily resurrect the object. */
626-
#ifdef Py_TRACE_REFS
627-
#ifndef Py_REF_DEBUG
628-
# error "Py_TRACE_REFS defined but Py_REF_DEBUG not."
629-
#endif
630-
/* much too complicated if Py_TRACE_REFS defined */
631-
inst->ob_type = &PyInstance_Type;
632-
_Py_NewReference((PyObject *)inst);
633-
#ifdef COUNT_ALLOCS
634-
/* compensate for boost in _Py_NewReference; note that
635-
* _Py_RefTotal was also boosted; we'll knock that down later.
636-
*/
637-
inst->ob_type->tp_allocs--;
638-
#endif
639-
#else /* !Py_TRACE_REFS */
640-
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
641-
Py_INCREF(inst);
642-
#endif /* !Py_TRACE_REFS */
624+
assert(inst->ob_type == &PyInstance_Type);
625+
assert(inst->ob_refcnt == 0);
626+
inst->ob_refcnt = 1;
643627

644628
/* Save the current exception, if any. */
645629
PyErr_Fetch(&error_type, &error_value, &error_traceback);
@@ -656,32 +640,37 @@ instance_dealloc(register PyInstanceObject *inst)
656640
}
657641
/* Restore the saved exception. */
658642
PyErr_Restore(error_type, error_value, error_traceback);
643+
659644
/* Undo the temporary resurrection; can't use DECREF here, it would
660645
* cause a recursive call.
661646
*/
662-
#ifdef Py_REF_DEBUG
663-
/* _Py_RefTotal was boosted either by _Py_NewReference or
664-
* Py_INCREF above.
665-
*/
666-
_Py_RefTotal--;
667-
#endif
668-
if (--inst->ob_refcnt > 0) {
669-
#ifdef COUNT_ALLOCS
670-
inst->ob_type->tp_frees--;
671-
#endif
672-
_PyObject_GC_TRACK(inst);
673-
return; /* __del__ added a reference; don't delete now */
647+
assert(inst->ob_refcnt > 0);
648+
if (--inst->ob_refcnt == 0) {
649+
Py_DECREF(inst->in_class);
650+
Py_XDECREF(inst->in_dict);
651+
PyObject_GC_Del(inst);
674652
}
675-
#ifdef Py_TRACE_REFS
676-
_Py_ForgetReference((PyObject *)inst);
653+
else {
654+
int refcnt = inst->ob_refcnt;
655+
/* __del__ resurrected it! Make it look like the original
656+
* Py_DECREF never happened.
657+
*/
658+
_Py_NewReference((PyObject *)inst);
659+
inst->ob_refcnt = refcnt;
660+
_PyObject_GC_TRACK(inst);
661+
/* If Py_REF_DEBUG, the original decref dropped _Py_RefTotal,
662+
* but _Py_NewReference bumped it again, so that's a wash.
663+
* If Py_TRACE_REFS, _Py_NewReference re-added self to the
664+
* object chain, so no more to do there either.
665+
* If COUNT_ALLOCS, the original decref bumped tp_frees, and
666+
* _Py_NewReference bumped tp_allocs: both of those need to
667+
* be undone.
668+
*/
677669
#ifdef COUNT_ALLOCS
678-
/* compensate for increment in _Py_ForgetReference */
679-
inst->ob_type->tp_frees--;
680-
#endif
670+
--inst->ob_type->tp_frees;
671+
--inst->ob_type->tp_allocs;
681672
#endif
682-
Py_DECREF(inst->in_class);
683-
Py_XDECREF(inst->in_dict);
684-
PyObject_GC_Del(inst);
673+
}
685674
}
686675

687676
static PyObject *
@@ -1097,7 +1086,7 @@ sliceobj_from_intint(int i, int j)
10971086
start = PyInt_FromLong((long)i);
10981087
if (!start)
10991088
return NULL;
1100-
1089+
11011090
end = PyInt_FromLong((long)j);
11021091
if (!end) {
11031092
Py_DECREF(start);
@@ -1131,9 +1120,9 @@ instance_slice(PyInstanceObject *inst, int i, int j)
11311120
if (func == NULL)
11321121
return NULL;
11331122
arg = Py_BuildValue("(N)", sliceobj_from_intint(i, j));
1134-
} else
1123+
} else
11351124
arg = Py_BuildValue("(ii)", i, j);
1136-
1125+
11371126
if (arg == NULL) {
11381127
Py_DECREF(func);
11391128
return NULL;
@@ -1266,7 +1255,7 @@ instance_contains(PyInstanceObject *inst, PyObject *member)
12661255
res = PyEval_CallObject(func, arg);
12671256
Py_DECREF(func);
12681257
Py_DECREF(arg);
1269-
if(res == NULL)
1258+
if(res == NULL)
12701259
return -1;
12711260
ret = PyObject_IsTrue(res);
12721261
Py_DECREF(res);
@@ -1339,15 +1328,15 @@ static PyObject *coerce_obj;
13391328

13401329
/* Try one half of a binary operator involving a class instance. */
13411330
static PyObject *
1342-
half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
1331+
half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
13431332
int swapped)
13441333
{
13451334
PyObject *args;
13461335
PyObject *coercefunc;
13471336
PyObject *coerced = NULL;
13481337
PyObject *v1;
13491338
PyObject *result;
1350-
1339+
13511340
if (!PyInstance_Check(v)) {
13521341
Py_INCREF(Py_NotImplemented);
13531342
return Py_NotImplemented;
@@ -1708,7 +1697,7 @@ bin_power(PyObject *v, PyObject *w)
17081697
/* This version is for ternary calls only (z != None) */
17091698
static PyObject *
17101699
instance_pow(PyObject *v, PyObject *w, PyObject *z)
1711-
{
1700+
{
17121701
if (z == Py_None) {
17131702
return do_binop(v, w, "__pow__", "__rpow__", bin_power);
17141703
}
@@ -1777,7 +1766,7 @@ instance_ipow(PyObject *v, PyObject *w, PyObject *z)
17771766
#define NAME_OPS 6
17781767
static PyObject **name_op = NULL;
17791768

1780-
static int
1769+
static int
17811770
init_name_op(void)
17821771
{
17831772
int i;
@@ -1818,7 +1807,7 @@ half_richcompare(PyObject *v, PyObject *w, int op)
18181807
instance_getattr2 directly because it will not set an
18191808
exception on failure. */
18201809
if (((PyInstanceObject *)v)->in_class->cl_getattr == NULL) {
1821-
method = instance_getattr2((PyInstanceObject *)v,
1810+
method = instance_getattr2((PyInstanceObject *)v,
18221811
name_op[op]);
18231812
if (method == NULL) {
18241813
assert(!PyErr_Occurred());

Objects/object.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "macglue.h"
88
#endif
99

10-
#if defined( Py_TRACE_REFS ) || defined( Py_REF_DEBUG )
10+
#ifdef Py_REF_DEBUG
1111
DL_IMPORT(long) _Py_RefTotal;
1212
#endif
1313

@@ -1876,13 +1876,13 @@ _Py_ResetReferences(void)
18761876
void
18771877
_Py_NewReference(PyObject *op)
18781878
{
1879-
_Py_RefTotal++;
1879+
_Py_INC_REFTOTAL;
18801880
op->ob_refcnt = 1;
18811881
op->_ob_next = refchain._ob_next;
18821882
op->_ob_prev = &refchain;
18831883
refchain._ob_next->_ob_prev = op;
18841884
refchain._ob_next = op;
1885-
_PyMAYBE_BUMP_COUNT(op);
1885+
_Py_INC_TPALLOCS(op);
18861886
}
18871887

18881888
void
@@ -1907,7 +1907,7 @@ _Py_ForgetReference(register PyObject *op)
19071907
op->_ob_next->_ob_prev = op->_ob_prev;
19081908
op->_ob_prev->_ob_next = op->_ob_next;
19091909
op->_ob_next = op->_ob_prev = NULL;
1910-
_PyMAYBE_BUMP_FREECOUNT(op);
1910+
_Py_INC_TPFREES(op);
19111911
}
19121912

19131913
void

Objects/stringobject.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,9 +3060,7 @@ _PyString_Resize(PyObject **pv, int newsize)
30603060
return -1;
30613061
}
30623062
/* XXX UNREF/NEWREF interface should be more symmetrical */
3063-
#ifdef Py_REF_DEBUG
3064-
--_Py_RefTotal;
3065-
#endif
3063+
_Py_DEC_REFTOTAL;
30663064
_Py_ForgetReference(v);
30673065
*pv = (PyObject *)
30683066
PyObject_REALLOC((char *)v,

Objects/tupleobject.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -677,9 +677,7 @@ _PyTuple_Resize(PyObject **pv, int newsize)
677677
}
678678

679679
/* XXX UNREF/NEWREF interface should be more symmetrical */
680-
#ifdef Py_REF_DEBUG
681-
--_Py_RefTotal;
682-
#endif
680+
_Py_DEC_REFTOTAL;
683681
_PyObject_GC_UNTRACK(v);
684682
_Py_ForgetReference((PyObject *) v);
685683
/* DECREF items deleted by shrinkage */

0 commit comments

Comments
 (0)