? config.debug
? config.release
? stfAv6O4
Index: Include/dictobject.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/dictobject.h,v
retrieving revision 2.32
diff -u -r2.32 dictobject.h
--- Include/dictobject.h	26 Dec 2003 17:17:49 -0000	2.32
+++ Include/dictobject.h	30 Aug 2005 15:04:37 -0000
@@ -49,6 +49,8 @@
 
 typedef struct {
 	long me_hash;      /* cached hash code of me_key */
+	long me_key_time;   /* time that me_key was inserted */
+	long me_value_time; /* time that me_value was modified */
 	PyObject *me_key;
 	PyObject *me_value;
 } PyDictEntry;
@@ -127,6 +129,7 @@
 PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key);
 PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item);
 PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key);
+PyAPI_FUNC(PyObject *) PyDict_GetTime(PyObject *mp, PyObject *args);
 
 #ifdef __cplusplus
 }
Index: Include/frameobject.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/frameobject.h,v
retrieving revision 2.38
diff -u -r2.38 frameobject.h
--- Include/frameobject.h	2 Jul 2004 06:41:04 -0000	2.38
+++ Include/frameobject.h	30 Aug 2005 15:04:37 -0000
@@ -40,10 +40,12 @@
     int f_ncells;
     int f_nfreevars;
     int f_stacksize;		/* size of value stack */
+	PyObject *f_description; /* (filename, line, back_description) tuple */
+	/* Line number and instruction at the time f_description was updated. */
+	int f_desclineno, f_desclasti;
     PyObject *f_localsplus[1];	/* locals+stack, dynamically sized */
 } PyFrameObject;
 
-
 /* Standard object interface */
 
 PyAPI_DATA(PyTypeObject) PyFrame_Type;
@@ -70,6 +72,10 @@
 PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int);
 PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
 
+/* Ensure that the f_description field is up-to-date.
+   Returns true if the field was updated. */
+PyAPI_FUNC(int) PyFrame_UpdateDescription(PyFrameObject *);
+
 #ifdef __cplusplus
 }
 #endif
Index: Include/object.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/object.h,v
retrieving revision 2.131
diff -u -r2.131 object.h
--- Include/object.h	12 Aug 2005 17:34:58 -0000	2.131
+++ Include/object.h	30 Aug 2005 15:04:39 -0000
@@ -74,15 +74,18 @@
 #define _PyObject_EXTRA_INIT
 #endif
 
+#define HAVE_OBJECT_FRAME_INFORMATION
+
 /* PyObject_HEAD defines the initial segment of every PyObject. */
 #define PyObject_HEAD			\
 	_PyObject_HEAD_EXTRA		\
 	int ob_refcnt;			\
-	struct _typeobject *ob_type;
+	struct _typeobject *ob_type; \
+	void * __ob_frame_description;
 
 #define PyObject_HEAD_INIT(type)	\
 	_PyObject_EXTRA_INIT		\
-	1, type,
+	1, type, NULL,
 
 /* PyObject_VAR_HEAD defines the initial segment of all variable-size
  * container objects.  These end with a declaration of an array with 1
@@ -601,12 +604,14 @@
 #define _Py_NewReference(op) (				\
 	_Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA	\
 	_Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA		\
+	_Py_SetObjectFrame((PyObject *)op), \
 	(op)->ob_refcnt = 1)
 
 #define _Py_ForgetReference(op) _Py_INC_TPFREES(op)
 
 #define _Py_Dealloc(op) (				\
 	_Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA	\
+	_Py_FreeFrame((PyObject *)op), \
 	(*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
 #endif /* !Py_TRACE_REFS */
 
@@ -634,6 +639,13 @@
 #define Py_XINCREF(op) if ((op) == NULL) ; else Py_INCREF(op)
 #define Py_XDECREF(op) if ((op) == NULL) ; else Py_DECREF(op)
 
