mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									5a3e812444
								
							
						
					
					
						commit
						ee3a1b5244
					
				
					 18 changed files with 61 additions and 22 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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) | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -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))					   \ | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Neal Norwitz
						Neal Norwitz