summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-08-16 11:21:34 (GMT)
committerGitHub <noreply@github.com>2021-08-16 11:21:34 (GMT)
commit1a511dc92dd10ee8fc2e5da9f52f795924bdc89a (patch)
treec98500f27aebb8cb371389d767f8eecd4ab17d0c /Objects
parent62bc716fde20fcb7b47416c7959be9e66df93212 (diff)
downloadcpython-1a511dc92dd10ee8fc2e5da9f52f795924bdc89a.zip
cpython-1a511dc92dd10ee8fc2e5da9f52f795924bdc89a.tar.gz
cpython-1a511dc92dd10ee8fc2e5da9f52f795924bdc89a.tar.bz2
bpo-44914: Maintain invariants of type version tags. (GH-27773)
* Do not invalidate type versions unnecessarily.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c40
1 files changed, 13 insertions, 27 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 7ae50c4..1efb9fc 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -45,7 +45,7 @@ class object "PyObject *" "&PyBaseObject_Type"
// bpo-42745: next_version_tag remains shared by all interpreters because of static types
// Used to set PyTypeObject.tp_version_tag
-static unsigned int next_version_tag = 0;
+static unsigned int next_version_tag = 1;
typedef struct PySlot_Offset {
short subslot_offset;
@@ -233,24 +233,14 @@ get_type_cache(void)
static void
-type_cache_clear(struct type_cache *cache, int use_none)
+type_cache_clear(struct type_cache *cache, PyObject *value)
{
for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
struct type_cache_entry *entry = &cache->hashtable[i];
entry->version = 0;
- if (use_none) {
- // Set to None so _PyType_Lookup() can use Py_SETREF(),
- // rather than using slower Py_XSETREF().
- Py_XSETREF(entry->name, Py_NewRef(Py_None));
- }
- else {
- Py_CLEAR(entry->name);
- }
+ Py_XSETREF(entry->name, _Py_XNewRef(value));
entry->value = NULL;
}
-
- // Mark all version tags as invalid
- PyType_Modified(&PyBaseObject_Type);
}
@@ -287,14 +277,11 @@ _PyType_ClearCache(PyInterpreterState *interp)
sizeof(cache->hashtable) / 1024);
#endif
- unsigned int cur_version_tag = next_version_tag - 1;
- if (_Py_IsMainInterpreter(interp)) {
- next_version_tag = 0;
- }
+ // Set to None, rather than NULL, so _PyType_Lookup() can
+ // use Py_SETREF() rather than using slower Py_XSETREF().
+ type_cache_clear(cache, Py_None);
- type_cache_clear(cache, 0);
-
- return cur_version_tag;
+ return next_version_tag - 1;
}
@@ -309,7 +296,8 @@ PyType_ClearCache(void)
void
_PyType_Fini(PyInterpreterState *interp)
{
- _PyType_ClearCache(interp);
+ struct type_cache *cache = &interp->type_cache;
+ type_cache_clear(cache, NULL);
if (_Py_IsMainInterpreter(interp)) {
clear_slotdefs();
}
@@ -426,14 +414,12 @@ assign_version_tag(struct type_cache *cache, PyTypeObject *type)
if (!_PyType_HasFeature(type, Py_TPFLAGS_READY))
return 0;
- type->tp_version_tag = next_version_tag++;
- /* for stress-testing: next_version_tag &= 0xFF; */
-
- if (type->tp_version_tag == 0) {
- // Wrap-around or just starting Python - clear the whole cache
- type_cache_clear(cache, 1);
+ if (next_version_tag == 0) {
+ /* We have run out of version numbers */
return 0;
}
+ type->tp_version_tag = next_version_tag++;
+ assert (type->tp_version_tag != 0);
bases = type->tp_bases;
n = PyTuple_GET_SIZE(bases);