@@ -4036,29 +4036,15 @@ subtype_getweakref(PyObject *obj, void *context)
40364036 return Py_NewRef (result );
40374037}
40384038
4039- /* Three variants on the subtype_getsets list. */
4040-
4041- static char subtype_getset_dict_name [] = "__dict__" ;
4042- static char subtype_getset_weakref_name [] = "__weakref__" ;
4043-
4044- static PyGetSetDef subtype_getsets_full [] = {
4045- {subtype_getset_dict_name , subtype_dict , subtype_setdict ,
4046- PyDoc_STR ("dictionary for instance variables" )},
4047- {subtype_getset_weakref_name , subtype_getweakref , NULL ,
4048- PyDoc_STR ("list of weak references to the object" )},
4049- {0 }
4039+ /* getset definitions for common descriptors */
4040+ static PyGetSetDef subtype_getset_dict = {
4041+ "__dict__" , subtype_dict , subtype_setdict ,
4042+ PyDoc_STR ("dictionary for instance variables" ),
40504043};
40514044
4052- static PyGetSetDef subtype_getsets_dict_only [] = {
4053- {subtype_getset_dict_name , subtype_dict , subtype_setdict ,
4054- PyDoc_STR ("dictionary for instance variables" )},
4055- {0 }
4056- };
4057-
4058- static PyGetSetDef subtype_getsets_weakref_only [] = {
4059- {subtype_getset_weakref_name , subtype_getweakref , NULL ,
4060- PyDoc_STR ("list of weak references to the object" )},
4061- {0 }
4045+ static PyGetSetDef subtype_getset_weakref = {
4046+ "__weakref__" , subtype_getweakref , NULL ,
4047+ PyDoc_STR ("list of weak references to the object" ),
40624048};
40634049
40644050static int
@@ -4594,10 +4580,36 @@ type_new_classmethod(PyObject *dict, PyObject *attr)
45944580 return 0 ;
45954581}
45964582
4583+ /* Add __dict__ or __weakref__ descriptor */
4584+ static int
4585+ type_add_common_descriptor (PyInterpreterState * interp ,
4586+ PyObject * * cache ,
4587+ PyGetSetDef * getset_def ,
4588+ PyObject * dict )
4589+ {
4590+ #ifdef Py_GIL_DISABLED
4591+ PyMutex_Lock (& interp -> cached_objects .descriptor_mutex );
4592+ #endif
4593+ PyObject * descr = * cache ;
4594+ if (!descr ) {
4595+ descr = PyDescr_NewGetSet (& PyBaseObject_Type , getset_def );
4596+ * cache = descr ;
4597+ }
4598+ #ifdef Py_GIL_DISABLED
4599+ PyMutex_Unlock (& interp -> cached_objects .descriptor_mutex );
4600+ #endif
4601+ if (!descr ) {
4602+ return -1 ;
4603+ }
4604+ if (PyDict_SetDefaultRef (dict , PyDescr_NAME (descr ), descr , NULL ) < 0 ) {
4605+ return -1 ;
4606+ }
4607+ return 0 ;
4608+ }
45974609
45984610/* Add descriptors for custom slots from __slots__, or for __dict__ */
45994611static int
4600- type_new_descriptors (const type_new_ctx * ctx , PyTypeObject * type )
4612+ type_new_descriptors (const type_new_ctx * ctx , PyTypeObject * type , PyObject * dict )
46014613{
46024614 PyHeapTypeObject * et = (PyHeapTypeObject * )type ;
46034615 Py_ssize_t slotoffset = ctx -> base -> tp_basicsize ;
@@ -4635,25 +4647,38 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
46354647 type -> tp_basicsize = slotoffset ;
46364648 type -> tp_itemsize = ctx -> base -> tp_itemsize ;
46374649 type -> tp_members = _PyHeapType_GET_MEMBERS (et );
4650+
4651+ PyInterpreterState * interp = _PyInterpreterState_GET ();
4652+
4653+ if (type -> tp_dictoffset ) {
4654+ if (type_add_common_descriptor (
4655+ interp ,
4656+ & interp -> cached_objects .dict_descriptor ,
4657+ & subtype_getset_dict ,
4658+ dict ) < 0 )
4659+ {
4660+ return -1 ;
4661+ }
4662+ }
4663+ if (type -> tp_weaklistoffset ) {
4664+ if (type_add_common_descriptor (
4665+ interp ,
4666+ & interp -> cached_objects .weakref_descriptor ,
4667+ & subtype_getset_weakref ,
4668+ dict ) < 0 )
4669+ {
4670+ return -1 ;
4671+ }
4672+ }
4673+
46384674 return 0 ;
46394675}
46404676
46414677
46424678static void
46434679type_new_set_slots (const type_new_ctx * ctx , PyTypeObject * type )
46444680{
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- }
4681+ type -> tp_getset = NULL ;
46574682
46584683 /* Special case some slots */
46594684 if (type -> tp_dictoffset != 0 || ctx -> nslot > 0 ) {
@@ -4758,7 +4783,7 @@ type_new_set_attrs(const type_new_ctx *ctx, PyTypeObject *type)
47584783 return -1 ;
47594784 }
47604785
4761- if (type_new_descriptors (ctx , type ) < 0 ) {
4786+ if (type_new_descriptors (ctx , type , dict ) < 0 ) {
47624787 return -1 ;
47634788 }
47644789
@@ -6642,6 +6667,14 @@ _PyStaticType_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
66426667}
66436668
66446669
6670+ void
6671+ _PyTypes_FiniCachedDescriptors (PyInterpreterState * interp )
6672+ {
6673+ Py_CLEAR (interp -> cached_objects .dict_descriptor );
6674+ Py_CLEAR (interp -> cached_objects .weakref_descriptor );
6675+ }
6676+
6677+
66456678static void
66466679type_dealloc (PyObject * self )
66476680{
@@ -8332,16 +8365,7 @@ type_add_getset(PyTypeObject *type)
83328365
83338366 PyObject * dict = lookup_tp_dict (type );
83348367 for (; gsp -> name != NULL ; gsp ++ ) {
8335- PyTypeObject * descr_type = type ;
8336- // Hack: dict and weakref descriptors are created for `object`,
8337- // rather than this specific type.
8338- // We identify their PyGetSetDef by pointer equality on name.
8339- if (gsp -> name == subtype_getset_dict_name
8340- || gsp -> name == subtype_getset_weakref_name )
8341- {
8342- descr_type = & PyBaseObject_Type ;
8343- }
8344- PyObject * descr = PyDescr_NewGetSet (descr_type , gsp );
8368+ PyObject * descr = PyDescr_NewGetSet (type , gsp );
83458369 if (descr == NULL ) {
83468370 return -1 ;
83478371 }
0 commit comments