diff options
author | Tim Peters <tim.peters@gmail.com> | 2002-07-11 06:23:50 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2002-07-11 06:23:50 (GMT) |
commit | 3459251d5a2b9589e03e818effc357e5e60ee4a9 (patch) | |
tree | dd1a63fc9f5904fb0032b87adbfb5dfd684ce823 /Objects/classobject.c | |
parent | dc1e70987f49aa23bf1d07f32c476edeba0cec30 (diff) | |
download | cpython-3459251d5a2b9589e03e818effc357e5e60ee4a9.zip cpython-3459251d5a2b9589e03e818effc357e5e60ee4a9.tar.gz cpython-3459251d5a2b9589e03e818effc357e5e60ee4a9.tar.bz2 |
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.
Diffstat (limited to 'Objects/classobject.c')
-rw-r--r-- | Objects/classobject.c | 87 |
1 files changed, 38 insertions, 49 deletions
diff --git a/Objects/classobject.c b/Objects/classobject.c index 90a0e22..32e8d2a 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -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()); |