@@ -4039,26 +4039,15 @@ subtype_getweakref(PyObject *obj, void *context)
40394039 return Py_NewRef (result );
40404040}
40414041
4042- /* Three variants on the subtype_getsets list. */
4043-
4044- static PyGetSetDef subtype_getsets_full [] = {
4045- {"__dict__" , subtype_dict , subtype_setdict ,
4046- PyDoc_STR ("dictionary for instance variables" )},
4047- {"__weakref__" , subtype_getweakref , NULL ,
4048- PyDoc_STR ("list of weak references to the object" )},
4049- {0 }
4050- };
4051-
4052- static PyGetSetDef subtype_getsets_dict_only [] = {
4053- {"__dict__" , subtype_dict , subtype_setdict ,
4054- PyDoc_STR ("dictionary for instance variables" )},
4055- {0 }
4042+ /* getset definitions for common descriptors */
4043+ static PyGetSetDef subtype_getset_dict = {
4044+ "__dict__" , subtype_dict , subtype_setdict ,
4045+ PyDoc_STR ("dictionary for instance variables" ),
40564046};
40574047
4058- static PyGetSetDef subtype_getsets_weakref_only [] = {
4059- {"__weakref__" , subtype_getweakref , NULL ,
4060- PyDoc_STR ("list of weak references to the object" )},
4061- {0 }
4048+ static PyGetSetDef subtype_getset_weakref = {
4049+ "__weakref__" , subtype_getweakref , NULL ,
4050+ PyDoc_STR ("list of weak references to the object" ),
40624051};
40634052
40644053static int
@@ -4594,10 +4583,36 @@ type_new_classmethod(PyObject *dict, PyObject *attr)
45944583 return 0 ;
45954584}
45964585
4586+ /* Add __dict__ or __weakref__ descriptor */
4587+ static int
4588+ type_add_common_descriptor (PyInterpreterState * interp ,
4589+ PyObject * * cache ,
4590+ PyGetSetDef * getset_def ,
4591+ PyObject * dict )
4592+ {
4593+ #ifdef Py_GIL_DISABLED
4594+ PyMutex_Lock (& interp -> cached_objects .descriptor_mutex );
4595+ #endif
4596+ PyObject * descr = * cache ;
4597+ if (!descr ) {
4598+ descr = PyDescr_NewGetSet (& PyBaseObject_Type , getset_def );
4599+ * cache = descr ;
4600+ }
4601+ #ifdef Py_GIL_DISABLED
4602+ PyMutex_Unlock (& interp -> cached_objects .descriptor_mutex );
4603+ #endif
4604+ if (!descr ) {
4605+ return -1 ;
4606+ }
4607+ if (PyDict_SetDefaultRef (dict , PyDescr_NAME (descr ), descr , NULL ) < 0 ) {
4608+ return -1 ;
4609+ }
4610+ return 0 ;
4611+ }
45974612
45984613/* Add descriptors for custom slots from __slots__, or for __dict__ */
45994614static int
4600- type_new_descriptors (const type_new_ctx * ctx , PyTypeObject * type )
4615+ type_new_descriptors (const type_new_ctx * ctx , PyTypeObject * type , PyObject * dict )
46014616{
46024617 PyHeapTypeObject * et = (PyHeapTypeObject * )type ;
46034618 Py_ssize_t slotoffset = ctx -> base -> tp_basicsize ;
@@ -4635,25 +4650,38 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
46354650 type -> tp_basicsize = slotoffset ;
46364651 type -> tp_itemsize = ctx -> base -> tp_itemsize ;
46374652 type -> tp_members = _PyHeapType_GET_MEMBERS (et );
4653+
4654+ PyInterpreterState * interp = _PyInterpreterState_GET ();
4655+
4656+ if (type -> tp_dictoffset ) {
4657+ if (type_add_common_descriptor (
4658+ interp ,
4659+ & interp -> cached_objects .dict_descriptor ,
4660+ & subtype_getset_dict ,
4661+ dict ) < 0 )
4662+ {
4663+ return -1 ;
4664+ }
4665+ }
4666+ if (type -> tp_weaklistoffset ) {
4667+ if (type_add_common_descriptor (
4668+ interp ,
4669+ & interp -> cached_objects .weakref_descriptor ,
4670+ & subtype_getset_weakref ,
4671+ dict ) < 0 )
4672+ {
4673+ return -1 ;
4674+ }
4675+ }
4676+
46384677 return 0 ;
46394678}
46404679
46414680
46424681static void
46434682type_new_set_slots (const type_new_ctx * ctx , PyTypeObject * type )
46444683{
4645- if (type -> tp_weaklistoffset && type -> tp_dictoffset ) {
4646- type -> tp_getset = subtype_getsets_full ;
4647- }
4648- else if (type -> tp_weaklistoffset && !type -> tp_dictoffset ) {
4649- type -> tp_getset = subtype_getsets_weakref_only ;
4650- }
4651- else if (!type -> tp_weaklistoffset && type -> tp_dictoffset ) {
4652- type -> tp_getset = subtype_getsets_dict_only ;
4653- }
4654- else {
4655- type -> tp_getset = NULL ;
4656- }
4684+ type -> tp_getset = NULL ;
46574685
46584686 /* Special case some slots */
46594687 if (type -> tp_dictoffset != 0 || ctx -> nslot > 0 ) {
@@ -4758,7 +4786,7 @@ type_new_set_attrs(const type_new_ctx *ctx, PyTypeObject *type)
47584786 return -1 ;
47594787 }
47604788
4761- if (type_new_descriptors (ctx , type ) < 0 ) {
4789+ if (type_new_descriptors (ctx , type , dict ) < 0 ) {
47624790 return -1 ;
47634791 }
47644792
@@ -6642,6 +6670,14 @@ _PyStaticType_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
66426670}
66436671
66446672
6673+ void
6674+ _PyTypes_FiniCachedDescriptors (PyInterpreterState * interp )
6675+ {
6676+ Py_CLEAR (interp -> cached_objects .dict_descriptor );
6677+ Py_CLEAR (interp -> cached_objects .weakref_descriptor );
6678+ }
6679+
6680+
66456681static void
66466682type_dealloc (PyObject * self )
66476683{
0 commit comments