+static inline int _Py_FreeFrame(PyObject * o)
+{
+	PyObject * f = (PyObject *)(o->__ob_frame_description);
+	Py_XDECREF(f);
+	return 0;
+}
+
 /*
 These are provided as conveniences to Python runtime embedders, so that
 they can have object code that is not dependent on Python compilation flags.
Index: Include/objimpl.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/objimpl.h,v
retrieving revision 2.61
diff -u -r2.61 objimpl.h
--- Include/objimpl.h	22 Jul 2005 18:39:18 -0000	2.61
+++ Include/objimpl.h	30 Aug 2005 15:04:40 -0000
@@ -149,6 +149,9 @@
                                                  PyTypeObject *, int);
 PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *);
 PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, int);
+PyAPI_FUNC(void) _Py_SetObjectFrame(PyObject *);
+
+#define Py_SetObjectFrame(op) _Py_SetObjectFrame((PyObject *)(op))
 
 #define PyObject_New(type, typeobj) \
 		( (type *) _PyObject_New(typeobj) )
Index: Objects/descrobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/descrobject.c,v
retrieving revision 2.39
diff -u -r2.39 descrobject.c
--- Objects/descrobject.c	19 Apr 2005 23:43:40 -0000	2.39
+++ Objects/descrobject.c	30 Aug 2005 15:04:46 -0000
@@ -766,6 +766,12 @@
 	return PyObject_CallMethod(pp->dict, "copy", NULL);
 }
 
+static PyObject *
+proxy_gettime(proxyobject * self, PyObject * args)
+{
+	return PyDict_GetTime(self->dict, args);
+}
+
 static PyMethodDef proxy_methods[] = {
 	{"has_key",   (PyCFunction)proxy_has_key,    METH_O,
 	 PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")},
@@ -785,6 +791,8 @@
 	{"iteritems", (PyCFunction)proxy_iteritems,  METH_NOARGS,
 	 PyDoc_STR("D.iteritems() ->"
 	 	   " an iterator over the (key, value) items of D")},
+	{"gettime",   (PyCFunction)proxy_gettime, METH_VARARGS,
+	 PyDoc_STR("")},
 	{"copy",      (PyCFunction)proxy_copy,       METH_NOARGS,
 	 PyDoc_STR("D.copy() -> a shallow copy of D")},
 	{0}
Index: Objects/dictobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/dictobject.c,v
retrieving revision 2.166
diff -u -r2.166 dictobject.c
--- Objects/dictobject.c	17 Aug 2005 02:19:36 -0000	2.166
+++ Objects/dictobject.c	30 Aug 2005 15:04:50 -0000
@@ -157,6 +157,9 @@
 static PyDictObject *free_dicts[MAXFREEDICTS];
 static int num_free_dicts = 0;
 
+/* The sequence number used to fill in me_key_time and me_value_time. */
+static long dict_time = 0;
+
 PyObject *
 PyDict_New(void)
 {
@@ -383,7 +386,8 @@
 Eats a reference to key and one to value.
 */
 static void
-insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
+insertdict_time(register dictobject *mp, PyObject *key, long hash,
+	PyObject *value, long key_time, long value_time)
 {
 	PyObject *old_value;
 	register dictentry *ep;
@@ -394,6 +398,7 @@
 	if (ep->me_value != NULL) {
 		old_value = ep->me_value;
 		ep->me_value = value;
+		ep->me_value_time = value_time;
 		Py_DECREF(old_value); /* which **CAN** re-enter */
 		Py_DECREF(key);
 	}
@@ -405,12 +410,21 @@
 			Py_DECREF(dummy);
 		}
 		ep->me_key = key;
+		ep->me_key_time = key_time;
 		ep->me_hash = hash;
 		ep->me_value = value;
+		ep->me_value_time = value_time;
 		mp->ma_used++;
 	}
 }
 
+static void
+insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
+{
+	dict_time++;
+	insertdict_time(mp, key, hash, value, dict_time - 1, dict_time - 1);
+}
+
 /*
 Restructure the table by allocating a new table and reinserting all
 items again.  When entries have been deleted, the new table may
@@ -483,7 +497,8 @@
 	for (ep = oldtable; i > 0; ep++) {
 		if (ep->me_value != NULL) {	/* active entry */
 			--i;
