@@ -1021,6 +1021,22 @@ set_version_unlocked(PyTypeObject *tp, unsigned int version)
10211021#endif
10221022}
10231023
1024+ static void
1025+ clear_spec_cache (PyTypeObject * type )
1026+ {
1027+ if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
1028+ // This field *must* be invalidated if the type is modified (see the
1029+ // comment on struct _specialization_cache):
1030+ PyHeapTypeObject * heap_type = (PyHeapTypeObject * )type ;
1031+ heap_type -> _spec_cache .getitem = NULL ;
1032+ struct local_type_cache * cache = heap_type -> _spec_cache .local_type_cache ;
1033+ if (cache != NULL ) {
1034+ _PyMem_FreeDelayed (cache );
1035+ heap_type -> _spec_cache .local_type_cache = NULL ;
1036+ }
1037+ }
1038+ }
1039+
10241040static void
10251041type_modified_unlocked (PyTypeObject * type )
10261042{
@@ -1082,11 +1098,7 @@ type_modified_unlocked(PyTypeObject *type)
10821098 }
10831099
10841100 set_version_unlocked (type , 0 ); /* 0 is not a valid version tag */
1085- if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
1086- // This field *must* be invalidated if the type is modified (see the
1087- // comment on struct _specialization_cache):
1088- ((PyHeapTypeObject * )type )-> _spec_cache .getitem = NULL ;
1089- }
1101+ clear_spec_cache (type );
10901102}
10911103
10921104void
@@ -1163,11 +1175,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
11631175 assert (!(type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
11641176 set_version_unlocked (type , 0 ); /* 0 is not a valid version tag */
11651177 type -> tp_versions_used = _Py_ATTR_CACHE_UNUSED ;
1166- if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
1167- // This field *must* be invalidated if the type is modified (see the
1168- // comment on struct _specialization_cache):
1169- ((PyHeapTypeObject * )type )-> _spec_cache .getitem = NULL ;
1170- }
1178+ clear_spec_cache (type );
11711179}
11721180
11731181/*
@@ -5553,6 +5561,19 @@ _PyType_LookupRefAndVersion(PyTypeObject *type, PyObject *name, unsigned int *ve
55535561 struct type_cache * cache = get_type_cache ();
55545562 struct type_cache_entry * entry = & cache -> hashtable [h ];
55555563#ifdef Py_GIL_DISABLED
5564+ PyHeapTypeObject * heap_type = (PyHeapTypeObject * )type ;
5565+ struct local_type_cache * local_cache = heap_type -> _spec_cache .local_type_cache ;
5566+
5567+ if (cache != NULL ) {
5568+ Py_ssize_t index = (((Py_ssize_t )(name )) >> 3 ) % LOCAL_CACHE_TYPE_SIZE ;
5569+ struct local_type_cache_entry * entry = & local_cache -> entries [index ];
5570+ PyObject * value ;
5571+ if (entry -> name == name && (value = _Py_TryXGetRef (& entry -> value )) != NULL ) {
5572+ * version = local_cache -> tp_version_tag ;
5573+ return value ;
5574+ }
5575+ }
5576+
55565577 // synchronize-with other writing threads by doing an acquire load on the sequence
55575578 while (1 ) {
55585579 uint32_t sequence = _PySeqLock_BeginRead (& entry -> sequence );
@@ -5638,6 +5659,28 @@ _PyType_LookupRefAndVersion(PyTypeObject *type, PyObject *name, unsigned int *ve
56385659 if (has_version ) {
56395660#if Py_GIL_DISABLED
56405661 update_cache_gil_disabled (entry , name , assigned_version , res );
5662+ if (res != NULL ) {
5663+ if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
5664+ PyHeapTypeObject * heap_type = (PyHeapTypeObject * )type ;
5665+ struct local_type_cache * local_cache = heap_type -> _spec_cache .local_type_cache ;
5666+ if (local_cache == NULL ) {
5667+ BEGIN_TYPE_LOCK ();
5668+ local_cache = PyMem_Calloc (1 , sizeof (struct local_type_cache ));
5669+ if (local_cache != NULL ) {
5670+ local_cache -> tp_version_tag = assigned_version ;
5671+ heap_type -> _spec_cache .local_type_cache = local_cache ;
5672+ }
5673+ END_TYPE_LOCK ();
5674+ }
5675+ if (local_cache != NULL ) {
5676+ struct local_type_cache_entry * entry =
5677+ & local_cache -> entries [(((Py_ssize_t )(name )) >> 3 ) % LOCAL_CACHE_TYPE_SIZE ];
5678+ entry -> name = name ;
5679+ entry -> value = res ;
5680+ }
5681+ }
5682+ }
5683+
56415684#else
56425685 PyObject * old_value = update_cache (entry , name , assigned_version , res );
56435686 Py_DECREF (old_value );
0 commit comments