[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}
  };