* Add version number to code object for better versioning of functions.
* Improves specialization for closures and list comprehensions.
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 \
extern PyCodeObject *
_Py_MakeShimCode(const _PyShimCodeDef *code);
+extern uint32_t _Py_next_func_version;
+
#ifdef __cplusplus
}
--- /dev/null
+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.
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "clinic/codeobject.c.h"
-
static void
notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
{
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;
#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
interp->active_func_watchers &= ~(1 << watcher_id);
return 0;
}
-
PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr)
{
#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)
{
Keep this file in sync with Programs/_freeze_module.py.
*/
+
#include <Python.h>
#include <marshal.h>
#include "pycore_fileutils.h" // _Py_stat_struct
#include <unistd.h>
#endif
+uint32_t _Py_next_func_version = 1;
+
/* Empty initializer for deepfrozen modules */
int _Py_Deepfreeze_Init(void)
{
func->func_defaults = POP();
}
+ func->func_version = ((PyCodeObject *)codeobj)->co_version;
PUSH((PyObject *)func);
}
func->func_defaults = POP();
}
+ func->func_version = ((PyCodeObject *)codeobj)->co_version;
PUSH((PyObject *)func);
DISPATCH();
}
CO_FAST_CELL = 0x40
CO_FAST_FREE = 0x80
+next_code_version = 1
def get_localsplus(code: types.CodeType):
a = collections.defaultdict(int)
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)
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},")
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}")