@@ -45,7 +45,9 @@ class object "PyObject *" "&PyBaseObject_Type"
45
45
PyUnicode_IS_READY(name) && \
46
46
(PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
47
47
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
49
51
50
52
typedef struct PySlot_Offset {
51
53
short subslot_offset ;
@@ -332,7 +334,7 @@ _PyType_ClearCache(PyInterpreterState *interp)
332
334
// use Py_SETREF() rather than using slower Py_XSETREF().
333
335
type_cache_clear (cache , Py_None );
334
336
335
- return next_version_tag - 1 ;
337
+ return NEXT_VERSION_TAG ( interp ) - 1 ;
336
338
}
337
339
338
340
@@ -401,7 +403,7 @@ PyType_ClearWatcher(int watcher_id)
401
403
return 0 ;
402
404
}
403
405
404
- static int assign_version_tag (PyTypeObject * type );
406
+ static int assign_version_tag (PyInterpreterState * interp , PyTypeObject * type );
405
407
406
408
int
407
409
PyType_Watch (int watcher_id , PyObject * obj )
@@ -416,7 +418,7 @@ PyType_Watch(int watcher_id, PyObject* obj)
416
418
return -1 ;
417
419
}
418
420
// ensure we will get a callback on the next modification
419
- assign_version_tag (type );
421
+ assign_version_tag (interp , type );
420
422
type -> tp_watched |= (1 << watcher_id );
421
423
return 0 ;
422
424
}
@@ -549,7 +551,9 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
549
551
}
550
552
}
551
553
return ;
554
+
552
555
clear :
556
+ assert (!(type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
553
557
type -> tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG ;
554
558
type -> tp_version_tag = 0 ; /* 0 is not a valid version tag */
555
559
if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
@@ -560,7 +564,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
560
564
}
561
565
562
566
static int
563
- assign_version_tag (PyTypeObject * type )
567
+ assign_version_tag (PyInterpreterState * interp , PyTypeObject * type )
564
568
{
565
569
/* Ensure that the tp_version_tag is valid and set
566
570
Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
@@ -574,18 +578,30 @@ assign_version_tag(PyTypeObject *type)
574
578
return 0 ;
575
579
}
576
580
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 );
580
598
}
581
- type -> tp_version_tag = next_version_tag ++ ;
582
- assert (type -> tp_version_tag != 0 );
583
599
584
600
PyObject * bases = type -> tp_bases ;
585
601
Py_ssize_t n = PyTuple_GET_SIZE (bases );
586
602
for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
587
603
PyObject * b = PyTuple_GET_ITEM (bases , i );
588
- if (!assign_version_tag (_PyType_CAST (b )))
604
+ if (!assign_version_tag (interp , _PyType_CAST (b )))
589
605
return 0 ;
590
606
}
591
607
type -> tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG ;
@@ -594,7 +610,8 @@ assign_version_tag(PyTypeObject *type)
594
610
595
611
int PyUnstable_Type_AssignVersionTag (PyTypeObject * type )
596
612
{
597
- return assign_version_tag (type );
613
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
614
+ return assign_version_tag (interp , type );
598
615
}
599
616
600
617
@@ -2346,7 +2363,15 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro)
2346
2363
from the custom MRO */
2347
2364
type_mro_modified (type , type -> tp_bases );
2348
2365
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
+ }
2350
2375
2351
2376
if (p_old_mro != NULL )
2352
2377
* p_old_mro = old_mro ; /* transfer the ownership */
@@ -4181,6 +4206,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
4181
4206
{
4182
4207
PyObject * res ;
4183
4208
int error ;
4209
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
4184
4210
4185
4211
unsigned int h = MCACHE_HASH_METHOD (type , name );
4186
4212
struct type_cache * cache = get_type_cache ();
@@ -4215,7 +4241,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
4215
4241
return NULL ;
4216
4242
}
4217
4243
4218
- if (MCACHE_CACHEABLE_NAME (name ) && assign_version_tag (type )) {
4244
+ if (MCACHE_CACHEABLE_NAME (name ) && assign_version_tag (interp , type )) {
4219
4245
h = MCACHE_HASH_METHOD (type , name );
4220
4246
struct type_cache_entry * entry = & cache -> hashtable [h ];
4221
4247
entry -> version = type -> tp_version_tag ;
@@ -6676,8 +6702,11 @@ type_ready_mro(PyTypeObject *type)
6676
6702
assert (type -> tp_mro != NULL );
6677
6703
assert (PyTuple_Check (type -> tp_mro ));
6678
6704
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. */
6680
6707
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 ;
6681
6710
PyObject * mro = type -> tp_mro ;
6682
6711
Py_ssize_t n = PyTuple_GET_SIZE (mro );
6683
6712
for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
@@ -6689,6 +6718,7 @@ type_ready_mro(PyTypeObject *type)
6689
6718
type -> tp_name , base -> tp_name );
6690
6719
return -1 ;
6691
6720
}
6721
+ assert (!isbuiltin || (base -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
6692
6722
}
6693
6723
}
6694
6724
return 0 ;
@@ -7000,7 +7030,11 @@ PyType_Ready(PyTypeObject *type)
7000
7030
int
7001
7031
_PyStaticType_InitBuiltin (PyTypeObject * self )
7002
7032
{
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 ;
7004
7038
7005
7039
static_builtin_state_init (self );
7006
7040
0 commit comments