[Python-checkins] python/dist/src/Objects typeobject.c,2.167,2.168
gvanrossum@users.sourceforge.net
gvanrossum@users.sourceforge.net
Thu, 08 Aug 2002 13:55:23 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv17558/Objects
Modified Files:
typeobject.c
Log Message:
A modest speedup of object deallocation. call_finalizer() did rather
a lot of work: it had to save and restore the current exception around
a call to lookup_maybe(), because that could fail in rare cases, and
most objects don't have a __del__ method, so the whole exercise was
usually a waste of time. Changed this to cache the __del__ method in
the type object just like all other special methods, in a new slot
tp_del. So now subtype_dealloc() can test whether tp_del is NULL and
skip the whole exercise if it is. The new slot doesn't need a new
flag bit: subtype_dealloc() is only called if the type was dynamically
allocated by type_new(), so it's guaranteed to have all current slots.
Types defined in C cannot fill in tp_del with a function of their own,
so there's no corresponding "wrapper". (That functionality is already
available through tp_dealloc.)
Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.167
retrieving revision 2.168
diff -C2 -d -r2.167 -r2.168
*** typeobject.c 7 Aug 2002 20:42:09 -0000 2.167
--- typeobject.c 8 Aug 2002 20:55:20 -0000 2.168
***************
*** 357,422 ****
}
- static PyObject *lookup_maybe(PyObject *, char *, PyObject **);
-
- static int
- call_finalizer(PyObject *self)
- {
- static PyObject *del_str = NULL;
- PyObject *del, *res;
- PyObject *error_type, *error_value, *error_traceback;
-
- /* 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);
-
- /* Execute __del__ method, if any. */
- del = lookup_maybe(self, "__del__", &del_str);
- if (del != NULL) {
- res = PyEval_CallObject(del, NULL);
- if (res == NULL)
- PyErr_WriteUnraisable(del);
- else
- Py_DECREF(res);
- Py_DECREF(del);
- }
-
- /* 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 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(!PyType_IS_GC(self->ob_type) ||
- _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
subtype_dealloc(PyObject *self)
--- 357,360 ----
***************
*** 439,444 ****
/* Maybe call finalizer; exit early if resurrected */
! if (call_finalizer(self) < 0)
! return;
/* Find the nearest base with a different tp_dealloc */
--- 377,385 ----
/* Maybe call finalizer; exit early if resurrected */
! if (type->tp_del) {
! type->tp_del(self);
! if (self->ob_refcnt > 0)
! return;
! }
/* Find the nearest base with a different tp_dealloc */
***************
*** 469,474 ****
/* Maybe call finalizer; exit early if resurrected */
! if (call_finalizer(self) < 0)
! goto endlabel;
/* Find the nearest base with a different tp_dealloc
--- 410,418 ----
/* Maybe call finalizer; exit early if resurrected */
! if (type->tp_del) {
! type->tp_del(self);
! if (self->ob_refcnt > 0)
! goto endlabel;
! }
/* Find the nearest base with a different tp_dealloc
***************
*** 3722,3725 ****
--- 3666,3728 ----
}
+ static void
+ slot_tp_del(PyObject *self)
+ {
+ static PyObject *del_str = NULL;
+ PyObject *del, *res;
+ PyObject *error_type, *error_value, *error_traceback;
+
+ /* 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);
+
+ /* Execute __del__ method, if any. */
+ del = lookup_maybe(self, "__del__", &del_str);
+ if (del != NULL) {
+ res = PyEval_CallObject(del, NULL);
+ if (res == NULL)
+ PyErr_WriteUnraisable(del);
+ else
+ Py_DECREF(res);
+ Py_DECREF(del);
+ }
+
+ /* 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 */
+
+ /* __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(!PyType_IS_GC(self->ob_type) ||
+ _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
+ }
+
/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper
***************
*** 3950,3953 ****
--- 3953,3957 ----
PyWrapperFlag_KEYWORDS),
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
+ TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
{NULL}
};