mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
3c5355496b
commit
fb713b2183
|
@ -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 \
|
||||
|
|
|
@ -474,6 +474,8 @@ typedef struct _PyShimCodeDef {
|
|||
extern PyCodeObject *
|
||||
_Py_MakeShimCode(const _PyShimCodeDef *code);
|
||||
|
||||
extern uint32_t _Py_next_func_version;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -3452,6 +3452,7 @@ dummy_func(
|
|||
func->func_defaults = POP();
|
||||
}
|
||||
|
||||
func->func_version = ((PyCodeObject *)codeobj)->co_version;
|
||||
PUSH((PyObject *)func);
|
||||
}
|
||||
|
||||
|
|
|
@ -3693,6 +3693,7 @@
|
|||
func->func_defaults = POP();
|
||||
}
|
||||
|
||||
func->func_version = ((PyCodeObject *)codeobj)->co_version;
|
||||
PUSH((PyObject *)func);
|
||||
DISPATCH();
|
||||
}
|
||||
|
|
|
@ -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}")
|
||||
|
||||
|
|
Loading…
Reference in New Issue