? 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