]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-81057: Move the global Dict-Related Versions to _PyRuntimeState (gh-99497)
authorEric Snow <ericsnowcurrently@gmail.com>
Wed, 16 Nov 2022 17:37:29 +0000 (10:37 -0700)
committerGitHub <noreply@github.com>
Wed, 16 Nov 2022 17:37:29 +0000 (10:37 -0700)
We also move the global func version.

https://github.com/python/cpython/issues/81057

16 files changed:
Include/internal/pycore_dict.h
Include/internal/pycore_dict_state.h [new file with mode: 0644]
Include/internal/pycore_function.h
Include/internal/pycore_interp.h
Include/internal/pycore_runtime.h
Include/internal/pycore_runtime_init.h
Makefile.pre.in
Modules/_functoolsmodule.c
Objects/call.c
Objects/dictobject.c
Objects/funcobject.c
Objects/typeobject.c
PCbuild/pythoncore.vcxproj
PCbuild/pythoncore.vcxproj.filters
Python/pystate.c
Tools/c-analyzer/cpython/globals-to-fix.tsv

index ae4094a095d879a5782a68889c1585116bfa4a00..25bd3bffb2e7aa2fa02b19a2aec1ec70acaa1983 100644 (file)
@@ -9,6 +9,9 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
+#include "pycore_dict_state.h"
+#include "pycore_runtime.h"         // _PyRuntime
+
 
 /* runtime lifecycle */
 
@@ -17,25 +20,6 @@ extern void _PyDict_Fini(PyInterpreterState *interp);
 
 /* other API */
 
