diff options
author | Guido van Rossum <guido@python.org> | 2021-11-22 10:09:48 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-22 10:09:48 -0800 |
commit | 1037ca5a8ea001bfa2a198e08655620234e9befd (patch) | |
tree | dcf9b1966caca1eab0437f730f487701a960d851 /Tools/scripts/deepfreeze.py | |
parent | 4d6c0c0cce05befa06e0cad7351b1303ac048277 (diff) | |
download | cpython-1037ca5a8ea001bfa2a198e08655620234e9befd.tar.gz cpython-1037ca5a8ea001bfa2a198e08655620234e9befd.zip |
bpo-45850: Implement deep-freeze on Windows (#29648)
Implement changes to build with deep-frozen modules on Windows.
Note that we now require Python 3.10 as the "bootstrap" or "host" Python.
This causes a modest startup speed (around 7%) on Windows.
Diffstat (limited to 'Tools/scripts/deepfreeze.py')
-rw-r--r-- | Tools/scripts/deepfreeze.py | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index 074127f9492..b6d52b74549 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -1,13 +1,16 @@ import argparse +import ast import builtins import collections import contextlib import os -import sys +import re import time import types import typing +import umarshal + verbose = False @@ -55,7 +58,8 @@ def get_localsplus_counts(code: types.CodeType, nplaincellvars += 1 elif kind & CO_FAST_FREE: nfreevars += 1 - assert nlocals == len(code.co_varnames) == code.co_nlocals + assert nlocals == len(code.co_varnames) == code.co_nlocals, \ + (nlocals, len(code.co_varnames), code.co_nlocals) assert ncellvars == len(code.co_cellvars) assert nfreevars == len(code.co_freevars) assert len(names) == nlocals + nplaincellvars + nfreevars @@ -274,14 +278,7 @@ class Printer: self.write(item + ",") return f"& {name}._object.ob_base.ob_base" - def generate_int(self, name: str, i: int) -> str: - maxint = sys.maxsize - if maxint == 2**31 - 1: - digit = 2**15 - elif maxint == 2**63 - 1: - digit = 2**30 - else: - assert False, f"What int size is this system?!? {maxint=}" + def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: sign = -1 if i < 0 else 0 if i == 0 else +1 i = abs(i) digits: list[int] = [] @@ -298,6 +295,20 @@ class Printer: if digits: ds = ", ".join(map(str, digits)) self.write(f".ob_digit = {{ {ds} }},") + + def generate_int(self, name: str, i: int) -> str: + if abs(i) < 2**15: + self._generate_int_for_bits(name, i, 2**15) + else: + connective = "if" + for bits_in_digit in 15, 30: + self.write(f"#{connective} PYLONG_BITS_IN_DIGIT == {bits_in_digit}") + self._generate_int_for_bits(name, i, 2**bits_in_digit) + connective = "elif" + self.write("#else") + self.write('#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"') + self.write("#endif") + # If neither clause applies, it won't compile return f"& {name}.ob_base.ob_base" def generate_float(self, name: str, x: float) -> str: @@ -326,7 +337,7 @@ class Printer: return self.cache[key] self.misses += 1 match obj: - case types.CodeType() as code: + case types.CodeType() | umarshal.Code() as code: val = self.generate_code(name, code) case tuple(t): val = self.generate_tuple(name, t) @@ -367,8 +378,31 @@ _Py_get_%%NAME%%_toplevel(void) } """ +FROZEN_COMMENT = "/* Auto-generated by Programs/_freeze_module.c */" + +FROZEN_DATA_LINE = r"\s*(\d+,\s*)+\s*" + + +def is_frozen_header(source: str) -> bool: + return source.startswith(FROZEN_COMMENT) + + +def decode_frozen_data(source: str) -> types.CodeType: + lines = source.splitlines() + while lines and re.match(FROZEN_DATA_LINE, lines[0]) is None: + del lines[0] + while lines and re.match(FROZEN_DATA_LINE, lines[-1]) is None: + del lines[-1] + values: tuple[int, ...] = ast.literal_eval("".join(lines)) + data = bytes(values) + return umarshal.loads(data) + + def generate(source: str, filename: str, modname: str, file: typing.TextIO) -> None: - code = compile(source, filename, "exec") + if is_frozen_header(source): + code = decode_frozen_data(source) + else: + code = compile(source, filename, "exec") printer = Printer(file) printer.generate("toplevel", code) printer.write("") |