aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-12-09 12:18:45 +0000
committerGitHub <noreply@github.com>2022-12-09 12:18:45 +0000
commitfb713b21833a17cba8022af0fa4c486512157d4b (patch)
tree2e75f1e59393160792f1097846a648ff7927de8d
parent3c5355496b54fa0a4ea0e22344d008528e45682c (diff)
downloadcpython-fb713b21833a17cba8022af0fa4c486512157d4b.tar.gz
cpython-fb713b21833a17cba8022af0fa4c486512157d4b.zip
GH-98522: Add version number to code objects. (GH-98525)
* Add version number to code object for better versioning of functions. * Improves specialization for closures and list comprehensions.
-rw-r--r--Include/cpython/code.h1
-rw-r--r--Include/internal/pycore_code.h2
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-10-21-16-10-39.gh-issue-98522.s_SixG.rst3
-rw-r--r--Objects/codeobject.c6
-rw-r--r--Objects/funcobject.c3
-rw-r--r--Programs/_bootstrap_python.c2
-rw-r--r--Programs/_freeze_module.c3
-rw-r--r--Python/bytecodes.c1
-rw-r--r--Python/generated_cases.c.h1
-rw-r--r--Tools/build/deepfreeze.py5
10 files changed, 23 insertions, 4 deletions
diff --git a/Include/cpython/code.h b/Include/cpython/code.h
index f11d099e037..fc7c5ed7024 100644
--- a/Include/cpython/code.h
+++ b/Include/cpython/code.h
@@ -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 \
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index 357fc85a95c..f22fd45f831 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -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
index 00000000000..d923af198f8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-21-16-10-39.gh-issue-98522.s_SixG.rst
@@ -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.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 0c197d767b0..c92c7deaf80 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -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;
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index bf97edc53ad..9df06520586 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -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)
{
diff --git a/Programs/_bootstrap_python.c b/Programs/_bootstrap_python.c
index bbac0c4e1a8..6e1593a0b59 100644
--- a/Programs/_bootstrap_python.c
+++ b/Programs/_bootstrap_python.c
@@ -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)
{
diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c
index 9e2169f32e9..90fc2dc6e87 100644
--- a/Programs/_freeze_module.c
+++ b/Programs/_freeze_module.c
@@ -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)
{
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 5807bd5dc2d..c56f1d3ef9f 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -3452,6 +3452,7 @@ dummy_func(
func->func_defaults = POP();
}
+ func->func_version = ((PyCodeObject *)codeobj)->co_version;
PUSH((PyObject *)func);
}
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 59e70b72226..45382a466b1 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -3693,6 +3693,7 @@
func->func_defaults = POP();
}
+ func->func_version = ((PyCodeObject *)codeobj)->co_version;
PUSH((PyObject *)func);
DISPATCH();
}
diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py
index 2eef649437a..7f4e2428013 100644
--- a/Tools/build/deepfreeze.py
+++ b/Tools/build/deepfreeze.py
@@ -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}")