]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-98522: Add version number to code objects. (GH-98525)
authorMark Shannon <mark@hotpy.org>
Fri, 9 Dec 2022 12:18:45 +0000 (12:18 +0000)
committerGitHub <noreply@github.com>
Fri, 9 Dec 2022 12:18:45 +0000 (12:18 +0000)
* Add version number to code object for better versioning of functions.

* Improves specialization for closures and list comprehensions.

Include/cpython/code.h
Include/internal/pycore_code.h
Misc/NEWS.d/next/Core and Builtins/2022-10-21-16-10-39.gh-issue-98522.s_SixG.rst [new file with mode: 0644]
Objects/codeobject.c
Objects/funcobject.c
Programs/_bootstrap_python.c
Programs/_freeze_module.c
Python/bytecodes.c
Python/generated_cases.c.h
Tools/build/deepfreeze.py

index f11d099e0379efa51f3a4d246ac281d17f431169..fc7c5ed702439f1bb87280e5065cde9f429bfad7 100644 (file)
@@ -87,6 +87,7 @@ typedef struct {
     int co_nplaincellvars;        /* number of non-arg cell variables */       \
     int co_ncellvars;             /* total number of cell variables */         \
     int co_nfreevars;             /* number of free variables */               \
+    uint32_t co_version;          /* version number */                         \
                                                                                \
     PyObject *co_localsplusnames; /* tuple mapping offsets to names */         \
     PyObject *co_localspluskinds; /* Bytes mapping to local kinds (one byte    \
index 357fc85a95cf1533d8270092e573bfa9d62ce0fe..f22fd45f8319d5a77a51f8246c6f3e83c8986268 100644 (file)
@@ -474,6 +474,8 @@ typedef struct _PyShimCodeDef {
 extern PyCodeObject *
 _Py_MakeShimCode(const _PyShimCodeDef *code);
 
+extern uint32_t _Py_next_func_version;
+
 
 #ifdef __cplusplus
 }
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-21-16-10-39.gh-issue-98522.s_SixG.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-21-16-10-39.gh-issue-98522.s_SixG.rst
new file mode 100644 (file)
index 0000000..d923af1
--- /dev/null
@@ -0,0 +1,3 @@
+Add an internal version number to code objects, to give better versioning of
+inner functions and comprehensions, and thus better specialization of those
+functions. This change is invisible to both Python and C extensions.
index 0c197d767b0a237f19b4daad8fdb8ef800f54e53..c92c7deaf8086f51becc9016a6e46646f47f3afd 100644 (file)
@@ -11,7 +11,6 @@
 #include "pycore_tuple.h"         // _PyTuple_ITEMS()
 #include "clinic/codeobject.c.h"
 
-
 static void
 notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
 {
@@ -398,7 +397,10 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
     co->co_nplaincellvars = nplaincellvars;
     co->co_ncellvars = ncellvars;
     co->co_nfreevars = nfreevars;
-
+    co->co_version = _Py_next_func_version;
+    if (_Py_next_func_version != 0) {
+        _Py_next_func_version++;
+    }
     /* not set */
     co->co_weakreflist = NULL;
     co->co_extra = NULL;
index bf97edc53ad7d97e6baa292d4c9924d57dcb3b6d..9df06520586ab71b5d943a0f59d8712a2eb025fd 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "Python.h"
 #include "pycore_ceval.h"         // _PyEval_BuiltinsFromGlobals()
-#include "pycore_function.h"      // FUNC_MAX_WATCHERS
+#include "pycore_code.h"          // _Py_next_func_version
 #include "pycore_object.h"        // _PyObject_GC_UNTRACK()
 #include "pycore_pyerrors.h"      // _PyErr_Occurred()
 #include "structmember.h"         // PyMemberDef
@@ -64,7 +64,6 @@ PyFunction_ClearWatcher(int watcher_id)
     interp->active_func_watchers &= ~(1 << watcher_id);
     return 0;
 }
-
 PyFunctionObject *
 _PyFunction_FromConstructor(PyFrameConstructor *constr)
 {
index bbac0c4e1a8a450c33ae166f71354bd29ab91c75..6e1593a0b5996a71aed2d97e2c83aaf3a9baa9ea 100644 (file)
@@ -14,6 +14,8 @@
 #include "Python/frozen_modules/importlib._bootstrap_external.h"
 /* End includes */
 
+uint32_t _Py_next_func_version = 1;
+
 /* Empty initializer for deepfrozen modules */
 int _Py_Deepfreeze_Init(void)
 {
index 9e2169f32e9211b334f589ebce76cff48a02015f..90fc2dc6e87da8280ed6bc86585e33f50c0c5315 100644 (file)
@@ -9,6 +9,7 @@
    Keep this file in sync with Programs/_freeze_module.py.
 */
 
+
 #include <Python.h>
 #include <marshal.h>
 #include "pycore_fileutils.h"     // _Py_stat_struct
@@ -22,6 +23,8 @@
 #include <unistd.h>
 #endif
 
+uint32_t _Py_next_func_version = 1;
+
 /* Empty initializer for deepfrozen modules */
 int _Py_Deepfreeze_Init(void)
 {
index 5807bd5dc2d29c6415ff748de9ea63555216e5fd..c56f1d3ef9f4985097401b7f784f70f7cd01956d 100644 (file)
@@ -3452,6 +3452,7 @@ dummy_func(
                 func->func_defaults = POP();
             }
 
+            func->func_version = ((PyCodeObject *)codeobj)->co_version;
             PUSH((PyObject *)func);
         }
 
index 59e70b7222696587f01d7b138442e51a5b6cf8ee..45382a466b1ca953e7d793ce2b78e6e99b0b5900 100644 (file)
                 func->func_defaults = POP();
             }
 
+            func->func_version = ((PyCodeObject *)codeobj)->co_version;
             PUSH((PyObject *)func);
             DISPATCH();
         }
index 2eef649437a680e06f6c4908e518abe8940665bd..7f4e24280133f23289d4d188ed4cad301e92aac0 100644 (file)
@@ -44,6 +44,7 @@ CO_FAST_LOCAL = 0x20
 CO_FAST_CELL = 0x40
 CO_FAST_FREE = 0x80
 
+next_code_version = 1
 
 def get_localsplus(code: types.CodeType):
     a = collections.defaultdict(int)
@@ -227,6 +228,7 @@ class Printer:
 
 
     def generate_code(self, name: str, code: types.CodeType) -> str:
+        global next_code_version
         # The ordering here matches PyCode_NewWithPosOnlyArgs()
         # (but see below).
         co_consts = self.generate(name + "_consts", code.co_consts)
@@ -268,6 +270,8 @@ class Printer:
             self.write(f".co_nplaincellvars = {nplaincellvars},")
             self.write(f".co_ncellvars = {ncellvars},")
             self.write(f".co_nfreevars = {nfreevars},")
+            self.write(f".co_version = {next_code_version},")
+            next_code_version += 1
             self.write(f".co_localsplusnames = {co_localsplusnames},")
             self.write(f".co_localspluskinds = {co_localspluskinds},")
             self.write(f".co_filename = {co_filename},")
@@ -461,6 +465,7 @@ def generate(args: list[str], output: TextIO) -> None:
             with printer.block(f"if ({p} < 0)"):
                 printer.write("return -1;")
         printer.write("return 0;")
+    printer.write(f"\nuint32_t _Py_next_func_version = {next_code_version};\n")
     if verbose:
         print(f"Cache hits: {printer.hits}, misses: {printer.misses}")