[Python-checkins] python/dist/src/Objects typeobject.c,2.126.4.12,2.126.4.13

gvanrossum@users.sourceforge.net gvanrossum@users.sourceforge.net
Tue, 04 Jun 2002 14:19:58 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv27530/Objects

Modified Files:
      Tag: release22-maint
	typeobject.c 
Log Message:
Backport to 2.2.x:

Address SF bug 519621: slots weren't traversed by GC.

While I was at it, I added a tp_clear handler and changed the
tp_dealloc handler to use the clear_slots helper for the tp_clear
handler.

Also set mp->flags = READONLY for the __weakref__ pseudo-slot.

[Note that I am *not* backporting the part of that patch that
tightened the __slot__ rules.]



Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.126.4.12
retrieving revision 2.126.4.13
diff -C2 -d -r2.126.4.12 -r2.126.4.13
*** typeobject.c	3 Jun 2002 19:54:10 -0000	2.126.4.12
--- typeobject.c	4 Jun 2002 21:19:55 -0000	2.126.4.13
***************
*** 5,8 ****
--- 5,22 ----
  #include "structmember.h"
  
+ #include <ctype.h>
+ 
+ /* The *real* layout of a type object when allocated on the heap */
+ /* XXX Should we publish this in a header file? */
+ typedef struct {
+ 	PyTypeObject type;
+ 	PyNumberMethods as_number;
+ 	PySequenceMethods as_sequence;
+ 	PyMappingMethods as_mapping;
+ 	PyBufferProcs as_buffer;
+ 	PyObject *name, *slots;
+ 	PyMemberDef members[1];
+ } etype;
+ 
  static PyMemberDef type_members[] = {
  	{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
***************
*** 224,237 ****
  
  static int
  subtype_traverse(PyObject *self, visitproc visit, void *arg)
  {
  	PyTypeObject *type, *base;
! 	traverseproc f;
! 	int err;
  
! 	/* Find the nearest base with a different tp_traverse */
  	type = self->ob_type;
! 	base = type->tp_base;
! 	while ((f = base->tp_traverse) == subtype_traverse) {
  		base = base->tp_base;
  		assert(base);
--- 238,278 ----
  
  static int
+ traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg)
+ {
+ 	int i, n;
+ 	PyMemberDef *mp;
+ 
+ 	n = type->ob_size;
+ 	mp = ((etype *)type)->members;
+ 	for (i = 0; i < n; i++, mp++) {
+ 		if (mp->type == T_OBJECT_EX) {
+ 			char *addr = (char *)self + mp->offset;
+ 			PyObject *obj = *(PyObject **)addr;
+ 			if (obj != NULL) {
+ 				int err = visit(obj, arg);
+ 				if (err)
+ 					return err;
+ 			}
+ 		}
+ 	}
+ 	return 0;
+ }
+ 
+ static int
  subtype_traverse(PyObject *self, visitproc visit, void *arg)
  {
  	PyTypeObject *type, *base;
! 	traverseproc basetraverse;
  
! 	/* Find the nearest base with a different tp_traverse,
! 	   and traverse slots while we're at it */
  	type = self->ob_type;
! 	base = type;
! 	while ((basetraverse = base->tp_traverse) == subtype_traverse) {
! 		if (base->ob_size) {
! 			int err = traverse_slots(base, self, visit, arg);
! 			if (err)
! 				return err;
! 		}
  		base = base->tp_base;
  		assert(base);
***************
*** 241,245 ****
  		PyObject **dictptr = _PyObject_GetDictPtr(self);
  		if (dictptr && *dictptr) {
! 			err = visit(*dictptr, arg);
  			if (err)
  				return err;
--- 282,286 ----
  		PyObject **dictptr = _PyObject_GetDictPtr(self);
  		if (dictptr && *dictptr) {
! 			int err = visit(*dictptr, arg);
  			if (err)
  				return err;
***************
*** 247,252 ****
  	}
  
! 	if (f)
! 		return f(self, visit, arg);
  	return 0;
  }
--- 288,342 ----
  	}
  
! 	if (basetraverse)
! 		return basetraverse(self, visit, arg);
! 	return 0;
! }
! 
! static void
! clear_slots(PyTypeObject *type, PyObject *self)
! {
! 	int i, n;
! 	PyMemberDef *mp;
! 
! 	n = type->ob_size;
! 	mp = ((etype *)type)->members;
! 	for (i = 0; i < n; i++, mp++) {
! 		if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) {
! 			char *addr = (char *)self + mp->offset;
! 			PyObject *obj = *(PyObject **)addr;
! 			if (obj != NULL) {
! 				Py_DECREF(obj);
! 				*(PyObject **)addr = NULL;
! 			}
! 		}
! 	}
! }
! 
! static int
! subtype_clear(PyObject *self)
! {
! 	PyTypeObject *type, *base;
! 	inquiry baseclear;
! 
! 	/* Find the nearest base with a different tp_clear
! 	   and clear slots while we're at it */
! 	type = self->ob_type;
! 	base = type;
! 	while ((baseclear = base->tp_clear) == subtype_clear) {
! 		if (base->ob_size)
! 			clear_slots(base, self);
! 		base = base->tp_base;
! 		assert(base);
! 	}
! 
! 	if (type->tp_dictoffset != base->tp_dictoffset) {
! 		PyObject **dictptr = _PyObject_GetDictPtr(self);
! 		if (dictptr && *dictptr) {
! 			PyDict_Clear(*dictptr);
! 		}
! 	}
! 
! 	if (baseclear)
! 		return baseclear(self);
  	return 0;
  }
***************
*** 327,331 ****
  {
  	PyTypeObject *type, *base;
! 	destructor f;
  
  	/* This exists so we can DECREF self->ob_type */
--- 417,421 ----
  {
  	PyTypeObject *type, *base;
! 	destructor basedealloc;
  
  	/* This exists so we can DECREF self->ob_type */
***************
*** 334,365 ****
  		return;
  
! 	/* Find the nearest base with a different tp_dealloc */
  	type = self->ob_type;
! 	base = type->tp_base;
! 	while ((f = base->tp_dealloc) == subtype_dealloc) {
  		base = base->tp_base;
  		assert(base);
  	}
  
- 	/* Clear __slots__ variables */
- 	if (type->tp_basicsize != base->tp_basicsize &&
- 	    type->tp_itemsize == 0)
- 	{
- 		char *addr = ((char *)self);
- 		char *p = addr + base->tp_basicsize;
- 		char *q = addr + type->tp_basicsize;
- 		for (; p < q; p += sizeof(PyObject *)) {
- 			PyObject **pp;
- 			if (p == addr + type->tp_dictoffset ||
- 			    p == addr + type->tp_weaklistoffset)
- 				continue;
- 			pp = (PyObject **)p;
- 			if (*pp != NULL) {
- 				Py_DECREF(*pp);
- 				*pp = NULL;
- 			}
- 		}
- 	}
- 
  	/* If we added a dict, DECREF it */
  	if (type->tp_dictoffset && !base->tp_dictoffset) {
--- 424,438 ----
  		return;
  
! 	/* Find the nearest base with a different tp_dealloc
! 	   and clear slots while we're at it */
  	type = self->ob_type;
! 	base = type;
! 	while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
! 		if (base->ob_size)
! 			clear_slots(base, self);
  		base = base->tp_base;
  		assert(base);
  	}
  
  	/* If we added a dict, DECREF it */
  	if (type->tp_dictoffset && !base->tp_dictoffset) {
***************
*** 383,388 ****
  
  	/* Call the base tp_dealloc() */
! 	assert(f);
! 	f(self);
  
  	/* Can't reference self beyond this point */
--- 456,461 ----
  
  	/* Call the base tp_dealloc() */
! 	assert(basedealloc);
! 	basedealloc(self);
  
  	/* Can't reference self beyond this point */
***************
*** 394,407 ****
  staticforward PyTypeObject *solid_base(PyTypeObject *type);
  
- typedef struct {
- 	PyTypeObject type;
- 	PyNumberMethods as_number;
- 	PySequenceMethods as_sequence;
- 	PyMappingMethods as_mapping;
- 	PyBufferProcs as_buffer;
- 	PyObject *name, *slots;
- 	PyMemberDef members[1];
- } etype;
- 
  /* type test with subclassing support */
  
--- 467,470 ----
***************
*** 1143,1146 ****
--- 1206,1210 ----
  			    strcmp(mp->name, "__weakref__") == 0) {
  				mp->type = T_OBJECT;
+ 				mp->flags = READONLY;
  				type->tp_weaklistoffset = slotoffset;
  			}
***************
*** 1192,1196 ****
  		type->tp_free = _PyObject_GC_Del;
  		type->tp_traverse = subtype_traverse;
! 		type->tp_clear = base->tp_clear;
  	}
  	else
--- 1256,1260 ----
  		type->tp_free = _PyObject_GC_Del;
  		type->tp_traverse = subtype_traverse;
! 		type->tp_clear = subtype_clear;
  	}
  	else