Skip to content

Commit

Permalink
GH-98522: Add version number to code objects. (GH-98525)
Browse files Browse the repository at this point in the history
* Add version number to code object for better versioning of functions.

* Improves specialization for closures and list comprehensions.
  • Loading branch information
markshannon authored Dec 9, 2022
1 parent 3c53554 commit fb713b2
Show file tree
Hide file tree
Showing 10 changed files with 23 additions and 4 deletions.
1 change: 1 addition & 0 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ typedef struct _PyShimCodeDef {
extern PyCodeObject *
_Py_MakeShimCode(const _PyShimCodeDef *code);

extern uint32_t _Py_next_func_version;


#ifdef __cplusplus
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 4 additions & 2 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "clinic/codeobject.c.h"


static void
notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
{
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -64,7 +64,6 @@ PyFunction_ClearWatcher(int watcher_id)
interp->active_func_watchers &= ~(1 << watcher_id);
return 0;
}

PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr)
{
Expand Down
2 changes: 2 additions & 0 deletions Programs/_bootstrap_python.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions Programs/_freeze_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3452,6 +3452,7 @@ dummy_func(
func->func_defaults = POP();
}

func->func_version = ((PyCodeObject *)codeobj)->co_version;
PUSH((PyObject *)func);
}

Expand Down
1 change: 1 addition & 0 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Tools/build/deepfreeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def make_string_literal(b: bytes) -> str:
CO_FAST_CELL = 0x40
CO_FAST_FREE = 0x80

next_code_version = 1

def get_localsplus(code: types.CodeType):
a = collections.defaultdict(int)
Expand Down Expand Up @@ -227,6 +228,7 @@ def generate_unicode(self, name: str, s: str) -> str:


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)
Expand Down Expand Up @@ -268,6 +270,8 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
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},")
Expand Down Expand Up @@ -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}")

Expand Down

0 comments on commit fb713b2

Please sign in to comment.