@@ -45,7 +45,9 @@ class object "PyObject *" "&PyBaseObject_Type"
4545 PyUnicode_IS_READY(name) && \
4646 (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
4747
48- #define next_version_tag (_PyRuntime.types.next_version_tag)
48+ #define NEXT_GLOBAL_VERSION_TAG _PyRuntime.types.next_version_tag
49+ #define NEXT_VERSION_TAG (interp ) \
50+ (interp)->types.next_version_tag
4951
5052typedef struct PySlot_Offset {
5153 short subslot_offset ;
@@ -332,7 +334,7 @@ _PyType_ClearCache(PyInterpreterState *interp)
332334 // use Py_SETREF() rather than using slower Py_XSETREF().
333335 type_cache_clear (cache , Py_None );
334336
335- return next_version_tag - 1 ;
337+ return NEXT_VERSION_TAG ( interp ) - 1 ;
336338}
337339
338340
@@ -401,7 +403,7 @@ PyType_ClearWatcher(int watcher_id)
401403 return 0 ;
402404}
403405
404- static int assign_version_tag (PyTypeObject * type );
406+ static int assign_version_tag (PyInterpreterState * interp , PyTypeObject * type );
405407
406408int
407409PyType_Watch (int watcher_id , PyObject * obj )
@@ -416,7 +418,7 @@ PyType_Watch(int watcher_id, PyObject* obj)
416418 return -1 ;
417419 }
418420 // ensure we will get a callback on the next modification
419- assign_version_tag (type );
421+ assign_version_tag (interp , type );
420422 type -> tp_watched |= (1 << watcher_id );
421423 return 0 ;
422424}
@@ -549,7 +551,9 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
549551 }
550552 }
551553 return ;
554+
552555 clear :
556+ assert (!(type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
553557 type -> tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG ;
554558 type -> tp_version_tag = 0 ; /* 0 is not a valid version tag */
555559 if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
@@ -560,7 +564,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
560564}
561565
562566static int
563- assign_version_tag (PyTypeObject * type )
567+ assign_version_tag (PyInterpreterState * interp , PyTypeObject * type )
564568{
565569 /* Ensure that the tp_version_tag is valid and set
566570 Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
@@ -574,18 +578,30 @@ assign_version_tag(PyTypeObject *type)
574578 return 0 ;
575579 }
576580
577- if (next_version_tag == 0 ) {
578- /* We have run out of version numbers */
579- return 0 ;
581+ if (type -> tp_flags & Py_TPFLAGS_IMMUTABLETYPE ) {
582+ /* static types */
583+ if (NEXT_GLOBAL_VERSION_TAG > _Py_MAX_GLOBAL_TYPE_VERSION_TAG ) {
584+ /* We have run out of version numbers */
585+ return 0 ;
586+ }
587+ type -> tp_version_tag = NEXT_GLOBAL_VERSION_TAG ++ ;
588+ assert (type -> tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG );
589+ }
590+ else {
591+ /* heap types */
592+ if (NEXT_VERSION_TAG (interp ) == 0 ) {
593+ /* We have run out of version numbers */
594+ return 0 ;
595+ }
596+ type -> tp_version_tag = NEXT_VERSION_TAG (interp )++ ;
597+ assert (type -> tp_version_tag != 0 );
580598 }
581- type -> tp_version_tag = next_version_tag ++ ;
582- assert (type -> tp_version_tag != 0 );
583599
584600 PyObject * bases = type -> tp_bases ;
585601 Py_ssize_t n = PyTuple_GET_SIZE (bases );
586602 for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
587603 PyObject * b = PyTuple_GET_ITEM (bases , i );
588- if (!assign_version_tag (_PyType_CAST (b )))
604+ if (!assign_version_tag (interp , _PyType_CAST (b )))
589605 return 0 ;
590606 }
591607 type -> tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG ;
@@ -594,7 +610,8 @@ assign_version_tag(PyTypeObject *type)
594610
595611int PyUnstable_Type_AssignVersionTag (PyTypeObject * type )
596612{
597- return assign_version_tag (type );
613+ PyInterpreterState * interp = _PyInterpreterState_GET ();
614+ return assign_version_tag (interp , type );
598615}
599616
600617
@@ -2346,7 +2363,15 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro)
23462363 from the custom MRO */
23472364 type_mro_modified (type , type -> tp_bases );
23482365
2349- PyType_Modified (type );
2366+ // XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE?
2367+ if (!(type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN )) {
2368+ PyType_Modified (type );
2369+ }
2370+ else {
2371+ /* For static builtin types, this is only called during init
2372+ before the method cache has been populated. */
2373+ assert (_PyType_HasFeature (type , Py_TPFLAGS_VALID_VERSION_TAG ));
2374+ }
23502375
23512376 if (p_old_mro != NULL )
23522377 * p_old_mro = old_mro ; /* transfer the ownership */
@@ -4181,6 +4206,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
41814206{
41824207 PyObject * res ;
41834208 int error ;
4209+ PyInterpreterState * interp = _PyInterpreterState_GET ();
41844210
41854211 unsigned int h = MCACHE_HASH_METHOD (type , name );
41864212 struct type_cache * cache = get_type_cache ();
@@ -4215,7 +4241,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
42154241 return NULL ;
42164242 }
42174243
4218- if (MCACHE_CACHEABLE_NAME (name ) && assign_version_tag (type )) {
4244+ if (MCACHE_CACHEABLE_NAME (name ) && assign_version_tag (interp , type )) {
42194245 h = MCACHE_HASH_METHOD (type , name );
42204246 struct type_cache_entry * entry = & cache -> hashtable [h ];
42214247 entry -> version = type -> tp_version_tag ;
@@ -6676,8 +6702,11 @@ type_ready_mro(PyTypeObject *type)
66766702 assert (type -> tp_mro != NULL );
66776703 assert (PyTuple_Check (type -> tp_mro ));
66786704
6679- /* All bases of statically allocated type should be statically allocated */
6705+ /* All bases of statically allocated type should be statically allocated,
6706+ and static builtin types must have static builtin bases. */
66806707 if (!(type -> tp_flags & Py_TPFLAGS_HEAPTYPE )) {
6708+ assert (type -> tp_flags & Py_TPFLAGS_IMMUTABLETYPE );
6709+ int isbuiltin = type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ;
66816710 PyObject * mro = type -> tp_mro ;
66826711 Py_ssize_t n = PyTuple_GET_SIZE (mro );
66836712 for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
@@ -6689,6 +6718,7 @@ type_ready_mro(PyTypeObject *type)
66896718 type -> tp_name , base -> tp_name );
66906719 return -1 ;
66916720 }
6721+ assert (!isbuiltin || (base -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
66926722 }
66936723 }
66946724 return 0 ;
@@ -7000,7 +7030,11 @@ PyType_Ready(PyTypeObject *type)
70007030int
70017031_PyStaticType_InitBuiltin (PyTypeObject * self )
70027032{
7003- self -> tp_flags = self -> tp_flags | _Py_TPFLAGS_STATIC_BUILTIN ;
7033+ self -> tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN ;
7034+
7035+ assert (NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG );
7036+ self -> tp_version_tag = NEXT_GLOBAL_VERSION_TAG ++ ;
7037+ self -> tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG ;
70047038
70057039 static_builtin_state_init (self );
70067040
0 commit comments