-			insertdict(mp, ep->me_key, ep->me_hash, ep->me_value);
+			insertdict_time(mp, ep->me_key, ep->me_hash, ep->me_value,
+				ep->me_key_time, ep->me_value_time);
 		}
 		else if (ep->me_key != NULL) {	/* dummy entry */
 			--i;
@@ -1224,8 +1239,9 @@
 			     PyDict_GetItem(a, entry->me_key) == NULL)) {
 				Py_INCREF(entry->me_key);
 				Py_INCREF(entry->me_value);
-				insertdict(mp, entry->me_key, entry->me_hash,
-					   entry->me_value);
+				insertdict_time(mp, entry->me_key, entry->me_hash,
+					entry->me_value, entry->me_key_time,
+					entry->me_value_time);
 			}
 		}
 	}
@@ -1754,6 +1770,35 @@
 	return dictiter_new(dict, &PyDictIterItem_Type);
 }
 
+/* Shamelessly lifted from dict_get :-) */
+PyObject *
+PyDict_GetTime(PyObject *self, PyObject *args)
+{
+	PyObject *key;
+	PyObject *failobj = Py_None;
+	PyDictEntry *entry;
+	dictobject *mp = (dictobject *)self;
+	
+	long hash;
+
+	if (!PyArg_UnpackTuple(args, "gettime", 1, 2, &key, &failobj))
+		return NULL;
+
+	if (!PyString_CheckExact(key) ||
+		(hash = ((PyStringObject *) key)->ob_shash) == -1) {
+		hash = PyObject_Hash(key);
+		if (hash == -1)
+			return NULL;
+	}
+	entry = (mp->ma_lookup)(mp, key, hash);
+
+	if (entry->me_value == NULL) {
+		Py_INCREF(failobj);
+		return failobj;
+	} else return Py_BuildValue("Oll", entry->me_value, 
+		entry->me_key_time, entry->me_value_time);
+}
+
 
 PyDoc_STRVAR(has_key__doc__,
 "D.has_key(k) -> True if D has a key k, else False");
@@ -1809,6 +1854,13 @@
 PyDoc_STRVAR(iteritems__doc__,
 "D.iteritems() -> an iterator over the (key, value) items of D");
 
+PyDoc_STRVAR(gettime__doc__,
+"D.gettime(k[,d]) <==> (D[k], kt, vt)\n if k in D"
+"where (kt, vt) gives the time that the key and value were last updated.\n"
+"The time is a sequence number such that x has a lower number than y iff\n"
+"x was inserted before y.\n"
+"If k is not in D, returns d, which defaults to None.");
+
 static PyMethodDef mapp_methods[] = {
 	{"__contains__",(PyCFunction)dict_has_key,      METH_O | METH_COEXIST,
 	 contains__doc__},
@@ -1844,6 +1896,8 @@
 	 itervalues__doc__},
 	{"iteritems",	(PyCFunction)dict_iteritems,	METH_NOARGS,
 	 iteritems__doc__},
+	{"gettime",   (PyCFunction)PyDict_GetTime, METH_VARARGS,
+	 gettime__doc__},
 	{NULL,		NULL}	/* sentinel */
 };
 
Index: Objects/frameobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/frameobject.c,v
retrieving revision 2.79
diff -u -r2.79 frameobject.c
--- Objects/frameobject.c	2 Jul 2004 06:41:06 -0000	2.79
+++ Objects/frameobject.c	30 Aug 2005 15:04:50 -0000
@@ -409,6 +409,7 @@
 	Py_XDECREF(f->f_exc_type);
 	Py_XDECREF(f->f_exc_value);
 	Py_XDECREF(f->f_exc_traceback);
