[static-roots] Build infrastructure for static roots
Add gen-static-roots.py to conveniently re-generate the static roots table when it needs changing. Additionally, ensure the first read-only page is allocated as first page during mksnapshot, to move static roots closer to start. Bug: v8:13466 Change-Id: Ie72b64d0ad0dd3e5fccd3b41e8ed00a4a55a0033 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4096481 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Auto-Submit: Olivier Flückiger <olivf@chromium.org> Commit-Queue: Olivier Flückiger <olivf@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/main@{#84844}
This commit is contained in:
parent
4677d3ba1b
commit
f6eab3830d
@ -132,6 +132,8 @@ v8_flag(name = "v8_enable_snapshot_code_comments")
|
||||
|
||||
v8_flag(name = "v8_enable_snapshot_native_code_counters")
|
||||
|
||||
v8_flag(name = "v8_enable_static_roots")
|
||||
|
||||
v8_flag(name = "v8_enable_trace_maps")
|
||||
|
||||
v8_flag(name = "v8_enable_v8_checks")
|
||||
@ -316,6 +318,7 @@ v8_config(
|
||||
"v8_enable_slow_dchecks": "ENABLE_SLOW_DCHECKS",
|
||||
"v8_enable_runtime_call_stats": "V8_RUNTIME_CALL_STATS",
|
||||
"v8_enable_snapshot_native_code_counters": "V8_SNAPSHOT_NATIVE_CODE_COUNTERS",
|
||||
"v8_enable_static_roots": "V8_STATIC_ROOTS",
|
||||
"v8_enable_trace_maps": "V8_TRACE_MAPS",
|
||||
"v8_enable_v8_checks": "V8_ENABLE_CHECKS",
|
||||
"v8_enable_verify_csa": "ENABLE_VERIFY_CSA",
|
||||
|
22
BUILD.gn
22
BUILD.gn
@ -120,6 +120,9 @@ declare_args() {
|
||||
# as per the --native-code-counters flag.
|
||||
v8_enable_snapshot_native_code_counters = ""
|
||||
|
||||
# Use pre-generated static root pointer values from static-roots.h.
|
||||
v8_enable_static_roots = false
|
||||
|
||||
# Enable code-generation-time checking of types in the CodeStubAssembler.
|
||||
v8_enable_verify_csa = false
|
||||
|
||||
@ -535,6 +538,22 @@ if (v8_enable_sandbox == "") {
|
||||
v8_enable_external_code_space && target_os != "fuchsia"
|
||||
}
|
||||
|
||||
if (v8_enable_static_roots == "") {
|
||||
# Static roots are only valid for builds with pointer compression and a
|
||||
# shared ro heap. Also, non-wasm and non-i18n builds have fewer read-only
|
||||
# roots.
|
||||
v8_enable_static_roots =
|
||||
v8_enable_pointer_compression && v8_enable_shared_ro_heap &&
|
||||
v8_enable_pointer_compression_shared_cage && v8_enable_webassembly &&
|
||||
v8_enable_i18n_support
|
||||
}
|
||||
|
||||
assert(!v8_enable_static_roots ||
|
||||
(v8_enable_pointer_compression && v8_enable_shared_ro_heap &&
|
||||
v8_enable_pointer_compression_shared_cage &&
|
||||
v8_enable_webassembly && v8_enable_i18n_support),
|
||||
"Trying to enable static roots in a configuration that is not supported")
|
||||
|
||||
assert(!v8_disable_write_barriers || v8_enable_single_generation,
|
||||
"Disabling write barriers works only with single generation")
|
||||
|
||||
@ -1060,6 +1079,9 @@ config("features") {
|
||||
if (v8_enable_pointer_compression_8gb) {
|
||||
defines += [ "V8_COMPRESS_POINTERS_8GB" ]
|
||||
}
|
||||
if (v8_enable_static_roots) {
|
||||
defines += [ "V8_STATIC_ROOTS" ]
|
||||
}
|
||||
if (v8_use_zlib) {
|
||||
defines += [ "V8_USE_ZLIB" ]
|
||||
}
|
||||
|
@ -122,13 +122,8 @@ namespace internal {
|
||||
#define V8_CAN_CREATE_SHARED_HEAP_BOOL false
|
||||
#endif
|
||||
|
||||
// Disabling WASM or INTL invalidates the contents of static-roots.h
|
||||
#if defined(V8_SHARED_RO_HEAP) && defined(V8_COMPRESS_POINTERS) && \
|
||||
defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE) && V8_ENABLE_WEBASSEMBLY && \
|
||||
defined(V8_INTL_SUPPORT)
|
||||
// TODO(olivf, v8:13466): Add build infra to conveniently re-regenerate the
|
||||
// static roots table and then enable it.
|
||||
#define V8_STATIC_ROOTS_BOOL false
|
||||
#if defined(V8_STATIC_ROOTS)
|
||||
#define V8_STATIC_ROOTS_BOOL true
|
||||
#else
|
||||
#define V8_STATIC_ROOTS_BOOL false
|
||||
#endif
|
||||
|
@ -4156,16 +4156,22 @@ VirtualMemoryCage* Isolate::GetPtrComprCodeCageForTesting() {
|
||||
// then called with --static-roots to re-regenerate the static-roots.h file.
|
||||
void Isolate::VerifyStaticRoots() {
|
||||
#if V8_STATIC_ROOTS_BOOL
|
||||
static_assert(ReadOnlyHeap::IsReadOnlySpaceShared(),
|
||||
"Static read only roots are only supported when there is one "
|
||||
"shared read only space per cage");
|
||||
#define STATIC_ROOTS_FAILED_MSG \
|
||||
"Run `tools/dev/gen-static-roots.py` to update static-roots.h."
|
||||
static_assert(static_cast<int>(RootIndex::kReadOnlyRootsCount) ==
|
||||
StaticReadOnlyRootsPointerTable.size(),
|
||||
STATIC_ROOTS_FAILED_MSG);
|
||||
auto& roots = roots_table();
|
||||
CHECK_EQ(static_cast<int>(RootIndex::kReadOnlyRootsCount),
|
||||
StaticReadOnlyRootsPointerTable.size());
|
||||
RootIndex idx = RootIndex::kFirstReadOnlyRoot;
|
||||
ReadOnlyPage* first_page = read_only_heap()->read_only_space()->pages()[0];
|
||||
for (Tagged_t cmp_ptr : StaticReadOnlyRootsPointerTable) {
|
||||
Address the_root = roots[idx];
|
||||
Address ptr =
|
||||
V8HeapCompressionScheme::DecompressTaggedPointer(cage_base(), cmp_ptr);
|
||||
CHECK_EQ(the_root, ptr);
|
||||
CHECK_WITH_MSG(the_root == ptr, STATIC_ROOTS_FAILED_MSG);
|
||||
// All roots must fit on first page, since only this page is guaranteed to
|
||||
// have a stable offset from the cage base. If this ever changes we need
|
||||
// to load more pages with predictable offset at
|
||||
@ -4173,6 +4179,7 @@ void Isolate::VerifyStaticRoots() {
|
||||
CHECK(first_page->Contains(the_root));
|
||||
++idx;
|
||||
}
|
||||
#undef STATIC_ROOTS_FAILED_MSG
|
||||
#endif // V8_STATIC_ROOTS_BOOL
|
||||
}
|
||||
|
||||
@ -4522,7 +4529,7 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data,
|
||||
can_rehash);
|
||||
startup_deserializer.DeserializeIntoIsolate();
|
||||
}
|
||||
if (DEBUG_BOOL) VerifyStaticRoots();
|
||||
if (DEBUG_BOOL || create_heap_objects) VerifyStaticRoots();
|
||||
load_stub_cache_->Initialize();
|
||||
store_stub_cache_->Initialize();
|
||||
interpreter_->Initialize();
|
||||
|
@ -99,6 +99,9 @@ void ReadOnlyHeap::SetUp(Isolate* isolate,
|
||||
artifacts = InitializeSharedReadOnlyArtifacts();
|
||||
|
||||
ro_heap = CreateInitalHeapForBootstrapping(isolate, artifacts);
|
||||
|
||||
// Ensure the first read-only page ends up first in the cage.
|
||||
ro_heap->read_only_space()->EnsurePage();
|
||||
artifacts->VerifyChecksum(read_only_snapshot_data, true);
|
||||
}
|
||||
} else {
|
||||
|
@ -558,6 +558,11 @@ void ReadOnlySpace::FreeLinearAllocationArea() {
|
||||
limit_ = kNullAddress;
|
||||
}
|
||||
|
||||
void ReadOnlySpace::EnsurePage() {
|
||||
if (pages_.empty()) EnsureSpaceForAllocation(1);
|
||||
CHECK(!pages_.empty());
|
||||
}
|
||||
|
||||
void ReadOnlySpace::EnsureSpaceForAllocation(int size_in_bytes) {
|
||||
if (top_ + size_in_bytes <= limit_) {
|
||||
return;
|
||||
|
@ -237,6 +237,9 @@ class ReadOnlySpace : public BaseSpace {
|
||||
|
||||
void InitFromMemoryDump(Isolate* isolate, SnapshotByteSource* source);
|
||||
|
||||
// Ensure the read only space has at least one allocated page
|
||||
void EnsurePage();
|
||||
|
||||
protected:
|
||||
friend class SingleCopyReadOnlyArtifacts;
|
||||
|
||||
|
@ -15,6 +15,9 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
void StaticRootsTableGen::write(Isolate* isolate, const char* file) {
|
||||
CHECK_WITH_MSG(!V8_STATIC_ROOTS_BOOL,
|
||||
"--static-roots is only supported in builds with "
|
||||
"v8_enable_static_roots disabled");
|
||||
CHECK(file);
|
||||
static_assert(static_cast<int>(RootIndex::kFirstReadOnlyRoot) == 0);
|
||||
|
||||
@ -31,8 +34,19 @@ void StaticRootsTableGen::write(Isolate* isolate, const char* file) {
|
||||
<< "#define V8_ROOTS_STATIC_ROOTS_H_\n"
|
||||
<< "\n"
|
||||
<< "#include \"src/common/globals.h\"\n"
|
||||
<< "\n"
|
||||
<< "#if V8_STATIC_ROOTS_BOOL\n"
|
||||
<< "\n"
|
||||
<< "// Disabling Wasm or Intl invalidates the contents of "
|
||||
"static-roots.h.\n"
|
||||
<< "// TODO(olivf): To support static roots for multiple build "
|
||||
"configurations we\n"
|
||||
<< "// will need to generate target specific versions of "
|
||||
"this "
|
||||
"file.\n"
|
||||
<< "static_assert(V8_ENABLE_WEBASSEMBLY);\n"
|
||||
<< "static_assert(V8_INTL_SUPPORT);\n"
|
||||
<< "\n"
|
||||
<< "namespace v8 {\n"
|
||||
<< "namespace internal {\n"
|
||||
<< "\n"
|
||||
|
126
tools/dev/gen-static-roots.py
Executable file
126
tools/dev/gen-static-roots.py
Executable file
@ -0,0 +1,126 @@
|
||||
#!/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
|
||||
from pathlib import Path
|
||||
|
||||
# Detect if we have goma
|
||||
|
||||
|
||||
def _Which(cmd):
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
if os.path.exists(os.path.join(path, cmd)):
|
||||
return os.path.join(path, cmd)
|
||||
return None
|
||||
|
||||
|
||||
def DetectGoma():
|
||||
if os.environ.get("GOMA_DIR"):
|
||||
return os.environ.get("GOMA_DIR")
|
||||
if os.environ.get("GOMADIR"):
|
||||
return os.environ.get("GOMADIR")
|
||||
# There is a copy of goma in depot_tools, but it might not be in use on
|
||||
# this machine.
|
||||
goma = _Which("goma_ctl")
|
||||
if goma is None:
|
||||
return None
|
||||
cipd_bin = os.path.join(os.path.dirname(goma), ".cipd_bin")
|
||||
if not os.path.exists(cipd_bin):
|
||||
return None
|
||||
goma_auth = os.path.expanduser("~/.goma_client_oauth2_config")
|
||||
if not os.path.exists(goma_auth):
|
||||
return None
|
||||
return cipd_bin
|
||||
|
||||
|
||||
GOMADIR = DetectGoma()
|
||||
IS_GOMA_MACHINE = GOMADIR is not None
|
||||
|
||||
USE_GOMA = "true" if IS_GOMA_MACHINE else "false"
|
||||
|
||||
# List of all supported build configurations for static roots
|
||||
|
||||
STATIC_ROOT_CONFIGURATIONS = {
|
||||
"ptr-cmpr-wasm-intl": {
|
||||
"target":
|
||||
"src/roots/static-roots.h",
|
||||
"gn_args":
|
||||
f"""\
|
||||
is_debug = false
|
||||
use_goma = {USE_GOMA}
|
||||
v8_enable_static_roots = false
|
||||
v8_enable_pointer_compression = true
|
||||
v8_enable_shared_ro_heap = true
|
||||
v8_enable_pointer_compression_shared_cage = true
|
||||
v8_enable_webassembly = true
|
||||
v8_enable_i18n_support = true
|
||||
"""
|
||||
},
|
||||
}
|
||||
|
||||
# Parse args
|
||||
|
||||
parser = argparse.ArgumentParser(description='Generates static-roots.h.')
|
||||
parser.add_argument(
|
||||
'--configuration',
|
||||
choices=STATIC_ROOT_CONFIGURATIONS.keys(),
|
||||
action='extend',
|
||||
default='ptr-cmpr-wasm-intl',
|
||||
nargs='*',
|
||||
help="""Build configuration. Refers to a set of configurations with
|
||||
identical static-roots.h. Currently there is only one supported configuration.
|
||||
Future configurations will need to generate multiple target files.""")
|
||||
parser.add_argument(
|
||||
'--out',
|
||||
default=Path('out'),
|
||||
required=False,
|
||||
type=Path,
|
||||
help='target build directory')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Some helpers
|
||||
|
||||
|
||||
def run(cmd, **kwargs):
|
||||
print(f"# CMD: {cmd} {kwargs}")
|
||||
return subprocess.run(cmd, **kwargs, check=True)
|
||||
|
||||
|
||||
def build(path, gn_args):
|
||||
if not path.exists():
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
with (path / "args.gn").open("w") as f:
|
||||
f.write(gn_args)
|
||||
run(["gn", "gen", path])
|
||||
run(["autoninja", "-C", path, "mksnapshot"])
|
||||
return path.absolute()
|
||||
|
||||
|
||||
# Generate all requested static root headers
|
||||
|
||||
v8_path = Path(__file__).parents[2]
|
||||
|
||||
changed = False
|
||||
for target in [args.configuration]:
|
||||
build_dir = args.out / f"gen-static-roots.{target}"
|
||||
config = STATIC_ROOT_CONFIGURATIONS[target]
|
||||
gn_args = config["gn_args"]
|
||||
build_path = build(build_dir, gn_args)
|
||||
out_file = Path(tempfile.gettempdir()) / f"static-roots-{target}.h"
|
||||
run([build_path / "mksnapshot", "--static-roots", out_file])
|
||||
target_file = v8_path / config["target"]
|
||||
if not filecmp.cmp(out_file, target_file):
|
||||
shutil.move(out_file, target_file)
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
exit(1)
|
@ -384,6 +384,10 @@ class Config(object):
|
||||
return_code, output = _CallWithOutput("autoninja -C %s %s" %
|
||||
(path, targets))
|
||||
if return_code != 0 and "FAILED:" in output and "snapshot_blob" in output:
|
||||
if "gen-static-roots.py" in output:
|
||||
_Notify("V8 build requires your attention",
|
||||
"Please re-generate static roots...")
|
||||
return return_code
|
||||
csa_trap = re.compile("Specify option( --csa-trap-on-node=[^ ]*)")
|
||||
match = csa_trap.search(output)
|
||||
extra_opt = match.group(1) if match else ""
|
||||
|
Loading…
Reference in New Issue
Block a user