node/deps/v8/tools/dev/gen-static-roots.py
Michaël Zasso f1e0b83e7b
deps: update V8 to 14.6.202.33
PR-URL: https://github.com/nodejs/node/pull/61898
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
2026-04-24 18:01:28 +02:00

281 lines
8.4 KiB
Python
Executable file

#!/usr/bin/env python3
# Copyright 2022 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can
# be found in the LICENSE file.
import subprocess
import argparse
import os
import filecmp
import tempfile
import shutil
import platform
import re
import sys
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
# List of all supported build configurations for static roots
STATIC_ROOT_CONFIGURATIONS = {
"intl-wasm": {
"gn_args": {
"v8_enable_static_roots": "false",
"v8_enable_static_roots_generation": "true",
"v8_enable_pointer_compression": "true",
"v8_enable_pointer_compression_shared_cage": "true",
"v8_enable_webassembly": "true",
"v8_enable_i18n_support": "true",
"dcheck_always_on": "false"
}
},
"intl-nowasm": {
"gn_args": {
"v8_enable_static_roots": "false",
"v8_enable_static_roots_generation": "true",
"v8_enable_pointer_compression": "true",
"v8_enable_pointer_compression_shared_cage": "true",
"v8_enable_webassembly": "false",
"v8_enable_i18n_support": "true",
"dcheck_always_on": "false"
}
},
"nointl-wasm": {
"gn_args": {
"v8_enable_static_roots": "false",
"v8_enable_static_roots_generation": "true",
"v8_enable_pointer_compression": "true",
"v8_enable_pointer_compression_shared_cage": "true",
"v8_enable_webassembly": "true",
"v8_enable_i18n_support": "false",
"dcheck_always_on": "false"
}
},
"nointl-nowasm": {
"gn_args": {
"v8_enable_static_roots": "false",
"v8_enable_static_roots_generation": "true",
"v8_enable_pointer_compression": "true",
"v8_enable_pointer_compression_shared_cage": "true",
"v8_enable_webassembly": "false",
"v8_enable_i18n_support": "false",
"dcheck_always_on": "false"
}
},
}
# Parse args
parser = argparse.ArgumentParser(description='Generates static-roots.h.')
parser.add_argument(
'-c',
'--configuration',
choices=STATIC_ROOT_CONFIGURATIONS.keys(),
action='extend',
default=None,
nargs='*',
help="""Build configuration. Refers to a set of configurations with
identical static-roots.h.""")
parser.add_argument(
'--out',
default=Path('out'),
required=False,
type=Path,
help='target build directory')
parser.add_argument(
'-p',
'--parallel',
action=argparse.BooleanOptionalAction,
default=True,
help='Run builds in parallel')
args = parser.parse_args()
# Some helpers
def run(cmd, **kwargs):
print(f"# CMD: {cmd}")
return subprocess.run(cmd, **kwargs, check=True)
def machine_target():
raw = platform.machine()
raw_lower = raw.lower()
if raw_lower == "x86_64" or raw_lower == "amd64":
return "x64"
if raw_lower == "aarch64":
return "arm64"
return raw
V8_PATH = Path(__file__).parents[2]
GM = V8_PATH / 'tools' / 'dev' / 'gm.py'
def build_and_check(target):
print(f"-> Building: {target}")
# Currently the out dir always needs to be exactly 2 levels deep relative to
# the project root or siso fails to remote compile (see b/429331398).
build_prefix = f"_gen-static-roots-{target}"
build_dir = args.out / f"{build_prefix}-{machine_target()}.release"
if not build_dir.exists():
build_dir.mkdir(parents=True, exist_ok=True)
config = STATIC_ROOT_CONFIGURATIONS[target]
# Let gm create the default config
e = dict(os.environ)
e['V8_GM_OUTDIR'] = f"{args.out}"
e['V8_GM_BUILD_DIR_PREFIX'] = build_prefix
run([f"{sys.executable}", f"{GM}", f"{machine_target()}.release.gn_args"],
env=e)
# Patch the default config according to our needs
gn_args_template = config["gn_args"].copy()
gn_args = (build_dir / "args.gn").open("r").read().splitlines()
needs_updating = False
found = 0
for line in filter(bool, gn_args):
result = re.search(r"^([^ ]+) = (.+)$", line)
if not result or len(result.groups()) != 2:
print(f"Error parsing {build_dir / 'args.gn'} at line '{line}'")
exit(255)
if result.group(1) in gn_args_template:
found += 1
if result.group(2) != f"{gn_args_template[result.group(1)]}":
needs_updating = True
if needs_updating or found < len(gn_args_template):
print("# Updating gn args")
with (build_dir / "args.gn").open("w") as f:
for line in filter(bool, gn_args):
result = re.search(r"^([^ ]+) = (.+)$", line)
if result.group(1) in gn_args_template:
line = f"{result.group(1)} = {gn_args_template[result.group(1)]}"
gn_args_template.pop(result.group(1))
f.write(f"{line}\n")
for extra, val in gn_args_template.items():
f.write(f"{extra} = {val}\n")
# Build mksnapshot
run([f"{sys.executable}", f"{GM}", f"{machine_target()}.release.mksnapshot"],
env=e)
# Generate static roots file and check if it changed
filename = f"static-roots-{target}.h"
out_file = Path(tempfile.gettempdir()) / filename
run([f"{build_dir / 'mksnapshot'}", "--static-roots-src", f"{out_file}"])
target_file = V8_PATH / 'src' / 'roots' / filename
if not filecmp.cmp(out_file, target_file):
shutil.move(out_file, target_file)
return True
return False
def update_v8_internal_h():
print("-> Updating v8-internal.h")
internal_h_path = V8_PATH / 'include' / 'v8-internal.h'
content = internal_h_path.read_text()
common_values = {}
hole_values = {}
common_names_map = {
'UndefinedValue': 'kUndefinedValue',
'NullValue': 'kNullValue',
'TrueValue': 'kTrueValue',
'FalseValue': 'kFalseValue',
'EmptyString': 'kempty_string'
}
for config in STATIC_ROOT_CONFIGURATIONS.keys():
file_path = V8_PATH / 'src' / 'roots' / f"static-roots-{config}.h"
if not file_path.exists():
print(
f"Warning: {file_path} does not exist. Skipping v8-internal.h update."
)
return False
file_content = file_path.read_text()
for internal_name, static_name in common_names_map.items():
match = re.search(
f"static constexpr Tagged_t {static_name} = (0x[0-9a-f]+);",
file_content)
if not match:
print(f"Error: Could not find {static_name} in {file_path}")
return False
val = match.group(1)
if internal_name in common_values:
if common_values[internal_name] != val:
print(
f"Error: Value mismatch for {internal_name}. {common_values[internal_name]} vs {val}"
)
return False
else:
common_values[internal_name] = val
match = re.search(
f"static constexpr Tagged_t kTheHoleValue = (0x[0-9a-f]+);",
file_content)
if not match:
print(f"Error: Could not find kTheHoleValue in {file_path}")
return False
hole_values[config] = match.group(1)
new_content = content
for name, val in common_values.items():
pattern = f"V\\({name}, 0x[0-9a-f]+\\)"
replacement = f"V({name}, {val})"
new_content = re.sub(pattern, replacement, new_content)
wasm_hole = hole_values['intl-wasm']
intl_hole = hole_values['intl-nowasm']
nointl_hole = hole_values['nointl-nowasm']
block_regex = re.compile(
r"""
(\#ifdef\ V8_ENABLE_WEBASSEMBLY\s+
static\ constexpr\ Tagged_t\ kBuildDependentTheHoleValue\ =\ )0x[0-9a-f]+(;\s+
\#else\s+
\#ifdef\ V8_INTL_SUPPORT\s+
static\ constexpr\ Tagged_t\ kBuildDependentTheHoleValue\ =\ )0x[0-9a-f]+(;\s+
\#else\s+
static\ constexpr\ Tagged_t\ kBuildDependentTheHoleValue\ =\ )0x[0-9a-f]+(;\s+
\#endif\s+
\#endif)
""", re.VERBOSE | re.MULTILINE)
def replace_block(m):
return f"{m.group(1)}{wasm_hole}{m.group(2)}{intl_hole}{m.group(3)}{nointl_hole}{m.group(4)}"
new_content = block_regex.sub(replace_block, new_content)
if content != new_content:
print(f"Updating {internal_h_path}")
internal_h_path.write_text(new_content)
return True
return False
all_configs = (
args.configuration
if args.configuration else STATIC_ROOT_CONFIGURATIONS.keys())
if args.parallel:
with ThreadPoolExecutor() as executor:
results = executor.map(build_and_check, all_configs)
changed = any(results)
else:
changed = False
for target in all_configs:
if build_and_check(target):
changed = True
if update_v8_internal_h():
changed = True
if changed:
exit(1)