Commit ee3a1b52 authored by Neal Norwitz's avatar Neal Norwitz

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.
parent 5a3e8124
...@@ -90,7 +90,8 @@ struct _dictobject { ...@@ -90,7 +90,8 @@ struct _dictobject {
PyAPI_DATA(PyTypeObject) PyDict_Type; 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) #define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type)
PyAPI_FUNC(PyObject *) PyDict_New(void); PyAPI_FUNC(PyObject *) PyDict_New(void);
......
...@@ -27,7 +27,8 @@ typedef struct { ...@@ -27,7 +27,8 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PyInt_Type; 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) #define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type)
PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int); PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int);
......
...@@ -40,7 +40,8 @@ typedef struct { ...@@ -40,7 +40,8 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PyList_Type; 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) #define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type)
PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size);
......
...@@ -11,7 +11,8 @@ typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ ...@@ -11,7 +11,8 @@ typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */
PyAPI_DATA(PyTypeObject) PyLong_Type; 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) #define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type)
PyAPI_FUNC(PyObject *) PyLong_FromLong(long); PyAPI_FUNC(PyObject *) PyLong_FromLong(long);
......
...@@ -376,7 +376,8 @@ PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */ ...@@ -376,7 +376,8 @@ PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */
PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */ PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */
PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */ 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) #define PyType_CheckExact(op) ((op)->ob_type == &PyType_Type)
PyAPI_FUNC(int) PyType_Ready(PyTypeObject *); PyAPI_FUNC(int) PyType_Ready(PyTypeObject *);
...@@ -517,6 +518,17 @@ given type object has a specified feature. ...@@ -517,6 +518,17 @@ given type object has a specified feature.
/* Objects support nb_index in PyNumberMethods */ /* Objects support nb_index in PyNumberMethods */
#define Py_TPFLAGS_HAVE_INDEX (1L<<17) #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 ( \ #define Py_TPFLAGS_DEFAULT ( \
Py_TPFLAGS_HAVE_GETCHARBUFFER | \ Py_TPFLAGS_HAVE_GETCHARBUFFER | \
Py_TPFLAGS_HAVE_SEQUENCE_IN | \ Py_TPFLAGS_HAVE_SEQUENCE_IN | \
...@@ -530,6 +542,7 @@ given type object has a specified feature. ...@@ -530,6 +542,7 @@ given type object has a specified feature.
0) 0)
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) #define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)
#define PyType_FastSubclass(t,f) PyType_HasFeature(t,f)
/* /*
......
...@@ -95,14 +95,12 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); ...@@ -95,14 +95,12 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
/* */ /* */
#define PyExceptionClass_Check(x) \ #define PyExceptionClass_Check(x) \
(PyClass_Check((x)) \ (PyClass_Check((x)) || (PyType_Check((x)) && \
|| (PyType_Check((x)) && PyType_IsSubtype( \ PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)))
(PyTypeObject*)(x), (PyTypeObject*)PyExc_BaseException)))
#define PyExceptionInstance_Check(x) \ #define PyExceptionInstance_Check(x) \
(PyInstance_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) \ #define PyExceptionClass_Name(x) \
(PyClass_Check((x)) \ (PyClass_Check((x)) \
......
...@@ -55,7 +55,8 @@ typedef struct { ...@@ -55,7 +55,8 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PyBaseString_Type; PyAPI_DATA(PyTypeObject) PyBaseString_Type;
PyAPI_DATA(PyTypeObject) PyString_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) #define PyString_CheckExact(op) ((op)->ob_type == &PyString_Type)
PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t); PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t);
......
...@@ -33,7 +33,8 @@ typedef struct { ...@@ -33,7 +33,8 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PyTuple_Type; 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) #define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type)
PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size);
......
...@@ -392,7 +392,8 @@ typedef struct { ...@@ -392,7 +392,8 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PyUnicode_Type; 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) #define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type)
/* Fast access macros */ /* Fast access macros */
......
...@@ -2112,7 +2112,7 @@ PyTypeObject PyDict_Type = { ...@@ -2112,7 +2112,7 @@ PyTypeObject PyDict_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 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 */ dictionary_doc, /* tp_doc */
dict_traverse, /* tp_traverse */ dict_traverse, /* tp_traverse */
dict_tp_clear, /* tp_clear */ dict_tp_clear, /* tp_clear */
......
...@@ -300,7 +300,8 @@ static PyTypeObject _PyExc_BaseException = { ...@@ -300,7 +300,8 @@ static PyTypeObject _PyExc_BaseException = {
PyObject_GenericGetAttr, /*tp_getattro*/ PyObject_GenericGetAttr, /*tp_getattro*/
PyObject_GenericSetAttr, /*tp_setattro*/ PyObject_GenericSetAttr, /*tp_setattro*/
0, /*tp_as_buffer*/ 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 */ PyDoc_STR("Common base class for all exceptions"), /* tp_doc */
(traverseproc)BaseException_traverse, /* tp_traverse */ (traverseproc)BaseException_traverse, /* tp_traverse */
(inquiry)BaseException_clear, /* tp_clear */ (inquiry)BaseException_clear, /* tp_clear */
......
...@@ -1138,7 +1138,7 @@ PyTypeObject PyInt_Type = { ...@@ -1138,7 +1138,7 @@ PyTypeObject PyInt_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS, /* tp_flags */
int_doc, /* tp_doc */ int_doc, /* tp_doc */
0, /* tp_traverse */ 0, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
......
...@@ -2672,7 +2672,7 @@ PyTypeObject PyList_Type = { ...@@ -2672,7 +2672,7 @@ PyTypeObject PyList_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 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 */ list_doc, /* tp_doc */
(traverseproc)list_traverse, /* tp_traverse */ (traverseproc)list_traverse, /* tp_traverse */
(inquiry)list_clear, /* tp_clear */ (inquiry)list_clear, /* tp_clear */
......
...@@ -3418,7 +3418,7 @@ PyTypeObject PyLong_Type = { ...@@ -3418,7 +3418,7 @@ PyTypeObject PyLong_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
long_doc, /* tp_doc */ long_doc, /* tp_doc */
0, /* tp_traverse */ 0, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
......
...@@ -4017,7 +4017,7 @@ PyTypeObject PyString_Type = { ...@@ -4017,7 +4017,7 @@ PyTypeObject PyString_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
&string_as_buffer, /* tp_as_buffer */ &string_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_STRING_SUBCLASS, /* tp_flags */
string_doc, /* tp_doc */ string_doc, /* tp_doc */
0, /* tp_traverse */ 0, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
......
...@@ -669,7 +669,7 @@ PyTypeObject PyTuple_Type = { ...@@ -669,7 +669,7 @@ PyTypeObject PyTuple_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 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 */ tuple_doc, /* tp_doc */
(traverseproc)tupletraverse, /* tp_traverse */ (traverseproc)tupletraverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
......
...@@ -2288,7 +2288,7 @@ PyTypeObject PyType_Type = { ...@@ -2288,7 +2288,7 @@ PyTypeObject PyType_Type = {
(setattrofunc)type_setattro, /* tp_setattro */ (setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | 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 */ type_doc, /* tp_doc */
(traverseproc)type_traverse, /* tp_traverse */ (traverseproc)type_traverse, /* tp_traverse */
(inquiry)type_clear, /* tp_clear */ (inquiry)type_clear, /* tp_clear */
...@@ -2967,6 +2967,26 @@ inherit_special(PyTypeObject *type, PyTypeObject *base) ...@@ -2967,6 +2967,26 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
COPYVAL(tp_dictoffset); 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 static void
......
...@@ -7967,7 +7967,7 @@ PyTypeObject PyUnicode_Type = { ...@@ -7967,7 +7967,7 @@ PyTypeObject PyUnicode_Type = {
0, /* tp_setattro */ 0, /* tp_setattro */
&unicode_as_buffer, /* tp_as_buffer */ &unicode_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_UNICODE_SUBCLASS, /* tp_flags */
unicode_doc, /* tp_doc */ unicode_doc, /* tp_doc */
0, /* tp_traverse */ 0, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment