Clear the field
This commit is contained in:
1 parent
291f350165
commit
0a4af991ef
16118 files changed
+8
-3736585
No files matched your search
@@ -1,31 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
# Pass CC, CXX and PATH from the environment
|
||||
build --action_env=CC
|
||||
build --action_env=CXX
|
||||
build --action_env=PATH
|
||||
|
||||
# Use Clang compiler
|
||||
build:clang --action_env=BAZEL_COMPILER=clang
|
||||
build:clang --action_env=CC=clang
|
||||
build:clang --action_env=CXX=clang++
|
||||
|
||||
# V8 debug config
|
||||
build:debug --compilation_mode=dbg
|
||||
build:debug --config=v8_enable_debugging_features
|
||||
build:debug --//:v8_enable_fast_mksnapshot
|
||||
build:debug --//:v8_enable_backtrace
|
||||
build:debug --//:v8_enable_handle_zapping
|
||||
|
||||
# v8_enable_debugging_features flags
|
||||
build:v8_enable_debugging_features --//:v8_enable_verify_heap
|
||||
build:v8_enable_debugging_features --//:v8_enable_object_print
|
||||
build:v8_enable_debugging_features --//:v8_enable_disassembler
|
||||
build:v8_enable_debugging_features --//:v8_enable_trace_maps
|
||||
build:v8_enable_debugging_features --//:v8_enable_test_features
|
||||
build:v8_enable_debugging_features --//:v8_enable_v8_checks
|
||||
build:v8_enable_debugging_features --//:v8_code_comments
|
||||
build:v8_enable_debugging_features --//:v8_enable_debug_code
|
||||
build:v8_enable_debugging_features --//:v8_enable_snapshot_native_code_counters
|
||||
@@ -1,15 +0,0 @@
|
||||
# Defines the Google C++ style for automatic reformatting.
|
||||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
BasedOnStyle: Google
|
||||
DerivePointerAlignment: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
IfMacros:
|
||||
- IF
|
||||
- IF_NOT
|
||||
Macros:
|
||||
# Make clang-format think TurboShaft `ELSE` expands to just `else`, so that
|
||||
# it formats well alongside `if`
|
||||
- ELSE=else
|
||||
StatementMacros:
|
||||
- DECL_CAST
|
||||
- DECL_VERIFIER
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
---
|
||||
---
|
||||
Checks: '-*,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
modernize-redundant-void-arg,
|
||||
modernize-replace-random-shuffle,
|
||||
modernize-shrink-to-fit,
|
||||
# modernize-use-auto,
|
||||
modernize-use-bool-literals,
|
||||
modernize-use-equals-default,
|
||||
# modernize-use-equals-delete,
|
||||
modernize-use-nullptr,
|
||||
modernize-use-override,
|
||||
# google-build-explicit-make-pair,
|
||||
google-default-arguments,
|
||||
google-explicit-constructor,
|
||||
google-readability-casting'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
...
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -1,10 +0,0 @@
|
||||
[flake8]
|
||||
ignore = E111,E114,E310 # We use 2-space indentation
|
||||
exclude =
|
||||
./third_party/, # third-party code
|
||||
./build/, # third-party code
|
||||
./buildtools/, # third-party code
|
||||
./test/wasm-js/, # third-party code
|
||||
./test/wasm-js/data/, # third-party code
|
||||
./test/test262/data/, # third-party code
|
||||
./test/test262/harness/, # third-party code
|
||||
@@ -1,123 +0,0 @@
|
||||
# git hyper-blame master ignore list.
|
||||
#
|
||||
# This file contains a list of git hashes of revisions to be ignored by git
|
||||
# hyper-blame (in depot_tools). These revisions are considered "unimportant" in
|
||||
# that they are unlikely to be what you are interested in when blaming.
|
||||
#
|
||||
# Instructions:
|
||||
# - Only large (generally automated) reformatting or renaming CLs should be
|
||||
# added to this list. Do not put things here just because you feel they are
|
||||
# trivial or unimportant. If in doubt, do not put it on this list.
|
||||
# - Precede each revision with a comment containing the first line of its log.
|
||||
# For bulk work over many commits, place all commits in a block with a single
|
||||
# comment at the top describing the work done in those commits.
|
||||
# - Only put full 40-character hashes on this list (not short hashes or any
|
||||
# other revision reference).
|
||||
# - Append to the bottom of the file (revisions should be in chronological order
|
||||
# from oldest to newest).
|
||||
# - Because you must use a hash, you need to append to this list in a follow-up
|
||||
# CL to the actual reformatting CL that you are trying to ignore.
|
||||
|
||||
# objects.h splitting
|
||||
0604031eb1d01c52b6c1c9ae3012d80b23d74a68
|
||||
09e405453359000d66cc0faaa102854e626bebeb
|
||||
766ef168fbcac6bd0728cc2c9bb3ae7cbd74278a
|
||||
b5a2839b927be04bdb50a236071c11764e4d6400
|
||||
c911f91b5b6219e038c0117b05a8375bdf3db0b0
|
||||
1bb48bf91ba8c887884a0fbd674c91f64964d8a5
|
||||
19da9f24df7b59fec72b9dd8a979ad0ce5639c87
|
||||
b090d7e7468236ffce0afdb55bb496bf0073f2ee
|
||||
f40638d148b7a435522d5b714993908061e3b10d
|
||||
e8a1c25f6afae9b77921abb70fad49da252eb6f0
|
||||
6fa8283d0e031c9585d190f751907ed45bf85de0
|
||||
9aa861c4bcfed612039259f93c2cd2b01337e99e
|
||||
8175648018bd9f70af866f9fa433f1d79644d86b
|
||||
c7b1ceb801ec7f639a093468d8e6424212cc197c
|
||||
e39d2cbe1b1baa6513ddce2d73c981e335cc34fb
|
||||
eda00a5c499b7a83479115eb275a816b8a2ed104
|
||||
68deca9b418976ca8b3375e81058a9e0a815357f
|
||||
0525e17847f39f80e3fd163021a58f68d8fcaf06
|
||||
81a3c699d6eef936452ac3d10c7c59a2c1e38c0c
|
||||
01452bedfca2b5447a7f62bda87edbbb76259a6e
|
||||
1baf1050113a5418696839c273e05ea5ad1b5c4d
|
||||
4b39fe3d608916b1cfea015de287511a1623fc7f
|
||||
c6effdbba9b301244475553538f6eb1b3d9670b9
|
||||
71e4c573199466ea4541e3d6b307c9b33d7bb785
|
||||
efc92f0d4aa77bb90f5b56606b6f0d0819fba4af
|
||||
a9db2c74b5bae2345ac52be404748954a3b5050d
|
||||
0a01b6202226bbe99c0b83acf6c5a80344f5fb6a
|
||||
a6c44361c8f2dc07b935e3f2bb3e0d3ad4f4a383
|
||||
10d8aab1de430695a69e9d75af6ea42c2cdc9d6d
|
||||
dd3c4fca2f0a2761b8b95cd47fcd62836d714890
|
||||
e9c932233980866074025e65051003d1f298516c
|
||||
2b1f79881c3f0b69bfb9274bda57ea50f7304982
|
||||
7f031160d71a3d836667dc98288eaff4c94e6f56
|
||||
490fabb4578f8a3c4096fdccff688c17ed5ed00d
|
||||
d953b2ab726acca0b3abe90ce090a16d7ccc2ae3
|
||||
bb514c426b9438cfb1149d219ac4ec2d8d1c8458
|
||||
dfb453d713d8a05e76f720a6aae2871eec210276
|
||||
b490fd66b873c89fca37b21eab58502b6367a864
|
||||
9a71683d9c8ff9470eda6be5b2b11babac7b9863
|
||||
37945f731c4d800ef788e3c32f8663773a93450e
|
||||
b90c98fc29a8d896354de4a22c055f6d98376171
|
||||
35f3e9d0e654e84646a0b98f29e4a2786cdca4b1
|
||||
260eb5bb9b62ea3d5fa6ad0b0e8c2de75d48bad4
|
||||
cc2c11441ce352360acce8638a19f58edf361f7d
|
||||
7be0159e4b1e0b064e215ae4ced34d649cb2552e
|
||||
95a7cfe0eaabbcff0f730ed60e1805779f6cfe41
|
||||
8f54d18ba4ad10770e9537a2803459feccfe79a3
|
||||
f44759d9ff52a3e5563e5f2bb23ee2c08222fcfd
|
||||
09050c8a967f5f2956305e5d016b304d7bf5e669
|
||||
c769745d5856a7eb3a0dbe6af5376c7638944364
|
||||
a1547aa914aeedd7862f74124c18d2bbaf432c36
|
||||
5f950698c0dc7c36b855961feb929022f74102fb
|
||||
4aedeb1bd50c12ebcd6cf954c4cbef1205fff5ac
|
||||
7366d8954cb1bd277d3283241da2fae62b886c48
|
||||
bc35251f5e55a65c3a4acf7cba52cee505c86a46
|
||||
4fb60b215801db70c694a799e735b64bfead59bb
|
||||
03762b8488de0e393077e3f40fe7b63e675b3af3
|
||||
a8a45d875f0a98b192cf0063ceda12aaf75ddfaf
|
||||
a48e5ab8804e9e97b5ea577d6f2667bacee92eb2
|
||||
|
||||
# Update of quotations in DEPS file.
|
||||
e50b49a0e38b34e2b28e026f4d1c7e0da0c7bb1a
|
||||
|
||||
# Rewrite code base to use "." instead of "->" to access Object members.
|
||||
878ccb33bd3cf0e6dc018ff8d15843f585ac07be
|
||||
|
||||
# Splitting src/ into subfolders
|
||||
632239011db501e76475d82ff6492f37fa8c1edc
|
||||
f455f86d899716df3b9550950ce172f5b867619a
|
||||
24a51e1eee4e286165dd0bba6afb4c35e8177a25
|
||||
f9a88acbc928f0fc5e9a3acbcd3b4ece52355f3d
|
||||
dec3298d9cfbe95759774a0e00302a08836b5f3d
|
||||
a0c3797461810e3159662851e64946e17654236e
|
||||
b72941e8b0d2843adf768442024d8950da798db1
|
||||
4c986c625f19e35c95f3492c662822f4695218b4
|
||||
0fa243af7096ee5b748b194476be2e4efecaec59
|
||||
786ce26341b7ab11b4d42f1c77202530d5138ad2
|
||||
a6eeea35cb7ff0c29b6cfdd1c786f382110241ce
|
||||
be014256adea1552d4a044ef80616cdab6a7d549
|
||||
93d3b7173fec7d010539057cdbd78d497f09fa9b
|
||||
5bfe84a0dab60289b3470c080908ce83ac2212d4
|
||||
a7695520556665ba73ab02c497ab73b162a5fb13
|
||||
61523c45a335fe3be76498e0b16bf8e7aec0d058
|
||||
bf372a73d8a5f4029fc9f4f69b675ef0cad80ada
|
||||
8ad6b335376c6275ffb3361c662a1a45c853f4fc
|
||||
06bf8261cf2c94fc071652652600b5790f719c05
|
||||
81a0102fe8586071cc68e9595b26c5c1207ee5b3
|
||||
5f28539599f6a6a265e18b8c897cc96ccbeec9c4
|
||||
3253767622a784866dc34aeb7b5d0f02ebdff61e
|
||||
9ac8b20086f95f1158a1901eefe12e25fd0333e4
|
||||
3cb560adfe26edb586a0e6e655e5a7c4755cad1a
|
||||
7bbd0bfe5161d57bcf268716ce4d1ce14d6786e6
|
||||
c39cabbcbea26891558b81fd2236c38a7aeada08
|
||||
a3187716d31a0ab9d7051adde6be9bd2b2c6fec1
|
||||
|
||||
# Move test/mjsunit/regress-*.js => test/mjsunit/regress/
|
||||
cb67be1a3842fcf6a0da18aee444e3b7ea789e04
|
||||
|
||||
# [include] Split out v8.h
|
||||
d1b27019d3bf86360ea838c317f8505fac6d3a7e
|
||||
44fe02ced6e4c6b49d627807e3b3fd0edbbeb36e
|
||||
ec06bb6ce5641cf65e400ec55b7421f87d04b999
|
||||
@@ -1,13 +0,0 @@
|
||||
# `true` will close all PRs.
|
||||
filters:
|
||||
- true
|
||||
|
||||
# The message to post to the closed PR.
|
||||
commentBody: |
|
||||
Thanks for your contribution! Unfortunately, we don't use GitHub pull
|
||||
requests to manage code contributions to this repository. Instead, please
|
||||
see https://v8.dev/docs/contribute which provides full instructions on
|
||||
how to get involved.
|
||||
|
||||
# Whether to add a label to the closed PR.
|
||||
addLabel: false
|
||||
@@ -1,38 +0,0 @@
|
||||
# This file is used by the GN meta build system to find the root of the source
|
||||
# tree and to set startup options. For documentation on the values set in this
|
||||
# file, run "gn help dotfile" at the command line.
|
||||
|
||||
import("//build/dotfile_settings.gni")
|
||||
|
||||
# The location of the build configuration file.
|
||||
buildconfig = "//build/config/BUILDCONFIG.gn"
|
||||
|
||||
# The python interpreter to use by default. On Windows, this will look
|
||||
# for python3.exe and python3.bat.
|
||||
script_executable = "python3"
|
||||
|
||||
# These are the targets to check headers for by default. The files in targets
|
||||
# matching these patterns (see "gn help label_pattern" for format) will have
|
||||
# their includes checked for proper dependencies when you run either
|
||||
# "gn check" or "gn gen --check".
|
||||
no_check_targets = [
|
||||
"//:cppgc_base",
|
||||
"//:v8_internal_headers",
|
||||
"//src/inspector:inspector",
|
||||
"//test/cctest:cctest_sources", # 15 errors
|
||||
"//test/unittests:inspector_unittests_sources", # 2 errors
|
||||
"//third_party/icu:*",
|
||||
]
|
||||
|
||||
default_args = {
|
||||
# Disable js dependencies like the closure compiler.
|
||||
enable_js_protobuf = false
|
||||
# Disable rust dependencies.
|
||||
enable_rust = false
|
||||
}
|
||||
|
||||
# These are the list of GN files that run exec_script. This whitelist exists
|
||||
# to force additional review for new uses of exec_script, which is strongly
|
||||
# discouraged except for gypi_to_gn calls.
|
||||
exec_script_whitelist = build_dotfile_settings.exec_script_whitelist +
|
||||
[ "//build_overrides/build.gni" ]
|
||||
@@ -1,16 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
# People change their names or email addresses for many reasons. This
|
||||
# list makes sure people’s preferences are respected when using Git
|
||||
# commands such as `git log` or `git blame`.
|
||||
#
|
||||
# See https://git-scm.com/docs/gitmailmap for more information.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Clemens Backes <clemensb@chromium.org> Clemens Hammacher <clemensh@chromium.org>
|
||||
Jakob Linke <jgruber@chromium.org>
|
||||
Jakob Linke <jgruber@chromium.org> <jgruber@google.com>
|
||||
Timothy Gu <timothygu@chromium.org> <timothygu99@gmail.com>
|
||||
@@ -1,2 +0,0 @@
|
||||
[style]
|
||||
based_on_style = yapf
|
||||
@@ -1,102 +0,0 @@
|
||||
# This is a vpython "spec" file.
|
||||
#
|
||||
# It describes patterns for python wheel dependencies of the python scripts in
|
||||
# the chromium repo, particularly for dependencies that have compiled components
|
||||
# (since pure-python dependencies can be easily vendored into third_party).
|
||||
#
|
||||
# When vpython is invoked, it finds this file and builds a python VirtualEnv,
|
||||
# containing all of the dependencies described in this file, fetching them from
|
||||
# CIPD (the "Chrome Infrastructure Package Deployer" service). Unlike `pip`,
|
||||
# this never requires the end-user machine to have a working python extension
|
||||
# compilation environment. All of these packages are built using:
|
||||
# https://chromium.googlesource.com/infra/infra/+/main/infra/tools/dockerbuild/
|
||||
#
|
||||
# All python scripts in the repo share this same spec, to avoid dependency
|
||||
# fragmentation.
|
||||
#
|
||||
# If you have depot_tools installed in your $PATH, you can invoke python scripts
|
||||
# in this repo by running them as you normally would run them, except
|
||||
# substituting `vpython` instead of `python` on the command line, e.g.:
|
||||
# vpython path/to/script.py some --arguments
|
||||
#
|
||||
# Read more about `vpython` and how to modify this file here:
|
||||
# https://chromium.googlesource.com/infra/infra/+/main/doc/users/vpython.md
|
||||
|
||||
python_version: "3.8"
|
||||
|
||||
# The default set of platforms vpython checks does not yet include mac-arm64.
|
||||
# Setting `verify_pep425_tag` to the list of platforms we explicitly must support
|
||||
# allows us to ensure that vpython specs stay mac-arm64-friendly
|
||||
verify_pep425_tag: [
|
||||
{python: "cp38", abi: "cp38", platform: "manylinux1_x86_64"},
|
||||
{python: "cp38", abi: "cp38", platform: "linux_arm64"},
|
||||
|
||||
{python: "cp38", abi: "cp38", platform: "macosx_10_10_intel"},
|
||||
{python: "cp38", abi: "cp38", platform: "macosx_11_0_arm64"},
|
||||
|
||||
{python: "cp38", abi: "cp38", platform: "win32"},
|
||||
{python: "cp38", abi: "cp38", platform: "win_amd64"}
|
||||
]
|
||||
|
||||
# TODO(https://crbug.com/898348): Add in necessary wheels as Python3 versions
|
||||
# become available.
|
||||
wheel: <
|
||||
name: "infra/python/wheels/six-py2_py3"
|
||||
version: "version:1.15.0"
|
||||
>
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/coverage/${vpython_platform}"
|
||||
version: "version:5.5.chromium.3"
|
||||
>
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/pbr-py2_py3"
|
||||
version: "version:3.0.0"
|
||||
>
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/funcsigs-py2_py3"
|
||||
version: "version:1.0.2"
|
||||
>
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/mock-py2_py3"
|
||||
version: "version:2.0.0"
|
||||
>
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/numpy/${vpython_platform}"
|
||||
version: "version:1.2x.supported.1"
|
||||
>
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/protobuf-py3"
|
||||
version: "version:3.19.3"
|
||||
>
|
||||
|
||||
# requests and its dependencies.
|
||||
wheel: <
|
||||
name: "infra/python/wheels/requests-py3"
|
||||
version: "version:2.31.0"
|
||||
>
|
||||
wheel: <
|
||||
name: "infra/python/wheels/urllib3-py2_py3"
|
||||
version: "version:1.26.6"
|
||||
>
|
||||
wheel: <
|
||||
name: "infra/python/wheels/idna-py2_py3"
|
||||
version: "version:2.8"
|
||||
>
|
||||
wheel: <
|
||||
name: "infra/python/wheels/certifi-py2_py3"
|
||||
version: "version:2020.11.8"
|
||||
>
|
||||
wheel: <
|
||||
name: "infra/python/wheels/charset_normalizer-py3"
|
||||
version: "version:2.0.4"
|
||||
>
|
||||
wheel: <
|
||||
name: "infra/python/wheels/pyfakefs-py2_py3"
|
||||
version: "version:3.7.2"
|
||||
>
|
||||
@@ -1,189 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
# Autocompletion config for YouCompleteMe in V8.
|
||||
#
|
||||
# USAGE:
|
||||
#
|
||||
# 1. Install YCM [https://github.com/Valloric/YouCompleteMe]
|
||||
# (Googlers should check out [go/ycm])
|
||||
#
|
||||
# 2. Profit
|
||||
#
|
||||
#
|
||||
# Usage notes:
|
||||
#
|
||||
# * You must use ninja & clang to build V8.
|
||||
#
|
||||
# * You must have run gyp_v8 and built V8 recently.
|
||||
#
|
||||
#
|
||||
# Hacking notes:
|
||||
#
|
||||
# * The purpose of this script is to construct an accurate enough command line
|
||||
# for YCM to pass to clang so it can build and extract the symbols.
|
||||
#
|
||||
# * Right now, we only pull the -I and -D flags. That seems to be sufficient
|
||||
# for everything I've used it for.
|
||||
#
|
||||
# * That whole ninja & clang thing? We could support other configs if someone
|
||||
# were willing to write the correct commands and a parser.
|
||||
#
|
||||
# * This has only been tested on gTrusty.
|
||||
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
# Flags from YCM's default config.
|
||||
flags = [
|
||||
'-DUSE_CLANG_COMPLETER',
|
||||
'-x',
|
||||
'c++',
|
||||
]
|
||||
|
||||
|
||||
def PathExists(*args):
|
||||
return os.path.exists(os.path.join(*args))
|
||||
|
||||
|
||||
def FindV8SrcFromFilename(filename):
|
||||
"""Searches for the root of the V8 checkout.
|
||||
|
||||
Simply checks parent directories until it finds .gclient and v8/.
|
||||
|
||||
Args:
|
||||
filename: (String) Path to source file being edited.
|
||||
|
||||
Returns:
|
||||
(String) Path of 'v8/', or None if unable to find.
|
||||
"""
|
||||
curdir = os.path.normpath(os.path.dirname(filename))
|
||||
while not (PathExists(curdir, 'v8') and PathExists(curdir, 'v8', 'DEPS')
|
||||
and (PathExists(curdir, '.gclient')
|
||||
or PathExists(curdir, 'v8', '.git'))):
|
||||
nextdir = os.path.normpath(os.path.join(curdir, '..'))
|
||||
if nextdir == curdir:
|
||||
return None
|
||||
curdir = nextdir
|
||||
return os.path.join(curdir, 'v8')
|
||||
|
||||
|
||||
def GetClangCommandFromNinjaForFilename(v8_root, filename):
|
||||
"""Returns the command line to build |filename|.
|
||||
|
||||
Asks ninja how it would build the source file. If the specified file is a
|
||||
header, tries to find its companion source file first.
|
||||
|
||||
Args:
|
||||
v8_root: (String) Path to v8/.
|
||||
filename: (String) Path to source file being edited.
|
||||
|
||||
Returns:
|
||||
(List of Strings) Command line arguments for clang.
|
||||
"""
|
||||
if not v8_root:
|
||||
return []
|
||||
|
||||
# Generally, everyone benefits from including V8's root, because all of
|
||||
# V8's includes are relative to that.
|
||||
v8_flags = ['-I' + os.path.join(v8_root)]
|
||||
|
||||
# Version of Clang used to compile V8 can be newer then version of
|
||||
# libclang that YCM uses for completion. So it's possible that YCM's libclang
|
||||
# doesn't know about some used warning options, which causes compilation
|
||||
# warnings (and errors, because of '-Werror');
|
||||
v8_flags.append('-Wno-unknown-warning-option')
|
||||
|
||||
# Header files can't be built. Instead, try to match a header file to its
|
||||
# corresponding source file.
|
||||
if filename.endswith('.h'):
|
||||
base = filename[:-6] if filename.endswith('-inl.h') else filename[:-2]
|
||||
for alternate in [base + e for e in ['.cc', '.cpp']]:
|
||||
if os.path.exists(alternate):
|
||||
filename = alternate
|
||||
break
|
||||
else:
|
||||
# If this is a standalone .h file with no source, we ask ninja for the
|
||||
# compile flags of some generic cc file ('src/utils/utils.cc'). This
|
||||
# should contain most/all of the interesting flags for other targets too.
|
||||
filename = os.path.join(v8_root, 'src', 'utils', 'utils.cc')
|
||||
|
||||
sys.path.append(os.path.join(v8_root, 'tools', 'vim'))
|
||||
from ninja_output import GetNinjaOutputDirectory
|
||||
out_dir = os.path.realpath(GetNinjaOutputDirectory(v8_root))
|
||||
|
||||
# Ninja needs the path to the source file relative to the output build
|
||||
# directory.
|
||||
rel_filename = os.path.relpath(os.path.realpath(filename), out_dir)
|
||||
|
||||
# Ask ninja how it would build our source file.
|
||||
p = subprocess.Popen(['ninja', '-v', '-C', out_dir, '-t',
|
||||
'commands', rel_filename + '^'],
|
||||
stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode:
|
||||
return v8_flags
|
||||
|
||||
# Ninja might execute several commands to build something. We want the last
|
||||
# clang command.
|
||||
clang_line = None
|
||||
for line in reversed(stdout.decode('utf-8').splitlines()):
|
||||
if 'clang' in line:
|
||||
clang_line = line
|
||||
break
|
||||
else:
|
||||
return v8_flags
|
||||
|
||||
# Parse flags that are important for YCM's purposes.
|
||||
for flag in clang_line.split(' '):
|
||||
if flag.startswith('-I'):
|
||||
v8_flags.append(MakeIncludePathAbsolute(flag, "-I", out_dir))
|
||||
elif flag.startswith('-isystem'):
|
||||
v8_flags.append(MakeIncludePathAbsolute(flag, "-isystem", out_dir))
|
||||
elif flag.startswith('-std') or flag.startswith(
|
||||
'-pthread') or flag.startswith('-no'):
|
||||
v8_flags.append(flag)
|
||||
elif flag.startswith('-') and flag[1] in 'DWFfmgOX':
|
||||
v8_flags.append(flag)
|
||||
return v8_flags
|
||||
|
||||
|
||||
def MakeIncludePathAbsolute(flag, prefix, out_dir):
|
||||
# Relative paths need to be resolved, because they're relative to the
|
||||
# output dir, not the source.
|
||||
if flag[len(prefix)] == '/':
|
||||
return flag
|
||||
else:
|
||||
abs_path = os.path.normpath(os.path.join(out_dir, flag[len(prefix):]))
|
||||
return prefix + abs_path
|
||||
|
||||
|
||||
def FlagsForFile(filename):
|
||||
"""This is the main entry point for YCM. Its interface is fixed.
|
||||
|
||||
Args:
|
||||
filename: (String) Path to source file being edited.
|
||||
|
||||
Returns:
|
||||
(Dictionary)
|
||||
'flags': (List of Strings) Command line flags.
|
||||
'do_cache': (Boolean) True if the result should be cached.
|
||||
"""
|
||||
v8_root = FindV8SrcFromFilename(filename)
|
||||
v8_flags = GetClangCommandFromNinjaForFilename(v8_root, filename)
|
||||
final_flags = flags + v8_flags
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
||||
|
||||
|
||||
def Settings(**kwargs):
|
||||
if kwargs['language'] == 'cfamily':
|
||||
return FlagsForFile(kwargs['filename'])
|
||||
return {}
|
||||
-4470
File diff suppressed because it is too large.
Load diff
@@ -1,8 +0,0 @@
|
||||
# V8 Code of Conduct
|
||||
|
||||
As part of the Chromium team, the V8 team is committed to preserving and
|
||||
fostering a diverse, welcoming community. To this end, the [Chromium Code of
|
||||
Conduct](https://chromium.googlesource.com/chromium/src/+/master/CODE_OF_CONDUCT.md)
|
||||
applies to our repos and organizations, mailing lists, blog content, and any
|
||||
other Chromium-supported communication group, as well as any private
|
||||
communication initiated in the context of these spaces.
|
||||
@@ -1,41 +0,0 @@
|
||||
adamk@chromium.org
|
||||
ahaas@chromium.org
|
||||
alexschulze@chromium.org
|
||||
bikineev@chromium.org
|
||||
bmeurer@chromium.org
|
||||
cbruni@chromium.org
|
||||
clemensb@chromium.org
|
||||
danno@chromium.org
|
||||
dinfuehr@chromium.org
|
||||
dlehmann@chromium.org
|
||||
dmercadier@chromium.org
|
||||
ecmziegler@chromium.org
|
||||
evih@chromium.org
|
||||
gdeepti@chromium.org
|
||||
hablich@chromium.org
|
||||
hpayer@chromium.org
|
||||
ishell@chromium.org
|
||||
jgruber@chromium.org
|
||||
jkummerow@chromium.org
|
||||
leszeks@chromium.org
|
||||
liviurau@chromium.org
|
||||
machenbach@chromium.org
|
||||
manoskouk@chromium.org
|
||||
marja@chromium.org
|
||||
mathias@chromium.org
|
||||
mliedtke@chromium.org
|
||||
mlippautz@chromium.org
|
||||
nicohartmann@chromium.org
|
||||
nikolaos@chromium.org
|
||||
olivf@chromium.org
|
||||
omerkatz@chromium.org
|
||||
pthier@chromium.org
|
||||
rezvan@chromium.org
|
||||
sroettger@google.com
|
||||
syg@chromium.org
|
||||
szuend@chromium.org
|
||||
thibaudm@chromium.org
|
||||
vahl@chromium.org
|
||||
verwaest@chromium.org
|
||||
victorgomes@chromium.org
|
||||
yangguo@chromium.org
|
||||
@@ -1,681 +0,0 @@
|
||||
# Note: The buildbots evaluate this file with CWD set to the parent
|
||||
# directory and assume that the root of the checkout is in ./v8/, so
|
||||
# all paths in here must match this assumption.
|
||||
|
||||
use_relative_paths = True
|
||||
|
||||
gclient_gn_args_file = 'build/config/gclient_args.gni'
|
||||
gclient_gn_args = [
|
||||
]
|
||||
|
||||
vars = {
|
||||
# Fetches only the SDK boot images which match at least one of the whitelist
|
||||
# entries in a comma-separated list.
|
||||
#
|
||||
# Available images:
|
||||
# Emulation:
|
||||
# - terminal.qemu-x64
|
||||
# - terminal.qemu-arm64
|
||||
# - workstation.qemu-x64-release
|
||||
# Hardware:
|
||||
# - minimal.x64
|
||||
# - core.x64-dfv2
|
||||
#
|
||||
# Since the images are hundreds of MB, default to only downloading the image
|
||||
# most commonly useful for developers. Bots and developers that need to use
|
||||
# other images (e.g., qemu.arm64) can override this with additional images.
|
||||
'checkout_fuchsia_boot_images': "terminal.x64",
|
||||
'checkout_fuchsia_product_bundles': '"{checkout_fuchsia_boot_images}" != ""',
|
||||
|
||||
'checkout_centipede_deps': False,
|
||||
'checkout_instrumented_libraries': False,
|
||||
'checkout_ittapi': False,
|
||||
|
||||
# Fetch the prebuilt binaries for llvm-cov and llvm-profdata. Needed to
|
||||
# process the raw profiles produced by instrumented targets (built with
|
||||
# the gn arg 'use_clang_coverage').
|
||||
'checkout_clang_coverage_tools': False,
|
||||
|
||||
# Fetch clang-tidy into the same bin/ directory as our clang binary.
|
||||
'checkout_clang_tidy': False,
|
||||
|
||||
# Fetch and build V8 builtins with PGO profiles
|
||||
'checkout_v8_builtins_pgo_profiles': False,
|
||||
|
||||
'android_url': 'https://android.googlesource.com',
|
||||
'boringssl_url': 'https://boringssl.googlesource.com',
|
||||
'chromium_url': 'https://chromium.googlesource.com',
|
||||
'download_gcmole': False,
|
||||
'download_jsfunfuzz': False,
|
||||
'download_prebuilt_bazel': False,
|
||||
'check_v8_header_includes': False,
|
||||
|
||||
# By default, download the fuchsia sdk from the public sdk directory.
|
||||
'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/core/',
|
||||
|
||||
# Used for downloading the Fuchsia SDK without running hooks.
|
||||
'checkout_fuchsia_no_hooks': False,
|
||||
|
||||
# reclient CIPD package version
|
||||
'reclient_version': 're_client_version:0.141.1.29a9d3c-gomaip',
|
||||
|
||||
# Fetch configuration files required for the 'use_remoteexec' gn arg
|
||||
'download_remoteexec_cfg': False,
|
||||
|
||||
# RBE instance to use for running remote builds
|
||||
'rbe_instance': Str('projects/rbe-chrome-untrusted/instances/default_instance'),
|
||||
|
||||
# RBE project to download rewrapper config files for. Only needed if
|
||||
# different from the project used in 'rbe_instance'
|
||||
'rewrapper_cfg_project': Str(''),
|
||||
|
||||
# This variable is overrided in Chromium's DEPS file.
|
||||
'build_with_chromium': False,
|
||||
|
||||
# GN CIPD package version.
|
||||
'gn_version': 'git_revision:b2afae122eeb6ce09c52d63f67dc53fc517dbdc8',
|
||||
|
||||
# ninja CIPD package version
|
||||
# https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja
|
||||
'ninja_version': 'version:2@1.11.1.chromium.6',
|
||||
|
||||
# siso CIPD package version
|
||||
'siso_version': 'git_revision:4524544994f4eac131378143f498ee4d0b7d1f36',
|
||||
|
||||
# luci-go CIPD package version.
|
||||
'luci_go': 'git_revision:69f852c6aea2797c75712d59145efd38d7032196',
|
||||
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling Fuchsia sdk
|
||||
# and whatever else without interference from each other.
|
||||
'fuchsia_version': 'version:20.20240430.3.1',
|
||||
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_build-tools_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_build-tools_version': 'YK9Rzw3fDzMHVzatNN6VlyoD_81amLZpN1AbmkdOd6AC',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_emulator_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_emulator_version': '9lGp8nTUCRRWGMnI_96HcKfzjnxEJKUcfvfwmA3wXNkC',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_extras_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_extras_version': 'bY55nDqO6FAm6FkGIj09sh2KW9oqAkCGKjYok5nUvBMC',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_patcher_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_patcher_version': 'I6FNMhrXlpB-E1lOhMlvld7xt9lBVNOO83KIluXDyA0C',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_platform-tools_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_platform-tools_version': 'HWVsGs2HCKgSVv41FsOcsfJbNcB0UFiNrF6Tc4yRArYC',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_platforms_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_platforms_version': 'u-bhWbTME6u-DjypTgr3ZikCyeAeU6txkR9ET6Uudc8C',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_sources_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_sources_version': 'qfTSF99e29-w3eIVPpfcif0Em5etyvxuicTDTntWHQMC',
|
||||
# Three lines of non-changing comments so that
|
||||
# the commit queue can handle CLs rolling android_sdk_tools-lint_version
|
||||
# and whatever else without interference from each other.
|
||||
'android_sdk_cmdline-tools_version': 'mU9jm4LkManzjSzRquV1UIA7fHBZ2pK7NtbCXxoVnVUC',
|
||||
}
|
||||
|
||||
deps = {
|
||||
'build':
|
||||
Var('chromium_url') + '/chromium/src/build.git' + '@' + '0eb093566a85381610a21f5e46f999ac106b0ee2',
|
||||
'buildtools':
|
||||
Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '2bd8dea61c53448c67f70419004ded4032590fe7',
|
||||
'buildtools/linux64': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'gn/gn/linux-${{arch}}',
|
||||
'version': Var('gn_version'),
|
||||
}
|
||||
],
|
||||
'dep_type': 'cipd',
|
||||
'condition': 'host_os == "linux" and host_cpu != "s390" and host_cpu != "ppc"',
|
||||
},
|
||||
'buildtools/mac': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'gn/gn/mac-${{arch}}',
|
||||
'version': Var('gn_version'),
|
||||
}
|
||||
],
|
||||
'dep_type': 'cipd',
|
||||
'condition': 'host_os == "mac"',
|
||||
},
|
||||
'buildtools/win': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'gn/gn/windows-amd64',
|
||||
'version': Var('gn_version'),
|
||||
}
|
||||
],
|
||||
'dep_type': 'cipd',
|
||||
'condition': 'host_os == "win"',
|
||||
},
|
||||
'buildtools/reclient': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'infra/rbe/client/${{platform}}',
|
||||
'version': Var('reclient_version'),
|
||||
}
|
||||
],
|
||||
'dep_type': 'cipd',
|
||||
'condition': '(host_os == "linux" or host_os == "mac" or host_os == "win") and host_cpu != "s390" and host_cpu != "ppc" and (host_cpu != "arm64" or host_os == "mac")',
|
||||
},
|
||||
'test/benchmarks/data':
|
||||
Var('chromium_url') + '/v8/deps/third_party/benchmarks.git' + '@' + '05d7188267b4560491ff9155c5ee13e207ecd65f',
|
||||
'test/mozilla/data':
|
||||
Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be',
|
||||
'test/test262/data':
|
||||
Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'a15874163e6a4f19ee7cd3e47592af382af0f5fd',
|
||||
'third_party/android_platform': {
|
||||
'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + '6337c445f9963ec3914e7e0c5787941d07b46509',
|
||||
'condition': 'checkout_android',
|
||||
},
|
||||
'third_party/android_sdk/public': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/build-tools/34.0.0',
|
||||
'version': Var('android_sdk_build-tools_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/emulator',
|
||||
'version': Var('android_sdk_emulator_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/extras',
|
||||
'version': Var('android_sdk_extras_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/patcher',
|
||||
'version': Var('android_sdk_patcher_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/platform-tools',
|
||||
'version': Var('android_sdk_platform-tools_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/platforms/android-34',
|
||||
'version': Var('android_sdk_platforms_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/sources/android-30',
|
||||
'version': Var('android_sdk_sources_version'),
|
||||
},
|
||||
{
|
||||
'package': 'chromium/third_party/android_sdk/public/cmdline-tools',
|
||||
'version': Var('android_sdk_cmdline-tools_version'),
|
||||
},
|
||||
],
|
||||
'condition': 'checkout_android',
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
'third_party/android_toolchain/ndk': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'chromium/third_party/android_toolchain/android_toolchain',
|
||||
'version': 'wpJvg81kuXdMM66r_l9Doa-pLfR6S26Jd1x40LpwWEoC',
|
||||
},
|
||||
],
|
||||
'condition': 'checkout_android',
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
'third_party/boringssl': {
|
||||
'url': Var('chromium_url') + '/chromium/src/third_party/boringssl.git' + '@' + 'd246272069be506602bd2a7dcf49526d7de603f9',
|
||||
'condition': "checkout_centipede_deps",
|
||||
},
|
||||
'third_party/boringssl/src': {
|
||||
'url': Var('boringssl_url') + '/boringssl.git' + '@' + '2db0eb3f96a5756298dcd7f9319e56a98585bd10',
|
||||
'condition': "checkout_centipede_deps",
|
||||
},
|
||||
'third_party/catapult': {
|
||||
'url': Var('chromium_url') + '/catapult.git' + '@' + 'c63cfff73e8785d9fd29aff91ed1fdbbd7a48b22',
|
||||
'condition': 'checkout_android',
|
||||
},
|
||||
'third_party/clang-format/script':
|
||||
Var('chromium_url') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + '3c0acd2d4e73dd911309d9e970ba09d58bf23a62',
|
||||
'third_party/colorama/src': {
|
||||
'url': Var('chromium_url') + '/external/colorama.git' + '@' + '3de9f013df4b470069d03d250224062e8cf15c49',
|
||||
'condition': 'checkout_android',
|
||||
},
|
||||
'third_party/cpu_features/src': {
|
||||
'url': Var('chromium_url') + '/external/github.com/google/cpu_features.git' + '@' + '936b9ab5515dead115606559502e3864958f7f6e',
|
||||
'condition': 'checkout_android',
|
||||
},
|
||||
'third_party/depot_tools':
|
||||
Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'e30d8fac34378beeb3d72cfca444e87f6fc28013',
|
||||
'third_party/fp16/src':
|
||||
Var('chromium_url') + '/external/github.com/Maratyszcza/FP16.git' + '@' + '0a92994d729ff76a58f692d3028ca1b64b145d91',
|
||||
'third_party/fuchsia-gn-sdk': {
|
||||
'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-gn-sdk.git' + '@' + '30fee7b68b3675e351fa47303c3b6ef322941ccd',
|
||||
'condition': 'checkout_fuchsia',
|
||||
},
|
||||
# Exists for rolling the Fuchsia SDK. Check out of the SDK should always
|
||||
# rely on the hook running |update_sdk.py| script below.
|
||||
'third_party/fuchsia-sdk/sdk': {
|
||||
'packages': [
|
||||
{
|
||||
'package': Var('fuchsia_sdk_cipd_prefix') + '${{platform}}',
|
||||
'version': Var('fuchsia_version'),
|
||||
},
|
||||
],
|
||||
'condition': 'checkout_fuchsia_no_hooks',
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
'third_party/google_benchmark_chrome': {
|
||||
'url': Var('chromium_url') + '/chromium/src/third_party/google_benchmark.git' + '@' + 'f049b96d7a50ae19f2748aae7fba7bde705bcd8c',
|
||||
},
|
||||
'third_party/google_benchmark_chrome/src': {
|
||||
'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + '344117638c8ff7e239044fd0fa7085839fc03021',
|
||||
},
|
||||
'third_party/fuzztest':
|
||||
Var('chromium_url') + '/chromium/src/third_party/fuzztest.git' + '@' + '647d62d39768e90bbb71b0c7758a436cba9c60d5',
|
||||
'third_party/fuzztest/src':
|
||||
Var('chromium_url') + '/external/github.com/google/fuzztest.git' + '@' + '32eb84a95951fa3a0148fb3e6a1a02f830ded136',
|
||||
'third_party/googletest/src':
|
||||
Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + 'a7f443b80b105f940225332ed3c31f2790092f47',
|
||||
'third_party/icu':
|
||||
Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '43953f57b037778a1b8005564afabe214834f7bd',
|
||||
'third_party/instrumented_libs': {
|
||||
'url': Var('chromium_url') + '/chromium/third_party/instrumented_libraries.git' + '@' + 'bb6dbcf2df7a9beb34c3773ef4df161800e3aed9',
|
||||
'condition': 'checkout_instrumented_libraries',
|
||||
},
|
||||
'third_party/ittapi': {
|
||||
# Force checkout ittapi libraries to pass v8 header includes check on
|
||||
# bots that has check_v8_header_includes enabled.
|
||||
'url': Var('chromium_url') + '/external/github.com/intel/ittapi' + '@' + 'a3911fff01a775023a06af8754f9ec1e5977dd97',
|
||||
'condition': "checkout_ittapi or check_v8_header_includes",
|
||||
},
|
||||
'third_party/jinja2':
|
||||
Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + '2f6f2ff5e4c1d727377f5e1b9e1903d871f41e74',
|
||||
'third_party/jsoncpp/source':
|
||||
Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '42e892d96e47b1f6e29844cc705e148ec4856448',
|
||||
'third_party/libc++/src':
|
||||
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '852bc6746f45add53fec19f3a29280e69e358d44',
|
||||
'third_party/libc++abi/src':
|
||||
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '43dd5b4bf62e8593461dce9a95e3d43fdcd0b9f2',
|
||||
'third_party/libunwind/src':
|
||||
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + 'c8f1d81998280ae2ea0e76ddb60aae6e1b4b860e',
|
||||
'third_party/logdog/logdog':
|
||||
Var('chromium_url') + '/infra/luci/luci-py/client/libs/logdog' + '@' + '0b2078a90f7a638d576b3a7c407d136f2fb62399',
|
||||
'third_party/markupsafe':
|
||||
Var('chromium_url') + '/chromium/src/third_party/markupsafe.git' + '@' + 'e582d7f0edb9d67499b0f5abd6ae5550e91da7f2',
|
||||
'third_party/ninja': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'infra/3pp/tools/ninja/${{platform}}',
|
||||
'version': Var('ninja_version'),
|
||||
}
|
||||
],
|
||||
'dep_type': 'cipd',
|
||||
'condition': 'host_cpu != "s390" and host_cpu != "ppc"'
|
||||
},
|
||||
'third_party/perfetto':
|
||||
Var('android_url') + '/platform/external/perfetto.git' + '@' + '6fc824d618d2f06b5d9cd8655ba0419b6b3b366e',
|
||||
'third_party/protobuf_chrome':
|
||||
Var('chromium_url') + '/chromium/src/third_party/protobuf.git' + '@' + 'ed9284c473211491ae6de41d60ac0329a79270d8',
|
||||
'third_party/re2/src':
|
||||
Var('chromium_url') + '/external/github.com/google/re2.git' + '@' + '33eba105f662c99c8f7d6a264c84ed350bd1dc39',
|
||||
'third_party/requests': {
|
||||
'url': Var('chromium_url') + '/external/github.com/kennethreitz/requests.git' + '@' + 'c7e0fc087ceeadb8b4c84a0953a422c474093d6d',
|
||||
'condition': 'checkout_android',
|
||||
},
|
||||
'third_party/siso': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'infra/build/siso/${{platform}}',
|
||||
'version': Var('siso_version'),
|
||||
}
|
||||
],
|
||||
'dep_type': 'cipd',
|
||||
'condition': 'not build_with_chromium and host_cpu != "s390" and host_cpu != "ppc"',
|
||||
},
|
||||
'third_party/zlib':
|
||||
Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '887bb57a1b1d38e348bd39ac7c2e6b4b6d18b9f7',
|
||||
'tools/clang':
|
||||
Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '686f88cb9f0de02f04f2df1769bb7668b45c9f41',
|
||||
'tools/luci-go': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'infra/tools/luci/isolate/${{platform}}',
|
||||
'version': Var('luci_go'),
|
||||
},
|
||||
{
|
||||
'package': 'infra/tools/luci/swarming/${{platform}}',
|
||||
'version': Var('luci_go'),
|
||||
},
|
||||
],
|
||||
'condition': 'host_cpu != "s390" and host_os != "aix"',
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
'tools/protoc_wrapper':
|
||||
Var('chromium_url') + '/chromium/src/tools/protoc_wrapper.git' + '@' + 'dbcbea90c20ae1ece442d8ef64e61c7b10e2b013',
|
||||
'third_party/abseil-cpp': {
|
||||
'url': Var('chromium_url') + '/chromium/src/third_party/abseil-cpp.git' + '@' + 'bfe59c2726fda7494a800f7d0ee461f0564653b3',
|
||||
'condition': 'not build_with_chromium',
|
||||
}
|
||||
}
|
||||
|
||||
include_rules = [
|
||||
# Everybody can use some things.
|
||||
'+include',
|
||||
'+unicode',
|
||||
'+third_party/fdlibm',
|
||||
'+third_party/ittapi/include',
|
||||
'+third_party/fp16/src/include',
|
||||
'+third_party/v8/codegen',
|
||||
'+third_party/fuzztest',
|
||||
# Abseil features are allow-listed. Please use your best judgement when adding
|
||||
# to this set -- if in doubt, email v8-dev@. For general guidance, refer to
|
||||
# the Chromium guidelines (though note that some requirements in V8 may be
|
||||
# different to Chromium's):
|
||||
# https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++11.md
|
||||
'+absl/container/flat_hash_map.h',
|
||||
'+absl/container/flat_hash_set.h',
|
||||
'+absl/container/btree_map.h',
|
||||
'+absl/types/optional.h',
|
||||
'+absl/types/variant.h',
|
||||
'+absl/status',
|
||||
# Some abseil features are explicitly banned.
|
||||
'-absl/types/any.h', # Requires RTTI.
|
||||
'-absl/types/flags', # Requires RTTI.
|
||||
]
|
||||
|
||||
# checkdeps.py shouldn't check for includes in these directories:
|
||||
skip_child_includes = [
|
||||
'build',
|
||||
'third_party',
|
||||
]
|
||||
|
||||
hooks = [
|
||||
{
|
||||
# Ensure that the DEPS'd "depot_tools" has its self-update capability
|
||||
# disabled.
|
||||
'name': 'disable_depot_tools_selfupdate',
|
||||
'pattern': '.',
|
||||
'action': [
|
||||
'python3',
|
||||
'third_party/depot_tools/update_depot_tools_toggle.py',
|
||||
'--disable',
|
||||
],
|
||||
},
|
||||
{
|
||||
# This clobbers when necessary (based on get_landmines.py). It must be the
|
||||
# first hook so that other things that get/generate into the output
|
||||
# directory will not subsequently be clobbered.
|
||||
'name': 'landmines',
|
||||
'pattern': '.',
|
||||
'action': [
|
||||
'python3',
|
||||
'build/landmines.py',
|
||||
'--landmine-scripts',
|
||||
'tools/get_landmines.py',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'bazel',
|
||||
'pattern': '.',
|
||||
'condition': 'download_prebuilt_bazel',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--bucket', 'chromium-v8-prebuilt-bazel/linux',
|
||||
'--no_resume',
|
||||
'-s', 'tools/bazel/bazel.sha1',
|
||||
'--platform=linux*',
|
||||
],
|
||||
},
|
||||
# Pull dsymutil binaries using checked-in hashes.
|
||||
{
|
||||
'name': 'dsymutil_mac_arm64',
|
||||
'pattern': '.',
|
||||
'condition': 'host_os == "mac" and host_cpu == "arm64"',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--no_resume',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-browser-clang',
|
||||
'-s', 'tools/clang/dsymutil/bin/dsymutil.arm64.sha1',
|
||||
'-o', 'tools/clang/dsymutil/bin/dsymutil',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'dsymutil_mac_x64',
|
||||
'pattern': '.',
|
||||
'condition': 'host_os == "mac" and host_cpu == "x64"',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--no_resume',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-browser-clang',
|
||||
'-s', 'tools/clang/dsymutil/bin/dsymutil.x64.sha1',
|
||||
'-o', 'tools/clang/dsymutil/bin/dsymutil',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'gcmole',
|
||||
'pattern': '.',
|
||||
'condition': 'download_gcmole',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--bucket', 'chrome-v8-gcmole',
|
||||
'-u', '--no_resume',
|
||||
'-s', 'tools/gcmole/gcmole-tools.tar.gz.sha1',
|
||||
'--platform=linux*',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'jsfunfuzz',
|
||||
'pattern': '.',
|
||||
'condition': 'download_jsfunfuzz',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--bucket', 'chrome-v8-jsfunfuzz',
|
||||
'-u', '--no_resume',
|
||||
'-s', 'tools/jsfunfuzz/jsfunfuzz.tar.gz.sha1',
|
||||
'--platform=linux*',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'wasm_spec_tests',
|
||||
'pattern': '.',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--no_resume',
|
||||
'--no_auth',
|
||||
'-u',
|
||||
'--bucket', 'v8-wasm-spec-tests',
|
||||
'-s', 'test/wasm-spec-tests/tests.tar.gz.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'wasm_js',
|
||||
'pattern': '.',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--no_resume',
|
||||
'--no_auth',
|
||||
'-u',
|
||||
'--bucket', 'v8-wasm-spec-tests',
|
||||
'-s', 'test/wasm-js/tests.tar.gz.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Case-insensitivity for the Win SDK. Must run before win_toolchain below.
|
||||
'name': 'ciopfs_linux',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_win and host_os == "linux"',
|
||||
'action': [ 'python3',
|
||||
'third_party/depot_tools/download_from_google_storage.py',
|
||||
'--no_resume',
|
||||
'--no_auth',
|
||||
'--bucket', 'chromium-browser-clang/ciopfs',
|
||||
'-s', 'build/ciopfs.sha1',
|
||||
]
|
||||
},
|
||||
{
|
||||
# Update the Windows toolchain if necessary.
|
||||
'name': 'win_toolchain',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_win',
|
||||
'action': ['python3', 'build/vs_toolchain.py', 'update', '--force'],
|
||||
},
|
||||
{
|
||||
# Update the Mac toolchain if necessary.
|
||||
'name': 'mac_toolchain',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_mac',
|
||||
'action': ['python3', 'build/mac_toolchain.py'],
|
||||
},
|
||||
{
|
||||
# Note: On Win, this should run after win_toolchain, as it may use it.
|
||||
'name': 'clang',
|
||||
'pattern': '.',
|
||||
# clang not supported on aix
|
||||
'condition': 'host_os != "aix"',
|
||||
'action': ['python3', 'tools/clang/scripts/update.py'],
|
||||
},
|
||||
{
|
||||
# This is supposed to support the same set of platforms as 'clang' above.
|
||||
'name': 'clang_coverage',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_clang_coverage_tools',
|
||||
'action': ['python3', 'tools/clang/scripts/update.py',
|
||||
'--package=coverage_tools'],
|
||||
},
|
||||
{
|
||||
'name': 'clang_tidy',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_clang_tidy',
|
||||
'action': ['python3', 'tools/clang/scripts/update.py',
|
||||
'--package=clang-tidy'],
|
||||
},
|
||||
{
|
||||
# Update LASTCHANGE.
|
||||
'name': 'lastchange',
|
||||
'pattern': '.',
|
||||
'action': ['python3', 'build/util/lastchange.py',
|
||||
'-o', 'build/util/LASTCHANGE'],
|
||||
},
|
||||
{
|
||||
'name': 'Download Fuchsia SDK from GCS',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_fuchsia',
|
||||
'action': [
|
||||
'python3',
|
||||
'build/fuchsia/update_sdk.py',
|
||||
'--cipd-prefix={fuchsia_sdk_cipd_prefix}',
|
||||
'--version={fuchsia_version}',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'Download Fuchsia system images',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_fuchsia and checkout_fuchsia_product_bundles',
|
||||
'action': [
|
||||
'python3',
|
||||
'build/fuchsia/update_product_bundles.py',
|
||||
'{checkout_fuchsia_boot_images}',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Mac does not have llvm-objdump, download it for cross builds in Fuchsia.
|
||||
'name': 'llvm-objdump',
|
||||
'pattern': '.',
|
||||
'condition': 'host_os == "mac" and checkout_fuchsia',
|
||||
'action': ['python3', 'tools/clang/scripts/update.py',
|
||||
'--package=objdump'],
|
||||
},
|
||||
{
|
||||
'name': 'vpython3_common',
|
||||
'pattern': '.',
|
||||
'action': [ 'vpython3',
|
||||
'-vpython-spec', '.vpython3',
|
||||
'-vpython-tool', 'install',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'check_v8_header_includes',
|
||||
'pattern': '.',
|
||||
'condition': 'check_v8_header_includes',
|
||||
'action': [
|
||||
'python3',
|
||||
'tools/generate-header-include-checks.py',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'checkout_v8_builtins_pgo_profiles',
|
||||
'pattern': '.',
|
||||
'condition': 'checkout_v8_builtins_pgo_profiles',
|
||||
'action': [
|
||||
'python3',
|
||||
'tools/builtins-pgo/download_profiles.py',
|
||||
'download',
|
||||
'--quiet',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Clean up build dirs for crbug.com/1337238.
|
||||
# After a libc++ roll and revert, .ninja_deps would get into a state
|
||||
# that breaks Ninja on Windows.
|
||||
# TODO(crbug.com/1337238): Remove in a month or so.
|
||||
'name': 'del_ninja_deps_cache',
|
||||
'pattern': '.',
|
||||
'condition': 'host_os == "win"',
|
||||
'action': ['python3', 'build/del_ninja_deps_cache.py'],
|
||||
},
|
||||
# Configure remote exec cfg files
|
||||
{
|
||||
'name': 'download_and_configure_reclient_cfgs',
|
||||
'pattern': '.',
|
||||
'condition': 'download_remoteexec_cfg and not build_with_chromium',
|
||||
'action': ['python3',
|
||||
'buildtools/reclient_cfgs/configure_reclient_cfgs.py',
|
||||
'--rbe_instance',
|
||||
Var('rbe_instance'),
|
||||
'--reproxy_cfg_template',
|
||||
'reproxy.cfg.template',
|
||||
'--rewrapper_cfg_project',
|
||||
Var('rewrapper_cfg_project'),
|
||||
'--quiet',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'configure_reclient_cfgs',
|
||||
'pattern': '.',
|
||||
'condition': 'not download_remoteexec_cfg and not build_with_chromium',
|
||||
'action': ['python3',
|
||||
'buildtools/reclient_cfgs/configure_reclient_cfgs.py',
|
||||
'--rbe_instance',
|
||||
Var('rbe_instance'),
|
||||
'--reproxy_cfg_template',
|
||||
'reproxy.cfg.template',
|
||||
'--rewrapper_cfg_project',
|
||||
Var('rewrapper_cfg_project'),
|
||||
'--skip_remoteexec_cfg_fetch',
|
||||
],
|
||||
},
|
||||
# Configure Siso for developer builds.
|
||||
{
|
||||
'name': 'configure_siso',
|
||||
'pattern': '.',
|
||||
'condition': 'not build_with_chromium',
|
||||
'action': ['python3',
|
||||
'build/config/siso/configure_siso.py',
|
||||
'--rbe_instance',
|
||||
Var('rbe_instance'),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
recursedeps = [
|
||||
'build',
|
||||
'buildtools',
|
||||
'third_party/instrumented_libs',
|
||||
]
|
||||
@@ -1,12 +0,0 @@
|
||||
# Metadata information for this directory.
|
||||
#
|
||||
# For more information on DIR_METADATA files, see:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
|
||||
#
|
||||
# For the schema of this file, see Metadata message:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
|
||||
|
||||
monorail {
|
||||
component: "Blink>JavaScript"
|
||||
}
|
||||
team_email: "v8-dev@googlegroups.com"
|
||||
File renamed without changes.
@@ -1,13 +0,0 @@
|
||||
# Eng reviewers. This is to define an escalation path for potential
|
||||
# disagreement among owners. Please consult before adding top-level
|
||||
# directories.
|
||||
|
||||
adamk@chromium.org
|
||||
danno@chromium.org
|
||||
gdeepti@chromium.org
|
||||
hpayer@chromium.org
|
||||
leszeks@chromium.org
|
||||
mlippautz@chromium.org
|
||||
syg@chromium.org
|
||||
verwaest@chromium.org
|
||||
vahl@chromium.org
|
||||
@@ -1,4 +0,0 @@
|
||||
alexschulze@chromium.org
|
||||
almuthanna@chromium.org
|
||||
liviurau@chromium.org
|
||||
machenbach@chromium.org
|
||||
@@ -1,4 +0,0 @@
|
||||
cira@chromium.org
|
||||
mnita@google.com
|
||||
jshin@chromium.org
|
||||
ftang@chromium.org
|
||||
@@ -1,3 +0,0 @@
|
||||
liuyu@loongson.cn
|
||||
yuyin-hf@loongson.cn
|
||||
zhaojiazhong-hf@loongson.cn
|
||||
@@ -1,3 +0,0 @@
|
||||
xwafish@gmail.com
|
||||
zhaojiazhong-hf@loongson.cn
|
||||
liuyu@loongson.cn
|
||||
@@ -1,28 +0,0 @@
|
||||
# Eng reviewer. Please reach out before adding new top-level directories.
|
||||
# Disagreement among owners should be escalated to eng reviewers.
|
||||
file:ENG_REVIEW_OWNERS
|
||||
|
||||
per-file .*=file:INFRA_OWNERS
|
||||
per-file .bazelrc=file:COMMON_OWNERS
|
||||
per-file .mailmap=file:COMMON_OWNERS
|
||||
per-file .ycm_extra_conf.py=file:COMMON_OWNERS
|
||||
per-file codereview.settings=file:INFRA_OWNERS
|
||||
per-file AUTHORS=file:COMMON_OWNERS
|
||||
per-file BUILD.bazel=file:COMMON_OWNERS
|
||||
per-file BUILD.gn=file:COMMON_OWNERS
|
||||
per-file DEPS=file:COMMON_OWNERS
|
||||
per-file INFRA_OWNERS=file:INFRA_OWNERS
|
||||
per-file PRESUBMIT.py=file:INFRA_OWNERS
|
||||
per-file WATCHLISTS=file:COMMON_OWNERS
|
||||
per-file WORKSPACE=file:COMMON_OWNERS
|
||||
|
||||
# Needed by the auto_tag builder
|
||||
per-file WATCHLISTS=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com
|
||||
per-file DEPS=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com
|
||||
|
||||
per-file ...-loong64*=file:LOONG_OWNERS
|
||||
per-file ...-mips*=file:MIPS_OWNERS
|
||||
per-file ...-mips64*=file:MIPS_OWNERS
|
||||
per-file ...-ppc*=file:PPC_OWNERS
|
||||
per-file ...-riscv*=file:RISCV_OWNERS
|
||||
per-file ...-s390*=file:S390_OWNERS
|
||||
@@ -1,4 +0,0 @@
|
||||
junyan@redhat.com
|
||||
joransiu@ca.ibm.com
|
||||
midawson@redhat.com
|
||||
mfarazma@redhat.com
|
||||
-578
@@ -1,578 +0,0 @@
|
||||
# Copyright 2012 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Top-level presubmit script for V8.
|
||||
|
||||
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
|
||||
for more details about the presubmit API built into gcl.
|
||||
"""
|
||||
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
# This line is 'magic' in that git-cl looks for it to decide whether to
|
||||
# use Python3 instead of Python2 when running the code in this file.
|
||||
USE_PYTHON3 = True
|
||||
|
||||
_EXCLUDED_PATHS = (
|
||||
r"^test[\\\/].*",
|
||||
r"^testing[\\\/].*",
|
||||
r"^third_party[\\\/].*",
|
||||
r"^tools[\\\/].*",
|
||||
)
|
||||
|
||||
_LICENSE_FILE = (
|
||||
r"LICENSE"
|
||||
)
|
||||
|
||||
# Regular expression that matches code which should not be run through cpplint.
|
||||
_NO_LINT_PATHS = (
|
||||
r'src[\\\/]base[\\\/]export-template\.h',
|
||||
)
|
||||
|
||||
|
||||
# Regular expression that matches code only used for test binaries
|
||||
# (best effort).
|
||||
_TEST_CODE_EXCLUDED_PATHS = (
|
||||
r'.+-unittest\.cc',
|
||||
# Has a method VisitForTest().
|
||||
r'src[\\\/]compiler[\\\/]ast-graph-builder\.cc',
|
||||
# Test extension.
|
||||
r'src[\\\/]extensions[\\\/]gc-extension\.cc',
|
||||
# Runtime functions used for testing.
|
||||
r'src[\\\/]runtime[\\\/]runtime-test\.cc',
|
||||
# Testing helpers.
|
||||
r'src[\\\/]heap[\\\/]cppgc[\\\/]testing\.cc',
|
||||
)
|
||||
|
||||
|
||||
_TEST_ONLY_WARNING = (
|
||||
'You might be calling functions intended only for testing from\n'
|
||||
'production code. It is OK to ignore this warning if you know what\n'
|
||||
'you are doing, as the heuristics used to detect the situation are\n'
|
||||
'not perfect. The commit queue will not block on this warning.')
|
||||
|
||||
|
||||
def _V8PresubmitChecks(input_api, output_api):
|
||||
"""Runs the V8 presubmit checks."""
|
||||
import sys
|
||||
sys.path.append(input_api.os_path.join(
|
||||
input_api.PresubmitLocalPath(), 'tools'))
|
||||
from v8_presubmit import CppLintProcessor
|
||||
from v8_presubmit import GCMoleProcessor
|
||||
from v8_presubmit import JSLintProcessor
|
||||
from v8_presubmit import TorqueLintProcessor
|
||||
from v8_presubmit import SourceProcessor
|
||||
from v8_presubmit import StatusFilesProcessor
|
||||
|
||||
def FilterFile(affected_file):
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=None,
|
||||
files_to_skip=_NO_LINT_PATHS)
|
||||
|
||||
def FilterTorqueFile(affected_file):
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(r'.+\.tq'))
|
||||
|
||||
def FilterJSFile(affected_file):
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(r'.+\.m?js'))
|
||||
|
||||
results = []
|
||||
if not CppLintProcessor().RunOnFiles(
|
||||
input_api.AffectedFiles(file_filter=FilterFile, include_deletes=False)):
|
||||
results.append(output_api.PresubmitError("C++ lint check failed"))
|
||||
if not TorqueLintProcessor().RunOnFiles(
|
||||
input_api.AffectedFiles(file_filter=FilterTorqueFile,
|
||||
include_deletes=False)):
|
||||
results.append(output_api.PresubmitError("Torque format check failed"))
|
||||
if not JSLintProcessor().RunOnFiles(
|
||||
input_api.AffectedFiles(file_filter=FilterJSFile,
|
||||
include_deletes=False)):
|
||||
results.append(output_api.PresubmitError("JS format check failed"))
|
||||
if not SourceProcessor().RunOnFiles(
|
||||
input_api.AffectedFiles(include_deletes=False)):
|
||||
results.append(output_api.PresubmitError(
|
||||
"Copyright header, trailing whitespaces and two empty lines " \
|
||||
"between declarations check failed"))
|
||||
if not StatusFilesProcessor().RunOnFiles(
|
||||
input_api.AffectedFiles(include_deletes=True)):
|
||||
results.append(output_api.PresubmitError("Status file check failed"))
|
||||
if not GCMoleProcessor().RunOnFiles(
|
||||
input_api.AffectedFiles(include_deletes=False)):
|
||||
results.append(output_api.PresubmitError("GCMole pattern check failed"))
|
||||
results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
|
||||
input_api, output_api, bot_allowlist=[
|
||||
'v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com',
|
||||
'v8-ci-test262-import-export@chops-service-accounts.iam.gserviceaccount.com',
|
||||
]))
|
||||
return results
|
||||
|
||||
|
||||
def _CheckPythonLiterals(input_api, output_api):
|
||||
"""Checks that all .pyl files are valid python literals."""
|
||||
affected_files = [
|
||||
af for af in input_api.AffectedFiles()
|
||||
if af.LocalPath().endswith('.pyl')
|
||||
]
|
||||
|
||||
results = []
|
||||
for af in affected_files:
|
||||
try:
|
||||
ast.literal_eval('\n'.join(af.NewContents()))
|
||||
except SyntaxError as e:
|
||||
results.append(output_api.PresubmitError(
|
||||
f'Failed to parse python literal {af.LocalPath()}:\n' +
|
||||
traceback.format_exc(0)
|
||||
))
|
||||
|
||||
return results
|
||||
|
||||
|
||||
|
||||
def _CheckUnwantedDependencies(input_api, output_api):
|
||||
"""Runs checkdeps on #include statements added in this
|
||||
change. Breaking - rules is an error, breaking ! rules is a
|
||||
warning.
|
||||
"""
|
||||
# We need to wait until we have an input_api object and use this
|
||||
# roundabout construct to import checkdeps because this file is
|
||||
# eval-ed and thus doesn't have __file__.
|
||||
original_sys_path = sys.path
|
||||
try:
|
||||
sys.path = sys.path + [input_api.os_path.join(
|
||||
input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
|
||||
import checkdeps
|
||||
from cpp_checker import CppChecker
|
||||
from rules import Rule
|
||||
finally:
|
||||
# Restore sys.path to what it was before.
|
||||
sys.path = original_sys_path
|
||||
|
||||
def _FilesImpactedByDepsChange(files):
|
||||
all_files = [f.AbsoluteLocalPath() for f in files]
|
||||
deps_files = [p for p in all_files if IsDepsFile(p)]
|
||||
impacted_files = union([_CollectImpactedFiles(path) for path in deps_files])
|
||||
impacted_file_objs = [ImpactedFile(path) for path in impacted_files]
|
||||
return impacted_file_objs
|
||||
|
||||
def IsDepsFile(p):
|
||||
return os.path.isfile(p) and os.path.basename(p) == 'DEPS'
|
||||
|
||||
def union(list_of_lists):
|
||||
"""Ensure no duplicates"""
|
||||
return set(sum(list_of_lists, []))
|
||||
|
||||
def _CollectImpactedFiles(deps_file):
|
||||
# TODO(liviurau): Do not walk paths twice. Then we have no duplicates.
|
||||
# Higher level DEPS changes may dominate lower level DEPS changes.
|
||||
# TODO(liviurau): Check if DEPS changed in the right way.
|
||||
# 'include_rules' impact c++ files but 'vars' or 'deps' do not.
|
||||
# Maybe we just eval both old and new DEPS content and check
|
||||
# if the list are the same.
|
||||
result = []
|
||||
parent_dir = os.path.dirname(deps_file)
|
||||
for relative_f in input_api.change.AllFiles(parent_dir):
|
||||
abs_f = os.path.join(parent_dir, relative_f)
|
||||
if CppChecker.IsCppFile(abs_f):
|
||||
result.append(abs_f)
|
||||
return result
|
||||
|
||||
class ImpactedFile(object):
|
||||
"""Duck type version of AffectedFile needed to check files under directories
|
||||
where a DEPS file changed. Extend the interface along the line of
|
||||
AffectedFile if you need it for other checks."""
|
||||
|
||||
def __init__(self, path):
|
||||
self._path = path
|
||||
|
||||
def LocalPath(self):
|
||||
path = self._path.replace(os.sep, '/')
|
||||
return os.path.normpath(path)
|
||||
|
||||
def ChangedContents(self):
|
||||
with open(self._path) as f:
|
||||
# TODO(liviurau): read only '#include' lines
|
||||
lines = f.readlines()
|
||||
return enumerate(lines, start=1)
|
||||
|
||||
def _FilterDuplicates(impacted_files, affected_files):
|
||||
""""We include all impacted files but exclude affected files that are also
|
||||
impacted. Files impacted by DEPS changes take precedence before files
|
||||
affected by direct changes."""
|
||||
result = impacted_files[:]
|
||||
only_paths = set([imf.LocalPath() for imf in impacted_files])
|
||||
for af in affected_files:
|
||||
if not af.LocalPath() in only_paths:
|
||||
result.append(af)
|
||||
return result
|
||||
|
||||
added_includes = []
|
||||
affected_files = input_api.AffectedFiles()
|
||||
impacted_by_deps = _FilesImpactedByDepsChange(affected_files)
|
||||
for f in _FilterDuplicates(impacted_by_deps, affected_files):
|
||||
if not CppChecker.IsCppFile(f.LocalPath()):
|
||||
continue
|
||||
|
||||
changed_lines = [line for line_num, line in f.ChangedContents()]
|
||||
added_includes.append([f.LocalPath(), changed_lines])
|
||||
|
||||
deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
|
||||
|
||||
error_descriptions = []
|
||||
warning_descriptions = []
|
||||
for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
|
||||
added_includes):
|
||||
description_with_path = '{}\n {}'.format(path, rule_description)
|
||||
if rule_type == Rule.DISALLOW:
|
||||
error_descriptions.append(description_with_path)
|
||||
else:
|
||||
warning_descriptions.append(description_with_path)
|
||||
|
||||
results = []
|
||||
if error_descriptions:
|
||||
results.append(output_api.PresubmitError(
|
||||
'You added one or more #includes that violate checkdeps rules.',
|
||||
error_descriptions))
|
||||
if warning_descriptions:
|
||||
results.append(output_api.PresubmitPromptOrNotify(
|
||||
'You added one or more #includes of files that are temporarily\n'
|
||||
'allowed but being removed. Can you avoid introducing the\n'
|
||||
'#include? See relevant DEPS file(s) for details and contacts.',
|
||||
warning_descriptions))
|
||||
return results
|
||||
|
||||
|
||||
def _CheckHeadersHaveIncludeGuards(input_api, output_api):
|
||||
"""Ensures that all header files have include guards."""
|
||||
file_inclusion_pattern = r'src/.+\.h'
|
||||
|
||||
def FilterFile(affected_file):
|
||||
files_to_skip = _EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(file_inclusion_pattern, ),
|
||||
files_to_skip=files_to_skip)
|
||||
|
||||
leading_src_pattern = input_api.re.compile(r'^src[\\\/]')
|
||||
dash_dot_slash_pattern = input_api.re.compile(r'[-.\\\/]')
|
||||
|
||||
def PathToGuardMacro(path):
|
||||
"""Guards should be of the form V8_PATH_TO_FILE_WITHOUT_SRC_H_."""
|
||||
x = input_api.re.sub(leading_src_pattern, 'v8_', path)
|
||||
x = input_api.re.sub(dash_dot_slash_pattern, '_', x)
|
||||
x = x.upper() + "_"
|
||||
return x
|
||||
|
||||
problems = []
|
||||
for f in input_api.AffectedSourceFiles(FilterFile):
|
||||
local_path = f.LocalPath()
|
||||
guard_macro = PathToGuardMacro(local_path)
|
||||
guard_patterns = [
|
||||
input_api.re.compile(r'^#ifndef ' + guard_macro + '$'),
|
||||
input_api.re.compile(r'^#define ' + guard_macro + '$'),
|
||||
input_api.re.compile(r'^#endif // ' + guard_macro + '$')]
|
||||
skip_check_pattern = input_api.re.compile(
|
||||
r'^// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD')
|
||||
found_patterns = [ False, False, False ]
|
||||
file_omitted = False
|
||||
|
||||
for line in f.NewContents():
|
||||
for i in range(len(guard_patterns)):
|
||||
if guard_patterns[i].match(line):
|
||||
found_patterns[i] = True
|
||||
if skip_check_pattern.match(line):
|
||||
file_omitted = True
|
||||
break
|
||||
|
||||
if not file_omitted and not all(found_patterns):
|
||||
problems.append('{}: Missing include guard \'{}\''.format(
|
||||
local_path, guard_macro))
|
||||
|
||||
if problems:
|
||||
return [output_api.PresubmitError(
|
||||
'You added one or more header files without an appropriate\n'
|
||||
'include guard. Add the include guard {#ifndef,#define,#endif}\n'
|
||||
'triplet or omit the check entirely through the magic comment:\n'
|
||||
'"// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD".', problems)]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def _CheckNoInlineHeaderIncludesInNormalHeaders(input_api, output_api):
|
||||
"""Attempts to prevent inclusion of inline headers into normal header
|
||||
files. This tries to establish a layering where inline headers can be
|
||||
included by other inline headers or compilation units only."""
|
||||
file_inclusion_pattern = r'(?!.+-inl\.h).+\.h'
|
||||
include_directive_pattern = input_api.re.compile(r'#include ".+-inl.h"')
|
||||
include_error = (
|
||||
'You are including an inline header (e.g. foo-inl.h) within a normal\n'
|
||||
'header (e.g. bar.h) file. This violates layering of dependencies.')
|
||||
|
||||
def FilterFile(affected_file):
|
||||
files_to_skip = _EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(file_inclusion_pattern, ),
|
||||
files_to_skip=files_to_skip)
|
||||
|
||||
problems = []
|
||||
for f in input_api.AffectedSourceFiles(FilterFile):
|
||||
local_path = f.LocalPath()
|
||||
for line_number, line in f.ChangedContents():
|
||||
if (include_directive_pattern.search(line)):
|
||||
problems.append('{}:{}\n {}'.format(local_path, line_number,
|
||||
line.strip()))
|
||||
|
||||
if problems:
|
||||
return [output_api.PresubmitError(include_error, problems)]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
|
||||
"""Attempts to prevent use of functions intended only for testing in
|
||||
non-testing code. For now this is just a best-effort implementation
|
||||
that ignores header files and may have some false positives. A
|
||||
better implementation would probably need a proper C++ parser.
|
||||
"""
|
||||
# We only scan .cc files, as the declaration of for-testing functions in
|
||||
# header files are hard to distinguish from calls to such functions without a
|
||||
# proper C++ parser.
|
||||
file_inclusion_pattern = r'.+\.cc'
|
||||
|
||||
base_function_pattern = r'[ :]test::[^\s]+|ForTest(ing)?|for_test(ing)?'
|
||||
inclusion_pattern = input_api.re.compile(
|
||||
r'({})\s*\('.format(base_function_pattern))
|
||||
comment_pattern = input_api.re.compile(
|
||||
r'//.*({})'.format(base_function_pattern))
|
||||
exclusion_pattern = input_api.re.compile(
|
||||
r'::[A-Za-z0-9_]+({})|({})[^;]+'.format(base_function_pattern,
|
||||
base_function_pattern) + '\{')
|
||||
|
||||
def FilterFile(affected_file):
|
||||
files_to_skip = (_EXCLUDED_PATHS +
|
||||
_TEST_CODE_EXCLUDED_PATHS +
|
||||
input_api.DEFAULT_FILES_TO_SKIP)
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(file_inclusion_pattern, ),
|
||||
files_to_skip=files_to_skip)
|
||||
|
||||
problems = []
|
||||
for f in input_api.AffectedSourceFiles(FilterFile):
|
||||
local_path = f.LocalPath()
|
||||
for line_number, line in f.ChangedContents():
|
||||
if (inclusion_pattern.search(line) and
|
||||
not comment_pattern.search(line) and
|
||||
not exclusion_pattern.search(line)):
|
||||
problems.append('{}:{}\n {}'.format(local_path, line_number,
|
||||
line.strip()))
|
||||
|
||||
if problems:
|
||||
return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def _CheckGenderNeutralInLicenses(input_api, output_api):
|
||||
# License files are taken as is, even if they include gendered pronouns.
|
||||
def LicenseFilter(path):
|
||||
input_api.FilterSourceFile(path, files_to_skip=_LICENSE_FILE)
|
||||
|
||||
return input_api.canned_checks.CheckGenderNeutral(
|
||||
input_api, output_api, source_file_filter=LicenseFilter)
|
||||
|
||||
|
||||
def _RunTestsWithVPythonSpec(input_api, output_api):
|
||||
return input_api.RunTests(
|
||||
input_api.canned_checks.CheckVPythonSpec(input_api, output_api))
|
||||
|
||||
|
||||
def _CommonChecks(input_api, output_api):
|
||||
"""Checks common to both upload and commit."""
|
||||
# TODO(machenbach): Replace some of those checks, e.g. owners and copyright,
|
||||
# with the canned PanProjectChecks. Need to make sure that the checks all
|
||||
# pass on all existing files.
|
||||
checks = [
|
||||
input_api.canned_checks.CheckOwnersFormat,
|
||||
input_api.canned_checks.CheckOwners,
|
||||
_CheckCommitMessageBugEntry,
|
||||
input_api.canned_checks.CheckPatchFormatted,
|
||||
_CheckGenderNeutralInLicenses,
|
||||
_V8PresubmitChecks,
|
||||
_CheckUnwantedDependencies,
|
||||
_CheckNoProductionCodeUsingTestOnlyFunctions,
|
||||
_CheckHeadersHaveIncludeGuards,
|
||||
_CheckNoInlineHeaderIncludesInNormalHeaders,
|
||||
_CheckJSONFiles,
|
||||
_CheckNoexceptAnnotations,
|
||||
_RunTestsWithVPythonSpec,
|
||||
_CheckPythonLiterals,
|
||||
]
|
||||
|
||||
return sum([check(input_api, output_api) for check in checks], [])
|
||||
|
||||
|
||||
def _SkipTreeCheck(input_api, output_api):
|
||||
"""Check the env var whether we want to skip tree check.
|
||||
Only skip if include/v8-version.h has been updated."""
|
||||
src_version = 'include/v8-version.h'
|
||||
if not input_api.AffectedSourceFiles(
|
||||
lambda file: file.LocalPath() == src_version):
|
||||
return False
|
||||
return input_api.environ.get('PRESUBMIT_TREE_CHECK') == 'skip'
|
||||
|
||||
|
||||
def _CheckCommitMessageBugEntry(input_api, output_api):
|
||||
"""Check that bug entries are well-formed in commit message."""
|
||||
bogus_bug_msg = (
|
||||
'Bogus BUG entry: {}. Please specify prefix:number for v8 or chromium '
|
||||
'(e.g. chromium:12345) or b/number for buganizer.')
|
||||
results = []
|
||||
for bug in (input_api.change.BUG or '').split(','):
|
||||
bug = bug.strip()
|
||||
if 'none'.startswith(bug.lower()):
|
||||
continue
|
||||
if ':' not in bug and not bug.startswith('b/'):
|
||||
try:
|
||||
if int(bug) < 10000000:
|
||||
if int(bug) > 200000:
|
||||
prefix_guess = 'chromium'
|
||||
else:
|
||||
prefix_guess = 'v8'
|
||||
results.append(
|
||||
'BUG entry requires issue tracker prefix, e.g. {}:{}'.format(
|
||||
prefix_guess, bug))
|
||||
except ValueError:
|
||||
results.append(bogus_bug_msg.format(bug))
|
||||
elif not re.match(r'\w+[:\/]\d+', bug):
|
||||
results.append(bogus_bug_msg.format(bug))
|
||||
return [output_api.PresubmitError(r) for r in results]
|
||||
|
||||
|
||||
def _CheckJSONFiles(input_api, output_api):
|
||||
def FilterFile(affected_file):
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(r'.+\.json',))
|
||||
|
||||
results = []
|
||||
for f in input_api.AffectedFiles(
|
||||
file_filter=FilterFile, include_deletes=False):
|
||||
with open(f.LocalPath()) as j:
|
||||
try:
|
||||
json.load(j)
|
||||
except Exception as e:
|
||||
results.append('JSON validation failed for {}. Error:\n{}'.format(
|
||||
f.LocalPath(), e))
|
||||
|
||||
return [output_api.PresubmitError(r) for r in results]
|
||||
|
||||
|
||||
def _CheckNoexceptAnnotations(input_api, output_api):
|
||||
"""
|
||||
Checks that all user-defined constructors and assignment operators are marked
|
||||
V8_NOEXCEPT.
|
||||
|
||||
This is required for standard containers to pick the right constructors. Our
|
||||
macros (like MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS) add this automatically.
|
||||
Omitting it at some places can result in weird compiler errors if this is
|
||||
mixed with other classes that have the annotation.
|
||||
|
||||
TODO(clemensb): This check should eventually be enabled for all files via
|
||||
tools/presubmit.py (https://crbug.com/v8/8616).
|
||||
"""
|
||||
|
||||
def FilterFile(affected_file):
|
||||
files_to_skip = _EXCLUDED_PATHS + (
|
||||
# Skip api.cc since we cannot easily add the 'noexcept' annotation to
|
||||
# public methods.
|
||||
r'src[\\\/]api[\\\/]api\.cc',
|
||||
# Skip src/bigint/ because it's meant to be V8-independent.
|
||||
r'src[\\\/]bigint[\\\/].*',
|
||||
)
|
||||
return input_api.FilterSourceFile(
|
||||
affected_file,
|
||||
files_to_check=(r'src[\\\/].*\.cc', r'src[\\\/].*\.h',
|
||||
r'test[\\\/].*\.cc', r'test[\\\/].*\.h'),
|
||||
files_to_skip=files_to_skip)
|
||||
|
||||
# matches any class name.
|
||||
class_name = r'\b([A-Z][A-Za-z0-9_:]*)(?:::\1)?'
|
||||
# initial class name is potentially followed by this to declare an assignment
|
||||
# operator.
|
||||
potential_assignment = r'(?:&\s+(?:\1::)?operator=)?\s*'
|
||||
# matches an argument list that contains only a reference to a class named
|
||||
# like the first capture group, potentially const.
|
||||
single_class_ref_arg = r'\(\s*(?:const\s+)?\1(?:::\1)?&&?[^,;)]*\)'
|
||||
# matches anything but a sequence of whitespaces followed by either
|
||||
# V8_NOEXCEPT or "= delete".
|
||||
not_followed_by_noexcept = r'(?!\s+(?:V8_NOEXCEPT|=\s+delete)\b)'
|
||||
full_pattern = r'^.*?' + class_name + potential_assignment + \
|
||||
single_class_ref_arg + not_followed_by_noexcept + '.*?$'
|
||||
regexp = input_api.re.compile(full_pattern, re.MULTILINE)
|
||||
|
||||
errors = []
|
||||
for f in input_api.AffectedFiles(file_filter=FilterFile,
|
||||
include_deletes=False):
|
||||
with open(f.LocalPath()) as fh:
|
||||
for match in re.finditer(regexp, fh.read()):
|
||||
errors.append(f'in {f.LocalPath()}: {match.group().strip()}')
|
||||
|
||||
if errors:
|
||||
return [output_api.PresubmitPromptOrNotify(
|
||||
'Copy constructors, move constructors, copy assignment operators and '
|
||||
'move assignment operators should be marked V8_NOEXCEPT.\n'
|
||||
'Please report false positives on https://crbug.com/v8/8616.',
|
||||
errors)]
|
||||
return []
|
||||
|
||||
|
||||
def CheckChangeOnUpload(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CommonChecks(input_api, output_api))
|
||||
return results
|
||||
|
||||
|
||||
def CheckChangeOnCommit(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CommonChecks(input_api, output_api))
|
||||
results.extend(input_api.canned_checks.CheckChangeHasDescription(
|
||||
input_api, output_api))
|
||||
if not _SkipTreeCheck(input_api, output_api):
|
||||
results.extend(input_api.canned_checks.CheckTreeIsOpen(
|
||||
input_api, output_api,
|
||||
json_url='http://v8-status.appspot.com/current?format=json'))
|
||||
return results
|
||||
@@ -1,40 +1,22 @@
|
||||
V8 JavaScript Engine
|
||||
darude JavaScript Engine
|
||||
=============
|
||||
|
||||
darude is a minimal set of v8 headers hacked together to get sandstorm to build from source. The full package is available as [Haboob](https://github.com/NotAlexNoyle/Haboob).
|
||||
|
||||
V8 is Google's open source JavaScript engine.
|
||||
|
||||
V8 implements ECMAScript as specified in ECMA-262.
|
||||
|
||||
V8 is written in C++ and is used in Google Chrome, the open source
|
||||
browser from Google.
|
||||
|
||||
V8 can run standalone, or can be embedded into any C++ application.
|
||||
|
||||
V8 Project page: https://v8.dev/docs
|
||||
|
||||
|
||||
Getting the Code
|
||||
=============
|
||||
|
||||
Checkout [depot tools](http://www.chromium.org/developers/how-tos/install-depot-tools), and run
|
||||
To get the darude headers alone:
|
||||
git clone https://github.com/NotAlexNoyle/darude
|
||||
|
||||
fetch v8
|
||||
To get a buildable downstream of sandstorm:
|
||||
git clone https://github.com/NotAlexNoyle/Haboob
|
||||
|
||||
This will checkout V8 into the directory `v8` and fetch all of its dependencies.
|
||||
To stay up to date, run
|
||||
|
||||
git pull origin
|
||||
gclient sync
|
||||
|
||||
For fetching all branches, add the following into your remote
|
||||
configuration in `.git/config`:
|
||||
|
||||
fetch = +refs/branch-heads/*:refs/remotes/branch-heads/*
|
||||
fetch = +refs/tags/*:refs/tags/*
|
||||
|
||||
|
||||
Contributing
|
||||
=============
|
||||
|
||||
Please follow the instructions mentioned at
|
||||
[v8.dev/docs/contribute](https://v8.dev/docs/contribute).
|
||||
git submodule update --force --recursive --init --remote
|
||||
@@ -1,4 +0,0 @@
|
||||
brice.dobry@futurewei.com
|
||||
peng.w@rioslab.org
|
||||
qiuji@iscas.ac.cn
|
||||
yahan@iscas.ac.cn
|
||||
@@ -1,4 +0,0 @@
|
||||
junyan@redhat.com
|
||||
joransiu@ca.ibm.com
|
||||
midawson@redhat.com
|
||||
mfarazma@redhat.com
|
||||
-181
@@ -1,181 +0,0 @@
|
||||
# Copyright 2013 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Watchlist Rules
|
||||
# Refer: http://dev.chromium.org/developers/contributing-code/watchlists
|
||||
|
||||
# IMPORTANT: The regular expression filepath is tested against each path using
|
||||
# re.search, so it is not usually necessary to add .*.
|
||||
|
||||
{
|
||||
'WATCHLIST_DEFINITIONS': {
|
||||
'api': {
|
||||
'filepath': 'include/',
|
||||
},
|
||||
'snapshot': {
|
||||
'filepath': 'src/snapshot/',
|
||||
},
|
||||
'devtools': {
|
||||
'filepath': 'src/debug/' \
|
||||
'|src/inspector/' \
|
||||
'|src/profiler/' \
|
||||
'|src/libsampler/' \
|
||||
'|src/tracing/' \
|
||||
'|include/js_protocol.pdl' \
|
||||
'|include/v8-inspector*\.h',
|
||||
},
|
||||
'baseline': {
|
||||
'filepath': 'src/baseline/',
|
||||
},
|
||||
'feature_shipping_status': {
|
||||
'filepath': 'src/flags/flag-definitions.h',
|
||||
},
|
||||
'heap_changes': {
|
||||
'filepath': 'src/heap/',
|
||||
},
|
||||
'arm': {
|
||||
'filepath': '/arm/',
|
||||
},
|
||||
'merges': {
|
||||
'filepath': '.',
|
||||
},
|
||||
'wasm': {
|
||||
'filepath': 'src/wasm/' \
|
||||
'|src/compiler/wasm',
|
||||
},
|
||||
'value_serializer': {
|
||||
'filepath': 'src/value-serializer',
|
||||
},
|
||||
'maglev': {
|
||||
'filepath': 'src/maglev/',
|
||||
},
|
||||
'parser': {
|
||||
'filepath': 'src/ast/' \
|
||||
'|src/parsing/',
|
||||
},
|
||||
'tracing': {
|
||||
'filepath': 'src/tracing/',
|
||||
},
|
||||
'ieee754': {
|
||||
'filepath': 'src/base/ieee754\.(cc|h)' \
|
||||
'|src/base/overflowing-math.h' \
|
||||
'|LICENSE.fdlibm',
|
||||
},
|
||||
'regexp': {
|
||||
'filepath': 'src/.*regexp',
|
||||
},
|
||||
'bazel': {
|
||||
'filepath': 'BUILD.gn' \
|
||||
'|BUILD.bazel' \
|
||||
'|WORKSPACE' \
|
||||
'|bazel/',
|
||||
},
|
||||
'cppgc': {
|
||||
'filepath': 'src/heap/cppgc/' \
|
||||
'|src/heap/cppgc-js/' \
|
||||
'|include/cppgc/' \
|
||||
'|test/unittests/heap/cppgc/' \
|
||||
'|test/unittests/heap/cppgc-js/',
|
||||
},
|
||||
'trap-handler': {
|
||||
'filepath': 'src/trap-handler/',
|
||||
},
|
||||
},
|
||||
|
||||
'WATCHLISTS': {
|
||||
'maglev': [
|
||||
'leszeks+watch@chromium.org',
|
||||
'verwaest+watch@chromium.org',
|
||||
'victorgomes+watch@chromium.org',
|
||||
],
|
||||
'snapshot': [
|
||||
'jgruber+watch@chromium.org',
|
||||
],
|
||||
'devtools': [
|
||||
'devtools-reviews+v8@chromium.org',
|
||||
],
|
||||
'baseline': [
|
||||
'leszeks+watch@chromium.org',
|
||||
'verwaest+watch@chromium.org',
|
||||
],
|
||||
'feature_shipping_status': [
|
||||
'hablich@chromium.org',
|
||||
'saelo+watch@chromium.org',
|
||||
],
|
||||
'heap_changes': [
|
||||
'hpayer@chromium.org',
|
||||
'mlippautz+watch@chromium.org',
|
||||
],
|
||||
'arm': [
|
||||
'v8-mips-ports@googlegroups.com',
|
||||
'v8-ppc-ports@googlegroups.com',
|
||||
'v8-risc-v-ports@chromium.org',
|
||||
],
|
||||
'merges': [
|
||||
# Only enabled on branches created with tools/release/create_release.py
|
||||
# 'v8-merges@googlegroups.com',
|
||||
],
|
||||
'wasm': [
|
||||
'wasm-v8@google.com',
|
||||
],
|
||||
'value_serializer': [
|
||||
'jbroman+watch@chromium.org',
|
||||
],
|
||||
'parser': [
|
||||
'marja+watch@chromium.org',
|
||||
],
|
||||
'tracing': [
|
||||
'alph+watch@chromium.org',
|
||||
'lpy+v8tracing@chromium.org',
|
||||
'fmeawad@chromium.org',
|
||||
'cbruni+watch@chromium.org',
|
||||
],
|
||||
'ieee754': [
|
||||
'rtoy+watch@chromium.org',
|
||||
'hongchan+watch@chromium.org',
|
||||
],
|
||||
'regexp': [
|
||||
'jgruber+watch@chromium.org',
|
||||
'pthier+watch@chromium.org',
|
||||
],
|
||||
'bazel': [
|
||||
'victorgomes+watch@chromium.org',
|
||||
],
|
||||
'api': [
|
||||
'cbruni+watch@chromium.org',
|
||||
],
|
||||
'cppgc': [
|
||||
'oilpan-reviews+v8@chromium.org',
|
||||
],
|
||||
'trap-handler': [
|
||||
'ahaas@chromium.org',
|
||||
'clemensb@chromium.org',
|
||||
'mark@chromium.org',
|
||||
'mseaborn@chromium.org',
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
workspace(name = "v8")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib",
|
||||
sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
|
||||
bazel_skylib_workspace()
|
||||
|
||||
http_archive(
|
||||
name = "rules_python",
|
||||
sha256 = "a30abdfc7126d497a7698c29c46ea9901c6392d6ed315171a6df5ce433aa4502",
|
||||
strip_prefix = "rules_python-0.6.0",
|
||||
url = "https://github.com/bazelbuild/rules_python/archive/0.6.0.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_python//python:pip.bzl", "pip_install")
|
||||
|
||||
pip_install(
|
||||
name = "v8_python_deps",
|
||||
extra_pip_args = ["--require-hashes"],
|
||||
requirements = "//:bazel/requirements.txt",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "com_google_absl",
|
||||
path = "third_party/abseil-cpp",
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "absl_optional",
|
||||
actual = "@com_google_absl//absl/types:optional"
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "absl_btree",
|
||||
actual = "@com_google_absl//absl/container:btree"
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "absl_flat_hash_map",
|
||||
actual = "@com_google_absl//absl/container:flat_hash_map"
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "absl_flat_hash_set",
|
||||
actual = "@com_google_absl//absl/container:flat_hash_set"
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "com_googlesource_chromium_icu",
|
||||
build_file = ":bazel/BUILD.icu",
|
||||
path = "third_party/icu",
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "icu",
|
||||
actual = "@com_googlesource_chromium_icu//:icu",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "intel_ittapi",
|
||||
add_prefix = "third_party/ittapi",
|
||||
build_file = "@//:bazel/BUILD.ittapi",
|
||||
sha256 = "36c42d3f2446ddfaa2d7dfa02dfaa79615933f1a68a72d7e4f1d70de7b56e2c9",
|
||||
strip_prefix = "ittapi-3.24.0",
|
||||
url = "https://github.com/intel/ittapi/archive/refs/tags/v3.24.0.tar.gz",
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "ittapi",
|
||||
actual = "@intel_ittapi//:lib_ittapi",
|
||||
)
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
filegroup(
|
||||
name = "icudata",
|
||||
srcs = ["common/icudtl.dat"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "icuuc",
|
||||
srcs = glob([
|
||||
"source/common/**/*.h",
|
||||
"source/common/**/*.cpp",
|
||||
]),
|
||||
copts = select({
|
||||
"@platforms//os:windows": [
|
||||
"/wd4005", # Macro redefinition.
|
||||
"/wd4068", # Unknown pragmas.
|
||||
"/wd4267", # Conversion from size_t on 64-bits.
|
||||
"/utf-8", # ICU source files are in UTF-8.
|
||||
],
|
||||
"//conditions:default": [
|
||||
"-Wno-deprecated-declarations",
|
||||
],
|
||||
}),
|
||||
data = [":icudata"],
|
||||
defines = [
|
||||
"HAVE_DLOPEN=0",
|
||||
"UCONFIG_ONLY_HTML_CONVERSION=1",
|
||||
"U_CHARSET_IS_UTF8=1",
|
||||
"U_USING_ICU_NAMESPACE=0",
|
||||
"U_ENABLE_DYLOAD=0",
|
||||
"USE_CHROMIUM_ICU=1",
|
||||
"U_ENABLE_TRACING=1",
|
||||
"U_ENABLE_RESOURCE_TRACING=0",
|
||||
"UNISTR_FROM_STRING_EXPLICIT=",
|
||||
"UNISTR_FROM_CHAR_EXPLICIT=",
|
||||
] + select({
|
||||
"@platforms//os:windows": [
|
||||
"U_STATIC_IMPLEMENTATION",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
includes = [
|
||||
"source/common",
|
||||
"source/i18n",
|
||||
],
|
||||
local_defines = [
|
||||
"U_COMMON_IMPLEMENTATION",
|
||||
"U_ICUDATAENTRY_IN_COMMON",
|
||||
],
|
||||
tags = ["requires-rtti"],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "icui18n",
|
||||
srcs = glob([
|
||||
"source/i18n/**/*.h",
|
||||
"source/i18n/**/*.cpp",
|
||||
]),
|
||||
copts = select({
|
||||
"@platforms//os:windows": [
|
||||
"/wd4005", # Macro redefinition.
|
||||
"/wd4068", # Unknown pragmas.
|
||||
"/wd4267", # Conversion from size_t on 64-bits.
|
||||
"/utf-8", # ICU source files are in UTF-8.
|
||||
],
|
||||
"//conditions:default": [
|
||||
"-Wno-deprecated-declarations",
|
||||
],
|
||||
}),
|
||||
local_defines = [
|
||||
"U_I18N_IMPLEMENTATION",
|
||||
],
|
||||
deps = [":icuuc"],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "icu",
|
||||
srcs = [
|
||||
"source/stubdata/stubdata.cpp",
|
||||
"source/stubdata/stubdata.h",
|
||||
],
|
||||
hdrs = glob([
|
||||
"source/common/unicode/*.h",
|
||||
"source/i18n/unicode/*.h",
|
||||
]),
|
||||
copts = select({
|
||||
"@platforms//os:windows": [
|
||||
"/wd4005", # Macro redefinition.
|
||||
"/wd4068", # Unknown pragmas.
|
||||
"/wd4267", # Conversion from size_t on 64-bits.
|
||||
"/utf-8", # ICU source files are in UTF-8.
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
include_prefix = "third_party/icu",
|
||||
local_defines = [
|
||||
"U_COMMON_IMPLEMENTATION",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":icui18n",
|
||||
":icuuc",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
cc_library(
|
||||
name = "lib_ittapi",
|
||||
srcs = [
|
||||
"third_party/ittapi/include/ittnotify.h",
|
||||
"third_party/ittapi/include/jitprofiling.h",
|
||||
"third_party/ittapi/src/ittnotify/ittnotify_config.h",
|
||||
"third_party/ittapi/src/ittnotify/jitprofiling.c",
|
||||
],
|
||||
hdrs = [
|
||||
"third_party/ittapi/include/ittnotify.h",
|
||||
"third_party/ittapi/src/ittnotify/ittnotify_types.h",
|
||||
],
|
||||
copts = ["-Iexternal/intel_ittapi/third_party/ittapi/include"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@@ -1,4 +0,0 @@
|
||||
# Google3 V8 owners
|
||||
ahaas@chromium.org
|
||||
cbruni@chromium.org
|
||||
victorgomes@chromium.org
|
||||
@@ -1,359 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load(
|
||||
":v8-target-cpu.bzl",
|
||||
"v8_configure_target_cpu",
|
||||
"v8_target_cpu",
|
||||
)
|
||||
|
||||
package(
|
||||
default_visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_fastbuild",
|
||||
values = {
|
||||
"compilation_mode": "fastbuild",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_opt",
|
||||
values = {
|
||||
"compilation_mode": "opt",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_debug",
|
||||
values = {
|
||||
"compilation_mode": "dbg",
|
||||
},
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_opt_android",
|
||||
match_all = [
|
||||
":is_opt",
|
||||
":is_android",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_x64",
|
||||
constraint_values = ["@platforms//cpu:x86_64"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_ia32",
|
||||
constraint_values = ["@platforms//cpu:x86_32"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_arm64",
|
||||
constraint_values = ["@platforms//cpu:aarch64"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_arm",
|
||||
constraint_values = ["@platforms//cpu:arm"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_s390x",
|
||||
constraint_values = ["@platforms//cpu:s390x"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_riscv64",
|
||||
constraint_values = ["@platforms//cpu:riscv64"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "platform_cpu_ppc64le",
|
||||
constraint_values = ["@platforms//cpu:ppc"],
|
||||
)
|
||||
|
||||
v8_target_cpu(
|
||||
name = "v8_target_cpu",
|
||||
build_setting_default = "none",
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "v8_host_target_is_none",
|
||||
flag_values = {
|
||||
":v8_target_cpu": "none",
|
||||
},
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "x64",
|
||||
matching_configs = [":platform_cpu_x64"],
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "ia32",
|
||||
matching_configs = [":platform_cpu_ia32"],
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "arm64",
|
||||
matching_configs = [":platform_cpu_arm64"],
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "arm",
|
||||
matching_configs = [":platform_cpu_arm"],
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "s390x",
|
||||
matching_configs = [":platform_cpu_s390x"],
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "riscv64",
|
||||
matching_configs = [":platform_cpu_riscv64"],
|
||||
)
|
||||
|
||||
v8_configure_target_cpu(
|
||||
name = "ppc64le",
|
||||
matching_configs = [":platform_cpu_ppc64le"],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "v8_target_is_32_bits",
|
||||
match_any = [
|
||||
":v8_target_ia32",
|
||||
":v8_target_arm",
|
||||
],
|
||||
)
|
||||
|
||||
# Running arm64 simulator on x64 host.
|
||||
selects.config_setting_group(
|
||||
name = "v8_arm64_simulator",
|
||||
match_all = [
|
||||
":v8_target_arm64",
|
||||
":is_x64",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_linux",
|
||||
constraint_values = ["@platforms//os:linux"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_android",
|
||||
constraint_values = ["@platforms//os:android"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_macos",
|
||||
constraint_values = ["@platforms//os:macos"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_windows",
|
||||
constraint_values = ["@platforms//os:windows"],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_64bit",
|
||||
match_any = [
|
||||
":v8_target_arm64",
|
||||
":is_x64",
|
||||
":is_arm64",
|
||||
":is_s390x",
|
||||
":is_riscv64",
|
||||
":is_ppc64le",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_windows_64bit",
|
||||
match_all = [
|
||||
":is_64bit",
|
||||
":is_windows",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_posix",
|
||||
match_any = [
|
||||
":is_linux",
|
||||
":is_android",
|
||||
":is_macos",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_not_android",
|
||||
match_any = [
|
||||
":is_windows",
|
||||
":is_linux",
|
||||
":is_macos",
|
||||
]
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_posix_x64",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_x64",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_x64",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_x64",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_ia32",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_ia32",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_arm64",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_arm64",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_arm",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_arm",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_s390x",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_s390x",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_riscv64",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_riscv64",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_inline_asm_ppc64le",
|
||||
match_all = [
|
||||
":is_posix",
|
||||
":is_ppc64le",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_msvc_asm_x64",
|
||||
match_all = [
|
||||
":is_windows",
|
||||
":is_x64",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_msvc_asm_ia32",
|
||||
match_all = [
|
||||
":is_windows",
|
||||
":is_ia32",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_msvc_asm_arm64",
|
||||
match_all = [
|
||||
":is_windows",
|
||||
":is_arm64",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_compiler_default",
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "compiler",
|
||||
},
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_compiler_default_on_linux",
|
||||
match_all = [
|
||||
":is_compiler_default",
|
||||
":is_linux",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_compiler_default_on_macos",
|
||||
match_all = [
|
||||
":is_compiler_default",
|
||||
":is_macos",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_compiler_clang",
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "clang",
|
||||
},
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_clang",
|
||||
match_any = [
|
||||
":is_compiler_default_on_macos",
|
||||
":is_compiler_clang",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_clang_s390x",
|
||||
match_all = [
|
||||
":is_clang",
|
||||
":is_s390x",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "is_compiler_gcc",
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "gcc",
|
||||
},
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_gcc",
|
||||
match_any = [
|
||||
":is_compiler_default_on_linux",
|
||||
":is_compiler_gcc",
|
||||
],
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "is_gcc_fastbuild",
|
||||
match_all = [
|
||||
":is_gcc",
|
||||
":is_fastbuild",
|
||||
],
|
||||
)
|
||||
@@ -1,61 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
"""Build rules to choose the v8 target architecture."""
|
||||
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
V8CpuTypeInfo = provider(
|
||||
doc = "A singleton provider that specifies the V8 target CPU type",
|
||||
fields = {
|
||||
"value": "The V8 Target CPU selected.",
|
||||
},
|
||||
)
|
||||
|
||||
def _host_target_cpu_impl(ctx):
|
||||
allowed_values = ["arm", "arm64", "ia32", "ppc64le", "riscv64", "s390x", "x64", "none"]
|
||||
cpu_type = ctx.build_setting_value
|
||||
if cpu_type in allowed_values:
|
||||
return V8CpuTypeInfo(value = cpu_type)
|
||||
else:
|
||||
fail("Error setting " + str(ctx.label) + ": invalid v8 target cpu '" +
|
||||
cpu_type + "'. Allowed values are " + str(allowed_values))
|
||||
|
||||
v8_target_cpu = rule(
|
||||
implementation = _host_target_cpu_impl,
|
||||
build_setting = config.string(flag = True),
|
||||
doc = "CPU that V8 will generate code for.",
|
||||
)
|
||||
|
||||
def v8_configure_target_cpu(name, matching_configs):
|
||||
selects.config_setting_group(
|
||||
name = "is_" + name,
|
||||
match_any = matching_configs,
|
||||
)
|
||||
|
||||
# If v8_target_cpu flag is set to 'name'
|
||||
native.config_setting(
|
||||
name = "v8_host_target_is_" + name,
|
||||
flag_values = {
|
||||
":v8_target_cpu": name,
|
||||
},
|
||||
)
|
||||
|
||||
# Default target if no v8_host_target flag is set.
|
||||
selects.config_setting_group(
|
||||
name = "v8_target_is_" + name,
|
||||
match_all = [
|
||||
":v8_host_target_is_none",
|
||||
":is_" + name,
|
||||
],
|
||||
)
|
||||
|
||||
# Select either the default target or the flag.
|
||||
selects.config_setting_group(
|
||||
name = "v8_target_" + name,
|
||||
match_any = [
|
||||
":v8_host_target_is_" + name,
|
||||
":v8_target_is_" + name,
|
||||
],
|
||||
)
|
||||
-607
@@ -1,607 +0,0 @@
|
||||
# Copyright 2021 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.
|
||||
|
||||
"""
|
||||
This module contains helper functions to compile V8.
|
||||
"""
|
||||
|
||||
FlagInfo = provider("The value of an option.",
|
||||
fields = ["value"])
|
||||
|
||||
def _options_impl(ctx):
|
||||
return FlagInfo(value = ctx.build_setting_value)
|
||||
|
||||
_create_option_flag = rule(
|
||||
implementation = _options_impl,
|
||||
build_setting = config.bool(flag = True),
|
||||
)
|
||||
|
||||
_create_option_string = rule(
|
||||
implementation = _options_impl,
|
||||
build_setting = config.string(flag = True),
|
||||
)
|
||||
|
||||
_create_option_int = rule(
|
||||
implementation = _options_impl,
|
||||
build_setting = config.int(flag = True),
|
||||
)
|
||||
|
||||
def v8_flag(name, default = False):
|
||||
_create_option_flag(name = name, build_setting_default = default)
|
||||
native.config_setting(name = "is_" + name, flag_values = {name: "True"})
|
||||
native.config_setting(name = "is_not_" + name, flag_values = {name: "False"})
|
||||
|
||||
def v8_string(name, default = ""):
|
||||
_create_option_string(name = name, build_setting_default = default)
|
||||
|
||||
def v8_int(name, default = 0):
|
||||
_create_option_int(name = name, build_setting_default = default)
|
||||
|
||||
def _custom_config_impl(ctx):
|
||||
defs = []
|
||||
defs.append("V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=" +
|
||||
str(ctx.attr._v8_typed_array_max_size_in_heap[FlagInfo].value))
|
||||
context = cc_common.create_compilation_context(defines = depset(defs))
|
||||
return [CcInfo(compilation_context = context)]
|
||||
|
||||
v8_custom_config = rule(
|
||||
implementation = _custom_config_impl,
|
||||
attrs = {
|
||||
"_v8_typed_array_max_size_in_heap": attr.label(default = ":v8_typed_array_max_size_in_heap"),
|
||||
},
|
||||
)
|
||||
|
||||
def _config_impl(ctx):
|
||||
hdrs = []
|
||||
|
||||
# Add headers
|
||||
for h in ctx.attr.hdrs:
|
||||
hdrs += h[DefaultInfo].files.to_list()
|
||||
defs = []
|
||||
|
||||
# Add conditional_defines
|
||||
for f, d in ctx.attr.conditional_defines.items():
|
||||
if f[FlagInfo].value:
|
||||
defs.append(d)
|
||||
|
||||
# Add defines
|
||||
for d in ctx.attr.defines:
|
||||
defs.append(d)
|
||||
context = cc_common.create_compilation_context(
|
||||
defines = depset(
|
||||
defs,
|
||||
transitive = [dep[CcInfo].compilation_context.defines for dep in ctx.attr.deps],
|
||||
),
|
||||
headers = depset(
|
||||
hdrs,
|
||||
transitive = [dep[CcInfo].compilation_context.headers for dep in ctx.attr.deps],
|
||||
),
|
||||
)
|
||||
return [CcInfo(compilation_context = context)]
|
||||
|
||||
v8_config = rule(
|
||||
implementation = _config_impl,
|
||||
attrs = {
|
||||
"conditional_defines": attr.label_keyed_string_dict(),
|
||||
"defines": attr.string_list(),
|
||||
"deps": attr.label_list(),
|
||||
"hdrs": attr.label_list(allow_files = True),
|
||||
},
|
||||
)
|
||||
|
||||
def _default_args():
|
||||
return struct(
|
||||
deps = [":define_flags"],
|
||||
defines = select({
|
||||
"@v8//bazel/config:is_windows": [
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"_CRT_RAND_S",
|
||||
"_WIN32_WINNT=0x0602", # Override bazel default to Windows 8
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
copts = select({
|
||||
"@v8//bazel/config:is_posix": [
|
||||
"-fPIC",
|
||||
"-fno-strict-aliasing",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
"-Wno-unneeded-internal-declaration",
|
||||
"-Wno-unknown-warning-option", # b/330781959
|
||||
"-Wno-cast-function-type-mismatch", # b/330781959
|
||||
"-Wno-bitwise-instead-of-logical",
|
||||
"-Wno-builtin-assume-aligned-alignment",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-implicit-int-float-conversion",
|
||||
"-Wno-deprecated-copy",
|
||||
"-Wno-non-virtual-dtor",
|
||||
"-isystem .",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}) + select({
|
||||
"@v8//bazel/config:is_clang": [
|
||||
"-Wno-invalid-offsetof",
|
||||
"-Wno-deprecated-this-capture",
|
||||
"-std=c++20",
|
||||
],
|
||||
"@v8//bazel/config:is_gcc": [
|
||||
"-Wno-extra",
|
||||
"-Wno-array-bounds",
|
||||
"-Wno-class-memaccess",
|
||||
"-Wno-comments",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-implicit-fallthrough",
|
||||
"-Wno-int-in-bool-context",
|
||||
"-Wno-maybe-uninitialized",
|
||||
"-Wno-mismatched-new-delete",
|
||||
"-Wno-redundant-move",
|
||||
"-Wno-return-type",
|
||||
"-Wno-stringop-overflow",
|
||||
"-Wno-deprecated-this-capture",
|
||||
# Use GNU dialect, because GCC doesn't allow using
|
||||
# ##__VA_ARGS__ when in standards-conforming mode.
|
||||
"-std=gnu++2a",
|
||||
],
|
||||
"@v8//bazel/config:is_windows": [
|
||||
"/std:c++20",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}) + select({
|
||||
"@v8//bazel/config:is_gcc_fastbuild": [
|
||||
# Non-debug builds without optimizations fail because
|
||||
# of recursive inlining of "always_inline" functions.
|
||||
"-O1",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}) + select({
|
||||
"@v8//bazel/config:is_clang_s390x": [
|
||||
"-fno-integrated-as",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}) + select({
|
||||
"@v8//bazel/config:is_opt_android": [
|
||||
"-fvisibility=hidden",
|
||||
"-fvisibility-inlines-hidden",
|
||||
],
|
||||
"//conditions:default": [
|
||||
],
|
||||
}),
|
||||
includes = ["include"],
|
||||
linkopts = select({
|
||||
"@v8//bazel/config:is_windows": [
|
||||
"Winmm.lib",
|
||||
"DbgHelp.lib",
|
||||
"Advapi32.lib",
|
||||
],
|
||||
"@v8//bazel/config:is_macos": ["-pthread"],
|
||||
"//conditions:default": ["-Wl,--no-as-needed -ldl -pthread"],
|
||||
}) + select({
|
||||
":should_add_rdynamic": ["-rdynamic"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
ENABLE_I18N_SUPPORT_DEFINES = [
|
||||
"-DV8_INTL_SUPPORT",
|
||||
"-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC",
|
||||
# src/regexp/regexp-compiler-tonode.cc uses an unsafe ICU method and
|
||||
# access a character implicitly.
|
||||
"-DUNISTR_FROM_CHAR_EXPLICIT=",
|
||||
]
|
||||
|
||||
def _should_emit_noicu_and_icu(noicu_srcs, noicu_deps, noicu_defines, icu_srcs, icu_deps, icu_defines):
|
||||
return noicu_srcs != [] or noicu_deps != [] or noicu_defines != [] or icu_srcs != [] or icu_deps != [] or icu_defines != []
|
||||
|
||||
# buildifier: disable=function-docstring
|
||||
def v8_binary(
|
||||
name,
|
||||
srcs,
|
||||
deps = [],
|
||||
defines = [],
|
||||
includes = [],
|
||||
copts = [],
|
||||
linkopts = [],
|
||||
noicu_srcs = [],
|
||||
noicu_deps = [],
|
||||
noicu_defines = [],
|
||||
icu_srcs = [],
|
||||
icu_deps = [],
|
||||
icu_defines = [],
|
||||
**kwargs):
|
||||
default = _default_args()
|
||||
if _should_emit_noicu_and_icu(noicu_srcs, noicu_deps, noicu_defines, icu_srcs, icu_deps, icu_defines):
|
||||
native.cc_binary(
|
||||
name = "noicu/" + name,
|
||||
srcs = srcs + noicu_srcs,
|
||||
deps = deps + noicu_deps + default.deps,
|
||||
defines = defines + noicu_defines + default.defines,
|
||||
includes = includes + ["noicu/"] + default.includes,
|
||||
copts = copts + default.copts,
|
||||
linkopts = linkopts + default.linkopts,
|
||||
**kwargs
|
||||
)
|
||||
native.cc_binary(
|
||||
name = "icu/" + name,
|
||||
srcs = srcs + icu_srcs,
|
||||
deps = deps + icu_deps + default.deps,
|
||||
includes = includes + ["icu/"] + default.includes,
|
||||
defines = defines + icu_defines + default.defines,
|
||||
copts = copts + default.copts + ENABLE_I18N_SUPPORT_DEFINES,
|
||||
linkopts = linkopts + default.linkopts,
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
native.cc_binary(
|
||||
name = name,
|
||||
srcs = srcs,
|
||||
deps = deps + default.deps,
|
||||
defines = defines + default.defines,
|
||||
includes = includes + default.includes,
|
||||
copts = copts + default.copts,
|
||||
linkopts = linkopts + default.linkopts,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# buildifier: disable=function-docstring
|
||||
def v8_library(
|
||||
name,
|
||||
srcs,
|
||||
deps = [],
|
||||
includes = [],
|
||||
copts = [],
|
||||
linkopts = [],
|
||||
noicu_srcs = [],
|
||||
noicu_deps = [],
|
||||
noicu_defines = [],
|
||||
icu_srcs = [],
|
||||
icu_deps = [],
|
||||
icu_defines = [],
|
||||
**kwargs):
|
||||
default = _default_args()
|
||||
if _should_emit_noicu_and_icu(noicu_srcs, noicu_deps, noicu_defines, icu_srcs, icu_deps, icu_defines):
|
||||
native.cc_library(
|
||||
name = name + "_noicu",
|
||||
srcs = srcs + noicu_srcs,
|
||||
deps = deps + noicu_deps + default.deps,
|
||||
includes = includes + ["noicu/"] + default.includes,
|
||||
copts = copts + default.copts,
|
||||
linkopts = linkopts + default.linkopts,
|
||||
alwayslink = 1,
|
||||
linkstatic = 1,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# Alias target used because of cc_library bug in bazel on windows
|
||||
# https://github.com/bazelbuild/bazel/issues/14237
|
||||
# TODO(victorgomes): Remove alias once bug is fixed
|
||||
native.alias(
|
||||
name = "noicu/" + name,
|
||||
actual = name + "_noicu",
|
||||
)
|
||||
native.cc_library(
|
||||
name = name + "_icu",
|
||||
srcs = srcs + icu_srcs,
|
||||
deps = deps + icu_deps + default.deps,
|
||||
includes = includes + ["icu/"] + default.includes,
|
||||
copts = copts + default.copts + ENABLE_I18N_SUPPORT_DEFINES,
|
||||
linkopts = linkopts + default.linkopts,
|
||||
alwayslink = 1,
|
||||
linkstatic = 1,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# Alias target used because of cc_library bug in bazel on windows
|
||||
# https://github.com/bazelbuild/bazel/issues/14237
|
||||
# TODO(victorgomes): Remove alias once bug is fixed
|
||||
native.alias(
|
||||
name = "icu/" + name,
|
||||
actual = name + "_icu",
|
||||
)
|
||||
else:
|
||||
native.cc_library(
|
||||
name = name,
|
||||
srcs = srcs,
|
||||
deps = deps + default.deps,
|
||||
includes = includes + default.includes,
|
||||
copts = copts + default.copts,
|
||||
linkopts = linkopts + default.linkopts,
|
||||
alwayslink = 1,
|
||||
linkstatic = 1,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# Use a single generator target for torque definitions and initializers. We can
|
||||
# split the set of outputs by using OutputGroupInfo, that way we do not need to
|
||||
# run the torque generator twice.
|
||||
def _torque_files_impl(ctx):
|
||||
v8root = "."
|
||||
|
||||
# Arguments
|
||||
args = []
|
||||
args += ctx.attr.args
|
||||
args.append("-o")
|
||||
args.append(ctx.bin_dir.path + "/" + v8root + "/" + ctx.attr.prefix + "/torque-generated")
|
||||
args.append("-strip-v8-root")
|
||||
args.append("-v8-root")
|
||||
args.append(v8root)
|
||||
|
||||
# Sources
|
||||
args += [f.path for f in ctx.files.srcs]
|
||||
|
||||
# Generate/declare output files
|
||||
defs = []
|
||||
inits = []
|
||||
for src in ctx.files.srcs:
|
||||
root, _period, _ext = src.path.rpartition(".")
|
||||
|
||||
# Strip v8root
|
||||
if root[:len(v8root)] == v8root:
|
||||
root = root[len(v8root):]
|
||||
file = ctx.attr.prefix + "/torque-generated/" + root
|
||||
defs.append(ctx.actions.declare_file(file + "-tq-inl.inc"))
|
||||
defs.append(ctx.actions.declare_file(file + "-tq.inc"))
|
||||
defs.append(ctx.actions.declare_file(file + "-tq.cc"))
|
||||
inits.append(ctx.actions.declare_file(file + "-tq-csa.cc"))
|
||||
inits.append(ctx.actions.declare_file(file + "-tq-csa.h"))
|
||||
|
||||
defs += [ctx.actions.declare_file(ctx.attr.prefix + "/torque-generated/" + f) for f in ctx.attr.definition_extras]
|
||||
inits += [ctx.actions.declare_file(ctx.attr.prefix + "/torque-generated/" + f) for f in ctx.attr.initializer_extras]
|
||||
outs = defs + inits
|
||||
ctx.actions.run(
|
||||
outputs = outs,
|
||||
inputs = ctx.files.srcs,
|
||||
arguments = args,
|
||||
executable = ctx.executable.tool,
|
||||
mnemonic = "GenTorqueFiles",
|
||||
progress_message = "Generating Torque files",
|
||||
)
|
||||
return [
|
||||
DefaultInfo(files = depset(outs)),
|
||||
OutputGroupInfo(
|
||||
initializers = depset(inits),
|
||||
definitions = depset(defs),
|
||||
),
|
||||
]
|
||||
|
||||
_v8_torque_files = rule(
|
||||
implementation = _torque_files_impl,
|
||||
# cfg = v8_target_cpu_transition,
|
||||
attrs = {
|
||||
"prefix": attr.string(mandatory = True),
|
||||
"srcs": attr.label_list(allow_files = True, mandatory = True),
|
||||
"definition_extras": attr.string_list(),
|
||||
"initializer_extras": attr.string_list(),
|
||||
"tool": attr.label(
|
||||
allow_files = True,
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
),
|
||||
"args": attr.string_list(),
|
||||
},
|
||||
)
|
||||
|
||||
def v8_torque_files(name, noicu_srcs, icu_srcs, args, definition_extras, initializer_extras):
|
||||
_v8_torque_files(
|
||||
name = "noicu/" + name,
|
||||
prefix = "noicu",
|
||||
srcs = noicu_srcs,
|
||||
args = args,
|
||||
definition_extras = definition_extras,
|
||||
initializer_extras = initializer_extras,
|
||||
tool = select({
|
||||
"@v8//bazel/config:v8_target_is_32_bits": ":noicu/torque_non_pointer_compression",
|
||||
"//conditions:default": ":noicu/torque",
|
||||
}),
|
||||
)
|
||||
_v8_torque_files(
|
||||
name = "icu/" + name,
|
||||
prefix = "icu",
|
||||
srcs = icu_srcs,
|
||||
args = args,
|
||||
definition_extras = definition_extras,
|
||||
initializer_extras = initializer_extras,
|
||||
tool = select({
|
||||
"@v8//bazel/config:v8_target_is_32_bits": ":icu/torque_non_pointer_compression",
|
||||
"//conditions:default": ":icu/torque",
|
||||
}),
|
||||
)
|
||||
|
||||
def _v8_target_cpu_transition_impl(settings,
|
||||
attr, # @unused
|
||||
):
|
||||
# Check for an existing v8_target_cpu flag.
|
||||
if "@v8//bazel/config:v8_target_cpu" in settings:
|
||||
if settings["@v8//bazel/config:v8_target_cpu"] != "none":
|
||||
return {}
|
||||
|
||||
# Auto-detect target architecture based on the --cpu flag.
|
||||
mapping = {
|
||||
"haswell": "x64",
|
||||
"k8": "x64",
|
||||
"x86_64": "x64",
|
||||
"darwin": "x64",
|
||||
"darwin_x86_64": "x64",
|
||||
"x64_windows": "x64",
|
||||
"x86": "ia32",
|
||||
"aarch64": "arm64",
|
||||
"arm64-v8a": "arm64",
|
||||
"arm": "arm64",
|
||||
"darwin_arm64": "arm64",
|
||||
"armeabi-v7a": "arm32",
|
||||
"s390x": "s390x",
|
||||
"riscv64": "riscv64",
|
||||
"ppc": "ppc64le",
|
||||
}
|
||||
v8_target_cpu = mapping[settings["//command_line_option:cpu"]]
|
||||
return {"@v8//bazel/config:v8_target_cpu": v8_target_cpu}
|
||||
|
||||
# Set the v8_target_cpu to be the correct architecture given the cpu specified
|
||||
# on the command line.
|
||||
v8_target_cpu_transition = transition(
|
||||
implementation = _v8_target_cpu_transition_impl,
|
||||
inputs = ["@v8//bazel/config:v8_target_cpu", "//command_line_option:cpu"],
|
||||
outputs = ["@v8//bazel/config:v8_target_cpu"],
|
||||
)
|
||||
|
||||
def _mksnapshot(ctx):
|
||||
prefix = ctx.attr.prefix
|
||||
suffix = ctx.attr.suffix
|
||||
outs = [
|
||||
ctx.actions.declare_file(prefix + "/snapshot" + suffix + ".cc"),
|
||||
ctx.actions.declare_file(prefix + "/embedded" + suffix + ".S"),
|
||||
]
|
||||
ctx.actions.run(
|
||||
outputs = outs,
|
||||
inputs = [],
|
||||
arguments = [
|
||||
"--embedded_variant=Default",
|
||||
"--target_os",
|
||||
ctx.attr.target_os,
|
||||
"--startup_src",
|
||||
outs[0].path,
|
||||
"--embedded_src",
|
||||
outs[1].path,
|
||||
] + ctx.attr.args,
|
||||
executable = ctx.executable.tool,
|
||||
progress_message = "Running mksnapshot",
|
||||
)
|
||||
return [DefaultInfo(files = depset(outs))]
|
||||
|
||||
_v8_mksnapshot = rule(
|
||||
implementation = _mksnapshot,
|
||||
attrs = {
|
||||
"args": attr.string_list(),
|
||||
"tool": attr.label(
|
||||
mandatory = True,
|
||||
allow_files = True,
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
),
|
||||
"target_os": attr.string(mandatory = True),
|
||||
"prefix": attr.string(mandatory = True),
|
||||
"suffix": attr.string(mandatory = True),
|
||||
},
|
||||
cfg = v8_target_cpu_transition,
|
||||
)
|
||||
|
||||
def v8_mksnapshot(name, args, suffix = ""):
|
||||
_v8_mksnapshot(
|
||||
name = "noicu/" + name,
|
||||
args = args,
|
||||
prefix = "noicu",
|
||||
tool = ":noicu/mksnapshot" + suffix,
|
||||
suffix = suffix,
|
||||
target_os = select({
|
||||
"@v8//bazel/config:is_macos": "mac",
|
||||
"//conditions:default": "",
|
||||
}),
|
||||
)
|
||||
_v8_mksnapshot(
|
||||
name = "icu/" + name,
|
||||
args = args,
|
||||
prefix = "icu",
|
||||
tool = ":icu/mksnapshot" + suffix,
|
||||
suffix = suffix,
|
||||
target_os = select({
|
||||
"@v8//bazel/config:is_macos": "mac",
|
||||
"//conditions:default": "",
|
||||
}),
|
||||
)
|
||||
|
||||
def _quote(val):
|
||||
if val[0] == '"' and val[-1] == '"':
|
||||
fail("String", val, "already quoted")
|
||||
return '"' + val + '"'
|
||||
|
||||
def _kv_bool_pair(k, v):
|
||||
return _quote(k) + ": " + v
|
||||
|
||||
def _json(kv_pairs):
|
||||
content = "{"
|
||||
for (k, v) in kv_pairs[:-1]:
|
||||
content += _kv_bool_pair(k, v) + ", "
|
||||
(k, v) = kv_pairs[-1]
|
||||
content += _kv_bool_pair(k, v)
|
||||
content += "}\n"
|
||||
return content
|
||||
|
||||
def build_config_content(cpu, icu):
|
||||
arch = cpu
|
||||
if cpu == 'x86':
|
||||
arch = 'ia32'
|
||||
return _json([
|
||||
("arch", arch),
|
||||
("asan", "false"),
|
||||
("atomic_object_field_writes", "false"),
|
||||
("cfi", "false"),
|
||||
("clang_coverage", "false"),
|
||||
("clang", "true"),
|
||||
("code_comments", "false"),
|
||||
("component_build", "false"),
|
||||
("concurrent_marking", "false"),
|
||||
("conservative_stack_scanning", "false"),
|
||||
("current_cpu", cpu),
|
||||
("dcheck_always_on", "false"),
|
||||
("debug_code", "false"),
|
||||
("DEBUG_defined", "false"),
|
||||
("debugging_features", "false"),
|
||||
("dict_property_const_tracking", "false"),
|
||||
("direct_handle", "false"),
|
||||
("direct_local", "false"),
|
||||
("disassembler", "false"),
|
||||
("full_debug", "false"),
|
||||
("gdbjit", "false"),
|
||||
("has_jitless", "false"),
|
||||
("has_maglev", "true"),
|
||||
("has_turbofan", "true"),
|
||||
("has_webassembly", "false"),
|
||||
("i18n", icu),
|
||||
("is_android", "false"),
|
||||
("is_ios", "false"),
|
||||
("js_shared_memory", "false"),
|
||||
("lite_mode", "false"),
|
||||
("local_off_stack_check", "false"),
|
||||
("memory_corruption_api", "false"),
|
||||
("mips_arch_variant", '""'),
|
||||
("mips_use_msa", "false"),
|
||||
("msan", "false"),
|
||||
("official_build", "false"),
|
||||
("pointer_compression_shared_cage", "false"),
|
||||
("pointer_compression", "true"),
|
||||
("runtime_call_stats", "false"),
|
||||
("sandbox", "false"),
|
||||
("shared_ro_heap", "false"),
|
||||
("simd_mips", "false"),
|
||||
("simulator_run", "false"),
|
||||
("single_generation", "false"),
|
||||
("slow_dchecks", "false"),
|
||||
("target_cpu", cpu),
|
||||
("third_party_heap", "false"),
|
||||
("tsan", "false"),
|
||||
("ubsan", "false"),
|
||||
("use_sanitizer", "false"),
|
||||
("v8_cfi", "false"),
|
||||
("v8_current_cpu", cpu),
|
||||
("v8_target_cpu", cpu),
|
||||
("verify_csa", "false"),
|
||||
("verify_heap", "false"),
|
||||
("verify_predictable", "false"),
|
||||
("write_barriers", "false"),
|
||||
])
|
||||
|
||||
# TODO(victorgomes): Create a rule (instead of a macro), that can
|
||||
# dynamically populate the build config.
|
||||
def v8_build_config(name, arch):
|
||||
cpu = '"' + arch + '"'
|
||||
native.genrule(
|
||||
name = "noicu/" + name,
|
||||
outs = ["noicu/" + name + ".json"],
|
||||
cmd = "echo '" + build_config_content(cpu, "false") + "' > \"$@\"",
|
||||
)
|
||||
native.genrule(
|
||||
name = "icu/" + name,
|
||||
outs = ["icu/" + name + ".json"],
|
||||
cmd = "echo '" + build_config_content(cpu, "true") + "' > \"$@\"",
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
jinja2
|
||||
@@ -1,81 +0,0 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.9
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --generate-hashes requirements.in
|
||||
#
|
||||
jinja2==3.0.3 \
|
||||
--hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \
|
||||
--hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7
|
||||
# via -r requirements.in
|
||||
markupsafe==2.0.1 \
|
||||
--hash=sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298 \
|
||||
--hash=sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64 \
|
||||
--hash=sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b \
|
||||
--hash=sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194 \
|
||||
--hash=sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567 \
|
||||
--hash=sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff \
|
||||
--hash=sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724 \
|
||||
--hash=sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74 \
|
||||
--hash=sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646 \
|
||||
--hash=sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35 \
|
||||
--hash=sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6 \
|
||||
--hash=sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a \
|
||||
--hash=sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6 \
|
||||
--hash=sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad \
|
||||
--hash=sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26 \
|
||||
--hash=sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38 \
|
||||
--hash=sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac \
|
||||
--hash=sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7 \
|
||||
--hash=sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6 \
|
||||
--hash=sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047 \
|
||||
--hash=sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75 \
|
||||
--hash=sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f \
|
||||
--hash=sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b \
|
||||
--hash=sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135 \
|
||||
--hash=sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8 \
|
||||
--hash=sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a \
|
||||
--hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a \
|
||||
--hash=sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1 \
|
||||
--hash=sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9 \
|
||||
--hash=sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864 \
|
||||
--hash=sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914 \
|
||||
--hash=sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee \
|
||||
--hash=sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f \
|
||||
--hash=sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18 \
|
||||
--hash=sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8 \
|
||||
--hash=sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2 \
|
||||
--hash=sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d \
|
||||
--hash=sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b \
|
||||
--hash=sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b \
|
||||
--hash=sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86 \
|
||||
--hash=sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6 \
|
||||
--hash=sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f \
|
||||
--hash=sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb \
|
||||
--hash=sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833 \
|
||||
--hash=sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28 \
|
||||
--hash=sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e \
|
||||
--hash=sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415 \
|
||||
--hash=sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902 \
|
||||
--hash=sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f \
|
||||
--hash=sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d \
|
||||
--hash=sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9 \
|
||||
--hash=sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d \
|
||||
--hash=sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145 \
|
||||
--hash=sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066 \
|
||||
--hash=sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c \
|
||||
--hash=sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1 \
|
||||
--hash=sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a \
|
||||
--hash=sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207 \
|
||||
--hash=sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f \
|
||||
--hash=sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53 \
|
||||
--hash=sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd \
|
||||
--hash=sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134 \
|
||||
--hash=sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85 \
|
||||
--hash=sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9 \
|
||||
--hash=sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5 \
|
||||
--hash=sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94 \
|
||||
--hash=sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509 \
|
||||
--hash=sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51 \
|
||||
--hash=sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872
|
||||
# via jinja2
|
||||
@@ -1,53 +0,0 @@
|
||||
"""
|
||||
Exposes the rule v8_binary_non_pointer_compression, which forces a label
|
||||
to be compiled without pointer compression.
|
||||
"""
|
||||
|
||||
def _v8_disable_pointer_compression(settings, attr):
|
||||
return {
|
||||
"//:v8_enable_pointer_compression": "False",
|
||||
}
|
||||
|
||||
v8_disable_pointer_compression = transition(
|
||||
implementation = _v8_disable_pointer_compression,
|
||||
inputs = [],
|
||||
outputs = ["//:v8_enable_pointer_compression"],
|
||||
)
|
||||
|
||||
# The implementation of transition_rule: all this does is copy the
|
||||
# cc_binary's output to its own output and propagate its runfiles
|
||||
# and executable to use for "$ bazel run".
|
||||
#
|
||||
# This makes transition_rule as close to a pure wrapper of cc_binary
|
||||
# as possible.
|
||||
def _v8_binary_non_pointer_compression(ctx):
|
||||
binary = ctx.attr.binary[0]
|
||||
outfile = ctx.actions.declare_file(ctx.label.name)
|
||||
cc_binary_outfile = binary[DefaultInfo].files.to_list()[0]
|
||||
|
||||
ctx.actions.run_shell(
|
||||
inputs = [cc_binary_outfile],
|
||||
outputs = [outfile],
|
||||
command = "cp %s %s" % (cc_binary_outfile.path, outfile.path),
|
||||
)
|
||||
return [
|
||||
DefaultInfo(
|
||||
executable = outfile,
|
||||
data_runfiles = binary[DefaultInfo].data_runfiles,
|
||||
),
|
||||
]
|
||||
|
||||
# The purpose of this rule is to transition to a config where v8_target_cpu is
|
||||
# set to the appropriate architecture, which will remain in place through exec
|
||||
# transitions, so mksnapshot can for instance build on x64 but for arm64.
|
||||
v8_binary_non_pointer_compression = rule(
|
||||
implementation = _v8_binary_non_pointer_compression,
|
||||
attrs = {
|
||||
# This is the cc_binary whose deps will select() on that feature.
|
||||
# Note specificaly how it's configured with v8_target_cpu_transition, which
|
||||
# ensures that setting propagates down the graph.
|
||||
"binary": attr.label(cfg = v8_disable_pointer_compression),
|
||||
},
|
||||
# Making this executable means it works with "$ bazel run".
|
||||
executable = True,
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
file:../INFRA_OWNERS
|
||||
@@ -1,74 +0,0 @@
|
||||
# Copyright 2016 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.
|
||||
|
||||
# Variable that can be used to support multiple build scenarios, like having
|
||||
# Chromium specific targets in a client project's GN file etc.
|
||||
build_with_chromium = false
|
||||
|
||||
# Variable that can be used to support multiple build scenarios, like when
|
||||
# V8 is embedded within a target.
|
||||
build_with_v8_embedder = false
|
||||
|
||||
# Not all of V8's dependencies are available in V8's Node.js build.
|
||||
build_with_node = false
|
||||
|
||||
# Used by perfetto to distinguish from its own standalone build and the
|
||||
# chromium build.
|
||||
perfetto_build_with_embedder = true
|
||||
|
||||
# TODO(https://crbug.com/337736622): Perfetto and FuzzTest need to know the
|
||||
# path to protobuf targets. V8 stores them in a different location than Chrome
|
||||
# until M129. Thereafter, it can move to //third_party/protobuf and these
|
||||
# variables can be removed.
|
||||
protobuf_target_prefix = "//third_party/protobuf_chrome/"
|
||||
perfetto_protobuf_target_prefix = protobuf_target_prefix
|
||||
perfetto_protobuf_gni = "//third_party/protobuf_chrome/proto_library.gni"
|
||||
perfetto_protobuf_src_dir = "//third_party/protobuf_chrome/src"
|
||||
|
||||
# We use Perfetto's Trace Processor to convert traces to the legacy JSON
|
||||
# format.
|
||||
enable_perfetto_trace_processor = true
|
||||
|
||||
# When building with chromium, determines whether we want to also use the
|
||||
# perfetto library from chromium instead declaring our own.
|
||||
use_perfetto_client_library = false
|
||||
|
||||
# Uncomment these to specify a different NDK location and version in
|
||||
# non-Chromium builds.
|
||||
# default_android_ndk_root = "//third_party/android_ndk"
|
||||
# default_android_ndk_version = "r10e"
|
||||
|
||||
# Some non-Chromium builds don't support building java targets.
|
||||
enable_java_templates = false
|
||||
|
||||
# Enables assertions on safety checks in libc++.
|
||||
enable_safe_libcxx = true
|
||||
|
||||
# Enable assertions on safety checks, also in libstdc++
|
||||
#
|
||||
# In case the C++ standard library implementation used is libstdc++, then
|
||||
# enable its own hardening checks.
|
||||
enable_safe_libstdcxx = true
|
||||
|
||||
# Allows different projects to specify their own suppressions files.
|
||||
asan_suppressions_file = "//build/sanitizers/asan_suppressions.cc"
|
||||
lsan_suppressions_file = "//build/sanitizers/lsan_suppressions.cc"
|
||||
tsan_suppressions_file = "//build/sanitizers/tsan_suppressions.cc"
|
||||
|
||||
# Skip assertions about 4GiB file size limit.
|
||||
ignore_elf32_limitations = true
|
||||
|
||||
if (host_os == "mac") {
|
||||
_result = exec_script("//build/mac/should_use_hermetic_xcode.py",
|
||||
[ target_os ],
|
||||
"value")
|
||||
assert(_result != 2,
|
||||
"Do not allow building targets with the default" +
|
||||
"hermetic toolchain if the minimum OS version is not met.")
|
||||
assert(_result != 3,
|
||||
"iOS does not support building with a hermetic toolchain. " +
|
||||
"Please install Xcode.")
|
||||
|
||||
use_system_xcode = _result == 0
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
# Copyright 2016 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.
|
||||
|
||||
# Exclude support for registering main function in multi-process tests.
|
||||
gtest_include_multiprocess = false
|
||||
|
||||
# Exclude support for platform-specific operations across unit tests.
|
||||
gtest_include_platform_test = false
|
||||
|
||||
# Exclude support for testing Objective C code on OS X and iOS.
|
||||
gtest_include_objc_support = false
|
||||
|
||||
# Exclude support for flushing coverage files on iOS.
|
||||
gtest_include_ios_coverage = false
|
||||
@@ -1,7 +0,0 @@
|
||||
PROJECT: v8
|
||||
GERRIT_HOST: True
|
||||
CODE_REVIEW_SERVER: https://codereview.chromium.org
|
||||
CC_LIST: v8-reviews@googlegroups.com
|
||||
VIEW_VC: https://chromium.googlesource.com/v8/v8/+/
|
||||
STATUS: http://v8-status.appspot.com/status
|
||||
RUN_POST_UPLOAD_HOOK: True
|
||||
@@ -1,4 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
!OWNERS
|
||||
!README.md
|
||||
@@ -1 +0,0 @@
|
||||
file:../INFRA_OWNERS
|
||||
@@ -1,2 +0,0 @@
|
||||
Common directory for custom dependencies pulled in via .gclient custom_deps.
|
||||
All subdirectories are ignored by git by default.
|
||||
@@ -1,2 +0,0 @@
|
||||
hablich@chromium.org
|
||||
mathias@chromium.org
|
||||
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UISupportedInterfaceOrientation</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,5 +0,0 @@
|
||||
file:../INFRA_OWNERS
|
||||
|
||||
per-file v8.cml=victorgomes@chromium.org
|
||||
per-file release_branch_toggle.gni=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com
|
||||
per-file release_branch_toggle.gni=vahl@chromium.org
|
||||
@@ -1,10 +0,0 @@
|
||||
# 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.
|
||||
|
||||
declare_args() {
|
||||
# TODO(liviurau): Remove old name after Chromium config update
|
||||
# https://crbug.com/1476977.
|
||||
is_on_release_branch = false
|
||||
v8_is_on_release_branch = false
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
# Copyright 2015 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import("//build/config/v8_target_cpu.gni")
|
||||
|
||||
declare_args() {
|
||||
# The v8 snapshot needs to be built by code that is compiled with a
|
||||
# toolchain that matches the bit-width of the target CPU, but runs on
|
||||
# the host.
|
||||
v8_snapshot_toolchain = ""
|
||||
}
|
||||
|
||||
# Try to infer the appropriate snapshot toolchain for the v8_current_cpu
|
||||
# where possible.
|
||||
#
|
||||
# Assume that v8_target_cpu (and hence v8_current_cpu) has been validated
|
||||
# as supported on the current host CPU and OS in v8_target_cpu.gni. The
|
||||
# logic below is complicated enough without also needing to do input
|
||||
# validation.
|
||||
#
|
||||
# There are test cases for this code posted as an attachment to
|
||||
# https://crbug.com/625353.
|
||||
|
||||
if (v8_snapshot_toolchain == "") {
|
||||
if (current_os == host_os && current_cpu == host_cpu) {
|
||||
# This is not a cross-compile, so build the snapshot with the current
|
||||
# toolchain.
|
||||
v8_snapshot_toolchain = current_toolchain
|
||||
} else if (current_os == host_os && current_cpu == "x86" &&
|
||||
host_cpu == "x64") {
|
||||
# This is an x64 -> x86 cross-compile, but x64 hosts can usually run x86
|
||||
# binaries built for the same OS, so build the snapshot with the current
|
||||
# toolchain here, too.
|
||||
v8_snapshot_toolchain = current_toolchain
|
||||
} else if (current_os == host_os && host_cpu == "arm64" &&
|
||||
current_cpu == "arm") {
|
||||
# Trying to compile 32-bit arm on arm64. Good luck!
|
||||
v8_snapshot_toolchain = current_toolchain
|
||||
} else if (host_cpu == "x64" && v8_current_cpu == "mips64") {
|
||||
# We don't support snapshot generation for big-endian targets,
|
||||
# therefore snapshots will need to be built using native mksnapshot
|
||||
# in combination with qemu
|
||||
v8_snapshot_toolchain = current_toolchain
|
||||
} else if (host_cpu == current_cpu) {
|
||||
# Cross-build from same ISA on one OS to another. For example:
|
||||
# * targeting win/x64 on a linux/x64 host
|
||||
# * targeting win/arm64 on a mac/arm64 host
|
||||
v8_snapshot_toolchain = host_toolchain
|
||||
} else if (host_cpu == "arm64" && current_cpu == "x64") {
|
||||
# Cross-build from arm64 to intel (likely on an Apple Silicon mac).
|
||||
v8_snapshot_toolchain =
|
||||
"//build/toolchain/${host_os}:clang_arm64_v8_$v8_current_cpu"
|
||||
} else if (host_cpu == "x64") {
|
||||
# This is a cross-compile from an x64 host to either a non-Intel target
|
||||
# cpu or to 32-bit x86 on a different target OS.
|
||||
|
||||
assert(v8_current_cpu != "x64", "handled by host_cpu == current_cpu branch")
|
||||
if (v8_current_cpu == "x86") {
|
||||
_cpus = v8_current_cpu
|
||||
} else if (v8_current_cpu == "arm64" || v8_current_cpu == "mips64el" ||
|
||||
v8_current_cpu == "riscv64" || v8_current_cpu == "loong64") {
|
||||
if (is_win && v8_current_cpu == "arm64") {
|
||||
# set _cpus to blank for Windows ARM64 so host_toolchain could be
|
||||
# selected as snapshot toolchain later.
|
||||
_cpus = ""
|
||||
} else {
|
||||
_cpus = "x64_v8_${v8_current_cpu}"
|
||||
}
|
||||
} else if (v8_current_cpu == "arm" || v8_current_cpu == "riscv32") {
|
||||
_cpus = "x86_v8_${v8_current_cpu}"
|
||||
} else {
|
||||
# This branch should not be reached; leave _cpus blank so the assert
|
||||
# below will fail.
|
||||
_cpus = ""
|
||||
}
|
||||
|
||||
if (_cpus != "") {
|
||||
v8_snapshot_toolchain = "//build/toolchain/${host_os}:clang_${_cpus}"
|
||||
} else if (is_win && v8_current_cpu == "arm64") {
|
||||
# cross compile Windows arm64 with host toolchain.
|
||||
v8_snapshot_toolchain = host_toolchain
|
||||
}
|
||||
} else if (host_cpu == "arm64" && current_cpu == "arm64" &&
|
||||
host_os == "mac") {
|
||||
# cross compile iOS arm64 with host_toolchain
|
||||
v8_snapshot_toolchain = host_toolchain
|
||||
}
|
||||
}
|
||||
|
||||
assert(v8_snapshot_toolchain != "",
|
||||
"Do not know how to build a snapshot for $current_toolchain " +
|
||||
"on $host_os $host_cpu")
|
||||
|
||||
# We reuse the snapshot toolchain for building torque and other generators to
|
||||
# avoid building v8_libbase on the host more than once. On mips with big endian,
|
||||
# the snapshot toolchain is the target toolchain and, hence, can't be used.
|
||||
v8_generator_toolchain = v8_snapshot_toolchain
|
||||
if (host_cpu == "x64" && v8_current_cpu == "mips64") {
|
||||
v8_generator_toolchain = "//build/toolchain/linux:clang_x64"
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
# Copyright 2019 the V8 project authors. All rights reserved.
|
||||
# Copyright 2016 The Chromium 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("//build/config/compiler/compiler.gni")
|
||||
|
||||
template("split_static_library") {
|
||||
assert(defined(invoker.split_count),
|
||||
"Must define split_count for split_static_library")
|
||||
|
||||
# In many conditions the number of inputs will be 1 (because the
|
||||
# count will be conditional on platform or configuration) and for
|
||||
# some build configurations it's unnecessary to split libraries
|
||||
# since the tooling will never create files of a problematic size.
|
||||
if (invoker.split_count == 1 || use_lld) {
|
||||
static_library(target_name) {
|
||||
forward_variables_from(invoker, "*")
|
||||
}
|
||||
} else {
|
||||
group_name = target_name
|
||||
|
||||
generated_static_libraries = []
|
||||
current_library_index = 0
|
||||
foreach(current_sources, split_list(invoker.sources, invoker.split_count)) {
|
||||
current_name = "${target_name}_$current_library_index"
|
||||
assert(
|
||||
current_sources != [],
|
||||
"Your values for splitting a static library generate one that has no sources.")
|
||||
generated_static_libraries += [ ":$current_name" ]
|
||||
|
||||
static_library(current_name) {
|
||||
# Generated static library shard gets everything but sources (which
|
||||
# we're redefining) and visibility (which is set to be the group
|
||||
# below).
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
[
|
||||
"check_includes",
|
||||
"sources",
|
||||
"visibility",
|
||||
])
|
||||
sources = current_sources
|
||||
visibility = [ ":$group_name" ]
|
||||
|
||||
# When splitting a target's sources up into a series of static
|
||||
# libraries, those targets will naturally include headers from each
|
||||
# other arbitrarily. We could theoretically generate a web of
|
||||
# dependencies and allow_circular_includes_from between all pairs of
|
||||
# targets, but that's very cumbersome. Typical usage in Chrome is that
|
||||
# only official Windows builds use split static libraries due to the
|
||||
# Visual Studio size limits, and this means we'll still get header
|
||||
# checking coverage for the other configurations.
|
||||
check_includes = false
|
||||
|
||||
# Uniquify the output name if one is specified.
|
||||
if (defined(invoker.output_name)) {
|
||||
output_name = "${invoker.output_name}_$current_library_index"
|
||||
}
|
||||
}
|
||||
|
||||
current_library_index = current_library_index + 1
|
||||
}
|
||||
|
||||
group(group_name) {
|
||||
public_deps = generated_static_libraries
|
||||
forward_variables_from(invoker,
|
||||
[
|
||||
"testonly",
|
||||
"visibility",
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_defaults("split_static_library") {
|
||||
configs = default_compiler_configs
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
// Copyright 2022 The V8 project authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
{
|
||||
include: [ "syslog/client.shard.cml" ],
|
||||
program: {
|
||||
runner: "elf",
|
||||
binary: "d8",
|
||||
},
|
||||
use: [
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.kernel.VmexResource",
|
||||
],
|
||||
},
|
||||
{
|
||||
storage: "tmp",
|
||||
path: "/tmp",
|
||||
},
|
||||
],
|
||||
}
|
||||
-431
@@ -1,431 +0,0 @@
|
||||
# Copyright 2016 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("//build/config/chrome_build.gni")
|
||||
import("//build/config/compiler/pgo/pgo.gni")
|
||||
import("//build/config/gclient_args.gni")
|
||||
import("//build/config/ios/config.gni")
|
||||
import("//build/config/ios/ios_sdk_overrides.gni")
|
||||
import("//build/config/sanitizers/sanitizers.gni")
|
||||
import("//build/config/v8_target_cpu.gni")
|
||||
import("//build_overrides/build.gni")
|
||||
import("release_branch_toggle.gni")
|
||||
import("split_static_library.gni")
|
||||
|
||||
declare_args() {
|
||||
# Includes files needed for correctness fuzzing.
|
||||
v8_correctness_fuzzer = false
|
||||
|
||||
# Adds additional compile target for building multiple architectures at once.
|
||||
v8_multi_arch_build = false
|
||||
|
||||
# Indicate if valgrind was fetched as a custom deps to make it available on
|
||||
# swarming.
|
||||
v8_has_valgrind = false
|
||||
|
||||
# Indicate if gcmole was fetched as a hook to make it available on swarming.
|
||||
v8_gcmole = false
|
||||
|
||||
# Turns on compiler optimizations in V8 in Debug build.
|
||||
v8_optimized_debug = true
|
||||
|
||||
# Support for backtrace_symbols on linux.
|
||||
v8_enable_backtrace = ""
|
||||
|
||||
# Use external files for startup data blobs:
|
||||
# the JS builtins sources and the start snapshot.
|
||||
v8_use_external_startup_data = ""
|
||||
|
||||
# Includes profiles to optimize builtins.
|
||||
v8_enable_builtins_optimization = ""
|
||||
|
||||
# Turns on all V8 debug features. Enables running V8 in a pseudo debug mode
|
||||
# within a release Chrome.
|
||||
v8_enable_debugging_features = is_debug
|
||||
|
||||
# Enable ECMAScript Internationalization API. Enabling this feature will
|
||||
# add a dependency on the ICU library.
|
||||
v8_enable_i18n_support = true
|
||||
|
||||
# Use static libraries instead of source_sets.
|
||||
v8_static_library = false
|
||||
|
||||
# Enable monolithic static library for embedders.
|
||||
v8_monolithic = false
|
||||
|
||||
# Expose public symbols for native modules of Node.js and Electron. Default
|
||||
# is false.
|
||||
v8_expose_public_symbols = ""
|
||||
|
||||
# Deprecated for v8_expose_public_symbols.
|
||||
v8_expose_symbols = false
|
||||
|
||||
# Implement tracing using Perfetto (https://perfetto.dev).
|
||||
v8_use_perfetto = false
|
||||
|
||||
# Override global symbol level setting for v8.
|
||||
v8_symbol_level = symbol_level
|
||||
|
||||
# Enable WebAssembly debugging via GDB-remote protocol.
|
||||
v8_enable_wasm_gdb_remote_debugging = false
|
||||
|
||||
# Lite mode disables a number of performance optimizations to reduce memory
|
||||
# at the cost of performance.
|
||||
# Sets -DV8_LITE_MODE.
|
||||
v8_enable_lite_mode = false
|
||||
|
||||
# iOS executable code pages is in 17.4 SDK. We
|
||||
# use target_os == "ios" here because it isn't equivalent
|
||||
# to is_ios (is_ios is based on host_os).
|
||||
if (target_os == "ios") {
|
||||
# TODO(dtapuska): Change this to an assert.
|
||||
v8_enable_lite_mode = ios_deployment_target != "17.4"
|
||||
}
|
||||
|
||||
# Enable the Turbofan compiler.
|
||||
# Sets -dV8_ENABLE_TURBOFAN.
|
||||
v8_enable_turbofan = ""
|
||||
|
||||
# Enable the Maglev compiler.
|
||||
# Sets -dV8_ENABLE_MAGLEV
|
||||
v8_enable_maglev = ""
|
||||
|
||||
# Include support for WebAssembly. If disabled, the 'WebAssembly' global
|
||||
# will not be available, and embedder APIs to generate WebAssembly modules
|
||||
# will fail. Also, asm.js will not be translated to WebAssembly and will be
|
||||
# executed as standard JavaScript instead.
|
||||
# Sets -dV8_ENABLE_WEBASSEMBLY.
|
||||
v8_enable_webassembly = ""
|
||||
|
||||
# Enable 256-bit long vector re-vectorization pass in WASM compilation pipeline.
|
||||
v8_enable_wasm_simd256_revec = false
|
||||
|
||||
# Enable runtime call stats.
|
||||
# TODO(liviurau): Remove old name after Chromium config update
|
||||
# https://crbug.com/1476977.
|
||||
v8_enable_runtime_call_stats =
|
||||
!(is_on_release_branch || v8_is_on_release_branch)
|
||||
|
||||
# Add fuzzilli fuzzer support.
|
||||
v8_fuzzilli = false
|
||||
|
||||
# Enable FuzzTest
|
||||
v8_enable_fuzztest = !build_with_v8_embedder &&
|
||||
!(defined(build_with_node) && build_with_node) &&
|
||||
!(is_win && is_component_build) && is_clang
|
||||
|
||||
# Scan the call stack conservatively during garbage collection.
|
||||
v8_enable_conservative_stack_scanning = false
|
||||
|
||||
# Use direct pointers in internal (direct) handles.
|
||||
v8_enable_direct_handle = ""
|
||||
|
||||
# Use direct pointers in local handles.
|
||||
v8_enable_direct_local = ""
|
||||
|
||||
# Check for off-stack allocated local handles.
|
||||
v8_enable_local_off_stack_check = false
|
||||
|
||||
v8_enable_google_benchmark = false
|
||||
|
||||
cppgc_is_standalone = false
|
||||
|
||||
# Enable object names in cppgc for profiling purposes.
|
||||
cppgc_enable_object_names = is_chrome_for_testing
|
||||
|
||||
# Enable young generation in cppgc.
|
||||
cppgc_enable_young_generation = false
|
||||
|
||||
# Enables a slim write barrier that only performs a single check in the fast
|
||||
# path and delegates all further checks to a slow path call. This is fast
|
||||
# in a setting with few slow-path checks, i.e., with disabled young generation
|
||||
# GC.
|
||||
cppgc_enable_slim_write_barrier = true
|
||||
|
||||
# Enable pointer compression in cppgc.
|
||||
cppgc_enable_pointer_compression = false
|
||||
|
||||
# Enable 2gb cage for fast compression/decompression. Currently disabled
|
||||
# due to an increased number of OOMs.
|
||||
cppgc_enable_2gb_cage = false
|
||||
|
||||
# Enable support for larger cages, up to 16GB.
|
||||
cppgc_enable_larger_cage = true
|
||||
|
||||
# Enable advanced BigInt algorithms, costing about 10-30 KB binary size
|
||||
# depending on platform. Disabled on Android to save binary size.
|
||||
v8_advanced_bigint_algorithms = !is_android
|
||||
|
||||
# TODO: macros for determining endian type are clang specific.
|
||||
v8_use_libm_trig_functions = is_clang
|
||||
|
||||
# Location of icu.
|
||||
v8_icu_path = "//third_party/icu"
|
||||
|
||||
# Location of zlib.
|
||||
v8_zlib_path = "//third_party/zlib"
|
||||
|
||||
# Change code emission and runtime features to be CET shadow-stack compliant
|
||||
# (incomplete and experimental).
|
||||
v8_enable_cet_shadow_stack = false
|
||||
|
||||
# Emit CET IBT landing pad instructions in JIT generated code (experimental).
|
||||
v8_enable_cet_ibt = false
|
||||
}
|
||||
|
||||
if (v8_use_external_startup_data == "") {
|
||||
# If not specified as a gn arg, use external startup data by default if
|
||||
# we're not on ios.
|
||||
v8_use_external_startup_data = !is_ios
|
||||
}
|
||||
|
||||
if (v8_enable_backtrace == "") {
|
||||
v8_enable_backtrace = is_debug && !v8_optimized_debug
|
||||
}
|
||||
|
||||
# Chromium is configured to use the perfetto client library, v8 should also
|
||||
# use perfetto for tracing.
|
||||
if (build_with_chromium) {
|
||||
v8_use_perfetto = true
|
||||
}
|
||||
|
||||
# Includes profiles to optimize builtins if
|
||||
# * it is a Chromium build, and
|
||||
# * Chromium builds with optimization.
|
||||
# If no profiles are downloaded during gclient runhooks, optimization fails
|
||||
# silently.
|
||||
if (v8_enable_builtins_optimization == "") {
|
||||
v8_enable_builtins_optimization = build_with_chromium && chrome_pgo_phase == 2
|
||||
}
|
||||
|
||||
# TODO(jgruber): Move v8_jitless from BUILD.gn here as these
|
||||
# all depend on each other and really should be derived from
|
||||
# v8_jitless.
|
||||
# WebAssembly is enabled by default, except in lite mode.
|
||||
if (v8_enable_webassembly == "") {
|
||||
v8_enable_webassembly = !v8_enable_lite_mode
|
||||
}
|
||||
assert(!(v8_enable_webassembly && v8_enable_lite_mode),
|
||||
"Webassembly is not available in lite mode.")
|
||||
|
||||
# Turbofan is enabled by default, except in lite mode.
|
||||
if (v8_enable_turbofan == "") {
|
||||
v8_enable_turbofan = !v8_enable_lite_mode
|
||||
}
|
||||
assert(v8_enable_turbofan || !v8_enable_webassembly,
|
||||
"Webassembly is not available when Turbofan is disabled.")
|
||||
|
||||
# Direct internal handles and direct locals are enabled by default if
|
||||
# conservative stack scanning is enabled.
|
||||
if (v8_enable_direct_handle == "") {
|
||||
v8_enable_direct_handle = v8_enable_conservative_stack_scanning
|
||||
}
|
||||
if (v8_enable_direct_local == "") {
|
||||
v8_enable_direct_local = v8_enable_conservative_stack_scanning
|
||||
}
|
||||
|
||||
# Points to // in v8 stand-alone or to //v8/ in chromium. We need absolute
|
||||
# paths for all configs in templates as they are shared in different
|
||||
# subdirectories.
|
||||
v8_path_prefix = get_path_info("../", "abspath")
|
||||
|
||||
v8_inspector_js_protocol = v8_path_prefix + "/include/js_protocol.pdl"
|
||||
|
||||
###############################################################################
|
||||
# Templates
|
||||
#
|
||||
|
||||
# Common configs to remove or add in all v8 targets.
|
||||
v8_remove_configs = []
|
||||
v8_add_configs = [
|
||||
v8_path_prefix + ":features",
|
||||
v8_path_prefix + ":toolchain",
|
||||
v8_path_prefix + ":strict_warnings",
|
||||
]
|
||||
|
||||
if (is_debug && !v8_optimized_debug) {
|
||||
v8_remove_configs += [ "//build/config/compiler:default_optimization" ]
|
||||
v8_add_configs += [ "//build/config/compiler:no_optimize" ]
|
||||
} else {
|
||||
v8_remove_configs += [ "//build/config/compiler:default_optimization" ]
|
||||
|
||||
# TODO(crbug.com/621335) Rework this so that we don't have the confusion
|
||||
# between "optimize_speed" and "optimize_max".
|
||||
if (((is_posix && !is_android) || is_win) && !using_sanitizer) {
|
||||
v8_add_configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
} else {
|
||||
v8_add_configs += [ "//build/config/compiler:optimize_max" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_debug) {
|
||||
v8_remove_configs += [
|
||||
# Too much performance impact, unclear security benefit.
|
||||
"//build/config/compiler:default_init_stack_vars",
|
||||
]
|
||||
}
|
||||
|
||||
if (v8_symbol_level != symbol_level) {
|
||||
v8_remove_configs += [ "//build/config/compiler:default_symbols" ]
|
||||
if (v8_symbol_level == 0) {
|
||||
v8_add_configs += [ "//build/config/compiler:no_symbols" ]
|
||||
} else if (v8_symbol_level == 1) {
|
||||
v8_add_configs += [ "//build/config/compiler:minimal_symbols" ]
|
||||
} else if (v8_symbol_level == 2) {
|
||||
v8_add_configs += [ "//build/config/compiler:symbols" ]
|
||||
} else {
|
||||
assert(false)
|
||||
}
|
||||
}
|
||||
|
||||
if ((is_posix || is_fuchsia) && (v8_enable_backtrace || v8_monolithic)) {
|
||||
v8_remove_configs += [ "//build/config/gcc:symbol_visibility_hidden" ]
|
||||
v8_add_configs += [ "//build/config/gcc:symbol_visibility_default" ]
|
||||
}
|
||||
|
||||
# On MIPS gcc_target_rpath and ldso_path might be needed for all builds.
|
||||
if (target_cpu == "mips64el" || target_cpu == "mips64") {
|
||||
v8_add_configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
|
||||
}
|
||||
|
||||
if (!build_with_chromium && is_clang) {
|
||||
v8_remove_configs += [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
|
||||
# All templates should be kept in sync.
|
||||
template("v8_source_set") {
|
||||
if (defined(invoker.split_count) && invoker.split_count > 1 &&
|
||||
defined(v8_static_library) && v8_static_library && is_win) {
|
||||
link_target_type = "split_static_library"
|
||||
} else if (defined(v8_static_library) && v8_static_library) {
|
||||
link_target_type = "static_library"
|
||||
} else {
|
||||
link_target_type = "source_set"
|
||||
}
|
||||
target(link_target_type, target_name) {
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
[
|
||||
"configs",
|
||||
"remove_configs",
|
||||
])
|
||||
configs -= v8_remove_configs
|
||||
configs += v8_add_configs
|
||||
if (defined(invoker.remove_configs)) {
|
||||
configs -= invoker.remove_configs
|
||||
}
|
||||
configs += invoker.configs
|
||||
}
|
||||
}
|
||||
|
||||
template("v8_header_set") {
|
||||
source_set(target_name) {
|
||||
forward_variables_from(invoker, "*", [ "configs" ])
|
||||
configs -= v8_remove_configs
|
||||
configs += v8_add_configs
|
||||
configs += invoker.configs
|
||||
}
|
||||
}
|
||||
|
||||
template("v8_executable") {
|
||||
if (is_ios) {
|
||||
import("//build/config/ios/rules.gni")
|
||||
|
||||
ios_app_bundle(target_name) {
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
[
|
||||
"configs",
|
||||
"remove_configs",
|
||||
])
|
||||
configs -= v8_remove_configs
|
||||
configs += v8_add_configs
|
||||
if (defined(invoker.remove_configs)) {
|
||||
configs -= invoker.remove_configs
|
||||
}
|
||||
configs += invoker.configs
|
||||
deps += [ v8_path_prefix + ":v8_dump_build_config" ]
|
||||
|
||||
# Provide sensible defaults in case invoker did not define any of those
|
||||
# required variables.
|
||||
if (!defined(info_plist) && !defined(info_plist_target)) {
|
||||
info_plist = v8_path_prefix + "/gni/Info.plist"
|
||||
}
|
||||
|
||||
bundle_identifier = "$ios_app_bundle_id_prefix.chrome.unittests.dev"
|
||||
}
|
||||
} else {
|
||||
executable(target_name) {
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
[
|
||||
"configs",
|
||||
"remove_configs",
|
||||
])
|
||||
configs -= v8_remove_configs
|
||||
configs += v8_add_configs
|
||||
if (defined(invoker.remove_configs)) {
|
||||
configs -= invoker.remove_configs
|
||||
}
|
||||
configs += invoker.configs
|
||||
if (is_linux || is_chromeos) {
|
||||
# For enabling ASLR.
|
||||
ldflags = [ "-pie" ]
|
||||
}
|
||||
deps += [ v8_path_prefix + ":v8_dump_build_config" ]
|
||||
|
||||
if (is_win && !v8_enable_cet_shadow_stack) {
|
||||
configs -= [ "//build/config/compiler:cet_shadow_stack" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template("v8_component") {
|
||||
component(target_name) {
|
||||
output_name = target_name
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
[
|
||||
"configs",
|
||||
"remove_configs",
|
||||
])
|
||||
configs -= v8_remove_configs
|
||||
configs += v8_add_configs
|
||||
if (defined(invoker.remove_configs)) {
|
||||
configs -= invoker.remove_configs
|
||||
}
|
||||
configs += invoker.configs
|
||||
}
|
||||
}
|
||||
|
||||
template("v8_shared_library") {
|
||||
shared_library(target_name) {
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
[
|
||||
"configs",
|
||||
"remove_configs",
|
||||
])
|
||||
configs -= v8_remove_configs
|
||||
configs += v8_add_configs
|
||||
if (defined(invoker.remove_configs)) {
|
||||
configs -= invoker.remove_configs
|
||||
}
|
||||
if (defined(invoker.configs)) {
|
||||
configs += invoker.configs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template("v8_static_library") {
|
||||
static_library(target_name) {
|
||||
complete_static_lib = true
|
||||
forward_variables_from(invoker, "*", [ "configs" ])
|
||||
configs -= v8_remove_configs
|
||||
configs -= [ "//build/config/compiler:thin_archive" ]
|
||||
configs += v8_add_configs
|
||||
configs += invoker.configs
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
# The V8 public C++ API
|
||||
|
||||
# Overview
|
||||
|
||||
The V8 public C++ API aims to support four use cases:
|
||||
|
||||
1. Enable applications that embed V8 (called the embedder) to configure and run
|
||||
one or more instances of V8.
|
||||
2. Expose ECMAScript-like capabilities to the embedder.
|
||||
3. Enable the embedder to interact with ECMAScript by exposing API objects.
|
||||
4. Provide access to the V8 debugger (inspector).
|
||||
|
||||
# Configuring and running an instance of V8
|
||||
|
||||
V8 requires access to certain OS-level primitives such as the ability to
|
||||
schedule work on threads, or allocate memory.
|
||||
|
||||
The embedder can define how to access those primitives via the v8::Platform
|
||||
interface. While V8 bundles a basic implementation, embedders are highly
|
||||
encouraged to implement v8::Platform themselves.
|
||||
|
||||
Currently, the v8::ArrayBuffer::Allocator is passed to the v8::Isolate factory
|
||||
method, however, conceptually it should also be part of the v8::Platform since
|
||||
all instances of V8 should share one allocator.
|
||||
|
||||
Once the v8::Platform is configured, an v8::Isolate can be created. All
|
||||
further interactions with V8 should explicitly reference the v8::Isolate they
|
||||
refer to. All API methods should eventually take an v8::Isolate parameter.
|
||||
|
||||
When a given instance of V8 is no longer needed, it can be destroyed by
|
||||
disposing the respective v8::Isolate. If the embedder wishes to free all memory
|
||||
associated with the v8::Isolate, it has to first clear all global handles
|
||||
associated with that v8::Isolate.
|
||||
|
||||
# ECMAScript-like capabilities
|
||||
|
||||
In general, the C++ API shouldn't enable capabilities that aren't available to
|
||||
scripts running in V8. Experience has shown that it's not possible to maintain
|
||||
such API methods in the long term. However, capabilities also available to
|
||||
scripts, i.e., ones that are defined in the ECMAScript standard are there to
|
||||
stay, and we can safely expose them to embedders.
|
||||
|
||||
The C++ API should also be pleasant to use, and not require learning new
|
||||
paradigms. Similarly to how the API exposed to scripts aims to provide good
|
||||
ergonomics, we should aim to provide a reasonable developer experience for this
|
||||
API surface.
|
||||
|
||||
ECMAScript makes heavy use of exceptions, however, V8's C++ code doesn't use
|
||||
C++ exceptions. Therefore, all API methods that can throw exceptions should
|
||||
indicate so by returning a v8::Maybe<> or v8::MaybeLocal<> result,
|
||||
and by taking a v8::Local<v8::Context> parameter that indicates in which
|
||||
context a possible exception should be thrown.
|
||||
|
||||
# API objects
|
||||
|
||||
V8 allows embedders to define special objects that expose additional
|
||||
capabilities and APIs to scripts. The most prominent example is exposing the
|
||||
HTML DOM in Blink. Other examples are e.g. node.js. It is less clear what kind
|
||||
of capabilities we want to expose via this API surface. As a rule of thumb, we
|
||||
want to expose operations as defined in the WebIDL and HTML spec: we
|
||||
assume that those requirements are somewhat stable, and that they are a
|
||||
superset of the requirements of other embedders including node.js.
|
||||
|
||||
Ideally, the API surfaces defined in those specs hook into the ECMAScript spec
|
||||
which in turn guarantees long-term stability of the API.
|
||||
|
||||
# The V8 inspector
|
||||
|
||||
All debugging capabilities of V8 should be exposed via the inspector protocol.
|
||||
The exception to this are profiling features exposed via v8-profiler.h.
|
||||
Changes to the inspector protocol need to ensure backwards compatibility and
|
||||
commitment to maintain.
|
||||
@@ -1,10 +0,0 @@
|
||||
include_rules = [
|
||||
# v8-inspector-protocol.h depends on generated files under include/inspector.
|
||||
"+inspector",
|
||||
"+cppgc/common.h",
|
||||
# Used by v8-cppgc.h to bridge to cppgc.
|
||||
"+cppgc/custom-space.h",
|
||||
"+cppgc/heap-statistics.h",
|
||||
"+cppgc/internal/write-barrier.h",
|
||||
"+cppgc/visitor.h",
|
||||
]
|
||||
@@ -1,11 +0,0 @@
|
||||
# Metadata information for this directory.
|
||||
#
|
||||
# For more information on DIR_METADATA files, see:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
|
||||
#
|
||||
# For the schema of this file, see Metadata message:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
|
||||
|
||||
monorail {
|
||||
component: "Blink>JavaScript>API"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
adamk@chromium.org
|
||||
cbruni@chromium.org
|
||||
leszeks@chromium.org
|
||||
mlippautz@chromium.org
|
||||
verwaest@chromium.org
|
||||
yangguo@chromium.org
|
||||
|
||||
per-file *DEPS=file:../COMMON_OWNERS
|
||||
per-file v8-internal.h=file:../COMMON_OWNERS
|
||||
|
||||
per-file v8-debug.h=file:../src/debug/OWNERS
|
||||
|
||||
per-file js_protocol.pdl=file:../src/inspector/OWNERS
|
||||
per-file v8-inspector*=file:../src/inspector/OWNERS
|
||||
per-file v8-inspector*=file:../src/inspector/OWNERS
|
||||
|
||||
# Needed by the auto_tag builder
|
||||
per-file v8-version.h=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com
|
||||
|
||||
# For branch updates:
|
||||
per-file v8-version.h=file:../INFRA_OWNERS
|
||||
per-file v8-version.h=hablich@chromium.org
|
||||
per-file v8-version.h=vahl@chromium.org
|
||||
@@ -1,9 +0,0 @@
|
||||
include_rules = [
|
||||
"-include",
|
||||
"+v8config.h",
|
||||
"+v8-platform.h",
|
||||
"+v8-source-location.h",
|
||||
"+cppgc",
|
||||
"-src",
|
||||
"+libplatform/libplatform.h",
|
||||
]
|
||||
@@ -1,2 +0,0 @@
|
||||
bikineev@chromium.org
|
||||
omerkatz@chromium.org
|
||||
@@ -1,135 +0,0 @@
|
||||
# Oilpan: C++ Garbage Collection
|
||||
|
||||
Oilpan is an open-source garbage collection library for C++ that can be used stand-alone or in collaboration with V8's JavaScript garbage collector.
|
||||
Oilpan implements mark-and-sweep garbage collection (GC) with limited compaction (for a subset of objects).
|
||||
|
||||
**Key properties**
|
||||
|
||||
- Trace-based garbage collection;
|
||||
- Incremental and concurrent marking;
|
||||
- Incremental and concurrent sweeping;
|
||||
- Precise on-heap memory layout;
|
||||
- Conservative on-stack memory layout;
|
||||
- Allows for collection with and without considering stack;
|
||||
- Non-incremental and non-concurrent compaction for selected spaces;
|
||||
|
||||
See the [Hello World](https://chromium.googlesource.com/v8/v8/+/main/samples/cppgc/hello-world.cc) example on how to get started using Oilpan to manage C++ code.
|
||||
|
||||
Oilpan follows V8's project organization, see e.g. on how we accept [contributions](https://v8.dev/docs/contribute) and [provide a stable API](https://v8.dev/docs/api).
|
||||
|
||||
## Threading model
|
||||
|
||||
Oilpan features thread-local garbage collection and assumes heaps are not shared among threads.
|
||||
In other words, objects are accessed and ultimately reclaimed by the garbage collector on the same thread that allocates them.
|
||||
This allows Oilpan to run garbage collection in parallel with mutators running in other threads.
|
||||
|
||||
References to objects belonging to another thread's heap are modeled using cross-thread roots.
|
||||
This is even true for on-heap to on-heap references.
|
||||
|
||||
Oilpan heaps may generally not be accessed from different threads unless otherwise noted.
|
||||
|
||||
## Heap partitioning
|
||||
|
||||
Oilpan's heaps are partitioned into spaces.
|
||||
The space for an object is chosen depending on a number of criteria, e.g.:
|
||||
|
||||
- Objects over 64KiB are allocated in a large object space
|
||||
- Objects can be assigned to a dedicated custom space.
|
||||
Custom spaces can also be marked as compactable.
|
||||
- Other objects are allocated in one of the normal page spaces bucketed depending on their size.
|
||||
|
||||
## Precise and conservative garbage collection
|
||||
|
||||
Oilpan supports two kinds of GCs:
|
||||
|
||||
1. **Conservative GC.**
|
||||
A GC is called conservative when it is executed while the regular native stack is not empty.
|
||||
In this case, the native stack might contain references to objects in Oilpan's heap, which should be kept alive.
|
||||
The GC scans the native stack and treats the pointers discovered via the native stack as part of the root set.
|
||||
This kind of GC is considered imprecise because values on stack other than references may accidentally appear as references to on-heap object, which means these objects will be kept alive despite being in practice unreachable from the application as an actual reference.
|
||||
|
||||
2. **Precise GC.**
|
||||
A precise GC is triggered at the end of an event loop, which is controlled by an embedder via a platform.
|
||||
At this point, it is guaranteed that there are no on-stack references pointing to Oilpan's heap.
|
||||
This means there is no risk of confusing other value types with references.
|
||||
Oilpan has precise knowledge of on-heap object layouts, and so it knows exactly where pointers lie in memory.
|
||||
Oilpan can just start marking from the regular root set and collect all garbage precisely.
|
||||
|
||||
## Atomic, incremental and concurrent garbage collection
|
||||
|
||||
Oilpan has three modes of operation:
|
||||
|
||||
1. **Atomic GC.**
|
||||
The entire GC cycle, including all its phases (e.g. see [Marking](#Marking-phase) and [Sweeping](#Sweeping-phase)), are executed back to back in a single pause.
|
||||
This mode of operation is also known as Stop-The-World (STW) garbage collection.
|
||||
It results in the most jank (due to a single long pause), but is overall the most efficient (e.g. no need for write barriers).
|
||||
|
||||
2. **Incremental GC.**
|
||||
Garbage collection work is split up into multiple steps which are interleaved with the mutator, i.e. user code chunked into tasks.
|
||||
Each step is a small chunk of work that is executed either as dedicated tasks between mutator tasks or, as needed, during mutator tasks.
|
||||
Using incremental GC introduces the need for write barriers that record changes to the object graph so that a consistent state is observed and no objects are accidentally considered dead and reclaimed.
|
||||
The incremental steps are followed by a smaller atomic pause to finalize garbage collection.
|
||||
The smaller pause times, due to smaller chunks of work, helps with reducing jank.
|
||||
|
||||
3. **Concurrent GC.**
|
||||
This is the most common type of GC.
|
||||
It builds on top of incremental GC and offloads much of the garbage collection work away from the mutator thread and on to background threads.
|
||||
Using concurrent GC allows the mutator thread to spend less time on GC and more on the actual mutator.
|
||||
|
||||
## Marking phase
|
||||
|
||||
The marking phase consists of the following steps:
|
||||
|
||||
1. Mark all objects in the root set.
|
||||
|
||||
2. Mark all objects transitively reachable from the root set by calling `Trace()` methods defined on each object.
|
||||
|
||||
3. Clear out all weak handles to unreachable objects and run weak callbacks.
|
||||
|
||||
The marking phase can be executed atomically in a stop-the-world manner, in which all 3 steps are executed one after the other.
|
||||
|
||||
Alternatively, it can also be executed incrementally/concurrently.
|
||||
With incremental/concurrent marking, step 1 is executed in a short pause after which the mutator regains control.
|
||||
Step 2 is repeatedly executed in an interleaved manner with the mutator.
|
||||
When the GC is ready to finalize, i.e. step 2 is (almost) finished, another short pause is triggered in which step 2 is finished and step 3 is performed.
|
||||
|
||||
To prevent a user-after-free (UAF) issues it is required for Oilpan to know about all edges in the object graph.
|
||||
This means that all pointers except on-stack pointers must be wrapped with Oilpan's handles (i.e., Persistent<>, Member<>, WeakMember<>).
|
||||
Raw pointers to on-heap objects create an edge that Oilpan cannot observe and cause UAF issues
|
||||
Thus, raw pointers shall not be used to reference on-heap objects (except for raw pointers on native stacks).
|
||||
|
||||
## Sweeping phase
|
||||
|
||||
The sweeping phase consists of the following steps:
|
||||
|
||||
1. Invoke pre-finalizers.
|
||||
At this point, no destructors have been invoked and no memory has been reclaimed.
|
||||
Pre-finalizers are allowed to access any other on-heap objects, even those that may get destructed.
|
||||
|
||||
2. Sweeping invokes destructors of the dead (unreachable) objects and reclaims memory to be reused by future allocations.
|
||||
|
||||
Assumptions should not be made about the order and the timing of their execution.
|
||||
There is no guarantee on the order in which the destructors are invoked.
|
||||
That's why destructors must not access any other on-heap objects (which might have already been destructed).
|
||||
If some destructor unavoidably needs to access other on-heap objects, it will have to be converted to a pre-finalizer.
|
||||
The pre-finalizer is allowed to access other on-heap objects.
|
||||
|
||||
The mutator is resumed before all destructors have ran.
|
||||
For example, imagine a case where X is a client of Y, and Y holds a list of clients.
|
||||
If the code relies on X's destructor removing X from the list, there is a risk that Y iterates the list and calls some method of X which may touch other on-heap objects.
|
||||
This causes a use-after-free.
|
||||
Care must be taken to make sure that X is explicitly removed from the list before the mutator resumes its execution in a way that doesn't rely on X's destructor (e.g. a pre-finalizer).
|
||||
|
||||
Similar to marking, sweeping can be executed in either an atomic stop-the-world manner or incrementally/concurrently.
|
||||
With incremental/concurrent sweeping, step 2 is interleaved with mutator.
|
||||
Incremental/concurrent sweeping can be atomically finalized in case it is needed to trigger another GC cycle.
|
||||
Even with concurrent sweeping, destructors are guaranteed to run on the thread the object has been allocated on to preserve C++ semantics.
|
||||
|
||||
Notes:
|
||||
|
||||
* Weak processing runs only when the holder object of the WeakMember outlives the pointed object.
|
||||
If the holder object and the pointed object die at the same time, weak processing doesn't run.
|
||||
It is wrong to write code assuming that the weak processing always runs.
|
||||
|
||||
* Pre-finalizers are heavy because the thread needs to scan all pre-finalizers at each sweeping phase to determine which pre-finalizers should be invoked (the thread needs to invoke pre-finalizers of dead objects).
|
||||
Adding pre-finalizers to frequently created objects should be avoided.
|
||||
@@ -1,309 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_ALLOCATION_H_
|
||||
#define INCLUDE_CPPGC_ALLOCATION_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "cppgc/custom-space.h"
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/gc-info.h"
|
||||
#include "cppgc/type-traits.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(assume_aligned)
|
||||
#define CPPGC_DEFAULT_ALIGNED \
|
||||
__attribute__((assume_aligned(api_constants::kDefaultAlignment)))
|
||||
#define CPPGC_DOUBLE_WORD_ALIGNED \
|
||||
__attribute__((assume_aligned(2 * api_constants::kDefaultAlignment)))
|
||||
#endif // __has_attribute(assume_aligned)
|
||||
#endif // defined(__has_attribute)
|
||||
|
||||
#if !defined(CPPGC_DEFAULT_ALIGNED)
|
||||
#define CPPGC_DEFAULT_ALIGNED
|
||||
#endif
|
||||
|
||||
#if !defined(CPPGC_DOUBLE_WORD_ALIGNED)
|
||||
#define CPPGC_DOUBLE_WORD_ALIGNED
|
||||
#endif
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* AllocationHandle is used to allocate garbage-collected objects.
|
||||
*/
|
||||
class AllocationHandle;
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Similar to C++17 std::align_val_t;
|
||||
enum class AlignVal : size_t {};
|
||||
|
||||
class MakeGarbageCollectedTraitInternal {
|
||||
protected:
|
||||
static inline void MarkObjectAsFullyConstructed(const void* payload) {
|
||||
// See api_constants for an explanation of the constants.
|
||||
std::atomic<uint16_t>* atomic_mutable_bitfield =
|
||||
reinterpret_cast<std::atomic<uint16_t>*>(
|
||||
const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
|
||||
reinterpret_cast<const uint8_t*>(payload) -
|
||||
api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
|
||||
// It's safe to split use load+store here (instead of a read-modify-write
|
||||
// operation), since it's guaranteed that this 16-bit bitfield is only
|
||||
// modified by a single thread. This is cheaper in terms of code bloat (on
|
||||
// ARM) and performance.
|
||||
uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed);
|
||||
value |= api_constants::kFullyConstructedBitMask;
|
||||
atomic_mutable_bitfield->store(value, std::memory_order_release);
|
||||
}
|
||||
|
||||
// Dispatch based on compile-time information.
|
||||
//
|
||||
// Default implementation is for a custom space with >`kDefaultAlignment` byte
|
||||
// alignment.
|
||||
template <typename GCInfoType, typename CustomSpace, size_t alignment>
|
||||
struct AllocationDispatcher final {
|
||||
static void* Invoke(AllocationHandle& handle, size_t size) {
|
||||
static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
|
||||
"Custom space must inherit from CustomSpaceBase.");
|
||||
static_assert(
|
||||
!CustomSpace::kSupportsCompaction,
|
||||
"Custom spaces that support compaction do not support allocating "
|
||||
"objects with non-default (i.e. word-sized) alignment.");
|
||||
return MakeGarbageCollectedTraitInternal::Allocate(
|
||||
handle, size, static_cast<AlignVal>(alignment),
|
||||
internal::GCInfoTrait<GCInfoType>::Index(), CustomSpace::kSpaceIndex);
|
||||
}
|
||||
};
|
||||
|
||||
// Fast path for regular allocations for the default space with
|
||||
// `kDefaultAlignment` byte alignment.
|
||||
template <typename GCInfoType>
|
||||
struct AllocationDispatcher<GCInfoType, void,
|
||||
api_constants::kDefaultAlignment>
|
||||
final {
|
||||
static void* Invoke(AllocationHandle& handle, size_t size) {
|
||||
return MakeGarbageCollectedTraitInternal::Allocate(
|
||||
handle, size, internal::GCInfoTrait<GCInfoType>::Index());
|
||||
}
|
||||
};
|
||||
|
||||
// Default space with >`kDefaultAlignment` byte alignment.
|
||||
template <typename GCInfoType, size_t alignment>
|
||||
struct AllocationDispatcher<GCInfoType, void, alignment> final {
|
||||
static void* Invoke(AllocationHandle& handle, size_t size) {
|
||||
return MakeGarbageCollectedTraitInternal::Allocate(
|
||||
handle, size, static_cast<AlignVal>(alignment),
|
||||
internal::GCInfoTrait<GCInfoType>::Index());
|
||||
}
|
||||
};
|
||||
|
||||
// Custom space with `kDefaultAlignment` byte alignment.
|
||||
template <typename GCInfoType, typename CustomSpace>
|
||||
struct AllocationDispatcher<GCInfoType, CustomSpace,
|
||||
api_constants::kDefaultAlignment>
|
||||
final {
|
||||
static void* Invoke(AllocationHandle& handle, size_t size) {
|
||||
static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
|
||||
"Custom space must inherit from CustomSpaceBase.");
|
||||
return MakeGarbageCollectedTraitInternal::Allocate(
|
||||
handle, size, internal::GCInfoTrait<GCInfoType>::Index(),
|
||||
CustomSpace::kSpaceIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
V8_EXPORT static void* CPPGC_DEFAULT_ALIGNED
|
||||
Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex);
|
||||
V8_EXPORT static void* CPPGC_DOUBLE_WORD_ALIGNED
|
||||
Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex);
|
||||
V8_EXPORT static void* CPPGC_DEFAULT_ALIGNED
|
||||
Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex);
|
||||
V8_EXPORT static void* CPPGC_DOUBLE_WORD_ALIGNED
|
||||
Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
|
||||
CustomSpaceIndex);
|
||||
|
||||
friend class HeapObjectHeader;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Base trait that provides utilities for advancers users that have custom
|
||||
* allocation needs (e.g., overriding size). It's expected that users override
|
||||
* MakeGarbageCollectedTrait (see below) and inherit from
|
||||
* MakeGarbageCollectedTraitBase and make use of the low-level primitives
|
||||
* offered to allocate and construct an object.
|
||||
*/
|
||||
template <typename T>
|
||||
class MakeGarbageCollectedTraitBase
|
||||
: private internal::MakeGarbageCollectedTraitInternal {
|
||||
private:
|
||||
static_assert(internal::IsGarbageCollectedType<T>::value,
|
||||
"T needs to be a garbage collected object");
|
||||
static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
|
||||
sizeof(T) <=
|
||||
internal::api_constants::kLargeObjectSizeThreshold,
|
||||
"GarbageCollectedMixin may not be a large object");
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Allocates memory for an object of type T.
|
||||
*
|
||||
* \param handle AllocationHandle identifying the heap to allocate the object
|
||||
* on.
|
||||
* \param size The size that should be reserved for the object.
|
||||
* \returns the memory to construct an object of type T on.
|
||||
*/
|
||||
V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
|
||||
static_assert(
|
||||
std::is_base_of<typename T::ParentMostGarbageCollectedType, T>::value,
|
||||
"U of GarbageCollected<U> must be a base of T. Check "
|
||||
"GarbageCollected<T> base class inheritance.");
|
||||
static constexpr size_t kWantedAlignment =
|
||||
alignof(T) < internal::api_constants::kDefaultAlignment
|
||||
? internal::api_constants::kDefaultAlignment
|
||||
: alignof(T);
|
||||
static_assert(
|
||||
kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
|
||||
"Requested alignment larger than alignof(std::max_align_t) bytes. "
|
||||
"Please file a bug to possibly get this restriction lifted.");
|
||||
return AllocationDispatcher<
|
||||
typename internal::GCInfoFolding<
|
||||
T, typename T::ParentMostGarbageCollectedType>::ResultType,
|
||||
typename SpaceTrait<T>::Space, kWantedAlignment>::Invoke(handle, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks an object as fully constructed, resulting in precise handling by the
|
||||
* garbage collector.
|
||||
*
|
||||
* \param payload The base pointer the object is allocated at.
|
||||
*/
|
||||
V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
|
||||
internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
|
||||
payload);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Passed to MakeGarbageCollected to specify how many bytes should be appended
|
||||
* to the allocated object.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* class InlinedArray final : public GarbageCollected<InlinedArray> {
|
||||
* public:
|
||||
* explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
|
||||
* void Trace(Visitor*) const {}
|
||||
|
||||
* size_t size;
|
||||
* char* byte_array;
|
||||
* };
|
||||
*
|
||||
* auto* inlined_array = MakeGarbageCollected<InlinedArray(
|
||||
* GetAllocationHandle(), AdditionalBytes(4), 4);
|
||||
* for (size_t i = 0; i < 4; i++) {
|
||||
* Process(inlined_array->byte_array[i]);
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
struct AdditionalBytes {
|
||||
constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
|
||||
const size_t value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default trait class that specifies how to construct an object of type T.
|
||||
* Advanced users may override how an object is constructed using the utilities
|
||||
* that are provided through MakeGarbageCollectedTraitBase.
|
||||
*
|
||||
* Any trait overriding construction must
|
||||
* - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
|
||||
* - mark the object as fully constructed using
|
||||
* `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
|
||||
*/
|
||||
template <typename T>
|
||||
class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
static T* Call(AllocationHandle& handle, Args&&... args) {
|
||||
void* memory =
|
||||
MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
|
||||
T* object = ::new (memory) T(std::forward<Args>(args)...);
|
||||
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
|
||||
Args&&... args) {
|
||||
void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
|
||||
handle, sizeof(T) + additional_bytes.value);
|
||||
T* object = ::new (memory) T(std::forward<Args>(args)...);
|
||||
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
|
||||
return object;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allows users to specify a post-construction callback for specific types. The
|
||||
* callback is invoked on the instance of type T right after it has been
|
||||
* constructed. This can be useful when the callback requires a
|
||||
* fully-constructed object to be able to dispatch to virtual methods.
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct PostConstructionCallbackTrait {
|
||||
static void Call(T*) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a managed object of type T where T transitively inherits from
|
||||
* GarbageCollected.
|
||||
*
|
||||
* \param args List of arguments with which an instance of T will be
|
||||
* constructed.
|
||||
* \returns an instance of type T.
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
|
||||
T* object =
|
||||
MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
|
||||
PostConstructionCallbackTrait<T>::Call(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a managed object of type T where T transitively inherits from
|
||||
* GarbageCollected. Created objects will have additional bytes appended to
|
||||
* it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
|
||||
*
|
||||
* \param additional_bytes Denotes how many bytes to append to T.
|
||||
* \param args List of arguments with which an instance of T will be
|
||||
* constructed.
|
||||
* \returns an instance of type T.
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
|
||||
AdditionalBytes additional_bytes,
|
||||
Args&&... args) {
|
||||
T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
|
||||
std::forward<Args>(args)...);
|
||||
PostConstructionCallbackTrait<T>::Call(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#undef CPPGC_DEFAULT_ALIGNED
|
||||
#undef CPPGC_DOUBLE_WORD_ALIGNED
|
||||
|
||||
#endif // INCLUDE_CPPGC_ALLOCATION_H_
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_COMMON_H_
|
||||
#define INCLUDE_CPPGC_COMMON_H_
|
||||
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* Indicator for the stack state of the embedder.
|
||||
*/
|
||||
enum class EmbedderStackState {
|
||||
/**
|
||||
* Stack may contain interesting heap pointers.
|
||||
*/
|
||||
kMayContainHeapPointers,
|
||||
/**
|
||||
* Stack does not contain any interesting heap pointers.
|
||||
*/
|
||||
kNoHeapPointers,
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_COMMON_H_
|
||||
@@ -1,466 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
|
||||
#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "cppgc/internal/persistent-node.h"
|
||||
#include "cppgc/internal/pointer-policies.h"
|
||||
#include "cppgc/persistent.h"
|
||||
#include "cppgc/visitor.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
// Wrapper around PersistentBase that allows accessing poisoned memory when
|
||||
// using ASAN. This is needed as the GC of the heap that owns the value
|
||||
// of a CTP, may clear it (heap termination, weakness) while the object
|
||||
// holding the CTP may be poisoned as itself may be deemed dead.
|
||||
class CrossThreadPersistentBase : public PersistentBase {
|
||||
public:
|
||||
CrossThreadPersistentBase() = default;
|
||||
explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {}
|
||||
|
||||
V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const {
|
||||
return raw_;
|
||||
}
|
||||
|
||||
V8_CLANG_NO_SANITIZE("address")
|
||||
PersistentNode* GetNodeFromGC() const { return node_; }
|
||||
|
||||
V8_CLANG_NO_SANITIZE("address")
|
||||
void ClearFromGC() const {
|
||||
raw_ = nullptr;
|
||||
SetNodeSafe(nullptr);
|
||||
}
|
||||
|
||||
// GetNodeSafe() can be used for a thread-safe IsValid() check in a
|
||||
// double-checked locking pattern. See ~BasicCrossThreadPersistent.
|
||||
PersistentNode* GetNodeSafe() const {
|
||||
return reinterpret_cast<std::atomic<PersistentNode*>*>(&node_)->load(
|
||||
std::memory_order_acquire);
|
||||
}
|
||||
|
||||
// The GC writes using SetNodeSafe() while holding the lock.
|
||||
V8_CLANG_NO_SANITIZE("address")
|
||||
void SetNodeSafe(PersistentNode* value) const {
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define V8_IS_ASAN 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef V8_IS_ASAN
|
||||
__atomic_store(&node_, &value, __ATOMIC_RELEASE);
|
||||
#else // !V8_IS_ASAN
|
||||
// Non-ASAN builds can use atomics. This also covers MSVC which does not
|
||||
// have the __atomic_store intrinsic.
|
||||
reinterpret_cast<std::atomic<PersistentNode*>*>(&node_)->store(
|
||||
value, std::memory_order_release);
|
||||
#endif // !V8_IS_ASAN
|
||||
|
||||
#undef V8_IS_ASAN
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
|
||||
typename CheckingPolicy>
|
||||
class BasicCrossThreadPersistent final : public CrossThreadPersistentBase,
|
||||
public LocationPolicy,
|
||||
private WeaknessPolicy,
|
||||
private CheckingPolicy {
|
||||
public:
|
||||
using typename WeaknessPolicy::IsStrongPersistent;
|
||||
using PointeeType = T;
|
||||
|
||||
~BasicCrossThreadPersistent() {
|
||||
// This implements fast path for destroying empty/sentinel.
|
||||
//
|
||||
// Simplified version of `AssignUnsafe()` to allow calling without a
|
||||
// complete type `T`. Uses double-checked locking with a simple thread-safe
|
||||
// check for a valid handle based on a node.
|
||||
if (GetNodeSafe()) {
|
||||
PersistentRegionLock guard;
|
||||
const void* old_value = GetValue();
|
||||
// The fast path check (GetNodeSafe()) does not acquire the lock. Recheck
|
||||
// validity while holding the lock to ensure the reference has not been
|
||||
// cleared.
|
||||
if (IsValid(old_value)) {
|
||||
CrossThreadPersistentRegion& region =
|
||||
this->GetPersistentRegion(old_value);
|
||||
region.FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
} else {
|
||||
CPPGC_DCHECK(!GetNode());
|
||||
}
|
||||
}
|
||||
// No need to call SetValue() as the handle is not used anymore. This can
|
||||
// leave behind stale sentinel values but will always destroy the underlying
|
||||
// node.
|
||||
}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: LocationPolicy(loc) {}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
std::nullptr_t, const SourceLocation& loc = SourceLocation::Current())
|
||||
: LocationPolicy(loc) {}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
|
||||
: CrossThreadPersistentBase(s), LocationPolicy(loc) {}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
T* raw, const SourceLocation& loc = SourceLocation::Current())
|
||||
: CrossThreadPersistentBase(raw), LocationPolicy(loc) {
|
||||
if (!IsValid(raw)) return;
|
||||
PersistentRegionLock guard;
|
||||
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
|
||||
SetNode(region.AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(raw);
|
||||
}
|
||||
|
||||
class UnsafeCtorTag {
|
||||
private:
|
||||
UnsafeCtorTag() = default;
|
||||
template <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy>
|
||||
friend class BasicCrossThreadPersistent;
|
||||
};
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
UnsafeCtorTag, T* raw,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: CrossThreadPersistentBase(raw), LocationPolicy(loc) {
|
||||
if (!IsValid(raw)) return;
|
||||
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
|
||||
SetNode(region.AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(raw);
|
||||
}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
T& raw, const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicCrossThreadPersistent(&raw, loc) {}
|
||||
|
||||
template <typename U, typename MemberBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicCrossThreadPersistent(
|
||||
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
|
||||
MemberCheckingPolicy, MemberStorageType>
|
||||
member,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicCrossThreadPersistent(member.Get(), loc) {}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
const BasicCrossThreadPersistent& other,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicCrossThreadPersistent(loc) {
|
||||
// Invoke operator=.
|
||||
*this = other;
|
||||
}
|
||||
|
||||
// Heterogeneous ctor.
|
||||
template <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicCrossThreadPersistent(
|
||||
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
|
||||
OtherLocationPolicy,
|
||||
OtherCheckingPolicy>& other,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicCrossThreadPersistent(loc) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
BasicCrossThreadPersistent(
|
||||
BasicCrossThreadPersistent&& other,
|
||||
const SourceLocation& loc = SourceLocation::Current()) noexcept {
|
||||
// Invoke operator=.
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
BasicCrossThreadPersistent& operator=(
|
||||
const BasicCrossThreadPersistent& other) {
|
||||
PersistentRegionLock guard;
|
||||
AssignSafe(guard, other.Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicCrossThreadPersistent& operator=(
|
||||
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
|
||||
OtherLocationPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
PersistentRegionLock guard;
|
||||
AssignSafe(guard, other.Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
|
||||
if (this == &other) return *this;
|
||||
Clear();
|
||||
PersistentRegionLock guard;
|
||||
PersistentBase::operator=(std::move(other));
|
||||
LocationPolicy::operator=(std::move(other));
|
||||
if (!IsValid(GetValue())) return *this;
|
||||
GetNode()->UpdateOwner(this);
|
||||
other.SetValue(nullptr);
|
||||
other.SetNode(nullptr);
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a raw pointer.
|
||||
*
|
||||
* Note: **Not thread-safe.**
|
||||
*/
|
||||
BasicCrossThreadPersistent& operator=(T* other) {
|
||||
AssignUnsafe(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assignment from member.
|
||||
template <typename U, typename MemberBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicCrossThreadPersistent& operator=(
|
||||
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
|
||||
MemberCheckingPolicy, MemberStorageType>
|
||||
member) {
|
||||
return operator=(member.Get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a nullptr.
|
||||
*
|
||||
* \returns the handle.
|
||||
*/
|
||||
BasicCrossThreadPersistent& operator=(std::nullptr_t) {
|
||||
Clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the sentinel pointer.
|
||||
*
|
||||
* \returns the handle.
|
||||
*/
|
||||
BasicCrossThreadPersistent& operator=(SentinelPointer s) {
|
||||
PersistentRegionLock guard;
|
||||
AssignSafe(guard, s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the stored object.
|
||||
*
|
||||
* Note: **Not thread-safe.**
|
||||
*
|
||||
* \returns a pointer to the stored object.
|
||||
*/
|
||||
// CFI cast exemption to allow passing SentinelPointer through T* and support
|
||||
// heterogeneous assignments between different Member and Persistent handles
|
||||
// based on their actual types.
|
||||
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
|
||||
return static_cast<T*>(const_cast<void*>(GetValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the stored object.
|
||||
*/
|
||||
void Clear() {
|
||||
PersistentRegionLock guard;
|
||||
AssignSafe(guard, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the stored object and releases it.
|
||||
*
|
||||
* Note: **Not thread-safe.**
|
||||
*
|
||||
* \returns a pointer to the stored object.
|
||||
*/
|
||||
T* Release() {
|
||||
T* result = Get();
|
||||
Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversio to boolean.
|
||||
*
|
||||
* Note: **Not thread-safe.**
|
||||
*
|
||||
* \returns true if an actual object has been stored and false otherwise.
|
||||
*/
|
||||
explicit operator bool() const { return Get(); }
|
||||
|
||||
/**
|
||||
* Conversion to object of type T.
|
||||
*
|
||||
* Note: **Not thread-safe.**
|
||||
*
|
||||
* \returns the object.
|
||||
*/
|
||||
operator T*() const { return Get(); }
|
||||
|
||||
/**
|
||||
* Dereferences the stored object.
|
||||
*
|
||||
* Note: **Not thread-safe.**
|
||||
*/
|
||||
T* operator->() const { return Get(); }
|
||||
T& operator*() const { return *Get(); }
|
||||
|
||||
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
|
||||
typename OtherLocationPolicy = LocationPolicy,
|
||||
typename OtherCheckingPolicy = CheckingPolicy>
|
||||
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>
|
||||
To() const {
|
||||
using OtherBasicCrossThreadPersistent =
|
||||
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>;
|
||||
PersistentRegionLock guard;
|
||||
return OtherBasicCrossThreadPersistent(
|
||||
typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
|
||||
static_cast<U*>(Get()));
|
||||
}
|
||||
|
||||
template <typename U = T,
|
||||
typename = typename std::enable_if<!BasicCrossThreadPersistent<
|
||||
U, WeaknessPolicy>::IsStrongPersistent::value>::type>
|
||||
BasicCrossThreadPersistent<U, internal::StrongCrossThreadPersistentPolicy>
|
||||
Lock() const {
|
||||
return BasicCrossThreadPersistent<
|
||||
U, internal::StrongCrossThreadPersistentPolicy>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool IsValid(const void* ptr) {
|
||||
return ptr && ptr != kSentinelPointer;
|
||||
}
|
||||
|
||||
static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
|
||||
root_visitor.Trace(*static_cast<const BasicCrossThreadPersistent*>(ptr));
|
||||
}
|
||||
|
||||
void AssignUnsafe(T* ptr) {
|
||||
const void* old_value = GetValue();
|
||||
if (IsValid(old_value)) {
|
||||
PersistentRegionLock guard;
|
||||
old_value = GetValue();
|
||||
// The fast path check (IsValid()) does not acquire the lock. Reload
|
||||
// the value to ensure the reference has not been cleared.
|
||||
if (IsValid(old_value)) {
|
||||
CrossThreadPersistentRegion& region =
|
||||
this->GetPersistentRegion(old_value);
|
||||
if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
|
||||
SetValue(ptr);
|
||||
this->CheckPointer(ptr);
|
||||
return;
|
||||
}
|
||||
region.FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
} else {
|
||||
CPPGC_DCHECK(!GetNode());
|
||||
}
|
||||
}
|
||||
SetValue(ptr);
|
||||
if (!IsValid(ptr)) return;
|
||||
PersistentRegionLock guard;
|
||||
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(ptr);
|
||||
}
|
||||
|
||||
void AssignSafe(PersistentRegionLock&, T* ptr) {
|
||||
PersistentRegionLock::AssertLocked();
|
||||
const void* old_value = GetValue();
|
||||
if (IsValid(old_value)) {
|
||||
CrossThreadPersistentRegion& region =
|
||||
this->GetPersistentRegion(old_value);
|
||||
if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
|
||||
SetValue(ptr);
|
||||
this->CheckPointer(ptr);
|
||||
return;
|
||||
}
|
||||
region.FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
}
|
||||
SetValue(ptr);
|
||||
if (!IsValid(ptr)) return;
|
||||
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(ptr);
|
||||
}
|
||||
|
||||
void ClearFromGC() const {
|
||||
if (IsValid(GetValueFromGC())) {
|
||||
WeaknessPolicy::GetPersistentRegion(GetValueFromGC())
|
||||
.FreeNode(GetNodeFromGC());
|
||||
CrossThreadPersistentBase::ClearFromGC();
|
||||
}
|
||||
}
|
||||
|
||||
// See Get() for details.
|
||||
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
|
||||
T* GetFromGC() const {
|
||||
return static_cast<T*>(const_cast<void*>(GetValueFromGC()));
|
||||
}
|
||||
|
||||
friend class internal::RootVisitor;
|
||||
};
|
||||
|
||||
template <typename T, typename LocationPolicy, typename CheckingPolicy>
|
||||
struct IsWeak<
|
||||
BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy,
|
||||
LocationPolicy, CheckingPolicy>>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace subtle {
|
||||
|
||||
/**
|
||||
* **DO NOT USE: Has known caveats, see below.**
|
||||
*
|
||||
* CrossThreadPersistent allows retaining objects from threads other than the
|
||||
* thread the owning heap is operating on.
|
||||
*
|
||||
* Known caveats:
|
||||
* - Does not protect the heap owning an object from terminating.
|
||||
* - Reaching transitively through the graph is unsupported as objects may be
|
||||
* moved concurrently on the thread owning the object.
|
||||
*/
|
||||
template <typename T>
|
||||
using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
|
||||
T, internal::StrongCrossThreadPersistentPolicy>;
|
||||
|
||||
/**
|
||||
* **DO NOT USE: Has known caveats, see below.**
|
||||
*
|
||||
* CrossThreadPersistent allows weakly retaining objects from threads other than
|
||||
* the thread the owning heap is operating on.
|
||||
*
|
||||
* Known caveats:
|
||||
* - Does not protect the heap owning an object from terminating.
|
||||
* - Reaching transitively through the graph is unsupported as objects may be
|
||||
* moved concurrently on the thread owning the object.
|
||||
*/
|
||||
template <typename T>
|
||||
using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
|
||||
T, internal::WeakCrossThreadPersistentPolicy>;
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_
|
||||
#define INCLUDE_CPPGC_CUSTOM_SPACE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* Index identifying a custom space.
|
||||
*/
|
||||
struct CustomSpaceIndex {
|
||||
constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT
|
||||
size_t value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Top-level base class for custom spaces. Users must inherit from CustomSpace
|
||||
* below.
|
||||
*/
|
||||
class CustomSpaceBase {
|
||||
public:
|
||||
virtual ~CustomSpaceBase() = default;
|
||||
virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0;
|
||||
virtual bool IsCompactable() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class custom spaces should directly inherit from. The class inheriting
|
||||
* from `CustomSpace` must define `kSpaceIndex` as unique space index. These
|
||||
* indices need for form a sequence starting at 0.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* class CustomSpace1 : public CustomSpace<CustomSpace1> {
|
||||
* public:
|
||||
* static constexpr CustomSpaceIndex kSpaceIndex = 0;
|
||||
* };
|
||||
* class CustomSpace2 : public CustomSpace<CustomSpace2> {
|
||||
* public:
|
||||
* static constexpr CustomSpaceIndex kSpaceIndex = 1;
|
||||
* };
|
||||
* \endcode
|
||||
*/
|
||||
template <typename ConcreteCustomSpace>
|
||||
class CustomSpace : public CustomSpaceBase {
|
||||
public:
|
||||
/**
|
||||
* Compaction is only supported on spaces that manually manage slots
|
||||
* recording.
|
||||
*/
|
||||
static constexpr bool kSupportsCompaction = false;
|
||||
|
||||
CustomSpaceIndex GetCustomSpaceIndex() const final {
|
||||
return ConcreteCustomSpace::kSpaceIndex;
|
||||
}
|
||||
bool IsCompactable() const final {
|
||||
return ConcreteCustomSpace::kSupportsCompaction;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* User-overridable trait that allows pinning types to custom spaces.
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct SpaceTrait {
|
||||
using Space = void;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename CustomSpace>
|
||||
struct IsAllocatedOnCompactableSpaceImpl {
|
||||
static constexpr bool value = CustomSpace::kSupportsCompaction;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IsAllocatedOnCompactableSpaceImpl<void> {
|
||||
// Non-custom spaces are by default not compactable.
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsAllocatedOnCompactableSpace {
|
||||
public:
|
||||
static constexpr bool value =
|
||||
IsAllocatedOnCompactableSpaceImpl<typename SpaceTrait<T>::Space>::value;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
|
||||
#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "cppgc/platform.h"
|
||||
#include "libplatform/libplatform.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* Platform provided by cppgc. Uses V8's DefaultPlatform provided by
|
||||
* libplatform internally. Exception: `GetForegroundTaskRunner()`, see below.
|
||||
*/
|
||||
class V8_EXPORT DefaultPlatform : public Platform {
|
||||
public:
|
||||
using IdleTaskSupport = v8::platform::IdleTaskSupport;
|
||||
explicit DefaultPlatform(
|
||||
int thread_pool_size = 0,
|
||||
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
|
||||
std::unique_ptr<TracingController> tracing_controller = {})
|
||||
: v8_platform_(v8::platform::NewDefaultPlatform(
|
||||
thread_pool_size, idle_task_support,
|
||||
v8::platform::InProcessStackDumping::kDisabled,
|
||||
std::move(tracing_controller))) {}
|
||||
|
||||
cppgc::PageAllocator* GetPageAllocator() override {
|
||||
return v8_platform_->GetPageAllocator();
|
||||
}
|
||||
|
||||
double MonotonicallyIncreasingTime() override {
|
||||
return v8_platform_->MonotonicallyIncreasingTime();
|
||||
}
|
||||
|
||||
std::shared_ptr<cppgc::TaskRunner> GetForegroundTaskRunner() override {
|
||||
// V8's default platform creates a new task runner when passed the
|
||||
// `v8::Isolate` pointer the first time. For non-default platforms this will
|
||||
// require getting the appropriate task runner.
|
||||
return v8_platform_->GetForegroundTaskRunner(kNoIsolate);
|
||||
}
|
||||
|
||||
std::unique_ptr<cppgc::JobHandle> PostJob(
|
||||
cppgc::TaskPriority priority,
|
||||
std::unique_ptr<cppgc::JobTask> job_task) override {
|
||||
return v8_platform_->PostJob(priority, std::move(job_task));
|
||||
}
|
||||
|
||||
TracingController* GetTracingController() override {
|
||||
return v8_platform_->GetTracingController();
|
||||
}
|
||||
|
||||
v8::Platform* GetV8Platform() const { return v8_platform_.get(); }
|
||||
|
||||
protected:
|
||||
static constexpr v8::Isolate* kNoIsolate = nullptr;
|
||||
|
||||
std::unique_ptr<v8::Platform> v8_platform_;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_
|
||||
#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_
|
||||
|
||||
#include "cppgc/liveness-broker.h"
|
||||
#include "cppgc/member.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* An ephemeron pair is used to conditionally retain an object.
|
||||
* The `value` will be kept alive only if the `key` is alive.
|
||||
*/
|
||||
template <typename K, typename V>
|
||||
struct EphemeronPair {
|
||||
EphemeronPair(K* k, V* v) : key(k), value(v) {}
|
||||
WeakMember<K> key;
|
||||
Member<V> value;
|
||||
|
||||
void ClearValueIfKeyIsDead(const LivenessBroker& broker) {
|
||||
if (!broker.IsHeapObjectAlive(key)) value = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
|
||||
#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "cppgc/allocation.h"
|
||||
#include "cppgc/internal/logging.h"
|
||||
#include "cppgc/type-traits.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
class HeapHandle;
|
||||
|
||||
namespace subtle {
|
||||
|
||||
template <typename T>
|
||||
void FreeUnreferencedObject(HeapHandle& heap_handle, T& object);
|
||||
template <typename T>
|
||||
bool Resize(T& object, AdditionalBytes additional_bytes);
|
||||
|
||||
} // namespace subtle
|
||||
|
||||
namespace internal {
|
||||
|
||||
class ExplicitManagementImpl final {
|
||||
private:
|
||||
V8_EXPORT static void FreeUnreferencedObject(HeapHandle&, void*);
|
||||
V8_EXPORT static bool Resize(void*, size_t);
|
||||
|
||||
template <typename T>
|
||||
friend void subtle::FreeUnreferencedObject(HeapHandle&, T&);
|
||||
template <typename T>
|
||||
friend bool subtle::Resize(T&, AdditionalBytes);
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
namespace subtle {
|
||||
|
||||
/**
|
||||
* Informs the garbage collector that `object` can be immediately reclaimed. The
|
||||
* destructor may not be invoked immediately but only on next garbage
|
||||
* collection.
|
||||
*
|
||||
* It is up to the embedder to guarantee that no other object holds a reference
|
||||
* to `object` after calling `FreeUnreferencedObject()`. In case such a
|
||||
* reference exists, it's use results in a use-after-free.
|
||||
*
|
||||
* To aid in using the API, `FreeUnreferencedObject()` may be called from
|
||||
* destructors on objects that would be reclaimed in the same garbage collection
|
||||
* cycle.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \param object Reference to an object that is of type `GarbageCollected` and
|
||||
* should be immediately reclaimed.
|
||||
*/
|
||||
template <typename T>
|
||||
void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) {
|
||||
static_assert(IsGarbageCollectedTypeV<T>,
|
||||
"Object must be of type GarbageCollected.");
|
||||
internal::ExplicitManagementImpl::FreeUnreferencedObject(heap_handle,
|
||||
&object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to resize `object` of type `T` with additional bytes on top of
|
||||
* sizeof(T). Resizing is only useful with trailing inlined storage, see e.g.
|
||||
* `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`.
|
||||
*
|
||||
* `Resize()` performs growing or shrinking as needed and may skip the operation
|
||||
* for internal reasons, see return value.
|
||||
*
|
||||
* It is up to the embedder to guarantee that in case of shrinking a larger
|
||||
* object down, the reclaimed area is not used anymore. Any subsequent use
|
||||
* results in a use-after-free.
|
||||
*
|
||||
* The `object` must be live when calling `Resize()`.
|
||||
*
|
||||
* \param object Reference to an object that is of type `GarbageCollected` and
|
||||
* should be resized.
|
||||
* \param additional_bytes Bytes in addition to sizeof(T) that the object should
|
||||
* provide.
|
||||
* \returns true when the operation was successful and the result can be relied
|
||||
* on, and false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool Resize(T& object, AdditionalBytes additional_bytes) {
|
||||
static_assert(IsGarbageCollectedTypeV<T>,
|
||||
"Object must be of type GarbageCollected.");
|
||||
return internal::ExplicitManagementImpl::Resize(
|
||||
&object, sizeof(T) + additional_bytes.value);
|
||||
}
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
|
||||
#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
|
||||
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/platform.h"
|
||||
#include "cppgc/trace-trait.h"
|
||||
#include "cppgc/type-traits.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
class Visitor;
|
||||
|
||||
/**
|
||||
* Base class for managed objects. Only descendent types of `GarbageCollected`
|
||||
* can be constructed using `MakeGarbageCollected()`. Must be inherited from as
|
||||
* left-most base class.
|
||||
*
|
||||
* Types inheriting from GarbageCollected must provide a method of
|
||||
* signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
|
||||
* pointers to the visitor and delegates to garbage-collected base classes.
|
||||
* The method must be virtual if the type is not directly a child of
|
||||
* GarbageCollected and marked as final.
|
||||
*
|
||||
* \code
|
||||
* // Example using final class.
|
||||
* class FinalType final : public GarbageCollected<FinalType> {
|
||||
* public:
|
||||
* void Trace(cppgc::Visitor* visitor) const {
|
||||
* // Dispatch using visitor->Trace(...);
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* // Example using non-final base class.
|
||||
* class NonFinalBase : public GarbageCollected<NonFinalBase> {
|
||||
* public:
|
||||
* virtual void Trace(cppgc::Visitor*) const {}
|
||||
* };
|
||||
*
|
||||
* class FinalChild final : public NonFinalBase {
|
||||
* public:
|
||||
* void Trace(cppgc::Visitor* visitor) const final {
|
||||
* // Dispatch using visitor->Trace(...);
|
||||
* NonFinalBase::Trace(visitor);
|
||||
* }
|
||||
* };
|
||||
* \endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class GarbageCollected {
|
||||
public:
|
||||
using IsGarbageCollectedTypeMarker = void;
|
||||
using ParentMostGarbageCollectedType = T;
|
||||
|
||||
// Must use MakeGarbageCollected.
|
||||
void* operator new(size_t) = delete;
|
||||
void* operator new[](size_t) = delete;
|
||||
// The garbage collector is taking care of reclaiming the object. Also,
|
||||
// virtual destructor requires an unambiguous, accessible 'operator delete'.
|
||||
void operator delete(void*) {
|
||||
#ifdef V8_ENABLE_CHECKS
|
||||
internal::Fatal(
|
||||
"Manually deleting a garbage collected object is not allowed");
|
||||
#endif // V8_ENABLE_CHECKS
|
||||
}
|
||||
void operator delete[](void*) = delete;
|
||||
|
||||
protected:
|
||||
GarbageCollected() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for managed mixin objects. Such objects cannot be constructed
|
||||
* directly but must be mixed into the inheritance hierarchy of a
|
||||
* GarbageCollected object.
|
||||
*
|
||||
* Types inheriting from GarbageCollectedMixin must override a virtual method
|
||||
* of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
|
||||
* pointers to the visitor and delegates to base classes.
|
||||
*
|
||||
* \code
|
||||
* class Mixin : public GarbageCollectedMixin {
|
||||
* public:
|
||||
* void Trace(cppgc::Visitor* visitor) const override {
|
||||
* // Dispatch using visitor->Trace(...);
|
||||
* }
|
||||
* };
|
||||
* \endcode
|
||||
*/
|
||||
class GarbageCollectedMixin {
|
||||
public:
|
||||
using IsGarbageCollectedMixinTypeMarker = void;
|
||||
|
||||
/**
|
||||
* This Trace method must be overriden by objects inheriting from
|
||||
* GarbageCollectedMixin.
|
||||
*/
|
||||
virtual void Trace(cppgc::Visitor*) const {}
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
|
||||
@@ -1,309 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
|
||||
#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "cppgc/internal/write-barrier.h"
|
||||
#include "cppgc/macros.h"
|
||||
#include "cppgc/member.h"
|
||||
#include "cppgc/trace-trait.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
class HeapHandle;
|
||||
|
||||
namespace subtle {
|
||||
|
||||
/**
|
||||
* **DO NOT USE: Use the appropriate managed types.**
|
||||
*
|
||||
* Consistency helpers that aid in maintaining a consistent internal state of
|
||||
* the garbage collector.
|
||||
*/
|
||||
class HeapConsistency final {
|
||||
public:
|
||||
using WriteBarrierParams = internal::WriteBarrier::Params;
|
||||
using WriteBarrierType = internal::WriteBarrier::Type;
|
||||
|
||||
/**
|
||||
* Gets the required write barrier type for a specific write.
|
||||
*
|
||||
* \param slot Slot containing the pointer to the object. The slot itself
|
||||
* must reside in an object that has been allocated using
|
||||
* `MakeGarbageCollected()`.
|
||||
* \param value The pointer to the object. May be an interior pointer to an
|
||||
* interface of the actual object.
|
||||
* \param params Parameters that may be used for actual write barrier calls.
|
||||
* Only filled if return value indicates that a write barrier is needed. The
|
||||
* contents of the `params` are an implementation detail.
|
||||
* \returns whether a write barrier is needed and which barrier to invoke.
|
||||
*/
|
||||
static V8_INLINE WriteBarrierType GetWriteBarrierType(
|
||||
const void* slot, const void* value, WriteBarrierParams& params) {
|
||||
return internal::WriteBarrier::GetWriteBarrierType(slot, value, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the required write barrier type for a specific write. This override is
|
||||
* only used for all the BasicMember types.
|
||||
*
|
||||
* \param slot Slot containing the pointer to the object. The slot itself
|
||||
* must reside in an object that has been allocated using
|
||||
* `MakeGarbageCollected()`.
|
||||
* \param value The pointer to the object held via `BasicMember`.
|
||||
* \param params Parameters that may be used for actual write barrier calls.
|
||||
* Only filled if return value indicates that a write barrier is needed. The
|
||||
* contents of the `params` are an implementation detail.
|
||||
* \returns whether a write barrier is needed and which barrier to invoke.
|
||||
*/
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
static V8_INLINE WriteBarrierType GetWriteBarrierType(
|
||||
const internal::BasicMember<T, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& value,
|
||||
WriteBarrierParams& params) {
|
||||
return internal::WriteBarrier::GetWriteBarrierType(
|
||||
value.GetRawSlot(), value.GetRawStorage(), params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the required write barrier type for a specific write.
|
||||
*
|
||||
* \param slot Slot to some part of an object. The object must not necessarily
|
||||
have been allocated using `MakeGarbageCollected()` but can also live
|
||||
off-heap or on stack.
|
||||
* \param params Parameters that may be used for actual write barrier calls.
|
||||
* Only filled if return value indicates that a write barrier is needed. The
|
||||
* contents of the `params` are an implementation detail.
|
||||
* \param callback Callback returning the corresponding heap handle. The
|
||||
* callback is only invoked if the heap cannot otherwise be figured out. The
|
||||
* callback must not allocate.
|
||||
* \returns whether a write barrier is needed and which barrier to invoke.
|
||||
*/
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrierType
|
||||
GetWriteBarrierType(const void* slot, WriteBarrierParams& params,
|
||||
HeapHandleCallback callback) {
|
||||
return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the required write barrier type for a specific write.
|
||||
* This version is meant to be used in conjunction with with a marking write
|
||||
* barrier barrier which doesn't consider the slot.
|
||||
*
|
||||
* \param value The pointer to the object. May be an interior pointer to an
|
||||
* interface of the actual object.
|
||||
* \param params Parameters that may be used for actual write barrier calls.
|
||||
* Only filled if return value indicates that a write barrier is needed. The
|
||||
* contents of the `params` are an implementation detail.
|
||||
* \returns whether a write barrier is needed and which barrier to invoke.
|
||||
*/
|
||||
static V8_INLINE WriteBarrierType
|
||||
GetWriteBarrierType(const void* value, WriteBarrierParams& params) {
|
||||
return internal::WriteBarrier::GetWriteBarrierType(value, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conservative Dijkstra-style write barrier that processes an object if it
|
||||
* has not yet been processed.
|
||||
*
|
||||
* \param params The parameters retrieved from `GetWriteBarrierType()`.
|
||||
* \param object The pointer to the object. May be an interior pointer to a
|
||||
* an interface of the actual object.
|
||||
*/
|
||||
static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params,
|
||||
const void* object) {
|
||||
internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conservative Dijkstra-style write barrier that processes a range of
|
||||
* elements if they have not yet been processed.
|
||||
*
|
||||
* \param params The parameters retrieved from `GetWriteBarrierType()`.
|
||||
* \param first_element Pointer to the first element that should be processed.
|
||||
* The slot itself must reside in an object that has been allocated using
|
||||
* `MakeGarbageCollected()`.
|
||||
* \param element_size Size of the element in bytes.
|
||||
* \param number_of_elements Number of elements that should be processed,
|
||||
* starting with `first_element`.
|
||||
* \param trace_callback The trace callback that should be invoked for each
|
||||
* element if necessary.
|
||||
*/
|
||||
static V8_INLINE void DijkstraWriteBarrierRange(
|
||||
const WriteBarrierParams& params, const void* first_element,
|
||||
size_t element_size, size_t number_of_elements,
|
||||
TraceCallback trace_callback) {
|
||||
internal::WriteBarrier::DijkstraMarkingBarrierRange(
|
||||
params, first_element, element_size, number_of_elements,
|
||||
trace_callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Steele-style write barrier that re-processes an object if it has already
|
||||
* been processed.
|
||||
*
|
||||
* \param params The parameters retrieved from `GetWriteBarrierType()`.
|
||||
* \param object The pointer to the object which must point to an object that
|
||||
* has been allocated using `MakeGarbageCollected()`. Interior pointers are
|
||||
* not supported.
|
||||
*/
|
||||
static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params,
|
||||
const void* object) {
|
||||
internal::WriteBarrier::SteeleMarkingBarrier(params, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generational barrier for maintaining consistency when running with multiple
|
||||
* generations.
|
||||
*
|
||||
* \param params The parameters retrieved from `GetWriteBarrierType()`.
|
||||
* \param slot Slot containing the pointer to the object. The slot itself
|
||||
* must reside in an object that has been allocated using
|
||||
* `MakeGarbageCollected()`.
|
||||
*/
|
||||
static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
|
||||
const void* slot) {
|
||||
internal::WriteBarrier::GenerationalBarrier<
|
||||
internal::WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params,
|
||||
slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generational barrier for maintaining consistency when running with multiple
|
||||
* generations. This version is used when slot contains uncompressed pointer.
|
||||
*
|
||||
* \param params The parameters retrieved from `GetWriteBarrierType()`.
|
||||
* \param slot Uncompressed slot containing the direct pointer to the object.
|
||||
* The slot itself must reside in an object that has been allocated using
|
||||
* `MakeGarbageCollected()`.
|
||||
*/
|
||||
static V8_INLINE void GenerationalBarrierForUncompressedSlot(
|
||||
const WriteBarrierParams& params, const void* uncompressed_slot) {
|
||||
internal::WriteBarrier::GenerationalBarrier<
|
||||
internal::WriteBarrier::GenerationalBarrierType::
|
||||
kPreciseUncompressedSlot>(params, uncompressed_slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generational barrier for source object that may contain outgoing pointers
|
||||
* to objects in young generation.
|
||||
*
|
||||
* \param params The parameters retrieved from `GetWriteBarrierType()`.
|
||||
* \param inner_pointer Pointer to the source object.
|
||||
*/
|
||||
static V8_INLINE void GenerationalBarrierForSourceObject(
|
||||
const WriteBarrierParams& params, const void* inner_pointer) {
|
||||
internal::WriteBarrier::GenerationalBarrier<
|
||||
internal::WriteBarrier::GenerationalBarrierType::kImpreciseSlot>(
|
||||
params, inner_pointer);
|
||||
}
|
||||
|
||||
private:
|
||||
HeapConsistency() = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* Disallows garbage collection finalizations. Any garbage collection triggers
|
||||
* result in a crash when in this scope.
|
||||
*
|
||||
* Note that the garbage collector already covers paths that can lead to garbage
|
||||
* collections, so user code does not require checking
|
||||
* `IsGarbageCollectionAllowed()` before allocations.
|
||||
*/
|
||||
class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final {
|
||||
CPPGC_STACK_ALLOCATED();
|
||||
|
||||
public:
|
||||
/**
|
||||
* \returns whether garbage collections are currently allowed.
|
||||
*/
|
||||
static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Enters a disallow garbage collection scope. Must be paired with `Leave()`.
|
||||
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
static void Enter(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Leaves a disallow garbage collection scope. Must be paired with `Enter()`.
|
||||
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
static void Leave(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Constructs a scoped object that automatically enters and leaves a disallow
|
||||
* garbage collection scope based on its lifetime.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle);
|
||||
~DisallowGarbageCollectionScope();
|
||||
|
||||
DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) =
|
||||
delete;
|
||||
DisallowGarbageCollectionScope& operator=(
|
||||
const DisallowGarbageCollectionScope&) = delete;
|
||||
|
||||
private:
|
||||
HeapHandle& heap_handle_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Avoids invoking garbage collection finalizations. Already running garbage
|
||||
* collection phase are unaffected by this scope.
|
||||
*
|
||||
* Should only be used temporarily as the scope has an impact on memory usage
|
||||
* and follow up garbage collections.
|
||||
*/
|
||||
class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final {
|
||||
CPPGC_STACK_ALLOCATED();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer
|
||||
* a scope instance of `NoGarbageCollectionScope`.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
static void Enter(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer
|
||||
* a scope instance of `NoGarbageCollectionScope`.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
static void Leave(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Constructs a scoped object that automatically enters and leaves a no
|
||||
* garbage collection scope based on its lifetime.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
explicit NoGarbageCollectionScope(HeapHandle& heap_handle);
|
||||
~NoGarbageCollectionScope();
|
||||
|
||||
NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete;
|
||||
NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete;
|
||||
|
||||
private:
|
||||
HeapHandle& heap_handle_;
|
||||
};
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
|
||||
@@ -1,48 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_HEAP_HANDLE_H_
|
||||
#define INCLUDE_CPPGC_HEAP_HANDLE_H_
|
||||
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace internal {
|
||||
class HeapBase;
|
||||
class WriteBarrierTypeForCagedHeapPolicy;
|
||||
class WriteBarrierTypeForNonCagedHeapPolicy;
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Opaque handle used for additional heap APIs.
|
||||
*/
|
||||
class HeapHandle {
|
||||
public:
|
||||
// Deleted copy ctor to avoid treating the type by value.
|
||||
HeapHandle(const HeapHandle&) = delete;
|
||||
HeapHandle& operator=(const HeapHandle&) = delete;
|
||||
|
||||
private:
|
||||
HeapHandle() = default;
|
||||
|
||||
V8_INLINE bool is_incremental_marking_in_progress() const {
|
||||
return is_incremental_marking_in_progress_;
|
||||
}
|
||||
|
||||
V8_INLINE bool is_young_generation_enabled() const {
|
||||
return is_young_generation_enabled_;
|
||||
}
|
||||
|
||||
bool is_incremental_marking_in_progress_ = false;
|
||||
bool is_young_generation_enabled_ = false;
|
||||
|
||||
friend class internal::HeapBase;
|
||||
friend class internal::WriteBarrierTypeForCagedHeapPolicy;
|
||||
friend class internal::WriteBarrierTypeForNonCagedHeapPolicy;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_HEAP_HANDLE_H_
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_HEAP_STATE_H_
|
||||
#define INCLUDE_CPPGC_HEAP_STATE_H_
|
||||
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
class HeapHandle;
|
||||
|
||||
namespace subtle {
|
||||
|
||||
/**
|
||||
* Helpers to peek into heap-internal state.
|
||||
*/
|
||||
class V8_EXPORT HeapState final {
|
||||
public:
|
||||
/**
|
||||
* Returns whether the garbage collector is marking. This API is experimental
|
||||
* and is expected to be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently marking, and false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool IsMarking(const HeapHandle& heap_handle);
|
||||
|
||||
/*
|
||||
* Returns whether the garbage collector is sweeping. This API is experimental
|
||||
* and is expected to be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently sweeping, and false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool IsSweeping(const HeapHandle& heap_handle);
|
||||
|
||||
/*
|
||||
* Returns whether the garbage collector is currently sweeping on the thread
|
||||
* owning this heap. This API allows the caller to determine whether it has
|
||||
* been called from a destructor of a managed object. This API is experimental
|
||||
* and may be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently sweeping on this
|
||||
* thread, and false otherwise.
|
||||
*/
|
||||
static bool IsSweepingOnOwningThread(const HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Returns whether the garbage collector is in the atomic pause, i.e., the
|
||||
* mutator is stopped from running. This API is experimental and is expected
|
||||
* to be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently in the atomic pause,
|
||||
* and false otherwise.
|
||||
*/
|
||||
static bool IsInAtomicPause(const HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Returns whether the last garbage collection was finalized conservatively
|
||||
* (i.e., with a non-empty stack). This API is experimental and is expected to
|
||||
* be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the last garbage collection was finalized conservatively,
|
||||
* and false otherwise.
|
||||
*/
|
||||
static bool PreviousGCWasConservative(const HeapHandle& heap_handle);
|
||||
|
||||
private:
|
||||
HeapState() = delete;
|
||||
};
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_HEAP_STATE_H_
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_HEAP_STATISTICS_H_
|
||||
#define INCLUDE_CPPGC_HEAP_STATISTICS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* `HeapStatistics` contains memory consumption and utilization statistics for a
|
||||
* cppgc heap.
|
||||
*/
|
||||
struct HeapStatistics final {
|
||||
/**
|
||||
* Specifies the detail level of the heap statistics. Brief statistics contain
|
||||
* only the top-level allocated and used memory statistics for the entire
|
||||
* heap. Detailed statistics also contain a break down per space and page, as
|
||||
* well as freelist statistics and object type histograms. Note that used
|
||||
* memory reported by brief statistics and detailed statistics might differ
|
||||
* slightly.
|
||||
*/
|
||||
enum DetailLevel : uint8_t {
|
||||
kBrief,
|
||||
kDetailed,
|
||||
};
|
||||
|
||||
/**
|
||||
* Object statistics for a single type.
|
||||
*/
|
||||
struct ObjectStatsEntry {
|
||||
/**
|
||||
* Number of allocated bytes.
|
||||
*/
|
||||
size_t allocated_bytes;
|
||||
/**
|
||||
* Number of allocated objects.
|
||||
*/
|
||||
size_t object_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Page granularity statistics. For each page the statistics record the
|
||||
* allocated memory size and overall used memory size for the page.
|
||||
*/
|
||||
struct PageStatistics {
|
||||
/** Overall committed amount of memory for the page. */
|
||||
size_t committed_size_bytes = 0;
|
||||
/** Resident amount of memory held by the page. */
|
||||
size_t resident_size_bytes = 0;
|
||||
/** Amount of memory actually used on the page. */
|
||||
size_t used_size_bytes = 0;
|
||||
/** Statistics for object allocated on the page. Filled only when
|
||||
* NameProvider::SupportsCppClassNamesAsObjectNames() is true. */
|
||||
std::vector<ObjectStatsEntry> object_statistics;
|
||||
};
|
||||
|
||||
/**
|
||||
* Statistics of the freelist (used only in non-large object spaces). For
|
||||
* each bucket in the freelist the statistics record the bucket size, the
|
||||
* number of freelist entries in the bucket, and the overall allocated memory
|
||||
* consumed by these freelist entries.
|
||||
*/
|
||||
struct FreeListStatistics {
|
||||
/** bucket sizes in the freelist. */
|
||||
std::vector<size_t> bucket_size;
|
||||
/** number of freelist entries per bucket. */
|
||||
std::vector<size_t> free_count;
|
||||
/** memory size consumed by freelist entries per size. */
|
||||
std::vector<size_t> free_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Space granularity statistics. For each space the statistics record the
|
||||
* space name, the amount of allocated memory and overall used memory for the
|
||||
* space. The statistics also contain statistics for each of the space's
|
||||
* pages, its freelist and the objects allocated on the space.
|
||||
*/
|
||||
struct SpaceStatistics {
|
||||
/** The space name */
|
||||
std::string name;
|
||||
/** Overall committed amount of memory for the heap. */
|
||||
size_t committed_size_bytes = 0;
|
||||
/** Resident amount of memory held by the heap. */
|
||||
size_t resident_size_bytes = 0;
|
||||
/** Amount of memory actually used on the space. */
|
||||
size_t used_size_bytes = 0;
|
||||
/** Statistics for each of the pages in the space. */
|
||||
std::vector<PageStatistics> page_stats;
|
||||
/** Statistics for the freelist of the space. */
|
||||
FreeListStatistics free_list_stats;
|
||||
};
|
||||
|
||||
/** Overall committed amount of memory for the heap. */
|
||||
size_t committed_size_bytes = 0;
|
||||
/** Resident amount of memory held by the heap. */
|
||||
size_t resident_size_bytes = 0;
|
||||
/** Amount of memory actually used on the heap. */
|
||||
size_t used_size_bytes = 0;
|
||||
/** Memory retained in the page pool, not used directly by the heap. */
|
||||
size_t pooled_memory_size_bytes = 0;
|
||||
/** Detail level of this HeapStatistics. */
|
||||
DetailLevel detail_level;
|
||||
|
||||
/** Statistics for each of the spaces in the heap. Filled only when
|
||||
* `detail_level` is `DetailLevel::kDetailed`. */
|
||||
std::vector<SpaceStatistics> space_stats;
|
||||
|
||||
/**
|
||||
* Vector of `cppgc::GarbageCollected` type names.
|
||||
*/
|
||||
std::vector<std::string> type_names;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_
|
||||
@@ -1,202 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_HEAP_H_
|
||||
#define INCLUDE_CPPGC_HEAP_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "cppgc/common.h"
|
||||
#include "cppgc/custom-space.h"
|
||||
#include "cppgc/platform.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
/**
|
||||
* cppgc - A C++ garbage collection library.
|
||||
*/
|
||||
namespace cppgc {
|
||||
|
||||
class AllocationHandle;
|
||||
class HeapHandle;
|
||||
|
||||
/**
|
||||
* Implementation details of cppgc. Those details are considered internal and
|
||||
* may change at any point in time without notice. Users should never rely on
|
||||
* the contents of this namespace.
|
||||
*/
|
||||
namespace internal {
|
||||
class Heap;
|
||||
} // namespace internal
|
||||
|
||||
class V8_EXPORT Heap {
|
||||
public:
|
||||
/**
|
||||
* Specifies the stack state the embedder is in.
|
||||
*/
|
||||
using StackState = EmbedderStackState;
|
||||
|
||||
/**
|
||||
* Specifies whether conservative stack scanning is supported.
|
||||
*/
|
||||
enum class StackSupport : uint8_t {
|
||||
/**
|
||||
* Conservative stack scan is supported.
|
||||
*/
|
||||
kSupportsConservativeStackScan,
|
||||
/**
|
||||
* Conservative stack scan is not supported. Embedders may use this option
|
||||
* when using custom infrastructure that is unsupported by the library.
|
||||
*/
|
||||
kNoConservativeStackScan,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies supported marking types.
|
||||
*/
|
||||
enum class MarkingType : uint8_t {
|
||||
/**
|
||||
* Atomic stop-the-world marking. This option does not require any write
|
||||
* barriers but is the most intrusive in terms of jank.
|
||||
*/
|
||||
kAtomic,
|
||||
/**
|
||||
* Incremental marking interleaves marking with the rest of the application
|
||||
* workload on the same thread.
|
||||
*/
|
||||
kIncremental,
|
||||
/**
|
||||
* Incremental and concurrent marking.
|
||||
*/
|
||||
kIncrementalAndConcurrent
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies supported sweeping types.
|
||||
*/
|
||||
enum class SweepingType : uint8_t {
|
||||
/**
|
||||
* Atomic stop-the-world sweeping. All of sweeping is performed at once.
|
||||
*/
|
||||
kAtomic,
|
||||
/**
|
||||
* Incremental sweeping interleaves sweeping with the rest of the
|
||||
* application workload on the same thread.
|
||||
*/
|
||||
kIncremental,
|
||||
/**
|
||||
* Incremental and concurrent sweeping. Sweeping is split and interleaved
|
||||
* with the rest of the application.
|
||||
*/
|
||||
kIncrementalAndConcurrent
|
||||
};
|
||||
|
||||
/**
|
||||
* Constraints for a Heap setup.
|
||||
*/
|
||||
struct ResourceConstraints {
|
||||
/**
|
||||
* Allows the heap to grow to some initial size in bytes before triggering
|
||||
* garbage collections. This is useful when it is known that applications
|
||||
* need a certain minimum heap to run to avoid repeatedly invoking the
|
||||
* garbage collector when growing the heap.
|
||||
*/
|
||||
size_t initial_heap_size_bytes = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options specifying Heap properties (e.g. custom spaces) when initializing a
|
||||
* heap through `Heap::Create()`.
|
||||
*/
|
||||
struct HeapOptions {
|
||||
/**
|
||||
* Creates reasonable defaults for instantiating a Heap.
|
||||
*
|
||||
* \returns the HeapOptions that can be passed to `Heap::Create()`.
|
||||
*/
|
||||
static HeapOptions Default() { return {}; }
|
||||
|
||||
/**
|
||||
* Custom spaces added to heap are required to have indices forming a
|
||||
* numbered sequence starting at 0, i.e., their `kSpaceIndex` must
|
||||
* correspond to the index they reside in the vector.
|
||||
*/
|
||||
std::vector<std::unique_ptr<CustomSpaceBase>> custom_spaces;
|
||||
|
||||
/**
|
||||
* Specifies whether conservative stack scan is supported. When conservative
|
||||
* stack scan is not supported, the collector may try to invoke
|
||||
* garbage collections using non-nestable task, which are guaranteed to have
|
||||
* no interesting stack, through the provided Platform. If such tasks are
|
||||
* not supported by the Platform, the embedder must take care of invoking
|
||||
* the GC through `ForceGarbageCollectionSlow()`.
|
||||
*/
|
||||
StackSupport stack_support = StackSupport::kSupportsConservativeStackScan;
|
||||
|
||||
/**
|
||||
* Specifies which types of marking are supported by the heap.
|
||||
*/
|
||||
MarkingType marking_support = MarkingType::kIncrementalAndConcurrent;
|
||||
|
||||
/**
|
||||
* Specifies which types of sweeping are supported by the heap.
|
||||
*/
|
||||
SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent;
|
||||
|
||||
/**
|
||||
* Resource constraints specifying various properties that the internal
|
||||
* GC scheduler follows.
|
||||
*/
|
||||
ResourceConstraints resource_constraints;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new heap that can be used for object allocation.
|
||||
*
|
||||
* \param platform implemented and provided by the embedder.
|
||||
* \param options HeapOptions specifying various properties for the Heap.
|
||||
* \returns a new Heap instance.
|
||||
*/
|
||||
static std::unique_ptr<Heap> Create(
|
||||
std::shared_ptr<Platform> platform,
|
||||
HeapOptions options = HeapOptions::Default());
|
||||
|
||||
virtual ~Heap() = default;
|
||||
|
||||
/**
|
||||
* Forces garbage collection.
|
||||
*
|
||||
* \param source String specifying the source (or caller) triggering a
|
||||
* forced garbage collection.
|
||||
* \param reason String specifying the reason for the forced garbage
|
||||
* collection.
|
||||
* \param stack_state The embedder stack state, see StackState.
|
||||
*/
|
||||
void ForceGarbageCollectionSlow(
|
||||
const char* source, const char* reason,
|
||||
StackState stack_state = StackState::kMayContainHeapPointers);
|
||||
|
||||
/**
|
||||
* \returns the opaque handle for allocating objects using
|
||||
* `MakeGarbageCollected()`.
|
||||
*/
|
||||
AllocationHandle& GetAllocationHandle();
|
||||
|
||||
/**
|
||||
* \returns the opaque heap handle which may be used to refer to this heap in
|
||||
* other APIs. Valid as long as the underlying `Heap` is alive.
|
||||
*/
|
||||
HeapHandle& GetHeapHandle();
|
||||
|
||||
private:
|
||||
Heap() = default;
|
||||
|
||||
friend class internal::Heap;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_HEAP_H_
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
// Embedders should not rely on this code!
|
||||
|
||||
// Internal constants to avoid exposing internal types on the API surface.
|
||||
namespace api_constants {
|
||||
|
||||
constexpr size_t kKB = 1024;
|
||||
constexpr size_t kMB = kKB * 1024;
|
||||
constexpr size_t kGB = kMB * 1024;
|
||||
|
||||
// Offset of the uint16_t bitfield from the payload contaning the
|
||||
// in-construction bit. This is subtracted from the payload pointer to get
|
||||
// to the right bitfield.
|
||||
static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload =
|
||||
2 * sizeof(uint16_t);
|
||||
// Mask for in-construction bit.
|
||||
static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1};
|
||||
|
||||
static constexpr size_t kPageSize = size_t{1} << 17;
|
||||
|
||||
#if defined(V8_HOST_ARCH_ARM64) && defined(V8_OS_DARWIN)
|
||||
constexpr size_t kGuardPageSize = 0;
|
||||
#elif defined(V8_HOST_ARCH_PPC64)
|
||||
constexpr size_t kGuardPageSize = 0;
|
||||
#elif defined(V8_HOST_ARCH_LOONG64) || defined(V8_HOST_ARCH_MIPS64)
|
||||
constexpr size_t kGuardPageSize = 0;
|
||||
#else
|
||||
constexpr size_t kGuardPageSize = 4096;
|
||||
#endif
|
||||
|
||||
static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2;
|
||||
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
#if defined(CPPGC_ENABLE_LARGER_CAGE)
|
||||
constexpr unsigned kPointerCompressionShift = 3;
|
||||
#else // !defined(CPPGC_ENABLE_LARGER_CAGE)
|
||||
constexpr unsigned kPointerCompressionShift = 1;
|
||||
#endif // !defined(CPPGC_ENABLE_LARGER_CAGE)
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
#if defined(CPPGC_2GB_CAGE)
|
||||
constexpr size_t kCagedHeapDefaultReservationSize =
|
||||
static_cast<size_t>(2) * kGB;
|
||||
constexpr size_t kCagedHeapMaxReservationSize =
|
||||
kCagedHeapDefaultReservationSize;
|
||||
#else // !defined(CPPGC_2GB_CAGE)
|
||||
constexpr size_t kCagedHeapDefaultReservationSize =
|
||||
static_cast<size_t>(4) * kGB;
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
constexpr size_t kCagedHeapMaxReservationSize =
|
||||
size_t{1} << (31 + kPointerCompressionShift);
|
||||
#else // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
constexpr size_t kCagedHeapMaxReservationSize =
|
||||
kCagedHeapDefaultReservationSize;
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
#endif // !defined(CPPGC_2GB_CAGE)
|
||||
constexpr size_t kCagedHeapReservationAlignment = kCagedHeapMaxReservationSize;
|
||||
#endif // defined(CPPGC_CAGED_HEAP)
|
||||
|
||||
static constexpr size_t kDefaultAlignment = sizeof(void*);
|
||||
|
||||
// Maximum support alignment for a type as in `alignof(T)`.
|
||||
static constexpr size_t kMaxSupportedAlignment = 2 * kDefaultAlignment;
|
||||
|
||||
// Granularity of heap allocations.
|
||||
constexpr size_t kAllocationGranularity = sizeof(void*);
|
||||
|
||||
// Default cacheline size.
|
||||
constexpr size_t kCachelineSize = 64;
|
||||
|
||||
} // namespace api_constants
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
// A flag which provides a fast check whether a scope may be entered on the
|
||||
// current thread, without needing to access thread-local storage or mutex. Can
|
||||
// have false positives (i.e., spuriously report that it might be entered), so
|
||||
// it is expected that this will be used in tandem with a precise check that the
|
||||
// scope is in fact entered on that thread.
|
||||
//
|
||||
// Example:
|
||||
// g_frobnicating_flag.MightBeEntered() &&
|
||||
// ThreadLocalFrobnicator().IsFrobnicating()
|
||||
//
|
||||
// Relaxed atomic operations are sufficient, since:
|
||||
// - all accesses remain atomic
|
||||
// - each thread must observe its own operations in order
|
||||
// - no thread ever exits the flag more times than it enters (if used correctly)
|
||||
// And so if a thread observes zero, it must be because it has observed an equal
|
||||
// number of exits as entries.
|
||||
class AtomicEntryFlag final {
|
||||
public:
|
||||
void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); }
|
||||
void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); }
|
||||
|
||||
// Returns false only if the current thread is not between a call to Enter
|
||||
// and a call to Exit. Returns true if this thread or another thread may
|
||||
// currently be in the scope guarded by this flag.
|
||||
bool MightBeEntered() const {
|
||||
return entries_.load(std::memory_order_relaxed) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_int entries_{0};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
|
||||
@@ -1,45 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_
|
||||
|
||||
#include "cppgc/heap-handle.h"
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/logging.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
// The class is needed in the header to allow for fast access to HeapHandle in
|
||||
// the write barrier.
|
||||
class BasePageHandle {
|
||||
public:
|
||||
static V8_INLINE BasePageHandle* FromPayload(void* payload) {
|
||||
return reinterpret_cast<BasePageHandle*>(
|
||||
(reinterpret_cast<uintptr_t>(payload) &
|
||||
~(api_constants::kPageSize - 1)) +
|
||||
api_constants::kGuardPageSize);
|
||||
}
|
||||
static V8_INLINE const BasePageHandle* FromPayload(const void* payload) {
|
||||
return FromPayload(const_cast<void*>(payload));
|
||||
}
|
||||
|
||||
HeapHandle& heap_handle() { return heap_handle_; }
|
||||
const HeapHandle& heap_handle() const { return heap_handle_; }
|
||||
|
||||
protected:
|
||||
explicit BasePageHandle(HeapHandle& heap_handle) : heap_handle_(heap_handle) {
|
||||
CPPGC_DCHECK(reinterpret_cast<uintptr_t>(this) % api_constants::kPageSize ==
|
||||
api_constants::kGuardPageSize);
|
||||
}
|
||||
|
||||
HeapHandle& heap_handle_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/caged-heap.h"
|
||||
#include "cppgc/internal/logging.h"
|
||||
#include "cppgc/platform.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if __cpp_lib_bitopts
|
||||
#include <bit>
|
||||
#endif // __cpp_lib_bitopts
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
class HeapBase;
|
||||
class HeapBaseHandle;
|
||||
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
|
||||
// AgeTable is the bytemap needed for the fast generation check in the write
|
||||
// barrier. AgeTable contains entries that correspond to 4096 bytes memory
|
||||
// regions (cards). Each entry in the table represents generation of the objects
|
||||
// that reside on the corresponding card (young, old or mixed).
|
||||
class V8_EXPORT AgeTable final {
|
||||
static constexpr size_t kRequiredSize = 1 * api_constants::kMB;
|
||||
static constexpr size_t kAllocationGranularity =
|
||||
api_constants::kAllocationGranularity;
|
||||
|
||||
public:
|
||||
// Represents age of the objects living on a single card.
|
||||
enum class Age : uint8_t { kOld, kYoung, kMixed };
|
||||
// When setting age for a range, consider or ignore ages of the adjacent
|
||||
// cards.
|
||||
enum class AdjacentCardsPolicy : uint8_t { kConsider, kIgnore };
|
||||
|
||||
static constexpr size_t kCardSizeInBytes =
|
||||
api_constants::kCagedHeapDefaultReservationSize / kRequiredSize;
|
||||
|
||||
static constexpr size_t CalculateAgeTableSizeForHeapSize(size_t heap_size) {
|
||||
return heap_size / kCardSizeInBytes;
|
||||
}
|
||||
|
||||
void SetAge(uintptr_t cage_offset, Age age) {
|
||||
table_[card(cage_offset)] = age;
|
||||
}
|
||||
|
||||
V8_INLINE Age GetAge(uintptr_t cage_offset) const {
|
||||
return table_[card(cage_offset)];
|
||||
}
|
||||
|
||||
void SetAgeForRange(uintptr_t cage_offset_begin, uintptr_t cage_offset_end,
|
||||
Age age, AdjacentCardsPolicy adjacent_cards_policy);
|
||||
|
||||
Age GetAgeForRange(uintptr_t cage_offset_begin,
|
||||
uintptr_t cage_offset_end) const;
|
||||
|
||||
void ResetForTesting();
|
||||
|
||||
private:
|
||||
V8_INLINE size_t card(uintptr_t offset) const {
|
||||
constexpr size_t kGranularityBits =
|
||||
#if __cpp_lib_bitopts
|
||||
std::countr_zero(static_cast<uint32_t>(kCardSizeInBytes));
|
||||
#elif V8_HAS_BUILTIN_CTZ
|
||||
__builtin_ctz(static_cast<uint32_t>(kCardSizeInBytes));
|
||||
#else //! V8_HAS_BUILTIN_CTZ
|
||||
// Hardcode and check with assert.
|
||||
#if defined(CPPGC_2GB_CAGE)
|
||||
11;
|
||||
#else // !defined(CPPGC_2GB_CAGE)
|
||||
12;
|
||||
#endif // !defined(CPPGC_2GB_CAGE)
|
||||
#endif // !V8_HAS_BUILTIN_CTZ
|
||||
static_assert((1 << kGranularityBits) == kCardSizeInBytes);
|
||||
const size_t entry = offset >> kGranularityBits;
|
||||
CPPGC_DCHECK(CagedHeapBase::GetAgeTableSize() > entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
#if defined(V8_CC_GNU)
|
||||
// gcc disallows flexible arrays in otherwise empty classes.
|
||||
Age table_[0];
|
||||
#else // !defined(V8_CC_GNU)
|
||||
Age table_[];
|
||||
#endif // !defined(V8_CC_GNU)
|
||||
};
|
||||
|
||||
#endif // CPPGC_YOUNG_GENERATION
|
||||
|
||||
struct CagedHeapLocalData final {
|
||||
V8_INLINE static CagedHeapLocalData& Get() {
|
||||
return *reinterpret_cast<CagedHeapLocalData*>(CagedHeapBase::GetBase());
|
||||
}
|
||||
|
||||
static constexpr size_t CalculateLocalDataSizeForHeapSize(size_t heap_size) {
|
||||
return AgeTable::CalculateAgeTableSizeForHeapSize(heap_size);
|
||||
}
|
||||
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
AgeTable age_table;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // defined(CPPGC_CAGED_HEAP)
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
|
||||
@@ -1,68 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/base-page-handle.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
class V8_EXPORT CagedHeapBase {
|
||||
public:
|
||||
V8_INLINE static uintptr_t OffsetFromAddress(const void* address) {
|
||||
return reinterpret_cast<uintptr_t>(address) &
|
||||
(api_constants::kCagedHeapReservationAlignment - 1);
|
||||
}
|
||||
|
||||
V8_INLINE static bool IsWithinCage(const void* address) {
|
||||
CPPGC_DCHECK(g_heap_base_);
|
||||
return (reinterpret_cast<uintptr_t>(address) &
|
||||
~(api_constants::kCagedHeapReservationAlignment - 1)) ==
|
||||
g_heap_base_;
|
||||
}
|
||||
|
||||
V8_INLINE static bool AreWithinCage(const void* addr1, const void* addr2) {
|
||||
#if defined(CPPGC_2GB_CAGE)
|
||||
static constexpr size_t kHeapBaseShift = sizeof(uint32_t) * CHAR_BIT - 1;
|
||||
#else //! defined(CPPGC_2GB_CAGE)
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
static constexpr size_t kHeapBaseShift =
|
||||
31 + api_constants::kPointerCompressionShift;
|
||||
#else // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
static constexpr size_t kHeapBaseShift = sizeof(uint32_t) * CHAR_BIT;
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
#endif //! defined(CPPGC_2GB_CAGE)
|
||||
static_assert((static_cast<size_t>(1) << kHeapBaseShift) ==
|
||||
api_constants::kCagedHeapMaxReservationSize);
|
||||
CPPGC_DCHECK(g_heap_base_);
|
||||
return !(((reinterpret_cast<uintptr_t>(addr1) ^ g_heap_base_) |
|
||||
(reinterpret_cast<uintptr_t>(addr2) ^ g_heap_base_)) >>
|
||||
kHeapBaseShift);
|
||||
}
|
||||
|
||||
V8_INLINE static uintptr_t GetBase() { return g_heap_base_; }
|
||||
V8_INLINE static size_t GetAgeTableSize() { return g_age_table_size_; }
|
||||
|
||||
private:
|
||||
friend class CagedHeap;
|
||||
|
||||
static uintptr_t g_heap_base_;
|
||||
static size_t g_age_table_size_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // defined(CPPGC_CAGED_HEAP)
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
#if defined(__has_attribute)
|
||||
#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE)
|
||||
#else
|
||||
#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE)
|
||||
#else
|
||||
#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0
|
||||
#endif
|
||||
|
||||
// [[no_unique_address]] comes in C++20 but supported in clang with -std >=
|
||||
// c++11.
|
||||
#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address)
|
||||
#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||
#else
|
||||
#define CPPGC_NO_UNIQUE_ADDRESS
|
||||
#endif
|
||||
|
||||
#if CPPGC_HAS_ATTRIBUTE(unused)
|
||||
#define CPPGC_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define CPPGC_UNUSED
|
||||
#endif
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
|
||||
@@ -1,93 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/type-traits.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
using FinalizationCallback = void (*)(void*);
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct HasFinalizeGarbageCollectedObject : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasFinalizeGarbageCollectedObject<
|
||||
T,
|
||||
std::void_t<decltype(std::declval<T>().FinalizeGarbageCollectedObject())>>
|
||||
: std::true_type {};
|
||||
|
||||
// The FinalizerTraitImpl specifies how to finalize objects.
|
||||
template <typename T, bool isFinalized>
|
||||
struct FinalizerTraitImpl;
|
||||
|
||||
template <typename T>
|
||||
struct FinalizerTraitImpl<T, true> {
|
||||
private:
|
||||
// Dispatch to custom FinalizeGarbageCollectedObject().
|
||||
struct Custom {
|
||||
static void Call(void* obj) {
|
||||
static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
|
||||
}
|
||||
};
|
||||
|
||||
// Dispatch to regular destructor.
|
||||
struct Destructor {
|
||||
static void Call(void* obj) { static_cast<T*>(obj)->~T(); }
|
||||
};
|
||||
|
||||
using FinalizeImpl =
|
||||
std::conditional_t<HasFinalizeGarbageCollectedObject<T>::value, Custom,
|
||||
Destructor>;
|
||||
|
||||
public:
|
||||
static void Finalize(void* obj) {
|
||||
static_assert(sizeof(T), "T must be fully defined");
|
||||
FinalizeImpl::Call(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FinalizerTraitImpl<T, false> {
|
||||
static void Finalize(void* obj) {
|
||||
static_assert(sizeof(T), "T must be fully defined");
|
||||
}
|
||||
};
|
||||
|
||||
// The FinalizerTrait is used to determine if a type requires finalization and
|
||||
// what finalization means.
|
||||
template <typename T>
|
||||
struct FinalizerTrait {
|
||||
private:
|
||||
// Object has a finalizer if it has
|
||||
// - a custom FinalizeGarbageCollectedObject method, or
|
||||
// - a destructor.
|
||||
static constexpr bool kNonTrivialFinalizer =
|
||||
internal::HasFinalizeGarbageCollectedObject<T>::value ||
|
||||
!std::is_trivially_destructible<typename std::remove_cv<T>::type>::value;
|
||||
|
||||
static void Finalize(void* obj) {
|
||||
internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr bool HasFinalizer() { return kNonTrivialFinalizer; }
|
||||
|
||||
// The callback used to finalize an object of type T.
|
||||
static constexpr FinalizationCallback kCallback =
|
||||
kNonTrivialFinalizer ? Finalize : nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr FinalizationCallback FinalizerTrait<T>::kCallback;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
|
||||
@@ -1,150 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/internal/finalizer-trait.h"
|
||||
#include "cppgc/internal/logging.h"
|
||||
#include "cppgc/internal/name-trait.h"
|
||||
#include "cppgc/trace-trait.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
using GCInfoIndex = uint16_t;
|
||||
|
||||
struct V8_EXPORT EnsureGCInfoIndexTrait final {
|
||||
// Acquires a new GC info object and updates `registered_index` with the index
|
||||
// that identifies that new info accordingly.
|
||||
template <typename T>
|
||||
V8_INLINE static GCInfoIndex EnsureIndex(
|
||||
std::atomic<GCInfoIndex>& registered_index) {
|
||||
return EnsureGCInfoIndexTraitDispatch<T>{}(registered_index);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, bool = FinalizerTrait<T>::HasFinalizer(),
|
||||
bool = NameTrait<T>::HasNonHiddenName()>
|
||||
struct EnsureGCInfoIndexTraitDispatch;
|
||||
|
||||
static GCInfoIndex V8_PRESERVE_MOST
|
||||
EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback,
|
||||
FinalizationCallback, NameCallback);
|
||||
static GCInfoIndex V8_PRESERVE_MOST EnsureGCInfoIndex(
|
||||
std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);
|
||||
static GCInfoIndex V8_PRESERVE_MOST
|
||||
EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);
|
||||
static GCInfoIndex V8_PRESERVE_MOST
|
||||
EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback);
|
||||
};
|
||||
|
||||
#define DISPATCH(has_finalizer, has_non_hidden_name, function) \
|
||||
template <typename T> \
|
||||
struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \
|
||||
T, has_finalizer, has_non_hidden_name> { \
|
||||
V8_INLINE GCInfoIndex \
|
||||
operator()(std::atomic<GCInfoIndex>& registered_index) { \
|
||||
return function; \
|
||||
} \
|
||||
};
|
||||
|
||||
// ------------------------------------------------------- //
|
||||
// DISPATCH(has_finalizer, has_non_hidden_name, function) //
|
||||
// ------------------------------------------------------- //
|
||||
DISPATCH(true, true, //
|
||||
EnsureGCInfoIndex(registered_index, //
|
||||
TraceTrait<T>::Trace, //
|
||||
FinalizerTrait<T>::kCallback, //
|
||||
NameTrait<T>::GetName)) //
|
||||
DISPATCH(true, false, //
|
||||
EnsureGCInfoIndex(registered_index, //
|
||||
TraceTrait<T>::Trace, //
|
||||
FinalizerTrait<T>::kCallback)) //
|
||||
DISPATCH(false, true, //
|
||||
EnsureGCInfoIndex(registered_index, //
|
||||
TraceTrait<T>::Trace, //
|
||||
NameTrait<T>::GetName)) //
|
||||
DISPATCH(false, false, //
|
||||
EnsureGCInfoIndex(registered_index, //
|
||||
TraceTrait<T>::Trace)) //
|
||||
|
||||
#undef DISPATCH
|
||||
|
||||
// Trait determines how the garbage collector treats objects wrt. to traversing,
|
||||
// finalization, and naming.
|
||||
template <typename T>
|
||||
struct GCInfoTrait final {
|
||||
V8_INLINE static GCInfoIndex Index() {
|
||||
static_assert(sizeof(T), "T must be fully defined");
|
||||
static std::atomic<GCInfoIndex>
|
||||
registered_index; // Uses zero initialization.
|
||||
GCInfoIndex index = registered_index.load(std::memory_order_acquire);
|
||||
if (V8_UNLIKELY(!index)) {
|
||||
index = EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index);
|
||||
CPPGC_DCHECK(index != 0);
|
||||
CPPGC_DCHECK(index == registered_index.load(std::memory_order_acquire));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static constexpr void CheckCallbacksAreDefined() {
|
||||
// No USE() macro available.
|
||||
(void)static_cast<TraceCallback>(TraceTrait<T>::Trace);
|
||||
(void)static_cast<FinalizationCallback>(FinalizerTrait<T>::kCallback);
|
||||
(void)static_cast<NameCallback>(NameTrait<T>::GetName);
|
||||
}
|
||||
};
|
||||
|
||||
// Fold types based on finalizer behavior. Note that finalizer characteristics
|
||||
// align with trace behavior, i.e., destructors are virtual when trace methods
|
||||
// are and vice versa.
|
||||
template <typename T, typename ParentMostGarbageCollectedType>
|
||||
struct GCInfoFolding final {
|
||||
static constexpr bool kHasVirtualDestructorAtBase =
|
||||
std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
|
||||
static constexpr bool kBothTypesAreTriviallyDestructible =
|
||||
std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
|
||||
std::is_trivially_destructible<T>::value;
|
||||
static constexpr bool kHasCustomFinalizerDispatchAtBase =
|
||||
internal::HasFinalizeGarbageCollectedObject<
|
||||
ParentMostGarbageCollectedType>::value;
|
||||
#ifdef CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
static constexpr bool kWantsDetailedObjectNames = true;
|
||||
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
static constexpr bool kWantsDetailedObjectNames = false;
|
||||
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
|
||||
// Always true. Forces the compiler to resolve callbacks which ensures that
|
||||
// both modes don't break without requiring compiling a separate
|
||||
// configuration. Only a single GCInfo (for `ResultType` below) will actually
|
||||
// be instantiated but existence (and well-formedness) of all callbacks is
|
||||
// checked.
|
||||
static constexpr bool WantToFold() {
|
||||
if constexpr ((kHasVirtualDestructorAtBase ||
|
||||
kBothTypesAreTriviallyDestructible ||
|
||||
kHasCustomFinalizerDispatchAtBase) &&
|
||||
!kWantsDetailedObjectNames) {
|
||||
GCInfoTrait<T>::CheckCallbacksAreDefined();
|
||||
GCInfoTrait<ParentMostGarbageCollectedType>::CheckCallbacksAreDefined();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Folding would regress name resolution when deriving names from C++
|
||||
// class names as it would just folds a name to the base class name.
|
||||
using ResultType =
|
||||
std::conditional_t<WantToFold(), ParentMostGarbageCollectedType, T>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_
|
||||
|
||||
#include "cppgc/source-location.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
void V8_EXPORT DCheckImpl(const char*,
|
||||
const SourceLocation& = SourceLocation::Current());
|
||||
[[noreturn]] void V8_EXPORT
|
||||
FatalImpl(const char*, const SourceLocation& = SourceLocation::Current());
|
||||
|
||||
// Used to ignore -Wunused-variable.
|
||||
template <typename>
|
||||
struct EatParams {};
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define CPPGC_DCHECK_MSG(condition, message) \
|
||||
do { \
|
||||
if (V8_UNLIKELY(!(condition))) { \
|
||||
::cppgc::internal::DCheckImpl(message); \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !defined(DEBUG)
|
||||
#define CPPGC_DCHECK_MSG(condition, message) \
|
||||
(static_cast<void>(::cppgc::internal::EatParams<decltype( \
|
||||
static_cast<void>(condition), message)>{}))
|
||||
#endif // !defined(DEBUG)
|
||||
|
||||
#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition)
|
||||
|
||||
#define CPPGC_CHECK_MSG(condition, message) \
|
||||
do { \
|
||||
if (V8_UNLIKELY(!(condition))) { \
|
||||
::cppgc::internal::FatalImpl(message); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_
|
||||
@@ -1,262 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/logging.h"
|
||||
#include "cppgc/sentinel-pointer.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
enum class WriteBarrierSlotType {
|
||||
kCompressed,
|
||||
kUncompressed,
|
||||
};
|
||||
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
#if defined(__clang__)
|
||||
// Attribute const allows the compiler to assume that CageBaseGlobal::g_base_
|
||||
// doesn't change (e.g. across calls) and thereby avoid redundant loads.
|
||||
#define CPPGC_CONST __attribute__((const))
|
||||
#define CPPGC_REQUIRE_CONSTANT_INIT \
|
||||
__attribute__((require_constant_initialization))
|
||||
#else // defined(__clang__)
|
||||
#define CPPGC_CONST
|
||||
#define CPPGC_REQUIRE_CONSTANT_INIT
|
||||
#endif // defined(__clang__)
|
||||
|
||||
class V8_EXPORT CageBaseGlobal final {
|
||||
public:
|
||||
V8_INLINE CPPGC_CONST static uintptr_t Get() {
|
||||
CPPGC_DCHECK(IsBaseConsistent());
|
||||
return g_base_.base;
|
||||
}
|
||||
|
||||
V8_INLINE CPPGC_CONST static bool IsSet() {
|
||||
CPPGC_DCHECK(IsBaseConsistent());
|
||||
return (g_base_.base & ~kLowerHalfWordMask) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
// We keep the lower halfword as ones to speed up decompression.
|
||||
static constexpr uintptr_t kLowerHalfWordMask =
|
||||
(api_constants::kCagedHeapReservationAlignment - 1);
|
||||
|
||||
static union alignas(api_constants::kCachelineSize) Base {
|
||||
uintptr_t base;
|
||||
char cache_line[api_constants::kCachelineSize];
|
||||
} g_base_ CPPGC_REQUIRE_CONSTANT_INIT;
|
||||
|
||||
CageBaseGlobal() = delete;
|
||||
|
||||
V8_INLINE static bool IsBaseConsistent() {
|
||||
return kLowerHalfWordMask == (g_base_.base & kLowerHalfWordMask);
|
||||
}
|
||||
|
||||
friend class CageBaseGlobalUpdater;
|
||||
};
|
||||
|
||||
#undef CPPGC_REQUIRE_CONSTANT_INIT
|
||||
#undef CPPGC_CONST
|
||||
|
||||
class V8_TRIVIAL_ABI CompressedPointer final {
|
||||
public:
|
||||
using IntegralType = uint32_t;
|
||||
static constexpr auto kWriteBarrierSlotType =
|
||||
WriteBarrierSlotType::kCompressed;
|
||||
|
||||
V8_INLINE CompressedPointer() : value_(0u) {}
|
||||
V8_INLINE explicit CompressedPointer(const void* ptr)
|
||||
: value_(Compress(ptr)) {}
|
||||
V8_INLINE explicit CompressedPointer(std::nullptr_t) : value_(0u) {}
|
||||
V8_INLINE explicit CompressedPointer(SentinelPointer)
|
||||
: value_(kCompressedSentinel) {}
|
||||
|
||||
V8_INLINE const void* Load() const { return Decompress(value_); }
|
||||
V8_INLINE const void* LoadAtomic() const {
|
||||
return Decompress(
|
||||
reinterpret_cast<const std::atomic<IntegralType>&>(value_).load(
|
||||
std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
V8_INLINE void Store(const void* ptr) { value_ = Compress(ptr); }
|
||||
V8_INLINE void StoreAtomic(const void* value) {
|
||||
reinterpret_cast<std::atomic<IntegralType>&>(value_).store(
|
||||
Compress(value), std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
V8_INLINE void Clear() { value_ = 0u; }
|
||||
V8_INLINE bool IsCleared() const { return !value_; }
|
||||
|
||||
V8_INLINE bool IsSentinel() const { return value_ == kCompressedSentinel; }
|
||||
|
||||
V8_INLINE uint32_t GetAsInteger() const { return value_; }
|
||||
|
||||
V8_INLINE friend bool operator==(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ == b.value_;
|
||||
}
|
||||
V8_INLINE friend bool operator!=(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ != b.value_;
|
||||
}
|
||||
V8_INLINE friend bool operator<(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ < b.value_;
|
||||
}
|
||||
V8_INLINE friend bool operator<=(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ <= b.value_;
|
||||
}
|
||||
V8_INLINE friend bool operator>(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ > b.value_;
|
||||
}
|
||||
V8_INLINE friend bool operator>=(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ >= b.value_;
|
||||
}
|
||||
|
||||
static V8_INLINE IntegralType Compress(const void* ptr) {
|
||||
static_assert(SentinelPointer::kSentinelValue ==
|
||||
1 << api_constants::kPointerCompressionShift,
|
||||
"The compression scheme relies on the sentinel encoded as 1 "
|
||||
"<< kPointerCompressionShift");
|
||||
static constexpr size_t kGigaCageMask =
|
||||
~(api_constants::kCagedHeapReservationAlignment - 1);
|
||||
static constexpr size_t kPointerCompressionShiftMask =
|
||||
(1 << api_constants::kPointerCompressionShift) - 1;
|
||||
|
||||
CPPGC_DCHECK(CageBaseGlobal::IsSet());
|
||||
const uintptr_t base = CageBaseGlobal::Get();
|
||||
CPPGC_DCHECK(!ptr || ptr == kSentinelPointer ||
|
||||
(base & kGigaCageMask) ==
|
||||
(reinterpret_cast<uintptr_t>(ptr) & kGigaCageMask));
|
||||
CPPGC_DCHECK(
|
||||
(reinterpret_cast<uintptr_t>(ptr) & kPointerCompressionShiftMask) == 0);
|
||||
|
||||
#if defined(CPPGC_2GB_CAGE)
|
||||
// Truncate the pointer.
|
||||
auto compressed =
|
||||
static_cast<IntegralType>(reinterpret_cast<uintptr_t>(ptr));
|
||||
#else // !defined(CPPGC_2GB_CAGE)
|
||||
const auto uptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
// Shift the pointer and truncate.
|
||||
auto compressed = static_cast<IntegralType>(
|
||||
uptr >> api_constants::kPointerCompressionShift);
|
||||
#endif // !defined(CPPGC_2GB_CAGE)
|
||||
// Normal compressed pointers must have the MSB set.
|
||||
CPPGC_DCHECK((!compressed || compressed == kCompressedSentinel) ||
|
||||
(compressed & (1 << 31)));
|
||||
return compressed;
|
||||
}
|
||||
|
||||
static V8_INLINE void* Decompress(IntegralType ptr) {
|
||||
CPPGC_DCHECK(CageBaseGlobal::IsSet());
|
||||
const uintptr_t base = CageBaseGlobal::Get();
|
||||
return Decompress(ptr, base);
|
||||
}
|
||||
|
||||
static V8_INLINE void* Decompress(IntegralType ptr, uintptr_t base) {
|
||||
CPPGC_DCHECK(CageBaseGlobal::IsSet());
|
||||
CPPGC_DCHECK(base == CageBaseGlobal::Get());
|
||||
// Treat compressed pointer as signed and cast it to uint64_t, which will
|
||||
// sign-extend it.
|
||||
#if defined(CPPGC_2GB_CAGE)
|
||||
const uint64_t mask = static_cast<uint64_t>(static_cast<int32_t>(ptr));
|
||||
#else // !defined(CPPGC_2GB_CAGE)
|
||||
// Then, shift the result. It's important to shift the unsigned
|
||||
// value, as otherwise it would result in undefined behavior.
|
||||
const uint64_t mask = static_cast<uint64_t>(static_cast<int32_t>(ptr))
|
||||
<< api_constants::kPointerCompressionShift;
|
||||
#endif // !defined(CPPGC_2GB_CAGE)
|
||||
return reinterpret_cast<void*>(mask & base);
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(CPPGC_2GB_CAGE)
|
||||
static constexpr IntegralType kCompressedSentinel =
|
||||
SentinelPointer::kSentinelValue;
|
||||
#else // !defined(CPPGC_2GB_CAGE)
|
||||
static constexpr IntegralType kCompressedSentinel =
|
||||
SentinelPointer::kSentinelValue >>
|
||||
api_constants::kPointerCompressionShift;
|
||||
#endif // !defined(CPPGC_2GB_CAGE)
|
||||
// All constructors initialize `value_`. Do not add a default value here as it
|
||||
// results in a non-atomic write on some builds, even when the atomic version
|
||||
// of the constructor is used.
|
||||
IntegralType value_;
|
||||
};
|
||||
|
||||
#endif // defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
class V8_TRIVIAL_ABI RawPointer final {
|
||||
public:
|
||||
using IntegralType = uintptr_t;
|
||||
static constexpr auto kWriteBarrierSlotType =
|
||||
WriteBarrierSlotType::kUncompressed;
|
||||
|
||||
V8_INLINE RawPointer() : ptr_(nullptr) {}
|
||||
V8_INLINE explicit RawPointer(const void* ptr) : ptr_(ptr) {}
|
||||
|
||||
V8_INLINE const void* Load() const { return ptr_; }
|
||||
V8_INLINE const void* LoadAtomic() const {
|
||||
return reinterpret_cast<const std::atomic<const void*>&>(ptr_).load(
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
V8_INLINE void Store(const void* ptr) { ptr_ = ptr; }
|
||||
V8_INLINE void StoreAtomic(const void* ptr) {
|
||||
reinterpret_cast<std::atomic<const void*>&>(ptr_).store(
|
||||
ptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
V8_INLINE void Clear() { ptr_ = nullptr; }
|
||||
V8_INLINE bool IsCleared() const { return !ptr_; }
|
||||
|
||||
V8_INLINE bool IsSentinel() const { return ptr_ == kSentinelPointer; }
|
||||
|
||||
V8_INLINE uintptr_t GetAsInteger() const {
|
||||
return reinterpret_cast<uintptr_t>(ptr_);
|
||||
}
|
||||
|
||||
V8_INLINE friend bool operator==(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ == b.ptr_;
|
||||
}
|
||||
V8_INLINE friend bool operator!=(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ != b.ptr_;
|
||||
}
|
||||
V8_INLINE friend bool operator<(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ < b.ptr_;
|
||||
}
|
||||
V8_INLINE friend bool operator<=(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ <= b.ptr_;
|
||||
}
|
||||
V8_INLINE friend bool operator>(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ > b.ptr_;
|
||||
}
|
||||
V8_INLINE friend bool operator>=(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ >= b.ptr_;
|
||||
}
|
||||
|
||||
private:
|
||||
// All constructors initialize `ptr_`. Do not add a default value here as it
|
||||
// results in a non-atomic write on some builds, even when the atomic version
|
||||
// of the constructor is used.
|
||||
const void* ptr_;
|
||||
};
|
||||
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
using DefaultMemberStorage = CompressedPointer;
|
||||
#else // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
using DefaultMemberStorage = RawPointer;
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/name-provider.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
#if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__)
|
||||
#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1
|
||||
|
||||
// Provides constexpr c-string storage for a name of fixed |Size| characters.
|
||||
// Automatically appends terminating 0 byte.
|
||||
template <size_t Size>
|
||||
struct NameBuffer {
|
||||
char name[Size + 1]{};
|
||||
|
||||
static constexpr NameBuffer FromCString(const char* str) {
|
||||
NameBuffer result;
|
||||
for (size_t i = 0; i < Size; ++i) result.name[i] = str[i];
|
||||
result.name[Size] = 0;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const char* GetTypename() {
|
||||
static constexpr char kSelfPrefix[] =
|
||||
"const char *cppgc::internal::GetTypename() [T =";
|
||||
static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix,
|
||||
sizeof(kSelfPrefix) - 1) == 0,
|
||||
"The prefix must match");
|
||||
static constexpr const char* kTypenameStart =
|
||||
__PRETTY_FUNCTION__ + sizeof(kSelfPrefix);
|
||||
static constexpr size_t kTypenameSize =
|
||||
__builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1;
|
||||
// NameBuffer is an indirection that is needed to make sure that only a
|
||||
// substring of __PRETTY_FUNCTION__ gets materialized in the binary.
|
||||
static constexpr auto buffer =
|
||||
NameBuffer<kTypenameSize>::FromCString(kTypenameStart);
|
||||
return buffer.name;
|
||||
}
|
||||
|
||||
#else
|
||||
#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0
|
||||
#endif
|
||||
|
||||
struct HeapObjectName {
|
||||
const char* value;
|
||||
bool name_was_hidden;
|
||||
};
|
||||
|
||||
enum class HeapObjectNameForUnnamedObject : uint8_t {
|
||||
kUseClassNameIfSupported,
|
||||
kUseHiddenName,
|
||||
};
|
||||
|
||||
class V8_EXPORT NameTraitBase {
|
||||
protected:
|
||||
static HeapObjectName GetNameFromTypeSignature(const char*);
|
||||
};
|
||||
|
||||
// Trait that specifies how the garbage collector retrieves the name for a
|
||||
// given object.
|
||||
template <typename T>
|
||||
class NameTrait final : public NameTraitBase {
|
||||
public:
|
||||
static constexpr bool HasNonHiddenName() {
|
||||
#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
|
||||
return true;
|
||||
#elif CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
return true;
|
||||
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
return std::is_base_of<NameProvider, T>::value;
|
||||
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
}
|
||||
|
||||
static HeapObjectName GetName(
|
||||
const void* obj, HeapObjectNameForUnnamedObject name_retrieval_mode) {
|
||||
return GetNameFor(static_cast<const T*>(obj), name_retrieval_mode);
|
||||
}
|
||||
|
||||
private:
|
||||
static HeapObjectName GetNameFor(const NameProvider* name_provider,
|
||||
HeapObjectNameForUnnamedObject) {
|
||||
// Objects inheriting from `NameProvider` are not considered unnamed as
|
||||
// users already provided a name for them.
|
||||
return {name_provider->GetHumanReadableName(), false};
|
||||
}
|
||||
|
||||
static HeapObjectName GetNameFor(
|
||||
const void*, HeapObjectNameForUnnamedObject name_retrieval_mode) {
|
||||
if (name_retrieval_mode == HeapObjectNameForUnnamedObject::kUseHiddenName)
|
||||
return {NameProvider::kHiddenName, true};
|
||||
|
||||
#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
|
||||
return {GetTypename<T>(), false};
|
||||
#elif CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
|
||||
#if defined(V8_CC_GNU)
|
||||
#define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__
|
||||
#elif defined(V8_CC_MSVC)
|
||||
#define PRETTY_FUNCTION_VALUE __FUNCSIG__
|
||||
#else
|
||||
#define PRETTY_FUNCTION_VALUE nullptr
|
||||
#endif
|
||||
|
||||
static const HeapObjectName leaky_name =
|
||||
GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE);
|
||||
return leaky_name;
|
||||
|
||||
#undef PRETTY_FUNCTION_VALUE
|
||||
|
||||
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
// We wanted to use a class name but were unable to provide one due to
|
||||
// compiler limitations or build configuration. As such, return the hidden
|
||||
// name with name_was_hidden=false, which will cause this object to be
|
||||
// visible in the snapshot.
|
||||
return {NameProvider::kHiddenName, false};
|
||||
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
}
|
||||
};
|
||||
|
||||
using NameCallback = HeapObjectName (*)(const void*,
|
||||
HeapObjectNameForUnnamedObject);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
|
||||
@@ -1,214 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "cppgc/internal/logging.h"
|
||||
#include "cppgc/trace-trait.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
class CrossThreadPersistentRegion;
|
||||
class FatalOutOfMemoryHandler;
|
||||
class RootVisitor;
|
||||
|
||||
// PersistentNode represents a variant of two states:
|
||||
// 1) traceable node with a back pointer to the Persistent object;
|
||||
// 2) freelist entry.
|
||||
class PersistentNode final {
|
||||
public:
|
||||
PersistentNode() = default;
|
||||
|
||||
PersistentNode(const PersistentNode&) = delete;
|
||||
PersistentNode& operator=(const PersistentNode&) = delete;
|
||||
|
||||
void InitializeAsUsedNode(void* owner, TraceRootCallback trace) {
|
||||
CPPGC_DCHECK(trace);
|
||||
owner_ = owner;
|
||||
trace_ = trace;
|
||||
}
|
||||
|
||||
void InitializeAsFreeNode(PersistentNode* next) {
|
||||
next_ = next;
|
||||
trace_ = nullptr;
|
||||
}
|
||||
|
||||
void UpdateOwner(void* owner) {
|
||||
CPPGC_DCHECK(IsUsed());
|
||||
owner_ = owner;
|
||||
}
|
||||
|
||||
PersistentNode* FreeListNext() const {
|
||||
CPPGC_DCHECK(!IsUsed());
|
||||
return next_;
|
||||
}
|
||||
|
||||
void Trace(RootVisitor& root_visitor) const {
|
||||
CPPGC_DCHECK(IsUsed());
|
||||
trace_(root_visitor, owner_);
|
||||
}
|
||||
|
||||
bool IsUsed() const { return trace_; }
|
||||
|
||||
void* owner() const {
|
||||
CPPGC_DCHECK(IsUsed());
|
||||
return owner_;
|
||||
}
|
||||
|
||||
private:
|
||||
// PersistentNode acts as a designated union:
|
||||
// If trace_ != nullptr, owner_ points to the corresponding Persistent handle.
|
||||
// Otherwise, next_ points to the next freed PersistentNode.
|
||||
union {
|
||||
void* owner_ = nullptr;
|
||||
PersistentNode* next_;
|
||||
};
|
||||
TraceRootCallback trace_ = nullptr;
|
||||
};
|
||||
|
||||
class V8_EXPORT PersistentRegionBase {
|
||||
using PersistentNodeSlots = std::array<PersistentNode, 256u>;
|
||||
|
||||
public:
|
||||
// Clears Persistent fields to avoid stale pointers after heap teardown.
|
||||
~PersistentRegionBase();
|
||||
|
||||
PersistentRegionBase(const PersistentRegionBase&) = delete;
|
||||
PersistentRegionBase& operator=(const PersistentRegionBase&) = delete;
|
||||
|
||||
void Iterate(RootVisitor&);
|
||||
|
||||
size_t NodesInUse() const;
|
||||
|
||||
void ClearAllUsedNodes();
|
||||
|
||||
protected:
|
||||
explicit PersistentRegionBase(const FatalOutOfMemoryHandler& oom_handler);
|
||||
|
||||
PersistentNode* TryAllocateNodeFromFreeList(void* owner,
|
||||
TraceRootCallback trace) {
|
||||
PersistentNode* node = nullptr;
|
||||
if (V8_LIKELY(free_list_head_)) {
|
||||
node = free_list_head_;
|
||||
free_list_head_ = free_list_head_->FreeListNext();
|
||||
CPPGC_DCHECK(!node->IsUsed());
|
||||
node->InitializeAsUsedNode(owner, trace);
|
||||
nodes_in_use_++;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void FreeNode(PersistentNode* node) {
|
||||
CPPGC_DCHECK(node);
|
||||
CPPGC_DCHECK(node->IsUsed());
|
||||
node->InitializeAsFreeNode(free_list_head_);
|
||||
free_list_head_ = node;
|
||||
CPPGC_DCHECK(nodes_in_use_ > 0);
|
||||
nodes_in_use_--;
|
||||
}
|
||||
|
||||
PersistentNode* RefillFreeListAndAllocateNode(void* owner,
|
||||
TraceRootCallback trace);
|
||||
|
||||
private:
|
||||
template <typename PersistentBaseClass>
|
||||
void ClearAllUsedNodes();
|
||||
|
||||
void RefillFreeList();
|
||||
|
||||
std::vector<std::unique_ptr<PersistentNodeSlots>> nodes_;
|
||||
PersistentNode* free_list_head_ = nullptr;
|
||||
size_t nodes_in_use_ = 0;
|
||||
const FatalOutOfMemoryHandler& oom_handler_;
|
||||
|
||||
friend class CrossThreadPersistentRegion;
|
||||
};
|
||||
|
||||
// Variant of PersistentRegionBase that checks whether the allocation and
|
||||
// freeing happens only on the thread that created the region.
|
||||
class V8_EXPORT PersistentRegion final : public PersistentRegionBase {
|
||||
public:
|
||||
explicit PersistentRegion(const FatalOutOfMemoryHandler&);
|
||||
// Clears Persistent fields to avoid stale pointers after heap teardown.
|
||||
~PersistentRegion() = default;
|
||||
|
||||
PersistentRegion(const PersistentRegion&) = delete;
|
||||
PersistentRegion& operator=(const PersistentRegion&) = delete;
|
||||
|
||||
V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) {
|
||||
CPPGC_DCHECK(IsCreationThread());
|
||||
auto* node = TryAllocateNodeFromFreeList(owner, trace);
|
||||
if (V8_LIKELY(node)) return node;
|
||||
|
||||
// Slow path allocation allows for checking thread correspondence.
|
||||
CPPGC_CHECK(IsCreationThread());
|
||||
return RefillFreeListAndAllocateNode(owner, trace);
|
||||
}
|
||||
|
||||
V8_INLINE void FreeNode(PersistentNode* node) {
|
||||
CPPGC_DCHECK(IsCreationThread());
|
||||
PersistentRegionBase::FreeNode(node);
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsCreationThread();
|
||||
|
||||
int creation_thread_id_;
|
||||
};
|
||||
|
||||
// CrossThreadPersistent uses PersistentRegionBase but protects it using this
|
||||
// lock when needed.
|
||||
class V8_EXPORT PersistentRegionLock final {
|
||||
public:
|
||||
PersistentRegionLock();
|
||||
~PersistentRegionLock();
|
||||
|
||||
static void AssertLocked();
|
||||
};
|
||||
|
||||
// Variant of PersistentRegionBase that checks whether the PersistentRegionLock
|
||||
// is locked.
|
||||
class V8_EXPORT CrossThreadPersistentRegion final
|
||||
: protected PersistentRegionBase {
|
||||
public:
|
||||
explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&);
|
||||
// Clears Persistent fields to avoid stale pointers after heap teardown.
|
||||
~CrossThreadPersistentRegion();
|
||||
|
||||
CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete;
|
||||
CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) =
|
||||
delete;
|
||||
|
||||
V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) {
|
||||
PersistentRegionLock::AssertLocked();
|
||||
auto* node = TryAllocateNodeFromFreeList(owner, trace);
|
||||
if (V8_LIKELY(node)) return node;
|
||||
|
||||
return RefillFreeListAndAllocateNode(owner, trace);
|
||||
}
|
||||
|
||||
V8_INLINE void FreeNode(PersistentNode* node) {
|
||||
PersistentRegionLock::AssertLocked();
|
||||
PersistentRegionBase::FreeNode(node);
|
||||
}
|
||||
|
||||
void Iterate(RootVisitor&);
|
||||
|
||||
size_t NodesInUse() const;
|
||||
|
||||
void ClearAllUsedNodes();
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
|
||||
@@ -1,243 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/internal/member-storage.h"
|
||||
#include "cppgc/internal/write-barrier.h"
|
||||
#include "cppgc/sentinel-pointer.h"
|
||||
#include "cppgc/source-location.h"
|
||||
#include "cppgc/type-traits.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
class HeapBase;
|
||||
class PersistentRegion;
|
||||
class CrossThreadPersistentRegion;
|
||||
|
||||
// Tags to distinguish between strong and weak member types.
|
||||
class StrongMemberTag;
|
||||
class WeakMemberTag;
|
||||
class UntracedMemberTag;
|
||||
|
||||
struct DijkstraWriteBarrierPolicy {
|
||||
V8_INLINE static void InitializingBarrier(const void*, const void*) {
|
||||
// Since in initializing writes the source object is always white, having no
|
||||
// barrier doesn't break the tri-color invariant.
|
||||
}
|
||||
|
||||
template <WriteBarrierSlotType SlotType>
|
||||
V8_INLINE static void AssigningBarrier(const void* slot, const void* value) {
|
||||
#ifdef CPPGC_SLIM_WRITE_BARRIER
|
||||
if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
|
||||
WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
|
||||
#else // !CPPGC_SLIM_WRITE_BARRIER
|
||||
WriteBarrier::Params params;
|
||||
const WriteBarrier::Type type =
|
||||
WriteBarrier::GetWriteBarrierType(slot, value, params);
|
||||
WriteBarrier(type, params, slot, value);
|
||||
#endif // !CPPGC_SLIM_WRITE_BARRIER
|
||||
}
|
||||
|
||||
template <WriteBarrierSlotType SlotType>
|
||||
V8_INLINE static void AssigningBarrier(const void* slot, RawPointer storage) {
|
||||
static_assert(
|
||||
SlotType == WriteBarrierSlotType::kUncompressed,
|
||||
"Assigning storages of Member and UncompressedMember is not supported");
|
||||
#ifdef CPPGC_SLIM_WRITE_BARRIER
|
||||
if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
|
||||
WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
|
||||
#else // !CPPGC_SLIM_WRITE_BARRIER
|
||||
WriteBarrier::Params params;
|
||||
const WriteBarrier::Type type =
|
||||
WriteBarrier::GetWriteBarrierType(slot, storage, params);
|
||||
WriteBarrier(type, params, slot, storage.Load());
|
||||
#endif // !CPPGC_SLIM_WRITE_BARRIER
|
||||
}
|
||||
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
template <WriteBarrierSlotType SlotType>
|
||||
V8_INLINE static void AssigningBarrier(const void* slot,
|
||||
CompressedPointer storage) {
|
||||
static_assert(
|
||||
SlotType == WriteBarrierSlotType::kCompressed,
|
||||
"Assigning storages of Member and UncompressedMember is not supported");
|
||||
#ifdef CPPGC_SLIM_WRITE_BARRIER
|
||||
if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
|
||||
WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
|
||||
#else // !CPPGC_SLIM_WRITE_BARRIER
|
||||
WriteBarrier::Params params;
|
||||
const WriteBarrier::Type type =
|
||||
WriteBarrier::GetWriteBarrierType(slot, storage, params);
|
||||
WriteBarrier(type, params, slot, storage.Load());
|
||||
#endif // !CPPGC_SLIM_WRITE_BARRIER
|
||||
}
|
||||
#endif // defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
private:
|
||||
V8_INLINE static void WriteBarrier(WriteBarrier::Type type,
|
||||
const WriteBarrier::Params& params,
|
||||
const void* slot, const void* value) {
|
||||
switch (type) {
|
||||
case WriteBarrier::Type::kGenerational:
|
||||
WriteBarrier::GenerationalBarrier<
|
||||
WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, slot);
|
||||
break;
|
||||
case WriteBarrier::Type::kMarking:
|
||||
WriteBarrier::DijkstraMarkingBarrier(params, value);
|
||||
break;
|
||||
case WriteBarrier::Type::kNone:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct NoWriteBarrierPolicy {
|
||||
V8_INLINE static void InitializingBarrier(const void*, const void*) {}
|
||||
template <WriteBarrierSlotType>
|
||||
V8_INLINE static void AssigningBarrier(const void*, const void*) {}
|
||||
template <WriteBarrierSlotType, typename MemberStorage>
|
||||
V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {}
|
||||
};
|
||||
|
||||
class V8_EXPORT SameThreadEnabledCheckingPolicyBase {
|
||||
protected:
|
||||
void CheckPointerImpl(const void* ptr, bool points_to_payload,
|
||||
bool check_off_heap_assignments);
|
||||
|
||||
const HeapBase* heap_ = nullptr;
|
||||
};
|
||||
|
||||
template <bool kCheckOffHeapAssignments>
|
||||
class V8_EXPORT SameThreadEnabledCheckingPolicy
|
||||
: private SameThreadEnabledCheckingPolicyBase {
|
||||
protected:
|
||||
template <typename T>
|
||||
void CheckPointer(const T* ptr) {
|
||||
if (!ptr || (kSentinelPointer == ptr)) return;
|
||||
|
||||
CheckPointersImplTrampoline<T>::Call(this, ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, bool = IsCompleteV<T>>
|
||||
struct CheckPointersImplTrampoline {
|
||||
static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) {
|
||||
policy->CheckPointerImpl(ptr, false, kCheckOffHeapAssignments);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CheckPointersImplTrampoline<T, true> {
|
||||
static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) {
|
||||
policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV<T>,
|
||||
kCheckOffHeapAssignments);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class DisabledCheckingPolicy {
|
||||
protected:
|
||||
V8_INLINE void CheckPointer(const void*) {}
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
// Off heap members are not connected to object graph and thus cannot ressurect
|
||||
// dead objects.
|
||||
using DefaultMemberCheckingPolicy =
|
||||
SameThreadEnabledCheckingPolicy<false /* kCheckOffHeapAssignments*/>;
|
||||
using DefaultPersistentCheckingPolicy =
|
||||
SameThreadEnabledCheckingPolicy<true /* kCheckOffHeapAssignments*/>;
|
||||
#else // !DEBUG
|
||||
using DefaultMemberCheckingPolicy = DisabledCheckingPolicy;
|
||||
using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy;
|
||||
#endif // !DEBUG
|
||||
// For CT(W)P neither marking information (for value), nor objectstart bitmap
|
||||
// (for slot) are guaranteed to be present because there's no synchronization
|
||||
// between heaps after marking.
|
||||
using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy;
|
||||
|
||||
class KeepLocationPolicy {
|
||||
public:
|
||||
constexpr const SourceLocation& Location() const { return location_; }
|
||||
|
||||
protected:
|
||||
constexpr KeepLocationPolicy() = default;
|
||||
constexpr explicit KeepLocationPolicy(const SourceLocation& location)
|
||||
: location_(location) {}
|
||||
|
||||
// KeepLocationPolicy must not copy underlying source locations.
|
||||
KeepLocationPolicy(const KeepLocationPolicy&) = delete;
|
||||
KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete;
|
||||
|
||||
// Location of the original moved from object should be preserved.
|
||||
KeepLocationPolicy(KeepLocationPolicy&&) = default;
|
||||
KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default;
|
||||
|
||||
private:
|
||||
SourceLocation location_;
|
||||
};
|
||||
|
||||
class IgnoreLocationPolicy {
|
||||
public:
|
||||
constexpr SourceLocation Location() const { return {}; }
|
||||
|
||||
protected:
|
||||
constexpr IgnoreLocationPolicy() = default;
|
||||
constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {}
|
||||
};
|
||||
|
||||
#if CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
using DefaultLocationPolicy = KeepLocationPolicy;
|
||||
#else
|
||||
using DefaultLocationPolicy = IgnoreLocationPolicy;
|
||||
#endif
|
||||
|
||||
struct StrongPersistentPolicy {
|
||||
using IsStrongPersistent = std::true_type;
|
||||
static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
|
||||
};
|
||||
|
||||
struct WeakPersistentPolicy {
|
||||
using IsStrongPersistent = std::false_type;
|
||||
static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
|
||||
};
|
||||
|
||||
struct StrongCrossThreadPersistentPolicy {
|
||||
using IsStrongPersistent = std::true_type;
|
||||
static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
|
||||
const void* object);
|
||||
};
|
||||
|
||||
struct WeakCrossThreadPersistentPolicy {
|
||||
using IsStrongPersistent = std::false_type;
|
||||
static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
|
||||
const void* object);
|
||||
};
|
||||
|
||||
// Forward declarations setting up the default policies.
|
||||
template <typename T, typename WeaknessPolicy,
|
||||
typename LocationPolicy = DefaultLocationPolicy,
|
||||
typename CheckingPolicy = DefaultCrossThreadPersistentCheckingPolicy>
|
||||
class BasicCrossThreadPersistent;
|
||||
template <typename T, typename WeaknessPolicy,
|
||||
typename LocationPolicy = DefaultLocationPolicy,
|
||||
typename CheckingPolicy = DefaultPersistentCheckingPolicy>
|
||||
class BasicPersistent;
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy = DefaultMemberCheckingPolicy,
|
||||
typename StorageType = DefaultMemberStorage>
|
||||
class BasicMember;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
|
||||
@@ -1,487 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
|
||||
#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "cppgc/heap-handle.h"
|
||||
#include "cppgc/heap-state.h"
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/atomic-entry-flag.h"
|
||||
#include "cppgc/internal/base-page-handle.h"
|
||||
#include "cppgc/internal/member-storage.h"
|
||||
#include "cppgc/platform.h"
|
||||
#include "cppgc/sentinel-pointer.h"
|
||||
#include "cppgc/trace-trait.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
#include "cppgc/internal/caged-heap-local-data.h"
|
||||
#include "cppgc/internal/caged-heap.h"
|
||||
#endif
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
class HeapHandle;
|
||||
|
||||
namespace internal {
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
class WriteBarrierTypeForCagedHeapPolicy;
|
||||
#else // !CPPGC_CAGED_HEAP
|
||||
class WriteBarrierTypeForNonCagedHeapPolicy;
|
||||
#endif // !CPPGC_CAGED_HEAP
|
||||
|
||||
class V8_EXPORT WriteBarrier final {
|
||||
public:
|
||||
enum class Type : uint8_t {
|
||||
kNone,
|
||||
kMarking,
|
||||
kGenerational,
|
||||
};
|
||||
|
||||
enum class GenerationalBarrierType : uint8_t {
|
||||
kPreciseSlot,
|
||||
kPreciseUncompressedSlot,
|
||||
kImpreciseSlot,
|
||||
};
|
||||
|
||||
struct Params {
|
||||
HeapHandle* heap = nullptr;
|
||||
#if V8_ENABLE_CHECKS
|
||||
Type type = Type::kNone;
|
||||
#endif // !V8_ENABLE_CHECKS
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
uintptr_t slot_offset = 0;
|
||||
uintptr_t value_offset = 0;
|
||||
#endif // CPPGC_CAGED_HEAP
|
||||
};
|
||||
|
||||
enum class ValueMode {
|
||||
kValuePresent,
|
||||
kNoValuePresent,
|
||||
};
|
||||
|
||||
// Returns the required write barrier for a given `slot` and `value`.
|
||||
static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value,
|
||||
Params& params);
|
||||
// Returns the required write barrier for a given `slot` and `value`.
|
||||
template <typename MemberStorage>
|
||||
static V8_INLINE Type GetWriteBarrierType(const void* slot, MemberStorage,
|
||||
Params& params);
|
||||
// Returns the required write barrier for a given `slot`.
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params,
|
||||
HeapHandleCallback callback);
|
||||
// Returns the required write barrier for a given `value`.
|
||||
static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params);
|
||||
|
||||
#ifdef CPPGC_SLIM_WRITE_BARRIER
|
||||
// A write barrier that combines `GenerationalBarrier()` and
|
||||
// `DijkstraMarkingBarrier()`. We only pass a single parameter here to clobber
|
||||
// as few registers as possible.
|
||||
template <WriteBarrierSlotType>
|
||||
static V8_NOINLINE void V8_PRESERVE_MOST
|
||||
CombinedWriteBarrierSlow(const void* slot);
|
||||
#endif // CPPGC_SLIM_WRITE_BARRIER
|
||||
|
||||
static V8_INLINE void DijkstraMarkingBarrier(const Params& params,
|
||||
const void* object);
|
||||
static V8_INLINE void DijkstraMarkingBarrierRange(
|
||||
const Params& params, const void* first_element, size_t element_size,
|
||||
size_t number_of_elements, TraceCallback trace_callback);
|
||||
static V8_INLINE void SteeleMarkingBarrier(const Params& params,
|
||||
const void* object);
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
template <GenerationalBarrierType>
|
||||
static V8_INLINE void GenerationalBarrier(const Params& params,
|
||||
const void* slot);
|
||||
#else // !CPPGC_YOUNG_GENERATION
|
||||
template <GenerationalBarrierType>
|
||||
static V8_INLINE void GenerationalBarrier(const Params& params,
|
||||
const void* slot){}
|
||||
#endif // CPPGC_YOUNG_GENERATION
|
||||
|
||||
#if V8_ENABLE_CHECKS
|
||||
static void CheckParams(Type expected_type, const Params& params);
|
||||
#else // !V8_ENABLE_CHECKS
|
||||
static void CheckParams(Type expected_type, const Params& params) {}
|
||||
#endif // !V8_ENABLE_CHECKS
|
||||
|
||||
// The FlagUpdater class allows cppgc internal to update
|
||||
// |write_barrier_enabled_|.
|
||||
class FlagUpdater;
|
||||
static bool IsEnabled() { return write_barrier_enabled_.MightBeEntered(); }
|
||||
|
||||
private:
|
||||
WriteBarrier() = delete;
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy;
|
||||
#else // !CPPGC_CAGED_HEAP
|
||||
using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy;
|
||||
#endif // !CPPGC_CAGED_HEAP
|
||||
|
||||
static void DijkstraMarkingBarrierSlow(const void* value);
|
||||
static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value);
|
||||
static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle,
|
||||
const void* first_element,
|
||||
size_t element_size,
|
||||
size_t number_of_elements,
|
||||
TraceCallback trace_callback);
|
||||
static void SteeleMarkingBarrierSlow(const void* value);
|
||||
static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value);
|
||||
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
static CagedHeapLocalData& GetLocalData(HeapHandle&);
|
||||
static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data,
|
||||
const AgeTable& age_table,
|
||||
const void* slot, uintptr_t value_offset,
|
||||
HeapHandle* heap_handle);
|
||||
static void GenerationalBarrierForUncompressedSlotSlow(
|
||||
const CagedHeapLocalData& local_data, const AgeTable& age_table,
|
||||
const void* slot, uintptr_t value_offset, HeapHandle* heap_handle);
|
||||
static void GenerationalBarrierForSourceObjectSlow(
|
||||
const CagedHeapLocalData& local_data, const void* object,
|
||||
HeapHandle* heap_handle);
|
||||
#endif // CPPGC_YOUNG_GENERATION
|
||||
|
||||
static AtomicEntryFlag write_barrier_enabled_;
|
||||
};
|
||||
|
||||
template <WriteBarrier::Type type>
|
||||
V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) {
|
||||
if constexpr (type == WriteBarrier::Type::kNone)
|
||||
return WriteBarrier::Type::kNone;
|
||||
#if V8_ENABLE_CHECKS
|
||||
params.type = type;
|
||||
#endif // !V8_ENABLE_CHECKS
|
||||
return type;
|
||||
}
|
||||
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final {
|
||||
public:
|
||||
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
|
||||
}
|
||||
|
||||
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback,
|
||||
typename MemberStorage>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
|
||||
}
|
||||
|
||||
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
return GetNoSlot(value, params, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
WriteBarrierTypeForCagedHeapPolicy() = delete;
|
||||
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback) {
|
||||
const bool within_cage = CagedHeapBase::IsWithinCage(value);
|
||||
if (!within_cage) return WriteBarrier::Type::kNone;
|
||||
|
||||
// We know that |value| points either within the normal page or to the
|
||||
// beginning of large-page, so extract the page header by bitmasking.
|
||||
BasePageHandle* page =
|
||||
BasePageHandle::FromPayload(const_cast<void*>(value));
|
||||
|
||||
HeapHandle& heap_handle = page->heap_handle();
|
||||
if (V8_UNLIKELY(heap_handle.is_incremental_marking_in_progress())) {
|
||||
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
|
||||
}
|
||||
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
}
|
||||
|
||||
template <WriteBarrier::ValueMode value_mode>
|
||||
struct ValueModeDispatch;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
|
||||
WriteBarrier::ValueMode::kValuePresent> {
|
||||
template <typename HeapHandleCallback, typename MemberStorage>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot,
|
||||
MemberStorage storage,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback) {
|
||||
if (V8_LIKELY(!WriteBarrier::IsEnabled()))
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
|
||||
return BarrierEnabledGet(slot, storage.Load(), params);
|
||||
}
|
||||
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback) {
|
||||
if (V8_LIKELY(!WriteBarrier::IsEnabled()))
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
|
||||
return BarrierEnabledGet(slot, value, params);
|
||||
}
|
||||
|
||||
private:
|
||||
static V8_INLINE WriteBarrier::Type BarrierEnabledGet(
|
||||
const void* slot, const void* value, WriteBarrier::Params& params) {
|
||||
const bool within_cage = CagedHeapBase::AreWithinCage(slot, value);
|
||||
if (!within_cage) return WriteBarrier::Type::kNone;
|
||||
|
||||
// We know that |value| points either within the normal page or to the
|
||||
// beginning of large-page, so extract the page header by bitmasking.
|
||||
BasePageHandle* page =
|
||||
BasePageHandle::FromPayload(const_cast<void*>(value));
|
||||
|
||||
HeapHandle& heap_handle = page->heap_handle();
|
||||
if (V8_LIKELY(!heap_handle.is_incremental_marking_in_progress())) {
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
if (!heap_handle.is_young_generation_enabled())
|
||||
return WriteBarrier::Type::kNone;
|
||||
params.heap = &heap_handle;
|
||||
params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
|
||||
params.value_offset = CagedHeapBase::OffsetFromAddress(value);
|
||||
return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
|
||||
#else // !CPPGC_YOUNG_GENERATION
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
#endif // !CPPGC_YOUNG_GENERATION
|
||||
}
|
||||
|
||||
// Use marking barrier.
|
||||
params.heap = &heap_handle;
|
||||
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
|
||||
WriteBarrier::ValueMode::kNoValuePresent> {
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
if (V8_LIKELY(!WriteBarrier::IsEnabled()))
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
|
||||
HeapHandle& handle = callback();
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
if (V8_LIKELY(!handle.is_incremental_marking_in_progress())) {
|
||||
if (!handle.is_young_generation_enabled()) {
|
||||
return WriteBarrier::Type::kNone;
|
||||
}
|
||||
params.heap = &handle;
|
||||
// Check if slot is on stack.
|
||||
if (V8_UNLIKELY(!CagedHeapBase::IsWithinCage(slot))) {
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
}
|
||||
params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
|
||||
return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
|
||||
}
|
||||
#else // !defined(CPPGC_YOUNG_GENERATION)
|
||||
if (V8_UNLIKELY(!handle.is_incremental_marking_in_progress())) {
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
}
|
||||
#endif // !defined(CPPGC_YOUNG_GENERATION)
|
||||
params.heap = &handle;
|
||||
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CPPGC_CAGED_HEAP
|
||||
|
||||
class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final {
|
||||
public:
|
||||
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
|
||||
}
|
||||
|
||||
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* slot, RawPointer value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
return ValueModeDispatch<value_mode>::Get(slot, value.Load(), params,
|
||||
callback);
|
||||
}
|
||||
|
||||
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void* value,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
// The slot will never be used in `Get()` below.
|
||||
return Get<WriteBarrier::ValueMode::kValuePresent>(nullptr, value, params,
|
||||
callback);
|
||||
}
|
||||
|
||||
private:
|
||||
template <WriteBarrier::ValueMode value_mode>
|
||||
struct ValueModeDispatch;
|
||||
|
||||
WriteBarrierTypeForNonCagedHeapPolicy() = delete;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
|
||||
WriteBarrier::ValueMode::kValuePresent> {
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void*, const void* object,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
// The following check covers nullptr as well as sentinel pointer.
|
||||
if (object <= static_cast<void*>(kSentinelPointer)) {
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
}
|
||||
if (V8_LIKELY(!WriteBarrier::IsEnabled())) {
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
}
|
||||
// We know that |object| is within the normal page or in the beginning of a
|
||||
// large page, so extract the page header by bitmasking.
|
||||
BasePageHandle* page =
|
||||
BasePageHandle::FromPayload(const_cast<void*>(object));
|
||||
|
||||
HeapHandle& heap_handle = page->heap_handle();
|
||||
if (V8_LIKELY(heap_handle.is_incremental_marking_in_progress())) {
|
||||
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
|
||||
}
|
||||
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
|
||||
WriteBarrier::ValueMode::kNoValuePresent> {
|
||||
template <typename HeapHandleCallback>
|
||||
static V8_INLINE WriteBarrier::Type Get(const void*, const void*,
|
||||
WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
if (V8_UNLIKELY(WriteBarrier::IsEnabled())) {
|
||||
HeapHandle& handle = callback();
|
||||
if (V8_LIKELY(handle.is_incremental_marking_in_progress())) {
|
||||
params.heap = &handle;
|
||||
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
|
||||
}
|
||||
}
|
||||
return WriteBarrier::Type::kNone;
|
||||
}
|
||||
};
|
||||
|
||||
// static
|
||||
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
|
||||
const void* slot, const void* value, WriteBarrier::Params& params) {
|
||||
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
|
||||
params, []() {});
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename MemberStorage>
|
||||
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
|
||||
const void* slot, MemberStorage value, WriteBarrier::Params& params) {
|
||||
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
|
||||
params, []() {});
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename HeapHandleCallback>
|
||||
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
|
||||
const void* slot, WriteBarrier::Params& params,
|
||||
HeapHandleCallback callback) {
|
||||
return WriteBarrierTypePolicy::Get<ValueMode::kNoValuePresent>(
|
||||
slot, nullptr, params, callback);
|
||||
}
|
||||
|
||||
// static
|
||||
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
|
||||
const void* value, WriteBarrier::Params& params) {
|
||||
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(value, params,
|
||||
[]() {});
|
||||
}
|
||||
|
||||
// static
|
||||
void WriteBarrier::DijkstraMarkingBarrier(const Params& params,
|
||||
const void* object) {
|
||||
CheckParams(Type::kMarking, params);
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
// Caged heap already filters out sentinels.
|
||||
DijkstraMarkingBarrierSlow(object);
|
||||
#else // !CPPGC_CAGED_HEAP
|
||||
DijkstraMarkingBarrierSlowWithSentinelCheck(object);
|
||||
#endif // !CPPGC_CAGED_HEAP
|
||||
}
|
||||
|
||||
// static
|
||||
void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params,
|
||||
const void* first_element,
|
||||
size_t element_size,
|
||||
size_t number_of_elements,
|
||||
TraceCallback trace_callback) {
|
||||
CheckParams(Type::kMarking, params);
|
||||
DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size,
|
||||
number_of_elements, trace_callback);
|
||||
}
|
||||
|
||||
// static
|
||||
void WriteBarrier::SteeleMarkingBarrier(const Params& params,
|
||||
const void* object) {
|
||||
CheckParams(Type::kMarking, params);
|
||||
#if defined(CPPGC_CAGED_HEAP)
|
||||
// Caged heap already filters out sentinels.
|
||||
SteeleMarkingBarrierSlow(object);
|
||||
#else // !CPPGC_CAGED_HEAP
|
||||
SteeleMarkingBarrierSlowWithSentinelCheck(object);
|
||||
#endif // !CPPGC_CAGED_HEAP
|
||||
}
|
||||
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
|
||||
// static
|
||||
template <WriteBarrier::GenerationalBarrierType type>
|
||||
void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) {
|
||||
CheckParams(Type::kGenerational, params);
|
||||
|
||||
const CagedHeapLocalData& local_data = CagedHeapLocalData::Get();
|
||||
const AgeTable& age_table = local_data.age_table;
|
||||
|
||||
// Bail out if the slot (precise or imprecise) is in young generation.
|
||||
if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung))
|
||||
return;
|
||||
|
||||
// Dispatch between different types of barriers.
|
||||
// TODO(chromium:1029379): Consider reload local_data in the slow path to
|
||||
// reduce register pressure.
|
||||
if constexpr (type == GenerationalBarrierType::kPreciseSlot) {
|
||||
GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset,
|
||||
params.heap);
|
||||
} else if constexpr (type ==
|
||||
GenerationalBarrierType::kPreciseUncompressedSlot) {
|
||||
GenerationalBarrierForUncompressedSlotSlow(
|
||||
local_data, age_table, slot, params.value_offset, params.heap);
|
||||
} else {
|
||||
GenerationalBarrierForSourceObjectSlow(local_data, slot, params.heap);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !CPPGC_YOUNG_GENERATION
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_
|
||||
#define INCLUDE_CPPGC_LIVENESS_BROKER_H_
|
||||
|
||||
#include "cppgc/heap.h"
|
||||
#include "cppgc/member.h"
|
||||
#include "cppgc/sentinel-pointer.h"
|
||||
#include "cppgc/trace-trait.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace internal {
|
||||
class LivenessBrokerFactory;
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* The broker is passed to weak callbacks to allow (temporarily) querying
|
||||
* the liveness state of an object. References to non-live objects must be
|
||||
* cleared when `IsHeapObjectAlive()` returns false.
|
||||
*
|
||||
* \code
|
||||
* class GCedWithCustomWeakCallback final
|
||||
* : public GarbageCollected<GCedWithCustomWeakCallback> {
|
||||
* public:
|
||||
* UntracedMember<Bar> bar;
|
||||
*
|
||||
* void CustomWeakCallbackMethod(const LivenessBroker& broker) {
|
||||
* if (!broker.IsHeapObjectAlive(bar))
|
||||
* bar = nullptr;
|
||||
* }
|
||||
*
|
||||
* void Trace(cppgc::Visitor* visitor) const {
|
||||
* visitor->RegisterWeakCallbackMethod<
|
||||
* GCedWithCustomWeakCallback,
|
||||
* &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this);
|
||||
* }
|
||||
* };
|
||||
* \endcode
|
||||
*/
|
||||
class V8_EXPORT LivenessBroker final {
|
||||
public:
|
||||
template <typename T>
|
||||
bool IsHeapObjectAlive(const T* object) const {
|
||||
// - nullptr objects are considered alive to allow weakness to be used from
|
||||
// stack while running into a conservative GC. Treating nullptr as dead
|
||||
// would mean that e.g. custom collections could not be strongified on
|
||||
// stack.
|
||||
// - Sentinel pointers are also preserved in weakness and not cleared.
|
||||
return !object || object == kSentinelPointer ||
|
||||
IsHeapObjectAliveImpl(
|
||||
TraceTrait<T>::GetTraceDescriptor(object).base_object_payload);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsHeapObjectAlive(const WeakMember<T>& weak_member) const {
|
||||
return IsHeapObjectAlive<T>(weak_member.Get());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsHeapObjectAlive(const UntracedMember<T>& untraced_member) const {
|
||||
return IsHeapObjectAlive<T>(untraced_member.Get());
|
||||
}
|
||||
|
||||
private:
|
||||
LivenessBroker() = default;
|
||||
|
||||
bool IsHeapObjectAliveImpl(const void*) const;
|
||||
|
||||
friend class internal::LivenessBrokerFactory;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_MACROS_H_
|
||||
#define INCLUDE_CPPGC_MACROS_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "cppgc/internal/compiler-specific.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
// Use CPPGC_STACK_ALLOCATED if the object is only stack allocated.
|
||||
// Add the CPPGC_STACK_ALLOCATED_IGNORE annotation on a case-by-case basis when
|
||||
// enforcement of CPPGC_STACK_ALLOCATED should be suppressed.
|
||||
#if defined(__clang__)
|
||||
#define CPPGC_STACK_ALLOCATED() \
|
||||
public: \
|
||||
using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \
|
||||
\
|
||||
private: \
|
||||
void* operator new(size_t) = delete; \
|
||||
void* operator new(size_t, void*) = delete; \
|
||||
static_assert(true, "Force semicolon.")
|
||||
#define CPPGC_STACK_ALLOCATED_IGNORE(bug_or_reason) \
|
||||
__attribute__((annotate("stack_allocated_ignore")))
|
||||
#else // !defined(__clang__)
|
||||
#define CPPGC_STACK_ALLOCATED() static_assert(true, "Force semicolon.")
|
||||
#define CPPGC_STACK_ALLOCATED_IGNORE(bug_or_reason)
|
||||
#endif // !defined(__clang__)
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_MACROS_H_
|
||||
@@ -1,629 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_MEMBER_H_
|
||||
#define INCLUDE_CPPGC_MEMBER_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
#include "cppgc/internal/member-storage.h"
|
||||
#include "cppgc/internal/pointer-policies.h"
|
||||
#include "cppgc/sentinel-pointer.h"
|
||||
#include "cppgc/type-traits.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace subtle {
|
||||
class HeapConsistency;
|
||||
} // namespace subtle
|
||||
|
||||
class Visitor;
|
||||
|
||||
namespace internal {
|
||||
|
||||
// MemberBase always refers to the object as const object and defers to
|
||||
// BasicMember on casting to the right type as needed.
|
||||
template <typename StorageType>
|
||||
class V8_TRIVIAL_ABI MemberBase {
|
||||
public:
|
||||
using RawStorage = StorageType;
|
||||
|
||||
protected:
|
||||
struct AtomicInitializerTag {};
|
||||
|
||||
V8_INLINE MemberBase() = default;
|
||||
V8_INLINE explicit MemberBase(const void* value) : raw_(value) {}
|
||||
V8_INLINE MemberBase(const void* value, AtomicInitializerTag) {
|
||||
SetRawAtomic(value);
|
||||
}
|
||||
|
||||
V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {}
|
||||
V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {}
|
||||
V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {}
|
||||
|
||||
V8_INLINE const void** GetRawSlot() const {
|
||||
return reinterpret_cast<const void**>(const_cast<MemberBase*>(this));
|
||||
}
|
||||
V8_INLINE const void* GetRaw() const { return raw_.Load(); }
|
||||
V8_INLINE void SetRaw(void* value) { raw_.Store(value); }
|
||||
|
||||
V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); }
|
||||
V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); }
|
||||
|
||||
V8_INLINE RawStorage GetRawStorage() const { return raw_; }
|
||||
V8_INLINE void SetRawStorageAtomic(RawStorage other) {
|
||||
reinterpret_cast<std::atomic<RawStorage>&>(raw_).store(
|
||||
other, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
V8_INLINE bool IsCleared() const { return raw_.IsCleared(); }
|
||||
|
||||
V8_INLINE void ClearFromGC() const { raw_.Clear(); }
|
||||
|
||||
private:
|
||||
friend class MemberDebugHelper;
|
||||
|
||||
mutable RawStorage raw_;
|
||||
};
|
||||
|
||||
// The basic class from which all Member classes are 'generated'.
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
class V8_TRIVIAL_ABI BasicMember final : private MemberBase<StorageType>,
|
||||
private CheckingPolicy {
|
||||
using Base = MemberBase<StorageType>;
|
||||
|
||||
public:
|
||||
using PointeeType = T;
|
||||
using RawStorage = typename Base::RawStorage;
|
||||
|
||||
V8_INLINE constexpr BasicMember() = default;
|
||||
V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT
|
||||
V8_INLINE BasicMember(SentinelPointer s) : Base(s) {} // NOLINT
|
||||
V8_INLINE BasicMember(T* raw) : Base(raw) { // NOLINT
|
||||
InitializingWriteBarrier(raw);
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
V8_INLINE BasicMember(T& raw) // NOLINT
|
||||
: BasicMember(&raw) {}
|
||||
|
||||
// Atomic ctor. Using the AtomicInitializerTag forces BasicMember to
|
||||
// initialize using atomic assignments. This is required for preventing
|
||||
// data races with concurrent marking.
|
||||
using AtomicInitializerTag = typename Base::AtomicInitializerTag;
|
||||
V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic)
|
||||
: Base(nullptr, atomic) {}
|
||||
V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic)
|
||||
: Base(s, atomic) {}
|
||||
V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic)
|
||||
: Base(raw, atomic) {
|
||||
InitializingWriteBarrier(raw);
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic)
|
||||
: BasicMember(&raw, atomic) {}
|
||||
|
||||
// Copy ctor.
|
||||
V8_INLINE BasicMember(const BasicMember& other)
|
||||
: BasicMember(other.GetRawStorage()) {}
|
||||
|
||||
// Heterogeneous copy constructors. When the source pointer have a different
|
||||
// type, perform a compress-decompress round, because the source pointer may
|
||||
// need to be adjusted.
|
||||
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
|
||||
typename OtherCheckingPolicy,
|
||||
std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr>
|
||||
V8_INLINE BasicMember( // NOLINT
|
||||
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy, StorageType>& other)
|
||||
: BasicMember(other.GetRawStorage()) {}
|
||||
|
||||
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
|
||||
typename OtherCheckingPolicy,
|
||||
std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr>
|
||||
V8_INLINE BasicMember( // NOLINT
|
||||
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy, StorageType>& other)
|
||||
: BasicMember(other.Get()) {}
|
||||
|
||||
// Move ctor.
|
||||
V8_INLINE BasicMember(BasicMember&& other) noexcept
|
||||
: BasicMember(other.GetRawStorage()) {
|
||||
other.Clear();
|
||||
}
|
||||
|
||||
// Heterogeneous move constructors. When the source pointer have a different
|
||||
// type, perform a compress-decompress round, because the source pointer may
|
||||
// need to be adjusted.
|
||||
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
|
||||
typename OtherCheckingPolicy,
|
||||
std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr>
|
||||
V8_INLINE BasicMember(
|
||||
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy,
|
||||
StorageType>&& other) noexcept
|
||||
: BasicMember(other.GetRawStorage()) {
|
||||
other.Clear();
|
||||
}
|
||||
|
||||
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
|
||||
typename OtherCheckingPolicy,
|
||||
std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr>
|
||||
V8_INLINE BasicMember(
|
||||
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy,
|
||||
StorageType>&& other) noexcept
|
||||
: BasicMember(other.Get()) {
|
||||
other.Clear();
|
||||
}
|
||||
|
||||
// Construction from Persistent.
|
||||
template <typename U, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy,
|
||||
typename PersistentCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
V8_INLINE BasicMember(const BasicPersistent<U, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy,
|
||||
PersistentCheckingPolicy>& p)
|
||||
: BasicMember(p.Get()) {}
|
||||
|
||||
// Copy assignment.
|
||||
V8_INLINE BasicMember& operator=(const BasicMember& other) {
|
||||
return operator=(other.GetRawStorage());
|
||||
}
|
||||
|
||||
// Heterogeneous copy assignment. When the source pointer have a different
|
||||
// type, perform a compress-decompress round, because the source pointer may
|
||||
// need to be adjusted.
|
||||
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
|
||||
typename OtherCheckingPolicy>
|
||||
V8_INLINE BasicMember& operator=(
|
||||
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy, StorageType>& other) {
|
||||
if constexpr (internal::IsDecayedSameV<T, U>) {
|
||||
return operator=(other.GetRawStorage());
|
||||
} else {
|
||||
static_assert(internal::IsStrictlyBaseOfV<T, U>);
|
||||
return operator=(other.Get());
|
||||
}
|
||||
}
|
||||
|
||||
// Move assignment.
|
||||
V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept {
|
||||
operator=(other.GetRawStorage());
|
||||
other.Clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Heterogeneous move assignment. When the source pointer have a different
|
||||
// type, perform a compress-decompress round, because the source pointer may
|
||||
// need to be adjusted.
|
||||
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
|
||||
typename OtherCheckingPolicy>
|
||||
V8_INLINE BasicMember& operator=(
|
||||
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy,
|
||||
StorageType>&& other) noexcept {
|
||||
if constexpr (internal::IsDecayedSameV<T, U>) {
|
||||
operator=(other.GetRawStorage());
|
||||
} else {
|
||||
static_assert(internal::IsStrictlyBaseOfV<T, U>);
|
||||
operator=(other.Get());
|
||||
}
|
||||
other.Clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assignment from Persistent.
|
||||
template <typename U, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy,
|
||||
typename PersistentCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
V8_INLINE BasicMember& operator=(
|
||||
const BasicPersistent<U, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
|
||||
V8_INLINE BasicMember& operator=(T* other) {
|
||||
Base::SetRawAtomic(other);
|
||||
AssigningWriteBarrier(other);
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
V8_INLINE BasicMember& operator=(std::nullptr_t) {
|
||||
Clear();
|
||||
return *this;
|
||||
}
|
||||
V8_INLINE BasicMember& operator=(SentinelPointer s) {
|
||||
Base::SetRawAtomic(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename OtherWeaknessTag, typename OtherBarrierPolicy,
|
||||
typename OtherCheckingPolicy>
|
||||
V8_INLINE void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy, StorageType>& other) {
|
||||
auto tmp = GetRawStorage();
|
||||
*this = other;
|
||||
other = tmp;
|
||||
}
|
||||
|
||||
V8_INLINE explicit operator bool() const { return !Base::IsCleared(); }
|
||||
V8_INLINE operator T*() const { return Get(); }
|
||||
V8_INLINE T* operator->() const { return Get(); }
|
||||
V8_INLINE T& operator*() const { return *Get(); }
|
||||
|
||||
// CFI cast exemption to allow passing SentinelPointer through T* and support
|
||||
// heterogeneous assignments between different Member and Persistent handles
|
||||
// based on their actual types.
|
||||
V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
|
||||
// Executed by the mutator, hence non atomic load.
|
||||
//
|
||||
// The const_cast below removes the constness from MemberBase storage. The
|
||||
// following static_cast re-adds any constness if specified through the
|
||||
// user-visible template parameter T.
|
||||
return static_cast<T*>(const_cast<void*>(Base::GetRaw()));
|
||||
}
|
||||
|
||||
V8_INLINE void Clear() {
|
||||
Base::SetRawStorageAtomic(RawStorage{});
|
||||
}
|
||||
|
||||
V8_INLINE T* Release() {
|
||||
T* result = Get();
|
||||
Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
V8_INLINE const T** GetSlotForTesting() const {
|
||||
return reinterpret_cast<const T**>(Base::GetRawSlot());
|
||||
}
|
||||
|
||||
V8_INLINE RawStorage GetRawStorage() const {
|
||||
return Base::GetRawStorage();
|
||||
}
|
||||
|
||||
private:
|
||||
V8_INLINE explicit BasicMember(RawStorage raw) : Base(raw) {
|
||||
InitializingWriteBarrier(Get());
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
V8_INLINE BasicMember& operator=(RawStorage other) {
|
||||
Base::SetRawStorageAtomic(other);
|
||||
AssigningWriteBarrier();
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
V8_INLINE const T* GetRawAtomic() const {
|
||||
return static_cast<const T*>(Base::GetRawAtomic());
|
||||
}
|
||||
|
||||
V8_INLINE void InitializingWriteBarrier(T* value) const {
|
||||
WriteBarrierPolicy::InitializingBarrier(Base::GetRawSlot(), value);
|
||||
}
|
||||
V8_INLINE void AssigningWriteBarrier(T* value) const {
|
||||
WriteBarrierPolicy::template AssigningBarrier<
|
||||
StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), value);
|
||||
}
|
||||
V8_INLINE void AssigningWriteBarrier() const {
|
||||
WriteBarrierPolicy::template AssigningBarrier<
|
||||
StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(),
|
||||
Base::GetRawStorage());
|
||||
}
|
||||
|
||||
V8_INLINE void ClearFromGC() const { Base::ClearFromGC(); }
|
||||
|
||||
V8_INLINE T* GetFromGC() const { return Get(); }
|
||||
|
||||
friend class cppgc::subtle::HeapConsistency;
|
||||
friend class cppgc::Visitor;
|
||||
template <typename U>
|
||||
friend struct cppgc::TraceTrait;
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename StorageType1>
|
||||
friend class BasicMember;
|
||||
};
|
||||
|
||||
// Member equality operators.
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator==(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
|
||||
StorageType>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
|
||||
StorageType>& member2) {
|
||||
if constexpr (internal::IsDecayedSameV<T1, T2>) {
|
||||
// Check compressed pointers if types are the same.
|
||||
return member1.GetRawStorage() == member2.GetRawStorage();
|
||||
} else {
|
||||
static_assert(internal::IsStrictlyBaseOfV<T1, T2> ||
|
||||
internal::IsStrictlyBaseOfV<T2, T1>);
|
||||
// Otherwise, check decompressed pointers.
|
||||
return member1.Get() == member2.Get();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator!=(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
|
||||
StorageType>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
|
||||
StorageType>& member2) {
|
||||
return !(member1 == member2);
|
||||
}
|
||||
|
||||
// Equality with raw pointers.
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType, typename U>
|
||||
V8_INLINE bool operator==(
|
||||
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
|
||||
StorageType>& member,
|
||||
U* raw) {
|
||||
// Never allow comparison with erased pointers.
|
||||
static_assert(!internal::IsDecayedSameV<void, U>);
|
||||
|
||||
if constexpr (internal::IsDecayedSameV<T, U>) {
|
||||
// Check compressed pointers if types are the same.
|
||||
return member.GetRawStorage() == StorageType(raw);
|
||||
} else if constexpr (internal::IsStrictlyBaseOfV<T, U>) {
|
||||
// Cast the raw pointer to T, which may adjust the pointer.
|
||||
return member.GetRawStorage() == StorageType(static_cast<T*>(raw));
|
||||
} else {
|
||||
// Otherwise, decompressed the member.
|
||||
return member.Get() == raw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType, typename U>
|
||||
V8_INLINE bool operator!=(
|
||||
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
|
||||
StorageType>& member,
|
||||
U* raw) {
|
||||
return !(member == raw);
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename WeaknessTag,
|
||||
typename WriteBarrierPolicy, typename CheckingPolicy,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator==(
|
||||
T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& member) {
|
||||
return member == raw;
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename WeaknessTag,
|
||||
typename WriteBarrierPolicy, typename CheckingPolicy,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator!=(
|
||||
T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& member) {
|
||||
return !(raw == member);
|
||||
}
|
||||
|
||||
// Equality with sentinel.
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator==(
|
||||
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
|
||||
StorageType>& member,
|
||||
SentinelPointer) {
|
||||
return member.GetRawStorage().IsSentinel();
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator!=(
|
||||
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
|
||||
StorageType>& member,
|
||||
SentinelPointer s) {
|
||||
return !(member == s);
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator==(
|
||||
SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& member) {
|
||||
return member == s;
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator!=(
|
||||
SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& member) {
|
||||
return !(s == member);
|
||||
}
|
||||
|
||||
// Equality with nullptr.
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator==(
|
||||
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
|
||||
StorageType>& member,
|
||||
std::nullptr_t) {
|
||||
return !static_cast<bool>(member);
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator!=(
|
||||
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
|
||||
StorageType>& member,
|
||||
std::nullptr_t n) {
|
||||
return !(member == n);
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator==(
|
||||
std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& member) {
|
||||
return member == n;
|
||||
}
|
||||
|
||||
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
|
||||
typename CheckingPolicy, typename StorageType>
|
||||
V8_INLINE bool operator!=(
|
||||
std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>& member) {
|
||||
return !(n == member);
|
||||
}
|
||||
|
||||
// Relational operators.
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator<(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
|
||||
StorageType>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
|
||||
StorageType>& member2) {
|
||||
static_assert(
|
||||
internal::IsDecayedSameV<T1, T2>,
|
||||
"Comparison works only for same pointer type modulo cv-qualifiers");
|
||||
return member1.GetRawStorage() < member2.GetRawStorage();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator<=(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
|
||||
StorageType>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
|
||||
StorageType>& member2) {
|
||||
static_assert(
|
||||
internal::IsDecayedSameV<T1, T2>,
|
||||
"Comparison works only for same pointer type modulo cv-qualifiers");
|
||||
return member1.GetRawStorage() <= member2.GetRawStorage();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator>(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
|
||||
StorageType>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
|
||||
StorageType>& member2) {
|
||||
static_assert(
|
||||
internal::IsDecayedSameV<T1, T2>,
|
||||
"Comparison works only for same pointer type modulo cv-qualifiers");
|
||||
return member1.GetRawStorage() > member2.GetRawStorage();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2,
|
||||
typename StorageType>
|
||||
V8_INLINE bool operator>=(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
|
||||
StorageType>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
|
||||
StorageType>& member2) {
|
||||
static_assert(
|
||||
internal::IsDecayedSameV<T1, T2>,
|
||||
"Comparison works only for same pointer type modulo cv-qualifiers");
|
||||
return member1.GetRawStorage() >= member2.GetRawStorage();
|
||||
}
|
||||
|
||||
template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy,
|
||||
typename StorageType>
|
||||
struct IsWeak<internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy,
|
||||
CheckingPolicy, StorageType>>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Members are used in classes to contain strong pointers to other garbage
|
||||
* collected objects. All Member fields of a class must be traced in the class'
|
||||
* trace method.
|
||||
*/
|
||||
template <typename T>
|
||||
using Member = internal::BasicMember<
|
||||
T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy,
|
||||
internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>;
|
||||
|
||||
/**
|
||||
* WeakMember is similar to Member in that it is used to point to other garbage
|
||||
* collected objects. However instead of creating a strong pointer to the
|
||||
* object, the WeakMember creates a weak pointer, which does not keep the
|
||||
* pointee alive. Hence if all pointers to to a heap allocated object are weak
|
||||
* the object will be garbage collected. At the time of GC the weak pointers
|
||||
* will automatically be set to null.
|
||||
*/
|
||||
template <typename T>
|
||||
using WeakMember = internal::BasicMember<
|
||||
T, internal::WeakMemberTag, internal::DijkstraWriteBarrierPolicy,
|
||||
internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>;
|
||||
|
||||
/**
|
||||
* UntracedMember is a pointer to an on-heap object that is not traced for some
|
||||
* reason. Do not use this unless you know what you are doing. Keeping raw
|
||||
* pointers to on-heap objects is prohibited unless used from stack. Pointee
|
||||
* must be kept alive through other means.
|
||||
*/
|
||||
template <typename T>
|
||||
using UntracedMember = internal::BasicMember<
|
||||
T, internal::UntracedMemberTag, internal::NoWriteBarrierPolicy,
|
||||
internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>;
|
||||
|
||||
namespace subtle {
|
||||
|
||||
/**
|
||||
* UncompressedMember. Use with care in hot paths that would otherwise cause
|
||||
* many decompression cycles.
|
||||
*/
|
||||
template <typename T>
|
||||
using UncompressedMember = internal::BasicMember<
|
||||
T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy,
|
||||
internal::DefaultMemberCheckingPolicy, internal::RawPointer>;
|
||||
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
/**
|
||||
* CompressedMember. Default implementation of cppgc::Member on builds with
|
||||
* pointer compression.
|
||||
*/
|
||||
template <typename T>
|
||||
using CompressedMember = internal::BasicMember<
|
||||
T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy,
|
||||
internal::DefaultMemberCheckingPolicy, internal::CompressedPointer>;
|
||||
#endif // defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
} // namespace subtle
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct Dummy;
|
||||
|
||||
static constexpr size_t kSizeOfMember = sizeof(Member<Dummy>);
|
||||
static constexpr size_t kSizeOfUncompressedMember =
|
||||
sizeof(subtle::UncompressedMember<Dummy>);
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
static constexpr size_t kSizeofCompressedMember =
|
||||
sizeof(subtle::CompressedMember<Dummy>);
|
||||
#endif // defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_MEMBER_H_
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_NAME_PROVIDER_H_
|
||||
#define INCLUDE_CPPGC_NAME_PROVIDER_H_
|
||||
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* NameProvider allows for providing a human-readable name for garbage-collected
|
||||
* objects.
|
||||
*
|
||||
* There's two cases of names to distinguish:
|
||||
* a. Explicitly specified names via using NameProvider. Such names are always
|
||||
* preserved in the system.
|
||||
* b. Internal names that Oilpan infers from a C++ type on the class hierarchy
|
||||
* of the object. This is not necessarily the type of the actually
|
||||
* instantiated object.
|
||||
*
|
||||
* Depending on the build configuration, Oilpan may hide names, i.e., represent
|
||||
* them with kHiddenName, of case b. to avoid exposing internal details.
|
||||
*/
|
||||
class V8_EXPORT NameProvider {
|
||||
public:
|
||||
/**
|
||||
* Name that is used when hiding internals.
|
||||
*/
|
||||
static constexpr const char kHiddenName[] = "InternalNode";
|
||||
|
||||
/**
|
||||
* Name that is used in case compiler support is missing for composing a name
|
||||
* from C++ types.
|
||||
*/
|
||||
static constexpr const char kNoNameDeducible[] = "<No name>";
|
||||
|
||||
/**
|
||||
* Indicating whether the build supports extracting C++ names as object names.
|
||||
*
|
||||
* @returns true if C++ names should be hidden and represented by kHiddenName.
|
||||
*/
|
||||
static constexpr bool SupportsCppClassNamesAsObjectNames() {
|
||||
#if CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
return true;
|
||||
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
return false;
|
||||
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
|
||||
}
|
||||
|
||||
virtual ~NameProvider() = default;
|
||||
|
||||
/**
|
||||
* Specifies a name for the garbage-collected object. Such names will never
|
||||
* be hidden, as they are explicitly specified by the user of this API.
|
||||
*
|
||||
* @returns a human readable name for the object.
|
||||
*/
|
||||
virtual const char* GetHumanReadableName() const = 0;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
|
||||
#define INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "cppgc/type-traits.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct V8_EXPORT BaseObjectSizeTrait {
|
||||
protected:
|
||||
static size_t GetObjectSizeForGarbageCollected(const void*);
|
||||
static size_t GetObjectSizeForGarbageCollectedMixin(const void*);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace subtle {
|
||||
|
||||
/**
|
||||
* Trait specifying how to get the size of an object that was allocated using
|
||||
* `MakeGarbageCollected()`. Also supports querying the size with an inner
|
||||
* pointer to a mixin.
|
||||
*/
|
||||
template <typename T, bool = IsGarbageCollectedMixinTypeV<T>>
|
||||
struct ObjectSizeTrait;
|
||||
|
||||
template <typename T>
|
||||
struct ObjectSizeTrait<T, false> : cppgc::internal::BaseObjectSizeTrait {
|
||||
static_assert(sizeof(T), "T must be fully defined");
|
||||
static_assert(IsGarbageCollectedTypeV<T>,
|
||||
"T must be of type GarbageCollected or GarbageCollectedMixin");
|
||||
|
||||
static size_t GetSize(const T& object) {
|
||||
return GetObjectSizeForGarbageCollected(&object);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ObjectSizeTrait<T, true> : cppgc::internal::BaseObjectSizeTrait {
|
||||
static_assert(sizeof(T), "T must be fully defined");
|
||||
|
||||
static size_t GetSize(const T& object) {
|
||||
return GetObjectSizeForGarbageCollectedMixin(&object);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
|
||||
@@ -1,377 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_PERSISTENT_H_
|
||||
#define INCLUDE_CPPGC_PERSISTENT_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "cppgc/internal/persistent-node.h"
|
||||
#include "cppgc/internal/pointer-policies.h"
|
||||
#include "cppgc/sentinel-pointer.h"
|
||||
#include "cppgc/source-location.h"
|
||||
#include "cppgc/type-traits.h"
|
||||
#include "cppgc/visitor.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
// PersistentBase always refers to the object as const object and defers to
|
||||
// BasicPersistent on casting to the right type as needed.
|
||||
class PersistentBase {
|
||||
protected:
|
||||
PersistentBase() = default;
|
||||
explicit PersistentBase(const void* raw) : raw_(raw) {}
|
||||
|
||||
const void* GetValue() const { return raw_; }
|
||||
void SetValue(const void* value) { raw_ = value; }
|
||||
|
||||
PersistentNode* GetNode() const { return node_; }
|
||||
void SetNode(PersistentNode* node) { node_ = node; }
|
||||
|
||||
// Performs a shallow clear which assumes that internal persistent nodes are
|
||||
// destroyed elsewhere.
|
||||
void ClearFromGC() const {
|
||||
raw_ = nullptr;
|
||||
node_ = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable const void* raw_ = nullptr;
|
||||
mutable PersistentNode* node_ = nullptr;
|
||||
|
||||
friend class PersistentRegionBase;
|
||||
};
|
||||
|
||||
// The basic class from which all Persistent classes are generated.
|
||||
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
|
||||
typename CheckingPolicy>
|
||||
class BasicPersistent final : public PersistentBase,
|
||||
public LocationPolicy,
|
||||
private WeaknessPolicy,
|
||||
private CheckingPolicy {
|
||||
public:
|
||||
using typename WeaknessPolicy::IsStrongPersistent;
|
||||
using PointeeType = T;
|
||||
|
||||
// Null-state/sentinel constructors.
|
||||
BasicPersistent( // NOLINT
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: LocationPolicy(loc) {}
|
||||
|
||||
BasicPersistent(std::nullptr_t, // NOLINT
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: LocationPolicy(loc) {}
|
||||
|
||||
BasicPersistent( // NOLINT
|
||||
SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
|
||||
: PersistentBase(s), LocationPolicy(loc) {}
|
||||
|
||||
// Raw value constructors.
|
||||
BasicPersistent(T* raw, // NOLINT
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: PersistentBase(raw), LocationPolicy(loc) {
|
||||
if (!IsValid()) return;
|
||||
SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
|
||||
.AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
BasicPersistent(T& raw, // NOLINT
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicPersistent(&raw, loc) {}
|
||||
|
||||
// Copy ctor.
|
||||
BasicPersistent(const BasicPersistent& other,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicPersistent(other.Get(), loc) {}
|
||||
|
||||
// Heterogeneous ctor.
|
||||
template <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
// NOLINTNEXTLINE
|
||||
BasicPersistent(
|
||||
const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>& other,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicPersistent(other.Get(), loc) {}
|
||||
|
||||
// Move ctor. The heterogeneous move ctor is not supported since e.g.
|
||||
// persistent can't reuse persistent node from weak persistent.
|
||||
BasicPersistent(
|
||||
BasicPersistent&& other,
|
||||
const SourceLocation& loc = SourceLocation::Current()) noexcept
|
||||
: PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
|
||||
if (!IsValid()) return;
|
||||
GetNode()->UpdateOwner(this);
|
||||
other.SetValue(nullptr);
|
||||
other.SetNode(nullptr);
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
// Constructor from member.
|
||||
template <typename U, typename MemberBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
// NOLINTNEXTLINE
|
||||
BasicPersistent(const internal::BasicMember<
|
||||
U, MemberBarrierPolicy, MemberWeaknessTag,
|
||||
MemberCheckingPolicy, MemberStorageType>& member,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicPersistent(member.Get(), loc) {}
|
||||
|
||||
~BasicPersistent() { Clear(); }
|
||||
|
||||
// Copy assignment.
|
||||
BasicPersistent& operator=(const BasicPersistent& other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
|
||||
template <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicPersistent& operator=(
|
||||
const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
|
||||
// Move assignment.
|
||||
BasicPersistent& operator=(BasicPersistent&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
Clear();
|
||||
PersistentBase::operator=(std::move(other));
|
||||
LocationPolicy::operator=(std::move(other));
|
||||
if (!IsValid()) return *this;
|
||||
GetNode()->UpdateOwner(this);
|
||||
other.SetValue(nullptr);
|
||||
other.SetNode(nullptr);
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assignment from member.
|
||||
template <typename U, typename MemberBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicPersistent& operator=(
|
||||
const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
|
||||
MemberCheckingPolicy, MemberStorageType>&
|
||||
member) {
|
||||
return operator=(member.Get());
|
||||
}
|
||||
|
||||
BasicPersistent& operator=(T* other) {
|
||||
Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BasicPersistent& operator=(std::nullptr_t) {
|
||||
Clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
BasicPersistent& operator=(SentinelPointer s) {
|
||||
Assign(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return Get(); }
|
||||
// Historically we allow implicit conversions to T*.
|
||||
// NOLINTNEXTLINE
|
||||
operator T*() const { return Get(); }
|
||||
T* operator->() const { return Get(); }
|
||||
T& operator*() const { return *Get(); }
|
||||
|
||||
// CFI cast exemption to allow passing SentinelPointer through T* and support
|
||||
// heterogeneous assignments between different Member and Persistent handles
|
||||
// based on their actual types.
|
||||
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
|
||||
// The const_cast below removes the constness from PersistentBase storage.
|
||||
// The following static_cast re-adds any constness if specified through the
|
||||
// user-visible template parameter T.
|
||||
return static_cast<T*>(const_cast<void*>(GetValue()));
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
// Simplified version of `Assign()` to allow calling without a complete type
|
||||
// `T`.
|
||||
if (IsValid()) {
|
||||
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
}
|
||||
SetValue(nullptr);
|
||||
}
|
||||
|
||||
T* Release() {
|
||||
T* result = Get();
|
||||
Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
|
||||
typename OtherLocationPolicy = LocationPolicy,
|
||||
typename OtherCheckingPolicy = CheckingPolicy>
|
||||
BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>
|
||||
To() const {
|
||||
return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>(static_cast<U*>(Get()));
|
||||
}
|
||||
|
||||
private:
|
||||
static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
|
||||
root_visitor.Trace(*static_cast<const BasicPersistent*>(ptr));
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
// Ideally, handling kSentinelPointer would be done by the embedder. On the
|
||||
// other hand, having Persistent aware of it is beneficial since no node
|
||||
// gets wasted.
|
||||
return GetValue() != nullptr && GetValue() != kSentinelPointer;
|
||||
}
|
||||
|
||||
void Assign(T* ptr) {
|
||||
if (IsValid()) {
|
||||
if (ptr && ptr != kSentinelPointer) {
|
||||
// Simply assign the pointer reusing the existing node.
|
||||
SetValue(ptr);
|
||||
this->CheckPointer(ptr);
|
||||
return;
|
||||
}
|
||||
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
}
|
||||
SetValue(ptr);
|
||||
if (!IsValid()) return;
|
||||
SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
|
||||
.AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
void ClearFromGC() const {
|
||||
if (IsValid()) {
|
||||
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
|
||||
PersistentBase::ClearFromGC();
|
||||
}
|
||||
}
|
||||
|
||||
// Set Get() for details.
|
||||
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
|
||||
T* GetFromGC() const {
|
||||
return static_cast<T*>(const_cast<void*>(GetValue()));
|
||||
}
|
||||
|
||||
friend class internal::RootVisitor;
|
||||
};
|
||||
|
||||
template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
|
||||
typename LocationPolicy2, typename CheckingPolicy2>
|
||||
bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
|
||||
CheckingPolicy1>& p1,
|
||||
const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
|
||||
CheckingPolicy2>& p2) {
|
||||
return p1.Get() == p2.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
|
||||
typename LocationPolicy2, typename CheckingPolicy2>
|
||||
bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
|
||||
CheckingPolicy1>& p1,
|
||||
const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
|
||||
CheckingPolicy2>& p2) {
|
||||
return !(p1 == p2);
|
||||
}
|
||||
|
||||
template <typename T1, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
|
||||
typename T2, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType>
|
||||
bool operator==(
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p,
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy, MemberStorageType>& m) {
|
||||
return p.Get() == m.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
|
||||
typename T2, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType>
|
||||
bool operator!=(
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p,
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy, MemberStorageType>& m) {
|
||||
return !(p == m);
|
||||
}
|
||||
|
||||
template <typename T1, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType, typename T2,
|
||||
typename PersistentWeaknessPolicy, typename PersistentLocationPolicy,
|
||||
typename PersistentCheckingPolicy>
|
||||
bool operator==(
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy, MemberStorageType>& m,
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p) {
|
||||
return m.Get() == p.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename MemberStorageType, typename T2,
|
||||
typename PersistentWeaknessPolicy, typename PersistentLocationPolicy,
|
||||
typename PersistentCheckingPolicy>
|
||||
bool operator!=(
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy, MemberStorageType>& m,
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p) {
|
||||
return !(m == p);
|
||||
}
|
||||
|
||||
template <typename T, typename LocationPolicy, typename CheckingPolicy>
|
||||
struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy,
|
||||
CheckingPolicy>> : std::true_type {};
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Persistent is a way to create a strong pointer from an off-heap object to
|
||||
* another on-heap object. As long as the Persistent handle is alive the GC will
|
||||
* keep the object pointed to alive. The Persistent handle is always a GC root
|
||||
* from the point of view of the GC. Persistent must be constructed and
|
||||
* destructed in the same thread.
|
||||
*/
|
||||
template <typename T>
|
||||
using Persistent =
|
||||
internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
|
||||
|
||||
/**
|
||||
* WeakPersistent is a way to create a weak pointer from an off-heap object to
|
||||
* an on-heap object. The pointer is automatically cleared when the pointee gets
|
||||
* collected. WeakPersistent must be constructed and destructed in the same
|
||||
* thread.
|
||||
*/
|
||||
template <typename T>
|
||||
using WeakPersistent =
|
||||
internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_PERSISTENT_H_
|
||||
@@ -1,163 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_PLATFORM_H_
|
||||
#define INCLUDE_CPPGC_PLATFORM_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "cppgc/source-location.h"
|
||||
#include "v8-platform.h" // NOLINT(build/include_directory)
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
// TODO(v8:10346): Create separate includes for concepts that are not
|
||||
// V8-specific.
|
||||
using IdleTask = v8::IdleTask;
|
||||
using JobHandle = v8::JobHandle;
|
||||
using JobDelegate = v8::JobDelegate;
|
||||
using JobTask = v8::JobTask;
|
||||
using PageAllocator = v8::PageAllocator;
|
||||
using Task = v8::Task;
|
||||
using TaskPriority = v8::TaskPriority;
|
||||
using TaskRunner = v8::TaskRunner;
|
||||
using TracingController = v8::TracingController;
|
||||
|
||||
/**
|
||||
* Platform interface used by Heap. Contains allocators and executors.
|
||||
*/
|
||||
class V8_EXPORT Platform {
|
||||
public:
|
||||
virtual ~Platform() = default;
|
||||
|
||||
/**
|
||||
* \returns the allocator used by cppgc to allocate its heap and various
|
||||
* support structures. Returning nullptr results in using the `PageAllocator`
|
||||
* provided by `cppgc::InitializeProcess()` instead.
|
||||
*/
|
||||
virtual PageAllocator* GetPageAllocator() = 0;
|
||||
|
||||
/**
|
||||
* Monotonically increasing time in seconds from an arbitrary fixed point in
|
||||
* the past. This function is expected to return at least
|
||||
* millisecond-precision values. For this reason,
|
||||
* it is recommended that the fixed point be no further in the past than
|
||||
* the epoch.
|
||||
**/
|
||||
virtual double MonotonicallyIncreasingTime() = 0;
|
||||
|
||||
/**
|
||||
* Foreground task runner that should be used by a Heap.
|
||||
*/
|
||||
virtual std::shared_ptr<TaskRunner> GetForegroundTaskRunner() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts `job_task` to run in parallel. Returns a `JobHandle` associated with
|
||||
* the `Job`, which can be joined or canceled.
|
||||
* This avoids degenerate cases:
|
||||
* - Calling `CallOnWorkerThread()` for each work item, causing significant
|
||||
* overhead.
|
||||
* - Fixed number of `CallOnWorkerThread()` calls that split the work and
|
||||
* might run for a long time. This is problematic when many components post
|
||||
* "num cores" tasks and all expect to use all the cores. In these cases,
|
||||
* the scheduler lacks context to be fair to multiple same-priority requests
|
||||
* and/or ability to request lower priority work to yield when high priority
|
||||
* work comes in.
|
||||
* A canonical implementation of `job_task` looks like:
|
||||
* \code
|
||||
* class MyJobTask : public JobTask {
|
||||
* public:
|
||||
* MyJobTask(...) : worker_queue_(...) {}
|
||||
* // JobTask implementation.
|
||||
* void Run(JobDelegate* delegate) override {
|
||||
* while (!delegate->ShouldYield()) {
|
||||
* // Smallest unit of work.
|
||||
* auto work_item = worker_queue_.TakeWorkItem(); // Thread safe.
|
||||
* if (!work_item) return;
|
||||
* ProcessWork(work_item);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* size_t GetMaxConcurrency() const override {
|
||||
* return worker_queue_.GetSize(); // Thread safe.
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* // ...
|
||||
* auto handle = PostJob(TaskPriority::kUserVisible,
|
||||
* std::make_unique<MyJobTask>(...));
|
||||
* handle->Join();
|
||||
* \endcode
|
||||
*
|
||||
* `PostJob()` and methods of the returned JobHandle/JobDelegate, must never
|
||||
* be called while holding a lock that could be acquired by `JobTask::Run()`
|
||||
* or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This
|
||||
* is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding
|
||||
* internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock
|
||||
* (B) if that lock is *never* held while calling back into `JobHandle` from
|
||||
* any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or
|
||||
* `JobTask::GetMaxConcurrency()` may be invoked synchronously from
|
||||
* `JobHandle` (B=>JobHandle::foo=>B deadlock).
|
||||
*
|
||||
* A sufficient `PostJob()` implementation that uses the default Job provided
|
||||
* in libplatform looks like:
|
||||
* \code
|
||||
* std::unique_ptr<JobHandle> PostJob(
|
||||
* TaskPriority priority, std::unique_ptr<JobTask> job_task) override {
|
||||
* return std::make_unique<DefaultJobHandle>(
|
||||
* std::make_shared<DefaultJobState>(
|
||||
* this, std::move(job_task), kNumThreads));
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
virtual std::unique_ptr<JobHandle> PostJob(
|
||||
TaskPriority priority, std::unique_ptr<JobTask> job_task) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a `TracingController`. This must be non-nullptr. The
|
||||
* default implementation returns an empty `TracingController` that consumes
|
||||
* trace data without effect.
|
||||
*/
|
||||
virtual TracingController* GetTracingController();
|
||||
};
|
||||
|
||||
/**
|
||||
* Process-global initialization of the garbage collector. Must be called before
|
||||
* creating a Heap.
|
||||
*
|
||||
* Can be called multiple times when paired with `ShutdownProcess()`.
|
||||
*
|
||||
* \param page_allocator The allocator used for maintaining meta data. Must stay
|
||||
* always alive and not change between multiple calls to InitializeProcess. If
|
||||
* no allocator is provided, a default internal version will be used.
|
||||
* \param desired_heap_size Desired amount of virtual address space to reserve
|
||||
* for the heap, in bytes. Actual size will be clamped to minimum and maximum
|
||||
* values based on compile-time settings and may be rounded up. If this
|
||||
* parameter is zero, a default value will be used.
|
||||
*/
|
||||
V8_EXPORT void InitializeProcess(PageAllocator* page_allocator = nullptr,
|
||||
size_t desired_heap_size = 0);
|
||||
|
||||
/**
|
||||
* Must be called after destroying the last used heap. Some process-global
|
||||
* metadata may not be returned and reused upon a subsequent
|
||||
* `InitializeProcess()` call.
|
||||
*/
|
||||
V8_EXPORT void ShutdownProcess();
|
||||
|
||||
namespace internal {
|
||||
|
||||
V8_EXPORT void Fatal(const std::string& reason = std::string(),
|
||||
const SourceLocation& = SourceLocation::Current());
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_PLATFORM_H_
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_PREFINALIZER_H_
|
||||
#define INCLUDE_CPPGC_PREFINALIZER_H_
|
||||
|
||||
#include "cppgc/internal/compiler-specific.h"
|
||||
#include "cppgc/liveness-broker.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
class V8_EXPORT PrefinalizerRegistration final {
|
||||
public:
|
||||
using Callback = bool (*)(const cppgc::LivenessBroker&, void*);
|
||||
|
||||
PrefinalizerRegistration(void*, Callback);
|
||||
|
||||
void* operator new(size_t, void* location) = delete;
|
||||
void* operator new(size_t) = delete;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Macro must be used in the private section of `Class` and registers a
|
||||
* prefinalization callback `void Class::PreFinalizer()`. The callback is
|
||||
* invoked on garbage collection after the collector has found an object to be
|
||||
* dead.
|
||||
*
|
||||
* Callback properties:
|
||||
* - The callback is invoked before a possible destructor for the corresponding
|
||||
* object.
|
||||
* - The callback may access the whole object graph, irrespective of whether
|
||||
* objects are considered dead or alive.
|
||||
* - The callback is invoked on the same thread as the object was created on.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* class WithPrefinalizer : public GarbageCollected<WithPrefinalizer> {
|
||||
* CPPGC_USING_PRE_FINALIZER(WithPrefinalizer, Dispose);
|
||||
*
|
||||
* public:
|
||||
* void Trace(Visitor*) const {}
|
||||
* void Dispose() { prefinalizer_called = true; }
|
||||
* ~WithPrefinalizer() {
|
||||
* // prefinalizer_called == true
|
||||
* }
|
||||
* private:
|
||||
* bool prefinalizer_called = false;
|
||||
* };
|
||||
* \endcode
|
||||
*/
|
||||
#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \
|
||||
public: \
|
||||
static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \
|
||||
void* object) { \
|
||||
static_assert(cppgc::IsGarbageCollectedOrMixinTypeV<Class>, \
|
||||
"Only garbage collected objects can have prefinalizers"); \
|
||||
Class* self = static_cast<Class*>(object); \
|
||||
if (liveness_broker.IsHeapObjectAlive(self)) return false; \
|
||||
self->PreFinalizer(); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \
|
||||
prefinalizer_dummy_{this, Class::InvokePreFinalizer}; \
|
||||
static_assert(true, "Force semicolon.")
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_PREFINALIZER_H_
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
|
||||
#define INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
class ProcessHeapStatisticsUpdater;
|
||||
} // namespace internal
|
||||
|
||||
class V8_EXPORT ProcessHeapStatistics final {
|
||||
public:
|
||||
static size_t TotalAllocatedObjectSize() {
|
||||
return total_allocated_object_size_.load(std::memory_order_relaxed);
|
||||
}
|
||||
static size_t TotalAllocatedSpace() {
|
||||
return total_allocated_space_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::atomic_size_t total_allocated_space_;
|
||||
static std::atomic_size_t total_allocated_object_size_;
|
||||
|
||||
friend class internal::ProcessHeapStatisticsUpdater;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_SENTINEL_POINTER_H_
|
||||
#define INCLUDE_CPPGC_SENTINEL_POINTER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "cppgc/internal/api-constants.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
// Special tag type used to denote some sentinel member. The semantics of the
|
||||
// sentinel is defined by the embedder.
|
||||
struct SentinelPointer {
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
static constexpr intptr_t kSentinelValue =
|
||||
1 << api_constants::kPointerCompressionShift;
|
||||
#else // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
static constexpr intptr_t kSentinelValue = 0b10;
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
template <typename T>
|
||||
operator T*() const {
|
||||
return reinterpret_cast<T*>(kSentinelValue);
|
||||
}
|
||||
// Hidden friends.
|
||||
friend bool operator==(SentinelPointer, SentinelPointer) { return true; }
|
||||
friend bool operator!=(SentinelPointer, SentinelPointer) { return false; }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
constexpr internal::SentinelPointer kSentinelPointer;
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_SENTINEL_POINTER_H_
|
||||
Loaded 100 of 16118 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user