diff options
-rw-r--r-- | Include/object.h | 8 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/object.c | 4 | ||||
-rw-r--r-- | Objects/typeobject.c | 210 |
4 files changed, 6 insertions, 219 deletions
diff --git a/Include/object.h b/Include/object.h index 7294158..b434a21 100644 --- a/Include/object.h +++ b/Include/object.h @@ -345,9 +345,6 @@ typedef struct _typeobject { PyObject *tp_weaklist; destructor tp_del; - /* Type attribute cache version tag. Added in version 2.6 */ - unsigned int tp_version_tag; - #ifdef COUNT_ALLOCS /* these must be last and never explicitly initialized */ Py_ssize_t tp_allocs; @@ -532,10 +529,6 @@ given type object has a specified feature. /* Objects support nb_index in PyNumberMethods */ #define Py_TPFLAGS_HAVE_INDEX (1L<<17) -/* Objects support type attribute cache */ -#define Py_TPFLAGS_HAVE_VERSION_TAG (1L<<18) -#define Py_TPFLAGS_VALID_VERSION_TAG (1L<<19) - /* These flags are used to determine if a type is a subclass. */ #define Py_TPFLAGS_INT_SUBCLASS (1L<<23) #define Py_TPFLAGS_LONG_SUBCLASS (1L<<24) @@ -557,7 +550,6 @@ given type object has a specified feature. Py_TPFLAGS_HAVE_CLASS | \ Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \ Py_TPFLAGS_HAVE_INDEX | \ - Py_TPFLAGS_HAVE_VERSION_TAG | \ 0) #define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) @@ -12,9 +12,6 @@ What's New in Python 2.6 alpha 1? Core and builtins ----------------- -- Patch #1700288: added a type attribute cache that caches method accesses, - resulting in speedups in heavily object-oriented code. - - Bug #1776: __import__() no longer accepts filenames on any platform. The first parameter to __import__() must be a valid module name. diff --git a/Objects/object.c b/Objects/object.c index dbe5658..788e732 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1287,7 +1287,6 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name) goto done; } -#if 0 /* XXX this is not quite _PyType_Lookup anymore */ /* Inline _PyType_Lookup */ { Py_ssize_t i, n; @@ -1312,9 +1311,6 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name) break; } } -#else - descr = _PyType_Lookup(tp, name); -#endif Py_XINCREF(descr); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d4a70d4..bfd2a4c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5,171 +5,6 @@ #include <ctype.h> - -/* Support type attribute cache */ - -/* The cache can keep references to the names alive for longer than - they normally would. This is why the maximum size is limited to - MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large - strings are used as attribute names. */ -#define MCACHE_MAX_ATTR_SIZE 100 -#define MCACHE_SIZE_EXP 10 -#define MCACHE_HASH(version, name_hash) \ - (((unsigned int)(version) * (unsigned int)(name_hash)) \ - >> (8*sizeof(unsigned int) - MCACHE_SIZE_EXP)) -#define MCACHE_HASH_METHOD(type, name) \ - MCACHE_HASH((type)->tp_version_tag, \ - ((PyStringObject *)(name))->ob_shash) -#define MCACHE_CACHEABLE_NAME(name) \ - PyString_CheckExact(name) && \ - PyString_GET_SIZE(name) <= MCACHE_MAX_ATTR_SIZE - -struct method_cache_entry { - unsigned int version; - PyObject *name; /* reference to exactly a str or None */ - PyObject *value; /* borrowed */ -}; - -static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP]; -static unsigned int next_version_tag = 0; - -static void -type_modified(PyTypeObject *type) -{ - /* Invalidate any cached data for the specified type and all - subclasses. This function is called after the base - classes, mro, or attributes of the type are altered. - - Invariants: - - - Py_TPFLAGS_VALID_VERSION_TAG is never set if - Py_TPFLAGS_HAVE_VERSION_TAG is not set (e.g. on type - objects coming from non-recompiled extension modules) - - - before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type, - it must first be set on all super types. - - This function clears the Py_TPFLAGS_VALID_VERSION_TAG of a - type (so it must first clear it on all subclasses). The - tp_version_tag value is meaningless unless this flag is set. - We don't assign new version tags eagerly, but only as - needed. - */ - PyObject *raw, *ref; - Py_ssize_t i, n; - - if(!PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) - return; - - raw = type->tp_subclasses; - if (raw != NULL) { - n = PyList_GET_SIZE(raw); - for (i = 0; i < n; i++) { - ref = PyList_GET_ITEM(raw, i); - ref = PyWeakref_GET_OBJECT(ref); - if (ref != Py_None) { - type_modified((PyTypeObject *)ref); - } - } - } - type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; -} - -static void -type_mro_modified(PyTypeObject *type, PyObject *bases) { - /* - Check that all base classes or elements of the mro of type are - able to be cached. This function is called after the base - classes or mro of the type are altered. - - Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type - inherits from an old-style class, either directly or if it - appears in the MRO of a new-style class. No support either for - custom MROs that include types that are not officially super - types. - - Called from mro_internal, which will subsequently be called on - each subclass when their mro is recursively updated. - */ - Py_ssize_t i, n; - int clear = 0; - - if(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG)) - return; - - n = PyTuple_GET_SIZE(bases); - for (i = 0; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - PyTypeObject *cls; - - if (!PyType_Check(b) ) { - clear = 1; - break; - } - - cls = (PyTypeObject *)b; - - if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) || - !PyType_IsSubtype(type, cls)) { - clear = 1; - break; - } - } - - if (clear) - type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG| - Py_TPFLAGS_VALID_VERSION_TAG); -} - -static int -assign_version_tag(PyTypeObject *type) -{ - /* Ensure that the tp_version_tag is valid and set - Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this - must first be done on all super classes. Return 0 if this - cannot be done, 1 if Py_TPFLAGS_VALID_VERSION_TAG. - */ - Py_ssize_t i, n; - PyObject *bases; - - if (PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) - return 1; - if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG)) - return 0; - if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) - return 0; - - type->tp_version_tag = next_version_tag++; - /* for stress-testing: next_version_tag &= 0xFF; */ - - if (type->tp_version_tag == 0) { - /* wrap-around or just starting Python - clear the whole - cache by filling names with references to Py_None. - Values are also set to NULL for added protection, as they - are borrowed reference */ - for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { - method_cache[i].value = NULL; - Py_XDECREF(method_cache[i].name); - method_cache[i].name = Py_None; - Py_INCREF(Py_None); - } - /* mark all version tags as invalid */ - type_modified(&PyBaseObject_Type); - return 1; - } - bases = type->tp_bases; - n = PyTuple_GET_SIZE(bases); - for (i = 0; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - assert(PyType_Check(b)); - if (!assign_version_tag((PyTypeObject *)b)) - return 0; - } - type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; - return 1; -} - - static PyMemberDef type_members[] = { {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY}, {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY}, @@ -282,8 +117,6 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context) return -1; } - type_modified(type); - return PyDict_SetItemString(type->tp_dict, "__module__", value); } @@ -1518,14 +1351,6 @@ mro_internal(PyTypeObject *type) } } type->tp_mro = tuple; - - type_mro_modified(type, type->tp_mro); - /* corner case: the old-style super class might have been hidden - from the custom MRO */ - type_mro_modified(type, type->tp_bases); - - type_modified(type); - return 0; } @@ -2318,16 +2143,6 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) { Py_ssize_t i, n; PyObject *mro, *res, *base, *dict; - unsigned int h; - - if (MCACHE_CACHEABLE_NAME(name) && - PyType_HasFeature(type,Py_TPFLAGS_VALID_VERSION_TAG)) { - /* fast path */ - h = MCACHE_HASH_METHOD(type, name); - if (method_cache[h].version == type->tp_version_tag && - method_cache[h].name == name) - return method_cache[h].value; - } /* Look in tp_dict of types in MRO */ mro = type->tp_mro; @@ -2338,7 +2153,6 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) if (mro == NULL) return NULL; - res = NULL; assert(PyTuple_Check(mro)); n = PyTuple_GET_SIZE(mro); for (i = 0; i < n; i++) { @@ -2352,18 +2166,9 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) assert(dict && PyDict_Check(dict)); res = PyDict_GetItem(dict, name); if (res != NULL) - break; - } - - if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) { - h = MCACHE_HASH_METHOD(type, name); - method_cache[h].version = type->tp_version_tag; - method_cache[h].value = res; /* borrowed */ - Py_INCREF(name); - Py_DECREF(method_cache[h].name); - method_cache[h].name = name; + return res; } - return res; + return NULL; } /* This is similar to PyObject_GenericGetAttr(), @@ -2453,6 +2258,10 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) type->tp_name); return -1; } + /* XXX Example of how I expect this to be used... + if (update_subclasses(type, name, invalidate_cache, NULL) < 0) + return -1; + */ if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) return -1; return update_slot(type, name); @@ -5875,13 +5684,6 @@ update_slot(PyTypeObject *type, PyObject *name) slotdef **pp; int offset; - /* Clear the VALID_VERSION flag of 'type' and all its - subclasses. This could possibly be unified with the - update_subclasses() recursion below, but carefully: - they each have their own conditions on which to stop - recursing into subclasses. */ - type_modified(type); - init_slotdefs(); pp = ptrs; for (p = slotdefs; p->name; p++) { |