+	Py_XDECREF(f->f_description);
 	if (numfree < MAXFREELIST) {
 		++numfree;
 		f->f_back = free_list;
@@ -435,6 +436,7 @@
 	VISIT(f->f_exc_type);
 	VISIT(f->f_exc_value);
 	VISIT(f->f_exc_traceback);
+	/* Leave this out since it's only for the memory profiler's use: VISIT(f->f_description); */
 
 	/* locals */
 	slots = f->f_nlocals + f->f_ncells + f->f_nfreevars;
@@ -469,6 +471,9 @@
 	Py_XDECREF(f->f_trace);
 	f->f_trace = NULL;
 
+	Py_XDECREF(f->f_description);
+	f->f_description = NULL;
+
 	/* locals */
 	slots = f->f_nlocals + f->f_ncells + f->f_nfreevars;
 	fastlocals = f->f_localsplus;
@@ -610,6 +615,11 @@
 	f->f_code = code;
 	Py_INCREF(globals);
 	f->f_globals = globals;
+
+	f->f_description = NULL;
+	f->f_desclasti = -1;
+	f->f_desclineno = -1;
+
 	/* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */
 	if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == 
 		(CO_NEWLOCALS | CO_OPTIMIZED))
@@ -807,6 +817,43 @@
 	PyErr_Restore(error_type, error_value, error_traceback);
 }
 
+int
+PyFrame_UpdateDescription(PyFrameObject * f)
+{
+	int need_update = 0;
+	int oldlineno;
+	
+	/* First update the parent frame, if needed. */
+	if (f->f_back)
+		need_update = need_update || PyFrame_UpdateDescription(f->f_back);
+		
+	/* If only the instruction has changed but not the line, we don't
+	   need to make a new description object.
+	   Update the line number even if we already know the description
+	   needs updating. */
+	if (f->f_desclasti != f->f_lasti) {
+		oldlineno = f->f_desclineno;
+		f->f_desclineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+		f->f_desclasti = f->f_lasti;
+	} else oldlineno = f->f_desclineno;	
+	
+	need_update = need_update || (f->f_desclineno != oldlineno);
+	need_update = need_update || !(f->f_description);
+	
+	/* OK, now see if we need a new description object. */
+	if (need_update) {
+		Py_XDECREF(f->f_description);
+		// Prevent infinite recursion building the tuple.
+		f->f_description = Py_None;
+		f->f_description = Py_BuildValue("OiO",
+			f->f_code ? f->f_code->co_filename : Py_None,
+			f->f_desclineno,
+			f->f_back ? f->f_back->f_description : Py_None);
+	}
+	
+	return need_update;
+}
+
 /* Clear out the free list */
 
 void
Index: Objects/object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.227
diff -u -r2.227 object.c
--- Objects/object.c	12 Aug 2005 17:34:57 -0000	2.227
+++ Objects/object.c	30 Aug 2005 15:04:52 -0000
@@ -2,6 +2,8 @@
 /* Generic object operations; and implementation of None (NoObject) */
 
 #include "Python.h"
+#include "compile.h"
+#include "frameobject.h"
 
 #ifdef Py_REF_DEBUG
 long _Py_RefTotal;
@@ -202,6 +204,28 @@
 	return PyObject_INIT_VAR(op, tp, nitems);
 }
 
+void
+_Py_SetObjectFrame(PyObject *op)
+{
+    /* Use this instead of PyThreadState_GET() since early on, objects are
+       created with _PyThreadState_Current == NULL, and the debug version of
+       Python dies with an error. */
+    PyThreadState * thread = _PyThreadState_Current;
+    struct _frame * frame;
+    
+    if (thread)
+        frame = thread->frame;
+    else
+        frame = NULL;
+        
+    /* Make sure that the line number in the frame is up-to-date. */
+    if (frame) {
+        PyFrame_UpdateDescription(frame);       
+        op->__ob_frame_description = frame->f_description;
+        Py_INCREF(frame->f_description);
+    } else op->__ob_frame_description = 0;
+}
+
 /* for binary compatibility with 2.2 */
 #undef _PyObject_Del
 void