-#ifndef WITH_FREELISTS
-// without freelists
-#  define PyDict_MAXFREELIST 0
-#endif
-
-#ifndef PyDict_MAXFREELIST
-#  define PyDict_MAXFREELIST 80
-#endif
-
-struct _Py_dict_state {
-#if PyDict_MAXFREELIST > 0
-    /* Dictionary reuse scheme to save calls to malloc and free */
-    PyDictObject *free_list[PyDict_MAXFREELIST];
-    int numfree;
-    PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
-    int keys_numfree;
-#endif
-};
-
 typedef struct {
     /* Cached hash code of me_key. */
     Py_hash_t me_hash;
@@ -152,13 +136,11 @@ struct _dictvalues {
      (PyDictUnicodeEntry*)(&((int8_t*)((dk)->dk_indices))[(size_t)1 << (dk)->dk_log2_index_bytes]))
 #define DK_IS_UNICODE(dk) ((dk)->dk_kind != DICT_KEYS_GENERAL)
 
-extern uint64_t _pydict_global_version;
-
-#define DICT_MAX_WATCHERS 8
 #define DICT_VERSION_INCREMENT (1 << DICT_MAX_WATCHERS)
 #define DICT_VERSION_MASK (DICT_VERSION_INCREMENT - 1)
 
-#define DICT_NEXT_VERSION() (_pydict_global_version += DICT_VERSION_INCREMENT)
+#define DICT_NEXT_VERSION() \
+    (_PyRuntime.dict_state.global_version += DICT_VERSION_INCREMENT)
 
 void
 _PyDict_SendEvent(int watcher_bits,
diff --git a/Include/internal/pycore_dict_state.h b/Include/internal/pycore_dict_state.h
new file mode 100644 (file)
index 0000000..77375ea
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef Py_INTERNAL_DICT_STATE_H
+#define Py_INTERNAL_DICT_STATE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+#  error "this header requires Py_BUILD_CORE define"
+#endif
+
+
+struct _Py_dict_runtime_state {
+    /*Global counter used to set ma_version_tag field of dictionary.
+     * It is incremented each time that a dictionary is created and each
+     * time that a dictionary is modified. */
+    uint64_t global_version;
+    uint32_t next_keys_version;
+};
+
+
+#ifndef WITH_FREELISTS
+// without freelists
+#  define PyDict_MAXFREELIST 0
+#endif
+
+#ifndef PyDict_MAXFREELIST
+#  define PyDict_MAXFREELIST 80
+#endif
+
+#define DICT_MAX_WATCHERS 8
+
+struct _Py_dict_state {
+#if PyDict_MAXFREELIST > 0
+    /* Dictionary reuse scheme to save calls to malloc and free */
+    PyDictObject *free_list[PyDict_MAXFREELIST];
+    PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
+    int numfree;
+    int keys_numfree;
+#endif
+    PyDict_WatchCallback watchers[DICT_MAX_WATCHERS];
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif   /* !Py_INTERNAL_DICT_STATE_H */
index 1c87aa31ddb611e82faf8b2fd0e5708298c1e940..c95190f5217315b4382f01dad538238b5b62e326 100644 (file)
@@ -8,6 +8,10 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
+struct _py_func_runtime_state {
+    uint32_t next_version;
+};
+
 extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr);
 
 extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
index b7fc4b480d7f80640e369bb2e2ae83c35c12e01d..437bf74b771dc053af9e6b40766b4c774102d8ef 100644 (file)
@@ -14,7 +14,7 @@ extern "C" {
 #include "pycore_ast_state.h"     // struct ast_state
 #include "pycore_code.h"          // struct callable_cache
 #include "pycore_context.h"       // struct _Py_context_state
-#include "pycore_dict.h"          // struct _Py_dict_state
+#include "pycore_dict_state.h"    // struct _Py_dict_state
 #include "pycore_exceptions.h"    // struct _Py_exc_state
 #include "pycore_floatobject.h"   // struct _Py_float_state
 #include "pycore_genobject.h"     // struct _Py_async_gen_state
@@ -171,8 +171,6 @@ struct _is {
     // Initialized to _PyEval_EvalFrameDefault().
     _PyFrameEvalFunction eval_frame;
 
-    PyDict_WatchCallback dict_watchers[DICT_MAX_WATCHERS];
-
     Py_ssize_t co_extra_user_count;
     freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS];
 
index f8b988021b9992a3c32fe34f5a6d76b45a4b3b24..c1829cb1bdadeb933d49650a84af2a4ef39593d1 100644 (file)
@@ -9,8 +9,10 @@ extern "C" {
 #endif
 
 #include "pycore_atomic.h"          /* _Py_atomic_address */
+#include "pycore_dict_state.h"      // struct _Py_dict_runtime_state
 #include "pycore_dtoa.h"            // struct _dtoa_runtime_state
 #include "pycore_floatobject.h"     // struct _Py_float_runtime_state
+#include "pycore_function.h"        // struct _func_runtime_state
 #include "pycore_gil.h"             // struct _gil_runtime_state
 #include "pycore_global_objects.h"  // struct _Py_global_objects
 #include "pycore_import.h"          // struct _import_runtime_state
@@ -151,6 +153,8 @@ typedef struct pyruntimestate {
 
     struct _Py_float_runtime_state float_state;
     struct _Py_unicode_runtime_state unicode_state;
+    struct _Py_dict_runtime_state dict_state;
+    struct _py_func_runtime_state func_state;
 
     struct {
         /* Used to set PyTypeObject.tp_version_tag */
index 334928e58acf2b2d16a5472afcf40e8dd10c95b6..ab53876e355fd8d2c606875f67b7921ef48ca92f 100644 (file)
@@ -58,6 +58,12 @@ extern "C" {
             .float_format = _py_float_format_unknown, \
             .double_format = _py_float_format_unknown, \
         }, \
+        .dict_state = { \
+            .next_keys_version = 2, \
+        }, \
+        .func_state = { \
+            .next_version = 1, \
+        }, \
         .types = { \
             .next_version_tag = 1, \
         }, \
index e1910f6aab8c14b873cbb0dcdd95cbdd3120389f..b7505c3364309bb6d82297b4c1462084247eebc4 100644 (file)
@@ -1627,6 +1627,7 @@ PYTHON_HEADERS= \
                $(srcdir)/Include/internal/pycore_condvar.h \
                $(srcdir)/Include/internal/pycore_context.h \
                $(srcdir)/Include/internal/pycore_dict.h \
+               $(srcdir)/Include/internal/pycore_dict_state.h \
                $(srcdir)/Include/internal/pycore_descrobject.h \
                $(srcdir)/Include/internal/pycore_dtoa.h \
                $(srcdir)/Include/internal/pycore_exceptions.h \
index 3aef296745ada13f87c1954f0e03a271666cfb72..9b30f41ec69932ecf16c5580e81d141e44e4307c 100644 (file)
@@ -1,5 +1,6 @@
 #include "Python.h"
 #include "pycore_call.h"          // _PyObject_CallNoArgs()
+#include "pycore_dict.h"          // _PyDict_Pop_KnownHash()
 #include "pycore_long.h"          // _PyLong_GetZero()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
 #include "pycore_object.h"        // _PyObject_GC_TRACK
index c4d31d0a27ece61bd0cdfd023b9c5d8492fc984d..bd027e41f8a9a5f4c1e87974a7b2868d6596a7ff 100644 (file)
@@ -1,6 +1,7 @@
 #include "Python.h"
 #include "pycore_call.h"          // _PyObject_CallNoArgsTstate()
 #include "pycore_ceval.h"         // _Py_EnterRecursiveCallTstate()
+#include "pycore_dict.h"          // _PyDict_FromItems()
 #include "pycore_object.h"        // _PyCFunctionWithKeywords_TrampolineCall()
 #include "pycore_pyerrors.h"      // _PyErr_Occurred()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
index 51903ab271d8cb8b16e56e557d0ca4f0de3f9c2a..c58d07b51bd89a35f7863222a268a7bfea2fca59 100644 (file)
@@ -236,11 +236,6 @@ static int dictresize(PyDictObject *mp, uint8_t log_newsize, int unicode);
 
 static PyObject* dict_iter(PyDictObject *dict);
 
-/*Global counter used to set ma_version_tag field of dictionary.
- * It is incremented each time that a dictionary is created and each
- * time that a dictionary is modified. */
-uint64_t _pydict_global_version = 0;
-
 #include "clinic/dictobject.c.h"
 
 
@@ -5658,17 +5653,15 @@ _PyDictKeys_DecRef(PyDictKeysObject *keys)
     dictkeys_decref(keys);
 }
 
-static uint32_t next_dict_keys_version = 2;
-
 uint32_t _PyDictKeys_GetVersionForCurrentState(PyDictKeysObject *dictkeys)
 {
     if (dictkeys->dk_version != 0) {
         return dictkeys->dk_version;
     }
-    if (next_dict_keys_version == 0) {
+    if (_PyRuntime.dict_state.next_keys_version == 0) {
         return 0;
     }
-    uint32_t v = next_dict_keys_version++;
+    uint32_t v = _PyRuntime.dict_state.next_keys_version++;
     dictkeys->dk_version = v;
     return v;
 }
@@ -5680,7 +5673,7 @@ validate_watcher_id(PyInterpreterState *interp, int watcher_id)
         PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
         return -1;
     }
-    if (!interp->dict_watchers[watcher_id]) {
+    if (!interp->dict_state.watchers[watcher_id]) {
         PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
         return -1;
     }
@@ -5723,8 +5716,8 @@ PyDict_AddWatcher(PyDict_WatchCallback callback)
     PyInterpreterState *interp = _PyInterpreterState_GET();
 
     for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
-        if (!interp->dict_watchers[i]) {
-            interp->dict_watchers[i] = callback;
+        if (!interp->dict_state.watchers[i]) {
+            interp->dict_state.watchers[i] = callback;
             return i;
         }
     }
@@ -5740,7 +5733,7 @@ PyDict_ClearWatcher(int watcher_id)
     if (validate_watcher_id(interp, watcher_id)) {
         return -1;
     }
-    interp->dict_watchers[watcher_id] = NULL;
+    interp->dict_state.watchers[watcher_id] = NULL;
     return 0;
 }
 
@@ -5754,7 +5747,7 @@ _PyDict_SendEvent(int watcher_bits,
     PyInterpreterState *interp = _PyInterpreterState_GET();
     for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
         if (watcher_bits & 1) {
-            PyDict_WatchCallback cb = interp->dict_watchers[i];
+            PyDict_WatchCallback cb = interp->dict_state.watchers[i];
             if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) {
                 // some dict modification paths (e.g. PyDict_Clear) can't raise, so we
                 // can't propagate exceptions from dict watchers.
index d60e4eb8486e72f56a7adcecb20b6f556159c085..cab80006589b48bf9827eef4e62ffb1f1872116c 100644 (file)
@@ -7,8 +7,6 @@
 #include "pycore_pyerrors.h"      // _PyErr_Occurred()
 #include "structmember.h"         // PyMemberDef
 
-static uint32_t next_func_version = 1;
-
 PyFunctionObject *
 _PyFunction_FromConstructor(PyFrameConstructor *constr)
 {
@@ -128,10 +126,10 @@ uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func)
     if (func->vectorcall != _PyFunction_Vectorcall) {
         return 0;
     }
-    if (next_func_version == 0) {
+    if (_PyRuntime.func_state.next_version == 0) {
         return 0;
     }
-    uint32_t v = next_func_version++;
+    uint32_t v = _PyRuntime.func_state.next_version++;
     func->func_version = v;
     return v;
 }
index 1e58d32f4962057be118e43ff0722bcc9b0447b1..9d868d51f027508240d1864c54db1a37db02b710 100644 (file)
@@ -4,6 +4,7 @@
 #include "pycore_call.h"
 #include "pycore_code.h"          // CO_FAST_FREE
 #include "pycore_compile.h"       // _Py_Mangle()
+#include "pycore_dict.h"          // _PyDict_KeysSize()
 #include "pycore_initconfig.h"    // _PyStatus_OK()
 #include "pycore_moduleobject.h"  // _PyModule_GetDef()
 #include "pycore_object.h"        // _PyType_HasFeature()
index 768f5f1ccc5181edbe208dd15baa4ea7137f592d..fd5c3175ce423bd7806549cb49e64cbba5925af3 100644 (file)
     <ClInclude Include="..\Include\internal\pycore_condvar.h" />
     <ClInclude Include="..\Include\internal\pycore_context.h" />
     <ClInclude Include="..\Include\internal\pycore_descrobject.h" />
+    <ClInclude Include="..\Include\internal\pycore_dict.h" />
+    <ClInclude Include="..\Include\internal\pycore_dict_state.h" />
     <ClInclude Include="..\Include\internal\pycore_dtoa.h" />
     <ClInclude Include="..\Include\internal\pycore_exceptions.h" />
     <ClInclude Include="..\Include\internal\pycore_fileutils.h" />
index fd03a7ac450f9d0fcdc7eb503c10415263ccbb7b..3ab7f31dff43f362607caf1ba8796731d84b3fd1 100644 (file)
     <ClInclude Include="..\Include\internal\pycore_descrobject.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_dict.h">
+      <Filter>Include\internal</Filter>
+    </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_dict_state.h">
+      <Filter>Include\internal</Filter>
+    </ClInclude>
     <ClInclude Include="..\Include\internal\pycore_dtoa.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
index d6f2645b36584f200d5c628448580b548e22369e..a53a9a3494a02affadc96424fa853c9df2522403 100644 (file)
@@ -458,7 +458,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
     Py_CLEAR(interp->interpreter_trampoline);
 
     for (int i=0; i < DICT_MAX_WATCHERS; i++) {
-        interp->dict_watchers[i] = NULL;
+        interp->dict_state.watchers[i] = NULL;
     }
 
     // XXX Once we have one allocator per interpreter (i.e.
index 87d8f637357b10dbb7c4ec2fe29c90768ed45909..cc465134a9e065f0b452f150f56ae58a3af7c6ac 100644 (file)
@@ -320,9 +320,6 @@ Objects/unicodeobject.c     -       ucnhash_capi    -
 Python/suggestions.c   levenshtein_distance    buffer  -
 
 # other
-Objects/dictobject.c   -       _pydict_global_version  -
-Objects/dictobject.c   -       next_dict_keys_version  -
-Objects/funcobject.c   -       next_func_version       -
 Objects/object.c       -       _Py_RefTotal    -
 Python/perf_trampoline.c       -       perf_status     -
 Python/perf_trampoline.c       -       extra_code_index        -