From ee3a1b5244e60566c5d5c8f6a1ea4b381de99f1c Mon Sep 17 00:00:00 2001 From: Neal Norwitz Date: Sun, 25 Feb 2007 19:44:48 +0000 Subject: Variation of patch # 1624059 to speed up checking if an object is a subclass of some of the common builtin types. Use a bit in tp_flags for each common builtin type. Check the bit to determine if any instance is a subclass of these common types. The check avoids a function call and O(n) search of the base classes. The check is done in the various Py*_Check macros rather than calling PyType_IsSubtype(). All the bits are set in tp_flags when the type is declared in the Objects/*object.c files because PyType_Ready() is not called for all the types. Should PyType_Ready() be called for all types? If so and the change is made, the changes to the Objects/*object.c files can be reverted (remove setting the tp_flags). Objects/typeobject.c would also have to be modified to add conditions for Py*_CheckExact() in addition to each the PyType_IsSubtype check. --- Include/dictobject.h | 3 ++- Include/intobject.h | 3 ++- Include/listobject.h | 3 ++- Include/longobject.h | 3 ++- Include/object.h | 15 ++++++++++++++- Include/pyerrors.h | 8 +++----- Include/stringobject.h | 3 ++- Include/tupleobject.h | 3 ++- Include/unicodeobject.h | 3 ++- Objects/dictobject.c | 2 +- Objects/exceptions.c | 3 ++- Objects/intobject.c | 2 +- Objects/listobject.c | 2 +- Objects/longobject.c | 2 +- Objects/stringobject.c | 2 +- Objects/tupleobject.c | 2 +- Objects/typeobject.c | 22 +++++++++++++++++++++- Objects/unicodeobject.c | 2 +- 18 files changed, 61 insertions(+), 22 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h index 44b0838..ec2e0c8 100644 --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -90,7 +90,8 @@ struct _dictobject { PyAPI_DATA(PyTypeObject) PyDict_Type; -#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type) +#define PyDict_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_DICT_SUBCLASS) #define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type) PyAPI_FUNC(PyObject *) PyDict_New(void); diff --git a/Include/intobject.h b/Include/intobject.h index 1f4846e..51d3e1b 100644 --- a/Include/intobject.h +++ b/Include/intobject.h @@ -27,7 +27,8 @@ typedef struct { PyAPI_DATA(PyTypeObject) PyInt_Type; -#define PyInt_Check(op) PyObject_TypeCheck(op, &PyInt_Type) +#define PyInt_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS) #define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type) PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int); diff --git a/Include/listobject.h b/Include/listobject.h index d9012ce..db3124e 100644 --- a/Include/listobject.h +++ b/Include/listobject.h @@ -40,7 +40,8 @@ typedef struct { PyAPI_DATA(PyTypeObject) PyList_Type; -#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type) +#define PyList_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LIST_SUBCLASS) #define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type) PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); diff --git a/Include/longobject.h b/Include/longobject.h index eef4e9b..3893ad6 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -11,7 +11,8 @@ typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ PyAPI_DATA(PyTypeObject) PyLong_Type; -#define PyLong_Check(op) PyObject_TypeCheck(op, &PyLong_Type) +#define PyLong_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LONG_SUBCLASS) #define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type) PyAPI_FUNC(PyObject *) PyLong_FromLong(long); diff --git a/Include/object.h b/Include/object.h index b0817e6..0f6ff77 100644 --- a/Include/object.h +++ b/Include/object.h @@ -376,7 +376,8 @@ PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */ PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */ PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */ -#define PyType_Check(op) PyObject_TypeCheck(op, &PyType_Type) +#define PyType_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TYPE_SUBCLASS) #define PyType_CheckExact(op) ((op)->ob_type == &PyType_Type) PyAPI_FUNC(int) PyType_Ready(PyTypeObject *); @@ -517,6 +518,17 @@ given type object has a specified feature. /* Objects support nb_index in PyNumberMethods */ #define Py_TPFLAGS_HAVE_INDEX (1L<<17) +/* 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) +#define Py_TPFLAGS_LIST_SUBCLASS (1L<<25) +#define Py_TPFLAGS_TUPLE_SUBCLASS (1L<<26) +#define Py_TPFLAGS_STRING_SUBCLASS (1L<<27) +#define Py_TPFLAGS_UNICODE_SUBCLASS (1L<<28) +#define Py_TPFLAGS_DICT_SUBCLASS (1L<<29) +#define Py_TPFLAGS_BASE_EXC_SUBCLASS (1L<<30) +#define Py_TPFLAGS_TYPE_SUBCLASS (1L<<31) + #define Py_TPFLAGS_DEFAULT ( \ Py_TPFLAGS_HAVE_GETCHARBUFFER | \ Py_TPFLAGS_HAVE_SEQUENCE_IN | \ @@ -530,6 +542,7 @@ given type object has a specified feature. 0) #define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) +#define PyType_FastSubclass(t,f) PyType_HasFeature(t,f) /* diff --git a/Include/pyerrors.h b/Include/pyerrors.h index 9532e32..9671692 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -95,14 +95,12 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); /* */ #define PyExceptionClass_Check(x) \ - (PyClass_Check((x)) \ - || (PyType_Check((x)) && PyType_IsSubtype( \ - (PyTypeObject*)(x), (PyTypeObject*)PyExc_BaseException))) - + (PyClass_Check((x)) || (PyType_Check((x)) && \ + PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS))) #define PyExceptionInstance_Check(x) \ (PyInstance_Check((x)) || \ - (PyType_IsSubtype((x)->ob_type, (PyTypeObject*)PyExc_BaseException))) + PyType_FastSubclass((x)->ob_type, Py_TPFLAGS_BASE_EXC_SUBCLASS)) #define PyExceptionClass_Name(x) \ (PyClass_Check((x)) \ diff --git a/Include/stringobject.h b/Include/stringobject.h index 5f8a6f0..03c3777 100644 --- a/Include/stringobject.h +++ b/Include/stringobject.h @@ -55,7 +55,8 @@ typedef struct { PyAPI_DATA(PyTypeObject) PyBaseString_Type; PyAPI_DATA(PyTypeObject) PyString_Type; -#define PyString_Check(op) PyObject_TypeCheck(op, &PyString_Type) +#define PyString_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_STRING_SUBCLASS) #define PyString_CheckExact(op) ((op)->ob_type == &PyString_Type) PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t); diff --git a/Include/tupleobject.h b/Include/tupleobject.h index 8c37cab..738cea1 100644 --- a/Include/tupleobject.h +++ b/Include/tupleobject.h @@ -33,7 +33,8 @@ typedef struct { PyAPI_DATA(PyTypeObject) PyTuple_Type; -#define PyTuple_Check(op) PyObject_TypeCheck(op, &PyTuple_Type) +#define PyTuple_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TUPLE_SUBCLASS) #define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type) PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h index 33aa185..0bad8c3 100644 --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -392,7 +392,8 @@ typedef struct { PyAPI_DATA(PyTypeObject) PyUnicode_Type; -#define PyUnicode_Check(op) PyObject_TypeCheck(op, &PyUnicode_Type) +#define PyUnicode_Check(op) \ + PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_UNICODE_SUBCLASS) #define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type) /* Fast access macros */ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 1cb3ee6..587dad3 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2112,7 +2112,7 @@ PyTypeObject PyDict_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS, /* tp_flags */ dictionary_doc, /* tp_doc */ dict_traverse, /* tp_traverse */ dict_tp_clear, /* tp_clear */ diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 0cd819c..c6ea6a4 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -300,7 +300,8 @@ static PyTypeObject _PyExc_BaseException = { PyObject_GenericGetAttr, /*tp_getattro*/ PyObject_GenericSetAttr, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASE_EXC_SUBCLASS, /*tp_flags*/ PyDoc_STR("Common base class for all exceptions"), /* tp_doc */ (traverseproc)BaseException_traverse, /* tp_traverse */ (inquiry)BaseException_clear, /* tp_clear */ diff --git a/Objects/intobject.c b/Objects/intobject.c index f504af7..9ffc295 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -1138,7 +1138,7 @@ PyTypeObject PyInt_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS, /* tp_flags */ int_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ diff --git a/Objects/listobject.c b/Objects/listobject.c index 3083b5f..2ac5e86 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2672,7 +2672,7 @@ PyTypeObject PyList_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS, /* tp_flags */ list_doc, /* tp_doc */ (traverseproc)list_traverse, /* tp_traverse */ (inquiry)list_clear, /* tp_clear */ diff --git a/Objects/longobject.c b/Objects/longobject.c index 4d886cd..ef3e242 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3418,7 +3418,7 @@ PyTypeObject PyLong_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */ long_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 416457d..ca94d72 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -4017,7 +4017,7 @@ PyTypeObject PyString_Type = { 0, /* tp_setattro */ &string_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_STRING_SUBCLASS, /* tp_flags */ string_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index c85b35a..dacc3ee 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -669,7 +669,7 @@ PyTypeObject PyTuple_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS, /* tp_flags */ tuple_doc, /* tp_doc */ (traverseproc)tupletraverse, /* tp_traverse */ 0, /* tp_clear */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 20b530c..4b0816e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2288,7 +2288,7 @@ PyTypeObject PyType_Type = { (setattrofunc)type_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS, /* tp_flags */ type_doc, /* tp_doc */ (traverseproc)type_traverse, /* tp_traverse */ (inquiry)type_clear, /* tp_clear */ @@ -2967,6 +2967,26 @@ inherit_special(PyTypeObject *type, PyTypeObject *base) if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { COPYVAL(tp_dictoffset); } + + /* Setup fast subclass flags */ + if (PyType_IsSubtype(base, (PyTypeObject*)PyExc_BaseException)) + type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS; + else if (PyType_IsSubtype(base, &PyType_Type)) + type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS; + else if (PyType_IsSubtype(base, &PyInt_Type)) + type->tp_flags |= Py_TPFLAGS_INT_SUBCLASS; + else if (PyType_IsSubtype(base, &PyLong_Type)) + type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS; + else if (PyType_IsSubtype(base, &PyString_Type)) + type->tp_flags |= Py_TPFLAGS_STRING_SUBCLASS; + else if (PyType_IsSubtype(base, &PyUnicode_Type)) + type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS; + else if (PyType_IsSubtype(base, &PyTuple_Type)) + type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS; + else if (PyType_IsSubtype(base, &PyList_Type)) + type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS; + else if (PyType_IsSubtype(base, &PyDict_Type)) + type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; } static void diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 290e8df..a49fe39 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7967,7 +7967,7 @@ PyTypeObject PyUnicode_Type = { 0, /* tp_setattro */ &unicode_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_UNICODE_SUBCLASS, /* tp_flags */ unicode_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ -- cgit v0.12