summaryrefslogtreecommitdiff
path: root/deps/v8/tools
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/tools')
-rw-r--r--deps/v8/tools/clusterfuzz/BUILD.gn2
-rw-r--r--deps/v8/tools/clusterfuzz/js_fuzzer/README.md9
-rw-r--r--deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js1
-rw-r--r--deps/v8/tools/clusterfuzz/js_fuzzer/run.js8
-rw-r--r--deps/v8/tools/clusterfuzz/js_fuzzer/tools/run_one.py2
-rw-r--r--deps/v8/tools/clusterfuzz/js_fuzzer/tools/workbench.py7
-rw-r--r--deps/v8/tools/clusterfuzz/testdata/smoke_test_output.txt (renamed from deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt)2
-rwxr-xr-xdeps/v8/tools/clusterfuzz/v8_foozzie.py35
-rwxr-xr-xdeps/v8/tools/clusterfuzz/v8_foozzie_test.py16
-rw-r--r--deps/v8/tools/clusterfuzz/v8_fuzz_flags.json3
-rw-r--r--deps/v8/tools/clusterfuzz/v8_smoke_tests.js (renamed from deps/v8/tools/clusterfuzz/v8_sanity_checks.js)2
-rw-r--r--deps/v8/tools/clusterfuzz/v8_suppressions.py3
-rw-r--r--deps/v8/tools/codemap.mjs6
-rw-r--r--deps/v8/tools/consarray.mjs86
-rw-r--r--deps/v8/tools/csvparser.mjs6
-rw-r--r--deps/v8/tools/debug_helper/get-object-properties.cc3
-rwxr-xr-xdeps/v8/tools/deprecation_stats.py54
-rw-r--r--deps/v8/tools/dumpcpp.mjs11
-rw-r--r--deps/v8/tools/gcmole/BUILD.gn4
-rw-r--r--deps/v8/tools/gcmole/README12
-rwxr-xr-xdeps/v8/tools/gcmole/bootstrap.sh77
-rw-r--r--deps/v8/tools/gcmole/gccause.lua62
-rw-r--r--deps/v8/tools/gcmole/gcmole-test.cc148
-rw-r--r--deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha12
-rw-r--r--deps/v8/tools/gcmole/gcmole.cc125
-rw-r--r--deps/v8/tools/gcmole/gcmole.lua532
-rw-r--r--deps/v8/tools/gcmole/gcmole.py575
-rwxr-xr-xdeps/v8/tools/gcmole/package.sh33
-rwxr-xr-xdeps/v8/tools/gcmole/parallel.py47
-rwxr-xr-xdeps/v8/tools/gcmole/run-gcmole.py9
-rw-r--r--deps/v8/tools/gcmole/test-expectations.txt63
-rw-r--r--deps/v8/tools/heap-stats/categories.js2
-rw-r--r--deps/v8/tools/ic-processor-driver.mjs6
-rw-r--r--deps/v8/tools/logreader.mjs346
-rw-r--r--deps/v8/tools/memory/asan/blacklist_win.txt4
-rw-r--r--deps/v8/tools/memory/asan/blocklist_win.txt (renamed from deps/v8/tools/memory/asan/blacklist.txt)0
-rw-r--r--deps/v8/tools/parse-processor.mjs14
-rw-r--r--deps/v8/tools/profile.mjs209
-rw-r--r--deps/v8/tools/profview/index.html21
-rw-r--r--deps/v8/tools/profview/profile-utils.js45
-rw-r--r--deps/v8/tools/profview/profview.js25
-rw-r--r--deps/v8/tools/splaytree.mjs484
-rw-r--r--deps/v8/tools/system-analyzer/app-model.mjs65
-rw-r--r--deps/v8/tools/system-analyzer/events.mjs51
-rw-r--r--deps/v8/tools/system-analyzer/helper.mjs263
-rw-r--r--deps/v8/tools/system-analyzer/ic-model.mjs57
-rw-r--r--deps/v8/tools/system-analyzer/ic-panel-template.html98
-rw-r--r--deps/v8/tools/system-analyzer/ic-panel.mjs191
-rw-r--r--deps/v8/tools/system-analyzer/index.css105
-rw-r--r--deps/v8/tools/system-analyzer/index.html214
-rw-r--r--deps/v8/tools/system-analyzer/index.mjs281
-rw-r--r--deps/v8/tools/system-analyzer/log/api.mjs32
-rw-r--r--deps/v8/tools/system-analyzer/log/code.mjs95
-rw-r--r--deps/v8/tools/system-analyzer/log/deopt.mjs10
-rw-r--r--deps/v8/tools/system-analyzer/log/ic.mjs18
-rw-r--r--deps/v8/tools/system-analyzer/log/log.mjs19
-rw-r--r--deps/v8/tools/system-analyzer/log/map.mjs99
-rw-r--r--deps/v8/tools/system-analyzer/map-panel-template.html21
-rw-r--r--deps/v8/tools/system-analyzer/map-panel.mjs72
-rw-r--r--deps/v8/tools/system-analyzer/map-panel/map-transitions.mjs184
-rw-r--r--deps/v8/tools/system-analyzer/processor.mjs292
-rw-r--r--deps/v8/tools/system-analyzer/source-panel-template.html54
-rw-r--r--deps/v8/tools/system-analyzer/stats-panel-template.html73
-rw-r--r--deps/v8/tools/system-analyzer/stats-panel.mjs129
-rw-r--r--deps/v8/tools/system-analyzer/timeline-panel-template.html13
-rw-r--r--deps/v8/tools/system-analyzer/timeline.mjs111
-rw-r--r--deps/v8/tools/system-analyzer/timeline/timeline-track-template.html138
-rw-r--r--deps/v8/tools/system-analyzer/timeline/timeline-track.mjs518
-rw-r--r--deps/v8/tools/system-analyzer/view/code-panel-template.html25
-rw-r--r--deps/v8/tools/system-analyzer/view/code-panel.mjs82
-rw-r--r--deps/v8/tools/system-analyzer/view/events.mjs93
-rw-r--r--deps/v8/tools/system-analyzer/view/helper.mjs314
-rw-r--r--deps/v8/tools/system-analyzer/view/list-panel-template.html78
-rw-r--r--deps/v8/tools/system-analyzer/view/list-panel.mjs198
-rw-r--r--deps/v8/tools/system-analyzer/view/log-file-reader-template.html (renamed from deps/v8/tools/system-analyzer/log-file-reader-template.html)0
-rw-r--r--deps/v8/tools/system-analyzer/view/log-file-reader.mjs (renamed from deps/v8/tools/system-analyzer/log-file-reader.mjs)2
-rw-r--r--deps/v8/tools/system-analyzer/view/map-panel-template.html36
-rw-r--r--deps/v8/tools/system-analyzer/view/map-panel.mjs106
-rw-r--r--deps/v8/tools/system-analyzer/view/map-panel/map-details-template.html (renamed from deps/v8/tools/system-analyzer/map-panel/map-details-template.html)16
-rw-r--r--deps/v8/tools/system-analyzer/view/map-panel/map-details.mjs (renamed from deps/v8/tools/system-analyzer/map-panel/map-details.mjs)2
-rw-r--r--deps/v8/tools/system-analyzer/view/map-panel/map-transitions-template.html (renamed from deps/v8/tools/system-analyzer/map-panel/map-transitions-template.html)10
-rw-r--r--deps/v8/tools/system-analyzer/view/map-panel/map-transitions.mjs181
-rw-r--r--deps/v8/tools/system-analyzer/view/script-panel-template.html72
-rw-r--r--deps/v8/tools/system-analyzer/view/script-panel.mjs (renamed from deps/v8/tools/system-analyzer/source-panel.mjs)112
-rw-r--r--deps/v8/tools/system-analyzer/view/timeline-panel-template.html29
-rw-r--r--deps/v8/tools/system-analyzer/view/timeline-panel.mjs (renamed from deps/v8/tools/system-analyzer/timeline-panel.mjs)2
-rw-r--r--deps/v8/tools/system-analyzer/view/timeline/timeline-track-template.html205
-rw-r--r--deps/v8/tools/system-analyzer/view/timeline/timeline-track.mjs605
-rw-r--r--deps/v8/tools/system-analyzer/view/tool-tip-template.html81
-rw-r--r--deps/v8/tools/system-analyzer/view/tool-tip.mjs110
-rw-r--r--deps/v8/tools/testrunner/base_runner.py6
-rw-r--r--deps/v8/tools/testrunner/local/junit_output.py49
-rw-r--r--deps/v8/tools/testrunner/local/utils.py3
-rw-r--r--deps/v8/tools/testrunner/local/variants.py13
-rw-r--r--deps/v8/tools/testrunner/testproc/progress.py40
-rw-r--r--deps/v8/tools/tickprocessor.mjs252
-rw-r--r--deps/v8/tools/v8heapconst.py691
-rw-r--r--deps/v8/tools/v8windbg/src/object-inspection.cc11
-rw-r--r--deps/v8/tools/v8windbg/src/v8-debug-helper-interop.cc2
-rw-r--r--deps/v8/tools/v8windbg/test/v8windbg-test.cc4
-rwxr-xr-xdeps/v8/tools/wasm/update-wasm-fuzzers.sh41
-rw-r--r--deps/v8/tools/whitespace.txt2
-rwxr-xr-xdeps/v8/tools/windows-tick-processor.bat2
-rw-r--r--deps/v8/tools/wpr.wprp68
104 files changed, 5581 insertions, 4266 deletions
diff --git a/deps/v8/tools/clusterfuzz/BUILD.gn b/deps/v8/tools/clusterfuzz/BUILD.gn
index d75e6f9687..54e4fded96 100644
--- a/deps/v8/tools/clusterfuzz/BUILD.gn
+++ b/deps/v8/tools/clusterfuzz/BUILD.gn
@@ -16,7 +16,7 @@ if (v8_correctness_fuzzer) {
"v8_mock.js",
"v8_mock_archs.js",
"v8_mock_webassembly.js",
- "v8_sanity_checks.js",
+ "v8_smoke_tests.js",
"v8_suppressions.js",
"v8_suppressions.py",
]
diff --git a/deps/v8/tools/clusterfuzz/js_fuzzer/README.md b/deps/v8/tools/clusterfuzz/js_fuzzer/README.md
index a537ad7a62..71a1140fe1 100644
--- a/deps/v8/tools/clusterfuzz/js_fuzzer/README.md
+++ b/deps/v8/tools/clusterfuzz/js_fuzzer/README.md
@@ -14,8 +14,11 @@ contained binary) out of this.
You need to intall nodejs and npm. Run `npm install` in this directory.
## Fuzzing DB
-This fuzzer requires a fuzzing DB. To build one, get the latest web_tests.zip
-from `gs://clusterfuzz-data/web_tests.zip` and run:
+This fuzzer requires a fuzzing DB. To build one, get the latest `web_tests.zip`
+from [gs://clusterfuzz-data/web_tests.zip](
+https://storage.cloud.google.com/clusterfuzz-data/web_tests.zip) and unzip it
+(note https://crbug.com/v8/10891 for making this data publicly available).
+Then run:
```bash
$ mkdir db
@@ -90,7 +93,7 @@ $ workdir/output
The `app_dir` folder can be a symlink or should contain the bundled
version of `d8` with all files required for execution.
-The copy the packaged `ochang_js_fuzzer` executable and the `db` folder
+Copy the packaged `ochang_js_fuzzer` executable and the `db` folder
to the `fuzzer` directory or use a symlink.
The `input` directory is the root folder of the corpus, i.e. pointing
to the unzipped data of `gs://clusterfuzz-data/web_tests.zip`.
diff --git a/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js b/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js
index 41255aa4d9..f981b82efc 100644
--- a/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js
+++ b/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js
@@ -113,6 +113,7 @@ const DISALLOWED_FLAGS = [
// Disallowed due to false positives.
'--check-handle-count',
+ '--correctness-fuzzer-suppressions',
'--expose-debug-as',
'--expose-natives-as',
'--expose-trigger-failure',
diff --git a/deps/v8/tools/clusterfuzz/js_fuzzer/run.js b/deps/v8/tools/clusterfuzz/js_fuzzer/run.js
index 3712172d9f..29049e326c 100644
--- a/deps/v8/tools/clusterfuzz/js_fuzzer/run.js
+++ b/deps/v8/tools/clusterfuzz/js_fuzzer/run.js
@@ -163,9 +163,11 @@ function main() {
app_name = app_name.substr(0, app_name.length - 4);
}
- if (app_name === 'd8' || app_name === 'v8_foozzie.py') {
- // V8 supports running the raw d8 executable or the differential fuzzing
- // harness 'foozzie'.
+ if (app_name === 'd8' ||
+ app_name === 'v8_simple_inspector_fuzzer' ||
+ app_name === 'v8_foozzie.py') {
+ // V8 supports running the raw d8 executable, the inspector fuzzer or
+ // the differential fuzzing harness 'foozzie'.
settings.engine = 'V8';
} else if (app_name === 'ch') {
settings.engine = 'chakra';
diff --git a/deps/v8/tools/clusterfuzz/js_fuzzer/tools/run_one.py b/deps/v8/tools/clusterfuzz/js_fuzzer/tools/run_one.py
index 7762cb2c94..7886c30b95 100644
--- a/deps/v8/tools/clusterfuzz/js_fuzzer/tools/run_one.py
+++ b/deps/v8/tools/clusterfuzz/js_fuzzer/tools/run_one.py
@@ -22,6 +22,8 @@ BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FOOZZIE = os.path.join(BASE_PATH, 'workdir', 'app_dir', 'v8_foozzie.py')
TEST_CASES = os.path.join(BASE_PATH, 'workdir', 'output')
+assert os.path.exists(FOOZZIE)
+
# Output pattern from foozzie.py when it finds a failure.
FAILURE_RE = re.compile(
r'# V8 correctness failure.'
diff --git a/deps/v8/tools/clusterfuzz/js_fuzzer/tools/workbench.py b/deps/v8/tools/clusterfuzz/js_fuzzer/tools/workbench.py
index 52a84bfca3..ee371f5482 100644
--- a/deps/v8/tools/clusterfuzz/js_fuzzer/tools/workbench.py
+++ b/deps/v8/tools/clusterfuzz/js_fuzzer/tools/workbench.py
@@ -37,8 +37,11 @@ RUN_ONE = os.path.join(BASE_PATH, 'tools', 'run_one.py')
os.chdir(BASE_PATH)
-assert not os.path.exists(TEST_CASES)
-os.makedirs(TEST_CASES)
+if os.path.exists(TEST_CASES):
+ if not os.path.isdir(TEST_CASES) or os.listdir(TEST_CASES):
+ sys.exit("'output' must be an empty directory")
+else:
+ os.mkdir(TEST_CASES)
# Use ~40000 for 24 hours of fuzzing on a modern work station.
RUNS = 8
diff --git a/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt b/deps/v8/tools/clusterfuzz/testdata/smoke_test_output.txt
index ea6b8a9466..4a41f9cbb5 100644
--- a/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt
+++ b/deps/v8/tools/clusterfuzz/testdata/smoke_test_output.txt
@@ -1,7 +1,7 @@
#
# V8 correctness failure
# V8 correctness configs: x64,ignition:x64,ignition_turbo
-# V8 correctness sources: sanity check failed
+# V8 correctness sources: smoke test failed
# V8 correctness suppression:
#
# CHECK
diff --git a/deps/v8/tools/clusterfuzz/v8_foozzie.py b/deps/v8/tools/clusterfuzz/v8_foozzie.py
index 558145973d..9f3810c9f5 100755
--- a/deps/v8/tools/clusterfuzz/v8_foozzie.py
+++ b/deps/v8/tools/clusterfuzz/v8_foozzie.py
@@ -96,10 +96,10 @@ RETURN_PASS = 0
RETURN_FAIL = 2
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
-SANITY_CHECKS = os.path.join(BASE_PATH, 'v8_sanity_checks.js')
+SMOKE_TESTS = os.path.join(BASE_PATH, 'v8_smoke_tests.js')
# Timeout for one d8 run.
-SANITY_CHECK_TIMEOUT_SEC = 1
+SMOKE_TEST_TIMEOUT_SEC = 1
TEST_TIMEOUT_SEC = 3
SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64']
@@ -243,6 +243,10 @@ class ExecutionConfig(object):
def flags(self):
return self.command.flags
+ @property
+ def is_error_simulation(self):
+ return '--simulate-errors' in self.flags
+
def parse_args():
first_config_arguments = ExecutionArgumentsConfig('first')
@@ -253,8 +257,8 @@ def parse_args():
'--random-seed', type=int, required=True,
help='random seed passed to both runs')
parser.add_argument(
- '--skip-sanity-checks', default=False, action='store_true',
- help='skip sanity checks for testing purposes')
+ '--skip-smoke-tests', default=False, action='store_true',
+ help='skip smoke tests for testing purposes')
parser.add_argument(
'--skip-suppressions', default=False, action='store_true',
help='skip suppressions to reproduce known issues')
@@ -384,7 +388,7 @@ def run_comparisons(suppress, execution_configs, test_case, timeout,
timeout: Timeout in seconds for one run.
verbose: Prints the executed commands.
ignore_crashes: Typically we ignore crashes during fuzzing as they are
- frequent. However, when running sanity checks we should not crash
+ frequent. However, when running smoke tests we should not crash
and immediately flag crashes as a failure.
source_key: A fixed source key. If not given, it will be inferred from the
output.
@@ -396,11 +400,13 @@ def run_comparisons(suppress, execution_configs, test_case, timeout,
baseline_config = execution_configs[0]
baseline_output = run_test_case(baseline_config)
has_crashed = baseline_output.HasCrashed()
+ simulated = baseline_config.is_error_simulation
# Iterate over the remaining configurations, run and compare.
for comparison_config in execution_configs[1:]:
comparison_output = run_test_case(comparison_config)
has_crashed = has_crashed or comparison_output.HasCrashed()
+ simulated = simulated or comparison_config.is_error_simulation
difference, source = suppress.diff(baseline_output, comparison_output)
if difference:
@@ -421,10 +427,11 @@ def run_comparisons(suppress, execution_configs, test_case, timeout,
# detected. This is only for the statistics during experiments.
raise PassException('# V8 correctness - C-R-A-S-H')
else:
- # Subsume unexpected crashes (e.g. during sanity checks) with one failure
- # state.
+ # Subsume simulated and unexpected crashes (e.g. during smoke tests)
+ # with one failure state.
+ crash_state = '_simulated_crash_' if simulated else '_unexpected_crash_'
raise FailException(FAILURE_HEADER_TEMPLATE % dict(
- configs='', source_key='', suppression='unexpected crash'))
+ configs='', source_key='', suppression=crash_state))
def main():
@@ -451,18 +458,18 @@ def main():
# First, run some fixed smoke tests in all configs to ensure nothing
# is fundamentally wrong, in order to prevent bug flooding.
- if not options.skip_sanity_checks:
+ if not options.skip_smoke_tests:
run_comparisons(
suppress, execution_configs,
- test_case=SANITY_CHECKS,
- timeout=SANITY_CHECK_TIMEOUT_SEC,
+ test_case=SMOKE_TESTS,
+ timeout=SMOKE_TEST_TIMEOUT_SEC,
verbose=False,
- # Don't accept crashes during sanity checks. A crash would hint at
+ # Don't accept crashes during smoke tests. A crash would hint at
# a flag that might be incompatible or a broken test file.
ignore_crashes=False,
- # Special source key for sanity checks so that clusterfuzz dedupes all
+ # Special source key for smoke tests so that clusterfuzz dedupes all
# cases on this in case it's hit.
- source_key = 'sanity check failed',
+ source_key = 'smoke test failed',
)
# Second, run all configs against the fuzz test case.
diff --git a/deps/v8/tools/clusterfuzz/v8_foozzie_test.py b/deps/v8/tools/clusterfuzz/v8_foozzie_test.py
index 8bb568cb60..eb8322ce62 100755
--- a/deps/v8/tools/clusterfuzz/v8_foozzie_test.py
+++ b/deps/v8/tools/clusterfuzz/v8_foozzie_test.py
@@ -270,7 +270,7 @@ class SystemTest(unittest.TestCase):
build3: As build1 but with an architecture difference as well.
"""
def testSyntaxErrorDiffPass(self):
- stdout = run_foozzie('build1', '--skip-sanity-checks')
+ stdout = run_foozzie('build1', '--skip-smoke-tests')
self.assertEqual('# V8 correctness - pass\n',
cut_verbose_output(stdout, 3))
# Default comparison includes suppressions.
@@ -283,7 +283,7 @@ class SystemTest(unittest.TestCase):
with open(os.path.join(TEST_DATA, 'failure_output.txt')) as f:
expected_output = f.read()
with self.assertRaises(subprocess.CalledProcessError) as ctx:
- run_foozzie('build2', '--skip-sanity-checks',
+ run_foozzie('build2', '--skip-smoke-tests',
'--first-config-extra-flags=--flag1',
'--first-config-extra-flags=--flag2=0',
'--second-config-extra-flags=--flag3')
@@ -291,8 +291,8 @@ class SystemTest(unittest.TestCase):
self.assertEqual(v8_foozzie.RETURN_FAIL, e.returncode)
self.assertEqual(expected_output, cut_verbose_output(e.output, 2))
- def testSanityCheck(self):
- with open(os.path.join(TEST_DATA, 'sanity_check_output.txt')) as f:
+ def testSmokeTest(self):
+ with open(os.path.join(TEST_DATA, 'smoke_test_output.txt')) as f:
expected_output = f.read()
with self.assertRaises(subprocess.CalledProcessError) as ctx:
run_foozzie('build2')
@@ -305,7 +305,7 @@ class SystemTest(unittest.TestCase):
we use executables with different architectures.
"""
# Build 3 simulates x86, while the baseline is x64.
- stdout = run_foozzie('build3', '--skip-sanity-checks')
+ stdout = run_foozzie('build3', '--skip-smoke-tests')
lines = stdout.split('\n')
# TODO(machenbach): Don't depend on the command-lines being printed in
# particular lines.
@@ -315,7 +315,7 @@ class SystemTest(unittest.TestCase):
def testJitless(self):
"""Test that webassembly is mocked out when comparing with jitless."""
stdout = run_foozzie(
- 'build1', '--skip-sanity-checks', second_config='jitless')
+ 'build1', '--skip-smoke-tests', second_config='jitless')
lines = stdout.split('\n')
# TODO(machenbach): Don't depend on the command-lines being printed in
# particular lines.
@@ -328,14 +328,14 @@ class SystemTest(unittest.TestCase):
"""
# Compare baseline with baseline. This passes as there is no difference.
stdout = run_foozzie(
- 'baseline', '--skip-sanity-checks', '--skip-suppressions')
+ 'baseline', '--skip-smoke-tests', '--skip-suppressions')
self.assertNotIn('v8_suppressions.js', stdout)
# Compare with a build that usually suppresses a difference. Now we fail
# since we skip suppressions.
with self.assertRaises(subprocess.CalledProcessError) as ctx:
run_foozzie(
- 'build1', '--skip-sanity-checks', '--skip-suppressions')
+ 'build1', '--skip-smoke-tests', '--skip-suppressions')
e = ctx.exception
self.assertEqual(v8_foozzie.RETURN_FAIL, e.returncode)
self.assertNotIn('v8_suppressions.js', e.output)
diff --git a/deps/v8/tools/clusterfuzz/v8_fuzz_flags.json b/deps/v8/tools/clusterfuzz/v8_fuzz_flags.json
index 71ab2c29e5..e3a6ef4066 100644
--- a/deps/v8/tools/clusterfuzz/v8_fuzz_flags.json
+++ b/deps/v8/tools/clusterfuzz/v8_fuzz_flags.json
@@ -30,5 +30,6 @@
[0.1, "--no-enable-popcnt"],
[0.25, "--no-lazy-feedback-allocation"],
[0.1, "--no-lazy-feedback-allocation --interrupt-budget=100"],
- [0.05, "--budget-for-feedback-vector-allocation=0"]
+ [0.05, "--budget-for-feedback-vector-allocation=0"],
+ [0.0001, "--simulate-errors"]
] \ No newline at end of file
diff --git a/deps/v8/tools/clusterfuzz/v8_sanity_checks.js b/deps/v8/tools/clusterfuzz/v8_smoke_tests.js
index c2f0b2a4d9..39eb2d4e21 100644
--- a/deps/v8/tools/clusterfuzz/v8_sanity_checks.js
+++ b/deps/v8/tools/clusterfuzz/v8_smoke_tests.js
@@ -31,7 +31,7 @@ print("https://crbug.com/985154");
print(Object.getOwnPropertyNames(foo().bar));
})();
-print("Suppresses sensitive natives");
+print("Sensitive runtime functions are neutered");
(function () {
function foo() {}
%PrepareFunctionForOptimization(foo);
diff --git a/deps/v8/tools/clusterfuzz/v8_suppressions.py b/deps/v8/tools/clusterfuzz/v8_suppressions.py
index 71c69fb6b2..18f9de7ac1 100644
--- a/deps/v8/tools/clusterfuzz/v8_suppressions.py
+++ b/deps/v8/tools/clusterfuzz/v8_suppressions.py
@@ -57,6 +57,8 @@ IGNORE_TEST_CASES = {
IGNORE_OUTPUT = {
'crbug.com/689877':
re.compile(r'^.*SyntaxError: .*Stack overflow$', re.M),
+ '_fake_difference_':
+ re.compile(r'^.*___fake_difference___$', re.M),
}
# Lines matching any of the following regular expressions will be ignored
@@ -70,7 +72,6 @@ ALLOWED_LINE_DIFFS = [
# Lines matching any of the following regular expressions will be ignored.
# Use uncompiled regular expressions - they'll be compiled later.
IGNORE_LINES = [
- r'^Warning: unknown flag .*$',
r'^Warning: .+ is deprecated.*$',
r'^Try --help for options$',
diff --git a/deps/v8/tools/codemap.mjs b/deps/v8/tools/codemap.mjs
index 245b6ba42e..4986fbd3b0 100644
--- a/deps/v8/tools/codemap.mjs
+++ b/deps/v8/tools/codemap.mjs
@@ -266,6 +266,7 @@ export class CodeMap {
* @param {number} size Code entry size in bytes.
* @param {string} opt_name Code entry name.
* @param {string} opt_type Code entry type, e.g. SHARED_LIB, CPP.
+ * @param {object} source Optional source position information
* @constructor
*/
export class CodeEntry {
@@ -274,6 +275,7 @@ export class CodeEntry {
this.name = opt_name || '';
this.type = opt_type || '';
this.nameUpdated_ = false;
+ this.source = undefined;
}
getName() {
@@ -283,6 +285,10 @@ export class CodeEntry {
toString() {
return this.name + ': ' + this.size.toString(16);
}
+
+ getSourceCode() {
+ return '';
+ }
}
class NameGenerator {
diff --git a/deps/v8/tools/consarray.mjs b/deps/v8/tools/consarray.mjs
index 1dc2afe886..b212eb720a 100644
--- a/deps/v8/tools/consarray.mjs
+++ b/deps/v8/tools/consarray.mjs
@@ -36,49 +36,47 @@
*
* @constructor
*/
-export function ConsArray() {
- this.tail_ = new ConsArray.Cell(null, null);
- this.currCell_ = this.tail_;
- this.currCellPos_ = 0;
-};
-
-
-/**
- * Concatenates another array for iterating. Empty arrays are ignored.
- * This operation can be safely performed during ongoing ConsArray
- * iteration.
- *
- * @param {Array} arr Array to concatenate.
- */
-ConsArray.prototype.concat = function(arr) {
- if (arr.length > 0) {
- this.tail_.data = arr;
- this.tail_ = this.tail_.next = new ConsArray.Cell(null, null);
+export class ConsArray {
+ constructor() {
+ this.tail_ = new ConsArrayCell(null, null);
+ this.currCell_ = this.tail_;
+ this.currCellPos_ = 0;
+ }
+ /**
+ * Concatenates another array for iterating. Empty arrays are ignored.
+ * This operation can be safely performed during ongoing ConsArray
+ * iteration.
+ *
+ * @param {Array} arr Array to concatenate.
+ */
+ concat(arr) {
+ if (arr.length > 0) {
+ this.tail_.data = arr;
+ this.tail_ = this.tail_.next = new ConsArrayCell(null, null);
+ }
}
-};
-
-
-/**
- * Whether the end of iteration is reached.
- */
-ConsArray.prototype.atEnd = function() {
- return this.currCell_ === null ||
- this.currCell_.data === null ||
- this.currCellPos_ >= this.currCell_.data.length;
-};
+ /**
+ * Whether the end of iteration is reached.
+ */
+ atEnd() {
+ return this.currCell_ === null ||
+ this.currCell_.data === null ||
+ this.currCellPos_ >= this.currCell_.data.length;
+ }
-/**
- * Returns the current item, moves to the next one.
- */
-ConsArray.prototype.next = function() {
- const result = this.currCell_.data[this.currCellPos_++];
- if (this.currCellPos_ >= this.currCell_.data.length) {
- this.currCell_ = this.currCell_.next;
- this.currCellPos_ = 0;
+ /**
+ * Returns the current item, moves to the next one.
+ */
+ next() {
+ const result = this.currCell_.data[this.currCellPos_++];
+ if (this.currCellPos_ >= this.currCell_.data.length) {
+ this.currCell_ = this.currCell_.next;
+ this.currCellPos_ = 0;
+ }
+ return result;
}
- return result;
-};
+}
/**
@@ -86,7 +84,9 @@ ConsArray.prototype.next = function() {
*
* @constructor
*/
-ConsArray.Cell = function(data, next) {
- this.data = data;
- this.next = next;
-};
+class ConsArrayCell {
+ constructor(data, next) {
+ this.data = data;
+ this.next = next;
+ }
+}
diff --git a/deps/v8/tools/csvparser.mjs b/deps/v8/tools/csvparser.mjs
index e027d47384..c43ee4c4fc 100644
--- a/deps/v8/tools/csvparser.mjs
+++ b/deps/v8/tools/csvparser.mjs
@@ -62,7 +62,11 @@ export class CsvParser {
}
// Convert the selected escape sequence to a single character.
let escapeChars = string.substring(pos, nextPos);
- result += String.fromCharCode(parseInt(escapeChars, 16));
+ if (escapeChars === '2C') {
+ result += ',';
+ } else {
+ result += String.fromCharCode(parseInt(escapeChars, 16));
+ }
}
// Continue looking for the next escape sequence.
diff --git a/deps/v8/tools/debug_helper/get-object-properties.cc b/deps/v8/tools/debug_helper/get-object-properties.cc
index 181c58dbf0..a6ebcc0761 100644
--- a/deps/v8/tools/debug_helper/get-object-properties.cc
+++ b/deps/v8/tools/debug_helper/get-object-properties.cc
@@ -413,6 +413,8 @@ class ReadStringVisitor : public TqObjectVisitor {
that_->index_ += index_adjust_;
that_->limit_ += limit_adjust_;
}
+ IndexModifier(const IndexModifier&) = delete;
+ IndexModifier& operator=(const IndexModifier&) = delete;
~IndexModifier() {
that_->index_ -= index_adjust_;
that_->limit_ -= limit_adjust_;
@@ -422,7 +424,6 @@ class ReadStringVisitor : public TqObjectVisitor {
ReadStringVisitor* that_;
int32_t index_adjust_;
int32_t limit_adjust_;
- DISALLOW_COPY_AND_ASSIGN(IndexModifier);
};
static constexpr int kMaxCharacters = 80; // How many characters to print.
diff --git a/deps/v8/tools/deprecation_stats.py b/deps/v8/tools/deprecation_stats.py
index 628eebc779..56b26c39ad 100755
--- a/deps/v8/tools/deprecation_stats.py
+++ b/deps/v8/tools/deprecation_stats.py
@@ -11,11 +11,13 @@ from datetime import datetime
import re
import subprocess
import sys
+from os import path
RE_GITHASH = re.compile(r"^[0-9a-f]{40}")
RE_AUTHOR_TIME = re.compile(r"^author-time (\d+)$")
RE_FILENAME = re.compile(r"^filename (.+)$")
+
def GetBlame(file_path):
result = subprocess.check_output(
['git', 'blame', '-t', '--line-porcelain', file_path])
@@ -43,66 +45,78 @@ def GetBlame(file_path):
blame_list.append(current_blame)
return blame_list
-RE_MACRO_END = re.compile(r"\);");
+
+RE_MACRO_END = re.compile(r"\);")
RE_DEPRECATE_MACRO = re.compile(r"\(.*?,(.*)\);", re.MULTILINE)
-def FilterAndPrint(blame_list, macro, before):
+
+def FilterAndPrint(blame_list, macro, options):
+ before = options.before
index = 0
re_macro = re.compile(macro)
deprecated = list()
while index < len(blame_list):
blame = blame_list[index]
- match = re_macro.search(blame['content'])
- if match and blame['time'] < before:
- line = blame['content']
- time = blame['time']
+ time = blame['time']
+ if time >= before:
+ index += 1
+ continue
+ line = blame['content']
+ match = re_macro.search(line)
+ if match:
pos = match.end()
start = -1
parens = 0
- quotes = 0
while True:
if pos >= len(line):
# extend to next line
index = index + 1
blame = blame_list[index]
- if line.endswith(','):
- # add whitespace when breaking line due to comma
- line = line + ' '
line = line + blame['content']
if line[pos] == '(':
parens = parens + 1
elif line[pos] == ')':
parens = parens - 1
if parens == 0:
+ # Exclud closing ")
+ pos = pos - 2
break
- elif line[pos] == '"':
- quotes = quotes + 1
- elif line[pos] == ',' and quotes % 2 == 0 and start == -1:
+ elif line[pos] == '"' and start == -1:
start = pos + 1
pos = pos + 1
- deprecated.append([index + 1, time, line[start:pos].strip()])
+ # Extract content and replace double quotes from merged lines
+ content = line[start:pos].strip().replace('""', '')
+ deprecated.append([index + 1, time, content])
index = index + 1
print("Marked as " + macro + ": " + str(len(deprecated)))
for linenumber, time, content in deprecated:
- print(str(linenumber).rjust(8) + " : " + str(time) + " : " + content)
+ print(" " + (options.v8_header + ":" +
+ str(linenumber)).rjust(len(options.v8_header) + 5) + "\t" +
+ str(time) + "\t" + content)
return len(deprecated)
+
def ParseOptions(args):
- parser = argparse.ArgumentParser(description="Collect deprecation statistics")
- parser.add_argument("file_path", help="Path to v8.h")
+ parser = argparse.ArgumentParser(
+ description="Collect deprecation statistics")
+ parser.add_argument("v8_header", nargs='?', help="Path to v8.h")
parser.add_argument("--before", help="Filter by date")
options = parser.parse_args(args)
if options.before:
options.before = datetime.strptime(options.before, '%Y-%m-%d')
else:
options.before = datetime.now()
+ if options.v8_header is None:
+ options.v8_header = path.join(path.dirname(__file__), '..', 'include', 'v8.h')
return options
+
def Main(args):
options = ParseOptions(args)
- blame_list = GetBlame(options.file_path)
- FilterAndPrint(blame_list, "V8_DEPRECATE_SOON", options.before)
- FilterAndPrint(blame_list, "V8_DEPRECATED", options.before)
+ blame_list = GetBlame(options.v8_header)
+ FilterAndPrint(blame_list, "V8_DEPRECATE_SOON", options)
+ FilterAndPrint(blame_list, "V8_DEPRECATED", options)
+
if __name__ == "__main__":
Main(sys.argv[1:])
diff --git a/deps/v8/tools/dumpcpp.mjs b/deps/v8/tools/dumpcpp.mjs
index be2dd996e4..9deab5d2aa 100644
--- a/deps/v8/tools/dumpcpp.mjs
+++ b/deps/v8/tools/dumpcpp.mjs
@@ -5,10 +5,9 @@
import { LogReader, parseString } from "./logreader.mjs";
import { CodeMap, CodeEntry } from "./codemap.mjs";
export {
- ArgumentsProcessor, UnixCppEntriesProvider,
+ ArgumentsProcessor, UnixCppEntriesProvider,
WindowsCppEntriesProvider, MacCppEntriesProvider,
} from "./tickprocessor.mjs";
- import { inherits } from "./tickprocessor.mjs";
export class CppProcessor extends LogReader {
@@ -29,7 +28,7 @@ export class CppProcessor extends LogReader {
*/
printError(str) {
print(str);
- };
+ }
processLogFile(fileName) {
this.lastLogFileName_ = fileName;
@@ -37,14 +36,14 @@ export class CppProcessor extends LogReader {
while (line = readline()) {
this.processLogLine(line);
}
- };
+ }
processLogFileInTest(fileName) {
// Hack file name to avoid dealing with platform specifics.
this.lastLogFileName_ = 'v8.log';
const contents = readFile(fileName);
this.processLogChunk(contents);
- };
+ }
processSharedLibrary(name, startAddr, endAddr, aslrSlide) {
const self = this;
@@ -53,7 +52,7 @@ export class CppProcessor extends LogReader {
const entry = new CodeEntry(fEnd - fStart, fName, 'CPP');
self.codeMap_.addStaticCode(fStart, entry);
});
- };
+ }
dumpCppSymbols() {
const staticEntries = this.codeMap_.getAllStaticEntriesWithAddresses();
diff --git a/deps/v8/tools/gcmole/BUILD.gn b/deps/v8/tools/gcmole/BUILD.gn
index 9767acbf5a..558766487d 100644
--- a/deps/v8/tools/gcmole/BUILD.gn
+++ b/deps/v8/tools/gcmole/BUILD.gn
@@ -8,12 +8,10 @@ group("v8_run_gcmole") {
testonly = true
data = [
- "gccause.lua",
"GCMOLE.gn",
- "gcmole.lua",
+ "gcmole.py",
"gcmole-test.cc",
"gcmole-tools/",
- "parallel.py",
"run-gcmole.py",
"suspects.whitelist",
"ignored_files",
diff --git a/deps/v8/tools/gcmole/README b/deps/v8/tools/gcmole/README
index 46b4717e3c..1d2acd3b1a 100644
--- a/deps/v8/tools/gcmole/README
+++ b/deps/v8/tools/gcmole/README
@@ -35,9 +35,9 @@ simply to store it as a Handle.
PREREQUISITES -----------------------------------------------------------------
-(1) Install Lua 5.1
+(1) Install Python
- $ sudo apt-get install lua5.1
+ $ sudo apt-get install python
(2) Get LLVM 8.0 and Clang 8.0 sources and build them.
@@ -62,14 +62,14 @@ PREREQUISITES -----------------------------------------------------------------
USING GCMOLE ------------------------------------------------------------------
-gcmole consists of driver script written in Lua and Clang plugin that does
+gcmole consists of driver script written in Python and Clang plugin that does
C++ AST processing. Plugin (libgcmole.so) is expected to be in the same
-folder as driver (gcmole.lua).
+folder as driver (gcmole.py).
To start analysis cd into the root of v8 checkout and execute the following
command:
-CLANG_BIN=<path-to-clang-bin-folder> lua tools/gcmole/gcmole.lua [<arch>]
+CLANG_BIN=<path-to-clang-bin-folder> python tools/gcmole/gcmole.py [<arch>]
where arch should be one of architectures supported by V8 (arm, ia32, x64).
@@ -89,7 +89,7 @@ If any errors were found driver exits with non-zero status.
TESTING -----------------------------------------------------------------------
-Tests are automatically run by the main lua runner. Expectations are in
+Tests are automatically run by the main python runner. Expectations are in
test-expectations.txt and need to be updated whenever the sources of the tests
in gcmole-test.cc are modified (line numbers also count).
diff --git a/deps/v8/tools/gcmole/bootstrap.sh b/deps/v8/tools/gcmole/bootstrap.sh
index 05ab1cbb8e..a0386a8054 100755
--- a/deps/v8/tools/gcmole/bootstrap.sh
+++ b/deps/v8/tools/gcmole/bootstrap.sh
@@ -33,14 +33,11 @@
# that the resulting binary is easier transferable between different
# environments.
-CLANG_RELEASE=8.0
+LLVM_RELEASE=9.0.1
THIS_DIR="$(readlink -f "$(dirname "${0}")")"
-LLVM_DIR="${THIS_DIR}/../../third_party/llvm"
-CLANG_DIR="${THIS_DIR}/../../third_party/clang"
-BUILD_DIR="${THIS_DIR}/../../third_party/llvm+clang-build"
-
-LLVM_REPO_URL=${LLVM_URL:-https://llvm.org/svn/llvm-project}
+LLVM_PROJECT_DIR="${THIS_DIR}/bootstrap/llvm"
+BUILD_DIR="${THIS_DIR}/bootstrap/build"
# Die if any command dies.
set -e
@@ -72,59 +69,59 @@ if [[ "${OS}" = "Darwin" ]] && xcodebuild -version | grep -q 'Xcode 3.2' ; then
fi
fi
-echo Getting LLVM release "${CLANG_RELEASE}" in "${LLVM_DIR}"
-if ! svn co --force \
- "${LLVM_REPO_URL}/llvm/branches/release_${CLANG_RELEASE/./}" \
- "${LLVM_DIR}"; then
- echo Checkout failed, retrying
- rm -rf "${LLVM_DIR}"
- svn co --force \
- "${LLVM_REPO_URL}/llvm/branches/release_${CLANG_RELEASE/./}" \
- "${LLVM_DIR}"
+echo Getting LLVM release "${LLVM_RELEASE}" in "${LLVM_PROJECT_DIR}"
+if ! [ -d "${LLVM_PROJECT_DIR}" ] || ! git -C "${LLVM_PROJECT_DIR}" remote get-url origin | grep -q -F "https://github.com/llvm/llvm-project.git" ; then
+ rm -rf "${LLVM_PROJECT_DIR}"
+ git clone --depth=1 --branch "llvmorg-${LLVM_RELEASE}" "https://github.com/llvm/llvm-project.git" "${LLVM_PROJECT_DIR}"
+else
+ git -C "${LLVM_PROJECT_DIR}" fetch --depth=1 origin "llvmorg-${LLVM_RELEASE}"
+ git -C "${LLVM_PROJECT_DIR}" checkout FETCH_HEAD
fi
-echo Getting clang release "${CLANG_RELEASE}" in "${CLANG_DIR}"
-svn co --force \
- "${LLVM_REPO_URL}/cfe/branches/release_${CLANG_RELEASE/./}" \
- "${CLANG_DIR}"
-
# Echo all commands
set -x
NUM_JOBS=3
if [[ "${OS}" = "Linux" ]]; then
- NUM_JOBS="$(grep -c "^processor" /proc/cpuinfo)"
+ if [[ -e "/proc/cpuinfo" ]]; then
+ NUM_JOBS="$(grep -c "^processor" /proc/cpuinfo)"
+ else
+ # Hack when running in chroot
+ NUM_JOBS="32"
+ fi
elif [ "${OS}" = "Darwin" ]; then
NUM_JOBS="$(sysctl -n hw.ncpu)"
fi
# Build clang.
-if [ ! -e "${BUILD_DIR}" ]; then
- mkdir "${BUILD_DIR}"
-fi
-cd "${BUILD_DIR}"
-cmake -DCMAKE_CXX_FLAGS="-static-libstdc++" -DLLVM_ENABLE_TERMINFO=OFF \
- -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=clang "${LLVM_DIR}"
-MACOSX_DEPLOYMENT_TARGET=10.5 make -j"${NUM_JOBS}"
-
-# Strip the clang binary.
-STRIP_FLAGS=
-if [ "${OS}" = "Darwin" ]; then
- # See http://crbug.com/256342
- STRIP_FLAGS=-x
-fi
-strip ${STRIP_FLAGS} bin/clang
-cd -
+# if [ ! -e "${BUILD_DIR}" ]; then
+# mkdir "${BUILD_DIR}"
+# fi
+# cd "${BUILD_DIR}"
+# cmake -GNinja -DCMAKE_CXX_FLAGS="-static-libstdc++" -DLLVM_ENABLE_TERMINFO=OFF \
+# -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=clang \
+# -DLLVM_ENABLE_Z3_SOLVER=OFF "${LLVM_PROJECT_DIR}/llvm"
+# MACOSX_DEPLOYMENT_TARGET=10.5 ninja -j"${NUM_JOBS}"
+#
+# # Strip the clang binary.
+# STRIP_FLAGS=
+# if [ "${OS}" = "Darwin" ]; then
+# # See http://crbug.com/256342
+# STRIP_FLAGS=-x
+# fi
+# strip ${STRIP_FLAGS} bin/clang
+# cd -
# Build libgcmole.so
make -C "${THIS_DIR}" clean
-make -C "${THIS_DIR}" LLVM_SRC_ROOT="${LLVM_DIR}" \
- CLANG_SRC_ROOT="${CLANG_DIR}" BUILD_ROOT="${BUILD_DIR}" libgcmole.so
+make -C "${THIS_DIR}" LLVM_SRC_ROOT="${LLVM_PROJECT_DIR}/llvm" \
+ CLANG_SRC_ROOT="${LLVM_PROJECT_DIR}/clang" \
+ BUILD_ROOT="${BUILD_DIR}" libgcmole.so
set +x
echo
echo You can now run gcmole using this command:
echo
-echo CLANG_BIN=\"third_party/llvm+clang-build/bin\" lua tools/gcmole/gcmole.lua
+echo CLANG_BIN=\"tools/gcmole/gcmole-tools/bin\" python tools/gcmole/gcmole.py
echo
diff --git a/deps/v8/tools/gcmole/gccause.lua b/deps/v8/tools/gcmole/gccause.lua
deleted file mode 100644
index b9891767de..0000000000
--- a/deps/v8/tools/gcmole/gccause.lua
+++ /dev/null
@@ -1,62 +0,0 @@
--- Copyright 2011 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.
-
--- This is an auxiliary tool that reads gccauses file generated by
--- gcmole.lua and prints tree of the calls that can potentially cause a GC
--- inside a given function.
---
--- Usage: lua tools/gcmole/gccause.lua <function-name-pattern>
---
-
-assert(loadfile "gccauses")()
-
-local P = ...
-
-local T = {}
-
-local function TrackCause(name, lvl)
- io.write((" "):rep(lvl or 0), name, "\n")
- if GC[name] then
- local causes = GC[name]
- for i = 1, #causes do
- local f = causes[i]
- if not T[f] then
- T[f] = true
- TrackCause(f, (lvl or 0) + 1)
- end
-
- if f == '<GC>' then break end
- end
- end
-end
-
-for name, _ in pairs(GC) do
- if name:match(P) then
- T = {}
- TrackCause(name)
- end
-end
diff --git a/deps/v8/tools/gcmole/gcmole-test.cc b/deps/v8/tools/gcmole/gcmole-test.cc
index 8512d7ab4c..038a514189 100644
--- a/deps/v8/tools/gcmole/gcmole-test.cc
+++ b/deps/v8/tools/gcmole/gcmole-test.cc
@@ -5,6 +5,7 @@
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
#include "src/handles/handles.h"
+#include "src/heap/local-heap.h"
#include "src/objects/foreign-inl.h"
#include "src/objects/managed.h"
#include "src/objects/maybe-object.h"
@@ -15,6 +16,8 @@ namespace internal {
// ------- Test simple argument evaluation order problems ---------
+void Safepoint() { LocalHeap::Current()->Safepoint(); }
+
Handle<Object> CauseGC(Handle<Object> obj, Isolate* isolate) {
isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
@@ -161,70 +164,187 @@ void TestDeadVarAnalysis(Isolate* isolate) {
raw_obj.Print();
}
+void TestDeadVarBecauseOfSafepointAnalysis(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ Safepoint();
+
+ // Should cause warning.
+ raw_obj.Print();
+}
+
void TestGuardedDeadVarAnalysis(Isolate* isolate) {
JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
- // Note: having DisallowHeapAllocation with the same function as CauseGC
- // normally doesn't make sense, but we want to test whether the gurads
+ // Note: having DisableGCMole with the same function as CauseGC
+ // normally doesn't make sense, but we want to test whether the guards
// are recognized by GCMole.
- DisallowHeapAllocation no_gc;
+ DisableGCMole no_gc_mole;
CauseGCRaw(raw_obj, isolate);
// Shouldn't cause warning.
raw_obj.Print();
}
-void TestGuardedDeadVarAnalysisNotOnStack(Isolate* isolate) {
+void TestGuardedDeadVarAnalysis2(Isolate* isolate) {
JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
- // {DisallowHeapAccess} has a {DisallowHeapAllocation} embedded as a member
- // field, so both are treated equally by gcmole.
- DisallowHeapAccess no_gc;
+ // Note: having DisallowGarbageCollection with the same function as CauseGC
+ // normally doesn't make sense, but we want to test whether the guards
+ // are recognized by GCMole.
+ DisallowGarbageCollection no_gc;
CauseGCRaw(raw_obj, isolate);
+ // Should cause warning.
+ raw_obj.Print();
+}
+
+void TestGuardedAgainstSafepointDeadVarAnalysis(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+
+ // Note: having DisableGCMole with the same function as CauseGC
+ // normally doesn't make sense, but we want to test whether the guards
+ // are recognized by GCMole.
+ DisableGCMole no_gc_mole;
+ Safepoint();
+
// Shouldn't cause warning.
raw_obj.Print();
}
-void TestGuardedDeadVarAnalysisNested(JSObject raw_obj, Isolate* isolate) {
+void TestGuardedAgainstSafepointDeadVarAnalysis2(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+
+ // Note: having DisallowGarbageCollection with the same function as CauseGC
+ // normally doesn't make sense, but we want to test whether the guards
+ // are recognized by GCMole.
+ DisallowGarbageCollection no_gc;
+ Safepoint();
+
+ // Should cause warning.
+ raw_obj.Print();
+}
+
+void TestGuardedAgainstSafepointDeadVarAnalysis3(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ // Note: having DisallowGarbageCollection with the same function as CauseGC
+ // normally doesn't make sense, but we want to test whether the guards
+ // are recognized by GCMole.
+ DisallowGarbageCollection no_gc;
+ Safepoint();
+ // Should cause warning.
+ raw_obj.Print();
+ {
+ DisableGCMole no_gc_mole;
+ // Shouldn't cause warning.
+ raw_obj.Print();
+ }
+ // Should cause warning.
+ raw_obj.Print();
+}
+
+void TestOnlyHeapGuardedDeadVarAnalysisInCompound(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ // {DisallowHeapAccess} has a {DisallowHeapAllocation}, but no
+ // {DisallowSafepoints}, so it could see objects move due to safepoints.
+ DisallowHeapAccess no_gc;
CauseGCRaw(raw_obj, isolate);
+ // Should cause warning.
+ raw_obj.Print();
+}
+
+void TestOnlyHeapGuardedDeadVarAnalysisInCompound2(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ // {DisallowHeapAccess} has a {DisallowHeapAllocation}, but no
+ // {DisallowSafepoints}, so it could see objects move due to safepoints.
+ DisallowHeapAccess no_gc;
+ CauseGCRaw(raw_obj, isolate);
+ // Should cause warning.
+ raw_obj.Print();
+ DisableGCMole no_gc_mole;
+ // Should cause warning.
+ raw_obj.Print();
+}
+void TestGuardedDeadVarAnalysisNested(JSObject raw_obj, Isolate* isolate) {
+ CauseGCRaw(raw_obj, isolate);
// Should cause warning.
raw_obj.Print();
}
void TestGuardedDeadVarAnalysisCaller(Isolate* isolate) {
- DisallowHeapAccess no_gc;
+ DisableGCMole no_gc_mole;
JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
+ // Shouldn't cause warning.
+ raw_obj.Print();
+}
+void TestGuardedDeadVarAnalysisCaller2(Isolate* isolate) {
+ DisallowGarbageCollection no_gc;
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
+ // Should cause warning.
+ raw_obj.Print();
+}
- // Shouldn't cause warning.
+void TestGuardedDeadVarAnalysisCaller3(Isolate* isolate) {
+ DisallowHeapAccess no_gc;
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
+ // Should cause warning.
+ raw_obj.Print();
+}
+
+void TestGuardedDeadVarAnalysisCaller4(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ TestGuardedDeadVarAnalysisNested(raw_obj, isolate);
+ // Should cause warning.
raw_obj.Print();
}
JSObject GuardedAllocation(Isolate* isolate) {
- DisallowHeapAllocation no_gc;
+ DisallowGarbageCollection no_gc;
+ return *isolate->factory()->NewJSObjectWithNullProto();
+}
+
+JSObject GuardedAllocation2(Isolate* isolate) {
+ DisableGCMole no_gc_mole;
return *isolate->factory()->NewJSObjectWithNullProto();
}
void TestNestedDeadVarAnalysis(Isolate* isolate) {
JSObject raw_obj = GuardedAllocation(isolate);
CauseGCRaw(raw_obj, isolate);
-
// Should cause warning.
raw_obj.Print();
}
+void TestNestedDeadVarAnalysis2(Isolate* isolate) {
+ DisableGCMole no_gc_mole;
+ JSObject raw_obj = GuardedAllocation(isolate);
+ CauseGCRaw(raw_obj, isolate);
+ // Shouldn't cause warning.
+ raw_obj.Print();
+}
+
// Test that putting a guard in the middle of the function doesn't
// mistakenly cover the whole scope of the raw variable.
void TestGuardedDeadVarAnalysisMidFunction(Isolate* isolate) {
JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
-
CauseGCRaw(raw_obj, isolate);
+ // Guarding the rest of the function from triggering a GC.
+ DisallowGarbageCollection no_gc;
+ // Should cause warning.
+ raw_obj.Print();
+}
+// Test that putting a guard in the middle of the function doesn't
+// mistakenly cover the whole scope of the raw variable.
+void TestGuardedDeadVarAnalysisMidFunction2(Isolate* isolate) {
+ JSObject raw_obj = *isolate->factory()->NewJSObjectWithNullProto();
+ CauseGCRaw(raw_obj, isolate);
// Guarding the rest of the function from triggering a GC.
- DisallowHeapAllocation no_gc;
+ DisableGCMole no_gc_mole;
// Should cause warning.
raw_obj.Print();
}
diff --git a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
index 84b3657c6c..4e18bae709 100644
--- a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
+++ b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
@@ -1 +1 @@
-7e31d257a711b1a77823633e4f19152c3e0718f4
+165dd133e7dff1583a6b6611e3d5a8382bcd0893
diff --git a/deps/v8/tools/gcmole/gcmole.cc b/deps/v8/tools/gcmole/gcmole.cc
index 7b32f6c7fd..3dc4baa722 100644
--- a/deps/v8/tools/gcmole/gcmole.cc
+++ b/deps/v8/tools/gcmole/gcmole.cc
@@ -27,22 +27,23 @@
// This is clang plugin used by gcmole tool. See README for more details.
+#include <bitset>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <set>
+#include <stack>
+
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
#include "llvm/Support/raw_ostream.h"
-#include <bitset>
-#include <fstream>
-#include <iostream>
-#include <map>
-#include <set>
-#include <stack>
-
namespace {
bool g_tracing_enabled = false;
@@ -228,8 +229,9 @@ class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
virtual bool VisitDeclRefExpr(clang::DeclRefExpr* expr) {
// If function mentions EXTERNAL VMState add artificial garbage collection
// mark.
- if (IsExternalVMState(expr->getDecl()))
+ if (IsExternalVMState(expr->getDecl())) {
AddCallee("CollectGarbage", "CollectGarbage");
+ }
return true;
}
@@ -684,17 +686,13 @@ class FunctionAnalyzer {
FunctionAnalyzer(clang::MangleContext* ctx, clang::CXXRecordDecl* object_decl,
clang::CXXRecordDecl* maybe_object_decl,
clang::CXXRecordDecl* smi_decl,
- clang::CXXRecordDecl* no_gc_decl,
- clang::CXXRecordDecl* no_gc_or_safepoint_decl,
- clang::CXXRecordDecl* no_heap_access_decl,
+ clang::CXXRecordDecl* no_gc_mole_decl,
clang::DiagnosticsEngine& d, clang::SourceManager& sm)
: ctx_(ctx),
object_decl_(object_decl),
maybe_object_decl_(maybe_object_decl),
smi_decl_(smi_decl),
- no_gc_decl_(no_gc_decl),
- no_gc_or_safepoint_decl_(no_gc_or_safepoint_decl),
- no_heap_access_decl_(no_heap_access_decl),
+ no_gc_mole_decl_(no_gc_mole_decl),
d_(d),
sm_(sm),
block_(NULL) {}
@@ -1281,9 +1279,7 @@ class FunctionAnalyzer {
DECL_VISIT_STMT(ForStmt) {
Block block (VisitStmt(stmt->getInit(), env), this);
do {
- block.Loop(stmt->getCond(),
- stmt->getBody(),
- stmt->getInc());
+ block.Loop(stmt->getCond(), stmt->getBody(), stmt->getInc());
} while (block.changed());
return block.out();
}
@@ -1338,25 +1334,15 @@ class FunctionAnalyzer {
const clang::CXXRecordDecl* GetDefinitionOrNull(
const clang::CXXRecordDecl* record) {
- if (record == NULL) {
- return NULL;
- }
-
+ if (record == NULL) return NULL;
if (!InV8Namespace(record)) return NULL;
-
- if (!record->hasDefinition()) {
- return NULL;
- }
-
+ if (!record->hasDefinition()) return NULL;
return record->getDefinition();
}
bool IsDerivedFromInternalPointer(const clang::CXXRecordDecl* record) {
const clang::CXXRecordDecl* definition = GetDefinitionOrNull(record);
- if (!definition) {
- return false;
- }
-
+ if (!definition) return false;
bool result = (IsDerivedFrom(record, object_decl_) &&
!IsDerivedFrom(record, smi_decl_)) ||
IsDerivedFrom(record, maybe_object_decl_);
@@ -1381,13 +1367,9 @@ class FunctionAnalyzer {
// such. For V8 that means Object and MaybeObject instances.
bool RepresentsRawPointerType(clang::QualType qtype) {
// Not yet assigned pointers can't get moved by the GC.
- if (qtype.isNull()) {
- return false;
- }
+ if (qtype.isNull()) return false;
// nullptr can't get moved by the GC.
- if (qtype->isNullPtrType()) {
- return false;
- }
+ if (qtype->isNullPtrType()) return false;
const clang::PointerType* pointer_type =
llvm::dyn_cast_or_null<clang::PointerType>(qtype.getTypePtrOrNull());
@@ -1399,25 +1381,15 @@ class FunctionAnalyzer {
}
bool IsGCGuard(clang::QualType qtype) {
- if (qtype.isNull()) {
- return false;
- }
- if (qtype->isNullPtrType()) {
- return false;
- }
+ if (!no_gc_mole_decl_) return false;
+ if (qtype.isNull()) return false;
+ if (qtype->isNullPtrType()) return false;
const clang::CXXRecordDecl* record = qtype->getAsCXXRecordDecl();
const clang::CXXRecordDecl* definition = GetDefinitionOrNull(record);
- if (!definition) {
- return false;
- }
-
- return (no_gc_decl_ && IsDerivedFrom(definition, no_gc_decl_)) ||
- (no_gc_or_safepoint_decl_ &&
- IsDerivedFrom(definition, no_gc_or_safepoint_decl_)) ||
- (no_heap_access_decl_ &&
- IsDerivedFrom(definition, no_heap_access_decl_));
+ if (!definition) return false;
+ return no_gc_mole_decl_ == definition;
}
Environment VisitDecl(clang::Decl* decl, Environment& env) {
@@ -1501,8 +1473,7 @@ class FunctionAnalyzer {
clang::CXXRecordDecl* object_decl_;
clang::CXXRecordDecl* maybe_object_decl_;
clang::CXXRecordDecl* smi_decl_;
- clang::CXXRecordDecl* no_gc_decl_;
- clang::CXXRecordDecl* no_gc_or_safepoint_decl_;
+ clang::CXXRecordDecl* no_gc_mole_decl_;
clang::CXXRecordDecl* no_heap_access_decl_;
clang::DiagnosticsEngine& d_;
@@ -1567,58 +1538,38 @@ class ProblemsFinder : public clang::ASTConsumer,
}
virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
- if (TranslationUnitIgnored()) {
- return;
- }
+ if (TranslationUnitIgnored()) return;
Resolver r(ctx);
- // It is a valid situation that no_gc_decl == NULL when the
- // DisallowHeapAllocation is not included and can't be resolved.
- // This is gracefully handled in the FunctionAnalyzer later.
- clang::CXXRecordDecl* no_gc_decl =
- r.ResolveNamespace("v8")
- .ResolveNamespace("internal")
- .ResolveTemplate("DisallowHeapAllocation");
-
- clang::CXXRecordDecl* no_gc_or_safepoint_decl =
- r.ResolveNamespace("v8")
- .ResolveNamespace("internal")
- .ResolveTemplate("DisallowGarbageCollection");
-
- clang::CXXRecordDecl* no_heap_access_decl =
- r.ResolveNamespace("v8")
- .ResolveNamespace("internal")
- .Resolve<clang::CXXRecordDecl>("DisallowHeapAccess");
+ // It is a valid situation that no_gc_mole_decl == NULL when DisableGCMole
+ // is not included and can't be resolved. This is gracefully handled in the
+ // FunctionAnalyzer later.
+ auto v8_internal = r.ResolveNamespace("v8").ResolveNamespace("internal");
+ clang::CXXRecordDecl* no_gc_mole_decl =
+ v8_internal.ResolveTemplate("DisableGCMole");
clang::CXXRecordDecl* object_decl =
- r.ResolveNamespace("v8").ResolveNamespace("internal").
- Resolve<clang::CXXRecordDecl>("Object");
+ v8_internal.Resolve<clang::CXXRecordDecl>("Object");
clang::CXXRecordDecl* maybe_object_decl =
- r.ResolveNamespace("v8")
- .ResolveNamespace("internal")
- .Resolve<clang::CXXRecordDecl>("MaybeObject");
+ v8_internal.Resolve<clang::CXXRecordDecl>("MaybeObject");
clang::CXXRecordDecl* smi_decl =
- r.ResolveNamespace("v8").ResolveNamespace("internal").
- Resolve<clang::CXXRecordDecl>("Smi");
+ v8_internal.Resolve<clang::CXXRecordDecl>("Smi");
if (object_decl != NULL) object_decl = object_decl->getDefinition();
- if (maybe_object_decl != NULL)
+ if (maybe_object_decl != NULL) {
maybe_object_decl = maybe_object_decl->getDefinition();
+ }
if (smi_decl != NULL) smi_decl = smi_decl->getDefinition();
- if (no_heap_access_decl != NULL)
- no_heap_access_decl = no_heap_access_decl->getDefinition();
-
if (object_decl != NULL && smi_decl != NULL && maybe_object_decl != NULL) {
function_analyzer_ = new FunctionAnalyzer(
clang::ItaniumMangleContext::create(ctx, d_), object_decl,
- maybe_object_decl, smi_decl, no_gc_decl, no_gc_or_safepoint_decl,
- no_heap_access_decl, d_, sm_);
+ maybe_object_decl, smi_decl, no_gc_mole_decl, d_, sm_);
TraverseDecl(ctx.getTranslationUnitDecl());
} else {
if (object_decl == NULL) {
diff --git a/deps/v8/tools/gcmole/gcmole.lua b/deps/v8/tools/gcmole/gcmole.lua
deleted file mode 100644
index 9705165d36..0000000000
--- a/deps/v8/tools/gcmole/gcmole.lua
+++ /dev/null
@@ -1,532 +0,0 @@
--- Copyright 2011 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.
-
--- This is main driver for gcmole tool. See README for more details.
--- Usage: CLANG_BIN=clang-bin-dir lua tools/gcmole/gcmole.lua [arm|ia32|x64]
-
-local DIR = arg[0]:match("^(.+)/[^/]+$")
-
-local FLAGS = {
- -- Do not build gcsuspects file and reuse previously generated one.
- reuse_gcsuspects = false;
-
- -- Don't use parallel python runner.
- sequential = false;
-
- -- Print commands to console before executing them.
- verbose = false;
-
- -- Perform dead variable analysis.
- dead_vars = true;
-
- -- Enable verbose tracing from the plugin itself.
- verbose_trace = false;
-
- -- When building gcsuspects whitelist certain functions as if they
- -- can be causing GC. Currently used to reduce number of false
- -- positives in dead variables analysis. See TODO for WHITELIST
- -- below.
- whitelist = true;
-}
-local ARGS = {}
-
-for i = 1, #arg do
- local flag = arg[i]:match "^%-%-([%w_-]+)$"
- if flag then
- local no, real_flag = flag:match "^(no)([%w_-]+)$"
- if real_flag then flag = real_flag end
-
- flag = flag:gsub("%-", "_")
- if FLAGS[flag] ~= nil then
- FLAGS[flag] = (no ~= "no")
- else
- error("Unknown flag: " .. flag)
- end
- else
- table.insert(ARGS, arg[i])
- end
-end
-
-local ARCHS = ARGS[1] and { ARGS[1] } or { 'ia32', 'arm', 'x64', 'arm64' }
-
-local io = require "io"
-local os = require "os"
-
-function log(...)
- io.stderr:write(string.format(...))
- io.stderr:write "\n"
-end
-
--------------------------------------------------------------------------------
--- Clang invocation
-
-local CLANG_BIN = os.getenv "CLANG_BIN"
-local CLANG_PLUGINS = os.getenv "CLANG_PLUGINS"
-
-if not CLANG_BIN or CLANG_BIN == "" then
- error "CLANG_BIN not set"
-end
-
-if not CLANG_PLUGINS or CLANG_PLUGINS == "" then
- CLANG_PLUGINS = DIR
-end
-
-local function MakeClangCommandLine(
- plugin, plugin_args, triple, arch_define, arch_options)
- if plugin_args then
- for i = 1, #plugin_args do
- plugin_args[i] = "-Xclang -plugin-arg-" .. plugin
- .. " -Xclang " .. plugin_args[i]
- end
- plugin_args = " " .. table.concat(plugin_args, " ")
- end
- return CLANG_BIN .. "/clang++ -std=c++14 -c"
- .. " -Xclang -load -Xclang " .. CLANG_PLUGINS .. "/libgcmole.so"
- .. " -Xclang -plugin -Xclang " .. plugin
- .. (plugin_args or "")
- .. " -Xclang -triple -Xclang " .. triple
- .. " -fno-exceptions"
- .. " -D" .. arch_define
- .. " -DENABLE_DEBUGGER_SUPPORT"
- .. " -DV8_INTL_SUPPORT"
- .. " -I./"
- .. " -Iinclude/"
- .. " -Iout/build/gen"
- .. " -Ithird_party/icu/source/common"
- .. " -Ithird_party/icu/source/i18n"
- .. " " .. arch_options
-end
-
-local function IterTable(t)
- return coroutine.wrap(function ()
- for i, v in ipairs(t) do
- coroutine.yield(v)
- end
- end)
-end
-
-local function SplitResults(lines, func)
- -- Splits the output of parallel.py and calls func on each result.
- -- Bails out in case of an error in one of the executions.
- local current = {}
- local filename = ""
- for line in lines do
- local new_file = line:match "^______________ (.*)$"
- local code = line:match "^______________ finish (%d+) ______________$"
- if code then
- if tonumber(code) > 0 then
- log(table.concat(current, "\n"))
- log("Failed to examine " .. filename)
- return false
- end
- log("-- %s", filename)
- func(filename, IterTable(current))
- elseif new_file then
- filename = new_file
- current = {}
- else
- table.insert(current, line)
- end
- end
- return true
-end
-
-function InvokeClangPluginForEachFile(filenames, cfg, func)
- local cmd_line = MakeClangCommandLine(cfg.plugin,
- cfg.plugin_args,
- cfg.triple,
- cfg.arch_define,
- cfg.arch_options)
- if FLAGS.sequential then
- log("** Sequential execution.")
- for _, filename in ipairs(filenames) do
- log("-- %s", filename)
- local action = cmd_line .. " " .. filename .. " 2>&1"
- if FLAGS.verbose then print('popen ', action) end
- local pipe = io.popen(action)
- func(filename, pipe:lines())
- local success = pipe:close()
- if not success then error("Failed to run: " .. action) end
- end
- else
- log("** Parallel execution.")
- local action = "python tools/gcmole/parallel.py \""
- .. cmd_line .. "\" " .. table.concat(filenames, " ")
- if FLAGS.verbose then print('popen ', action) end
- local pipe = io.popen(action)
- local success = SplitResults(pipe:lines(), func)
- local closed = pipe:close()
- if not (success and closed) then error("Failed to run: " .. action) end
- end
-end
-
--------------------------------------------------------------------------------
-
-local function ParseGNFile(for_test)
- local result = {}
- local gn_files
- if for_test then
- gn_files = {
- { "tools/gcmole/GCMOLE.gn", '"([^"]-%.cc)"', "" }
- }
- else
- gn_files = {
- { "BUILD.gn", '"([^"]-%.cc)"', "" },
- { "test/cctest/BUILD.gn", '"(test-[^"]-%.cc)"', "test/cctest/" }
- }
- end
-
- for i = 1, #gn_files do
- local filename = gn_files[i][1]
- local pattern = gn_files[i][2]
- local prefix = gn_files[i][3]
- local gn_file = assert(io.open(filename), "failed to open GN file")
- local gn = gn_file:read('*a')
- for condition, sources in
- gn:gmatch "### gcmole%((.-)%) ###(.-)%]" do
- if result[condition] == nil then result[condition] = {} end
- for file in sources:gmatch(pattern) do
- table.insert(result[condition], prefix .. file)
- end
- end
- gn_file:close()
- end
-
- return result
-end
-
-local function EvaluateCondition(cond, props)
- if cond == 'all' then return true end
-
- local p, v = cond:match "(%w+):(%w+)"
-
- assert(p and v, "failed to parse condition: " .. cond)
- assert(props[p] ~= nil, "undefined configuration property: " .. p)
-
- return props[p] == v
-end
-
-local function BuildFileList(sources, props)
- local list = {}
- for condition, files in pairs(sources) do
- if EvaluateCondition(condition, props) then
- for i = 1, #files do table.insert(list, files[i]) end
- end
- end
- return list
-end
-
-
-local gn_sources = ParseGNFile(false)
-local gn_test_sources = ParseGNFile(true)
-
-local function FilesForArch(arch)
- return BuildFileList(gn_sources, { os = 'linux',
- arch = arch,
- mode = 'debug',
- simulator = ''})
-end
-
-local function FilesForTest(arch)
- return BuildFileList(gn_test_sources, { os = 'linux',
- arch = arch,
- mode = 'debug',
- simulator = ''})
-end
-
-local mtConfig = {}
-
-mtConfig.__index = mtConfig
-
-local function config (t) return setmetatable(t, mtConfig) end
-
-function mtConfig:extend(t)
- local e = {}
- for k, v in pairs(self) do e[k] = v end
- for k, v in pairs(t) do e[k] = v end
- return config(e)
-end
-
-local ARCHITECTURES = {
- ia32 = config { triple = "i586-unknown-linux",
- arch_define = "V8_TARGET_ARCH_IA32",
- arch_options = "-m32" },
- arm = config { triple = "i586-unknown-linux",
- arch_define = "V8_TARGET_ARCH_ARM",
- arch_options = "-m32" },
- x64 = config { triple = "x86_64-unknown-linux",
- arch_define = "V8_TARGET_ARCH_X64",
- arch_options = "" },
- arm64 = config { triple = "x86_64-unknown-linux",
- arch_define = "V8_TARGET_ARCH_ARM64",
- arch_options = "" },
-}
-
--------------------------------------------------------------------------------
--- GCSuspects Generation
-
-local gc, gc_caused, funcs
-
--- Note that the gcsuspects file lists functions in the form:
--- mangled_name,unmangled_function_name
---
--- This means that we can match just the function name by matching only
--- after a comma.
-local WHITELIST = {
- -- The following functions call CEntryStub which is always present.
- "MacroAssembler.*,CallRuntime",
- "CompileCallLoadPropertyWithInterceptor",
- "CallIC.*,GenerateMiss",
-
- -- DirectCEntryStub is a special stub used on ARM.
- -- It is pinned and always present.
- "DirectCEntryStub.*,GenerateCall",
-
- -- TODO GCMole currently is sensitive enough to understand that certain
- -- functions only cause GC and return Failure simulataneously.
- -- Callsites of such functions are safe as long as they are properly
- -- check return value and propagate the Failure to the caller.
- -- It should be possible to extend GCMole to understand this.
- "Heap.*,TryEvacuateObject",
-
- -- Ignore all StateTag methods.
- "StateTag",
-
- -- Ignore printing of elements transition.
- "PrintElementsTransition",
-
- -- CodeCreateEvent receives AbstractCode (a raw ptr) as an argument.
- "CodeCreateEvent",
- "WriteField",
-};
-
-local function AddCause(name, cause)
- local t = gc_caused[name]
- if not t then
- t = {}
- gc_caused[name] = t
- end
- table.insert(t, cause)
-end
-
-local function resolve(name)
- local f = funcs[name]
-
- if not f then
- f = {}
- funcs[name] = f
-
- if name:match ",.*Collect.*Garbage" then
- gc[name] = true
- AddCause(name, "<GC>")
- end
-
- if FLAGS.whitelist then
- for i = 1, #WHITELIST do
- if name:match(WHITELIST[i]) then
- gc[name] = false
- end
- end
- end
- end
-
- return f
-end
-
-local function parse (filename, lines)
- local scope
-
- for funcname in lines do
- if funcname:sub(1, 1) ~= '\t' then
- resolve(funcname)
- scope = funcname
- else
- local name = funcname:sub(2)
- resolve(name)[scope] = true
- end
- end
-end
-
-local function propagate ()
- log "** Propagating GC information"
-
- local function mark(from, callers)
- for caller, _ in pairs(callers) do
- if gc[caller] == nil then
- gc[caller] = true
- mark(caller, funcs[caller])
- end
- AddCause(caller, from)
- end
- end
-
- for funcname, callers in pairs(funcs) do
- if gc[funcname] then mark(funcname, callers) end
- end
-end
-
-local function GenerateGCSuspects(arch, files, cfg)
- -- Reset the global state.
- gc, gc_caused, funcs = {}, {}, {}
-
- log ("** Building GC Suspects for %s", arch)
- InvokeClangPluginForEachFile (files,
- cfg:extend { plugin = "dump-callees" },
- parse)
-
- propagate()
-
- local out = assert(io.open("gcsuspects", "w"))
- for name, value in pairs(gc) do if value then out:write (name, '\n') end end
- out:close()
-
- local out = assert(io.open("gccauses", "w"))
- out:write "GC = {"
- for name, causes in pairs(gc_caused) do
- out:write("['", name, "'] = {")
- for i = 1, #causes do out:write ("'", causes[i], "';") end
- out:write("};\n")
- end
- out:write "}"
- out:close()
-
- log ("** GCSuspects generated for %s", arch)
-end
-
---------------------------------------------------------------------------------
--- Analysis
-
-local function CheckCorrectnessForArch(arch, for_test)
- local files
- if for_test then
- files = FilesForTest(arch)
- else
- files = FilesForArch(arch)
- end
- local cfg = ARCHITECTURES[arch]
-
- if not FLAGS.reuse_gcsuspects then
- GenerateGCSuspects(arch, files, cfg)
- end
-
- local processed_files = 0
- local errors_found = false
- local output = ""
- local function SearchForErrors(filename, lines)
- processed_files = processed_files + 1
- for l in lines do
- errors_found = errors_found or
- l:match "^[^:]+:%d+:%d+:" or
- l:match "error" or
- l:match "warning"
- if for_test then
- output = output.."\n"..l
- else
- print(l)
- end
- end
- end
-
- log("** Searching for evaluation order problems%s for %s",
- FLAGS.dead_vars and " and dead variables" or "",
- arch)
- local plugin_args = {}
- if FLAGS.dead_vars then table.insert(plugin_args, "--dead-vars") end
- if FLAGS.verbose_trace then table.insert(plugin_args, '--verbose') end
- InvokeClangPluginForEachFile(files,
- cfg:extend { plugin = "find-problems",
- plugin_args = plugin_args },
- SearchForErrors)
- log("** Done processing %d files. %s",
- processed_files,
- errors_found and "Errors found" or "No errors found")
-
- return errors_found, output
-end
-
-local function SafeCheckCorrectnessForArch(arch, for_test)
- local status, errors, output = pcall(CheckCorrectnessForArch, arch, for_test)
- if not status then
- print(string.format("There was an error: %s", errors))
- errors = true
- end
- return errors, output
-end
-
--- Source: https://stackoverflow.com/a/41515925/1540248
-local function StringDifference(str1,str2)
- for i = 1,#str1 do -- Loop over strings
- -- If that character is not equal to its counterpart
- if str1:sub(i,i) ~= str2:sub(i,i) then
- return i --Return that index
- end
- end
- return #str1+1 -- Return the index after where the shorter one ends as fallback.
-end
-
-local function TestRun()
- local errors, output = SafeCheckCorrectnessForArch('x64', true)
- if not errors then
- log("** Test file should produce errors, but none were found. Output:")
- log(output)
- return false
- end
-
- local filename = "tools/gcmole/test-expectations.txt"
- local exp_file = assert(io.open(filename), "failed to open test expectations file")
- local expectations = exp_file:read('*all')
-
- if output ~= expectations then
- log("** Output mismatch from running tests. Please run them manually.")
- local idx = StringDifference(output, expectations)
-
- log("Difference at byte "..idx)
- log("Expected: "..expectations:sub(idx-10,idx+10))
- log("Actual: "..output:sub(idx-10,idx+10))
-
- log("--- Full output ---")
- log(output)
- log("------")
-
- return false
- end
-
- log("** Tests ran successfully")
- return true
-end
-
-local errors = not TestRun()
-
-for _, arch in ipairs(ARCHS) do
- if not ARCHITECTURES[arch] then
- error("Unknown arch: " .. arch)
- end
-
- errors = SafeCheckCorrectnessForArch(arch, false) or errors
-end
-
-os.exit(errors and 1 or 0)
diff --git a/deps/v8/tools/gcmole/gcmole.py b/deps/v8/tools/gcmole/gcmole.py
new file mode 100644
index 0000000000..978cd31598
--- /dev/null
+++ b/deps/v8/tools/gcmole/gcmole.py
@@ -0,0 +1,575 @@
+#!/usr/bin/env python
+# 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.
+
+# This is main driver for gcmole tool. See README for more details.
+# Usage: CLANG_BIN=clang-bin-dir python tools/gcmole/gcmole.py [arm|arm64|ia32|x64]
+
+# for py2/py3 compatibility
+from __future__ import print_function
+
+import collections
+import difflib
+from multiprocessing import cpu_count
+import os
+import re
+import subprocess
+import sys
+import threading
+if sys.version_info.major > 2:
+ import queue
+else:
+ import Queue as queue
+
+ArchCfg = collections.namedtuple("ArchCfg",
+ ["triple", "arch_define", "arch_options"])
+
+ARCHITECTURES = {
+ "ia32":
+ ArchCfg(
+ triple="i586-unknown-linux",
+ arch_define="V8_TARGET_ARCH_IA32",
+ arch_options=["-m32"],
+ ),
+ "arm":
+ ArchCfg(
+ triple="i586-unknown-linux",
+ arch_define="V8_TARGET_ARCH_ARM",
+ arch_options=["-m32"],
+ ),
+ "x64":
+ ArchCfg(
+ triple="x86_64-unknown-linux",
+ arch_define="V8_TARGET_ARCH_X64",
+ arch_options=[]),
+ "arm64":
+ ArchCfg(
+ triple="x86_64-unknown-linux",
+ arch_define="V8_TARGET_ARCH_ARM64",
+ arch_options=[],
+ ),
+}
+
+
+def log(format, *args):
+ print(format.format(*args))
+
+
+def fatal(format, *args):
+ log(format, *args)
+ sys.exit(1)
+
+
+# -----------------------------------------------------------------------------
+# Clang invocation
+
+
+def MakeClangCommandLine(plugin, plugin_args, arch_cfg, clang_bin_dir,
+ clang_plugins_dir):
+ prefixed_plugin_args = []
+ if plugin_args:
+ for arg in plugin_args:
+ prefixed_plugin_args += [
+ "-Xclang",
+ "-plugin-arg-{}".format(plugin),
+ "-Xclang",
+ arg,
+ ]
+
+ return ([
+ os.path.join(clang_bin_dir, "clang++"),
+ "-std=c++14",
+ "-c",
+ "-Xclang",
+ "-load",
+ "-Xclang",
+ os.path.join(clang_plugins_dir, "libgcmole.so"),
+ "-Xclang",
+ "-plugin",
+ "-Xclang",
+ plugin,
+ ] + prefixed_plugin_args + [
+ "-Xclang",
+ "-triple",
+ "-Xclang",
+ arch_cfg.triple,
+ "-fno-exceptions",
+ "-D",
+ arch_cfg.arch_define,
+ "-DENABLE_DEBUGGER_SUPPORT",
+ "-DV8_INTL_SUPPORT",
+ "-I./",
+ "-Iinclude/",
+ "-Iout/build/gen",
+ "-Ithird_party/icu/source/common",
+ "-Ithird_party/icu/source/i18n",
+ ] + arch_cfg.arch_options)
+
+
+def InvokeClangPluginForFile(filename, cmd_line, verbose):
+ if verbose:
+ print("popen ", " ".join(cmd_line + [filename]))
+ p = subprocess.Popen(
+ cmd_line + [filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ return p.returncode, stdout, stderr
+
+
+def InvokeClangPluginForFilesInQueue(i, input_queue, output_queue, cancel_event,
+ cmd_line, verbose):
+ success = False
+ try:
+ while not cancel_event.is_set():
+ filename = input_queue.get_nowait()
+ ret, stdout, stderr = InvokeClangPluginForFile(filename, cmd_line,
+ verbose)
+ output_queue.put_nowait((filename, ret, stdout.decode('utf-8'), stderr.decode('utf-8')))
+ if ret != 0:
+ break
+ except KeyboardInterrupt:
+ log("-- [{}] Interrupting", i)
+ except queue.Empty:
+ success = True
+ finally:
+ # Emit a success bool so that the reader knows that there was either an
+ # error or all files were processed.
+ output_queue.put_nowait(success)
+
+
+def InvokeClangPluginForEachFile(
+ filenames,
+ plugin,
+ plugin_args,
+ arch_cfg,
+ flags,
+ clang_bin_dir,
+ clang_plugins_dir,
+):
+ cmd_line = MakeClangCommandLine(plugin, plugin_args, arch_cfg, clang_bin_dir,
+ clang_plugins_dir)
+ verbose = flags["verbose"]
+ if flags["sequential"]:
+ log("** Sequential execution.")
+ for filename in filenames:
+ log("-- {}", filename)
+ returncode, stdout, stderr = InvokeClangPluginForFile(
+ filename, cmd_line, verbose)
+ if returncode != 0:
+ sys.stderr.write(stderr)
+ sys.exit(returncode)
+ yield filename, stdout, stderr
+ else:
+ log("** Parallel execution.")
+ cpus = cpu_count()
+ input_queue = queue.Queue()
+ output_queue = queue.Queue()
+ threads = []
+ try:
+ for filename in filenames:
+ input_queue.put(filename)
+
+ cancel_event = threading.Event()
+
+ for i in range(min(len(filenames), cpus)):
+ threads.append(
+ threading.Thread(
+ target=InvokeClangPluginForFilesInQueue,
+ args=(i, input_queue, output_queue, cancel_event, cmd_line,
+ verbose)))
+
+ for t in threads:
+ t.start()
+
+ num_finished = 0
+ while num_finished < len(threads):
+ output = output_queue.get()
+ if type(output) == bool:
+ if output:
+ num_finished += 1
+ continue
+ else:
+ break
+ filename, returncode, stdout, stderr = output
+ log("-- {}", filename)
+ if returncode != 0:
+ sys.stderr.write(stderr)
+ sys.exit(returncode)
+ yield filename, stdout, stderr
+
+ finally:
+ cancel_event.set()
+ for t in threads:
+ t.join()
+
+
+# -----------------------------------------------------------------------------
+
+
+def ParseGNFile(for_test):
+ result = {}
+ if for_test:
+ gn_files = [("tools/gcmole/GCMOLE.gn", re.compile('"([^"]*?\.cc)"'), "")]
+ else:
+ gn_files = [
+ ("BUILD.gn", re.compile('"([^"]*?\.cc)"'), ""),
+ ("test/cctest/BUILD.gn", re.compile('"(test-[^"]*?\.cc)"'),
+ "test/cctest/"),
+ ]
+
+ for filename, pattern, prefix in gn_files:
+ with open(filename) as gn_file:
+ gn = gn_file.read()
+ for condition, sources in re.findall("### gcmole\((.*?)\) ###(.*?)\]", gn,
+ re.MULTILINE | re.DOTALL):
+ if condition not in result:
+ result[condition] = []
+ for file in pattern.findall(sources):
+ result[condition].append(prefix + file)
+
+ return result
+
+
+def EvaluateCondition(cond, props):
+ if cond == "all":
+ return True
+
+ m = re.match("(\w+):(\w+)", cond)
+ if m is None:
+ fatal("failed to parse condition: {}", cond)
+ p, v = m.groups()
+ if p not in props:
+ fatal("undefined configuration property: {}", p)
+
+ return props[p] == v
+
+
+def BuildFileList(sources, props):
+ ret = []
+ for condition, files in sources.items():
+ if EvaluateCondition(condition, props):
+ ret += files
+ return ret
+
+
+gn_sources = ParseGNFile(for_test=False)
+gn_test_sources = ParseGNFile(for_test=True)
+
+
+def FilesForArch(arch):
+ return BuildFileList(gn_sources, {
+ "os": "linux",
+ "arch": arch,
+ "mode": "debug",
+ "simulator": ""
+ })
+
+
+def FilesForTest(arch):
+ return BuildFileList(gn_test_sources, {
+ "os": "linux",
+ "arch": arch,
+ "mode": "debug",
+ "simulator": ""
+ })
+
+
+# -----------------------------------------------------------------------------
+# GCSuspects Generation
+
+# Note that the gcsuspects file lists functions in the form:
+# mangled_name,unmangled_function_name
+#
+# This means that we can match just the function name by matching only
+# after a comma.
+ALLOWLIST = [
+ # The following functions call CEntryStub which is always present.
+ "MacroAssembler.*,CallRuntime",
+ "CompileCallLoadPropertyWithInterceptor",
+ "CallIC.*,GenerateMiss",
+ # DirectCEntryStub is a special stub used on ARM.
+ # It is pinned and always present.
+ "DirectCEntryStub.*,GenerateCall",
+ # TODO GCMole currently is sensitive enough to understand that certain
+ # functions only cause GC and return Failure simulataneously.
+ # Callsites of such functions are safe as long as they are properly
+ # check return value and propagate the Failure to the caller.
+ # It should be possible to extend GCMole to understand this.
+ "Heap.*,TryEvacuateObject",
+ # Ignore all StateTag methods.
+ "StateTag",
+ # Ignore printing of elements transition.
+ "PrintElementsTransition",
+ # CodeCreateEvent receives AbstractCode (a raw ptr) as an argument.
+ "CodeCreateEvent",
+ "WriteField",
+]
+
+GC_PATTERN = ",.*Collect.*Garbage"
+SAFEPOINT_PATTERN = ",EnterSafepoint"
+ALLOWLIST_PATTERN = "|".join("(?:%s)" % p for p in ALLOWLIST)
+
+
+def MergeRegexp(pattern_dict):
+ return re.compile("|".join(
+ "(?P<%s>%s)" % (key, value) for (key, value) in pattern_dict.items()))
+
+
+IS_SPECIAL_WITHOUT_ALLOW_LIST = MergeRegexp({
+ "gc": GC_PATTERN,
+ "safepoint": SAFEPOINT_PATTERN
+})
+IS_SPECIAL_WITH_ALLOW_LIST = MergeRegexp({
+ "gc": GC_PATTERN,
+ "safepoint": SAFEPOINT_PATTERN,
+ "allow": ALLOWLIST_PATTERN
+})
+
+
+class GCSuspectsCollector:
+
+ def __init__(self, flags):
+ self.gc = {}
+ self.gc_caused = collections.defaultdict(lambda: [])
+ self.funcs = {}
+ self.current_caller = None
+ self.allowlist = flags["allowlist"]
+ self.is_special = IS_SPECIAL_WITH_ALLOW_LIST if self.allowlist else IS_SPECIAL_WITHOUT_ALLOW_LIST
+
+ def AddCause(self, name, cause):
+ self.gc_caused[name].append(cause)
+
+ def Parse(self, lines):
+ for funcname in lines:
+ if not funcname:
+ continue
+
+ if funcname[0] != "\t":
+ self.Resolve(funcname)
+ self.current_caller = funcname
+ else:
+ name = funcname[1:]
+ callers_for_name = self.Resolve(name)
+ callers_for_name.add(self.current_caller)
+
+ def Resolve(self, name):
+ if name not in self.funcs:
+ self.funcs[name] = set()
+ m = self.is_special.search(name)
+ if m:
+ if m.group("gc"):
+ self.gc[name] = True
+ self.AddCause(name, "<GC>")
+ elif m.group("safepoint"):
+ self.gc[name] = True
+ self.AddCause(name, "<Safepoint>")
+ elif m.group("allow"):
+ self.gc[name] = False
+
+ return self.funcs[name]
+
+ def Propagate(self):
+ log("** Propagating GC information")
+
+ def mark(funcname, callers):
+ for caller in callers:
+ if caller not in self.gc:
+ self.gc[caller] = True
+ mark(caller, self.funcs[caller])
+
+ self.AddCause(caller, funcname)
+
+ for funcname, callers in self.funcs.items():
+ if self.gc.get(funcname, False):
+ mark(funcname, callers)
+
+
+def GenerateGCSuspects(arch, files, arch_cfg, flags, clang_bin_dir,
+ clang_plugins_dir):
+ # Reset the global state.
+ collector = GCSuspectsCollector(flags)
+
+ log("** Building GC Suspects for {}", arch)
+ for filename, stdout, stderr in InvokeClangPluginForEachFile(
+ files, "dump-callees", [], arch_cfg, flags, clang_bin_dir,
+ clang_plugins_dir):
+ collector.Parse(stdout.splitlines())
+
+ collector.Propagate()
+
+ with open("gcsuspects", "w") as out:
+ for name, value in collector.gc.items():
+ if value:
+ out.write(name + "\n")
+
+ with open("gccauses", "w") as out:
+ out.write("GC = {\n")
+ for name, causes in collector.gc_caused.items():
+ out.write(" '{}': [\n".format(name))
+ for cause in causes:
+ out.write(" '{}',\n".format(cause))
+ out.write(" ],\n")
+ out.write("}\n")
+
+ log("** GCSuspects generated for {}", arch)
+
+
+# ------------------------------------------------------------------------------
+# Analysis
+
+
+def CheckCorrectnessForArch(arch, for_test, flags, clang_bin_dir,
+ clang_plugins_dir):
+ if for_test:
+ files = FilesForTest(arch)
+ else:
+ files = FilesForArch(arch)
+ arch_cfg = ARCHITECTURES[arch]
+
+ if not flags["reuse_gcsuspects"]:
+ GenerateGCSuspects(arch, files, arch_cfg, flags, clang_bin_dir,
+ clang_plugins_dir)
+ else:
+ log("** Reusing GCSuspects for {}", arch)
+
+ processed_files = 0
+ errors_found = False
+ output = ""
+
+ log(
+ "** Searching for evaluation order problems{} for {}",
+ " and dead variables" if flags["dead_vars"] else "",
+ arch,
+ )
+ plugin_args = []
+ if flags["dead_vars"]:
+ plugin_args.append("--dead-vars")
+ if flags["verbose_trace"]:
+ plugin_args.append("--verbose")
+ for filename, stdout, stderr in InvokeClangPluginForEachFile(
+ files,
+ "find-problems",
+ plugin_args,
+ arch_cfg,
+ flags,
+ clang_bin_dir,
+ clang_plugins_dir,
+ ):
+ processed_files = processed_files + 1
+ if not errors_found:
+ errors_found = re.search("^[^:]+:\d+:\d+: (warning|error)", stderr,
+ re.MULTILINE) is not None
+ if for_test:
+ output = output + stderr
+ else:
+ sys.stdout.write(stderr)
+
+ log(
+ "** Done processing {} files. {}",
+ processed_files,
+ "Errors found" if errors_found else "No errors found",
+ )
+
+ return errors_found, output
+
+
+def TestRun(flags, clang_bin_dir, clang_plugins_dir):
+ log("** Test Run")
+ errors_found, output = CheckCorrectnessForArch("x64", True, flags,
+ clang_bin_dir,
+ clang_plugins_dir)
+ if not errors_found:
+ log("** Test file should produce errors, but none were found. Output:")
+ log(output)
+ return False
+
+ filename = "tools/gcmole/test-expectations.txt"
+ with open(filename) as exp_file:
+ expectations = exp_file.read()
+
+ if output != expectations:
+ log("** Output mismatch from running tests. Please run them manually.")
+
+ for line in difflib.unified_diff(
+ expectations.splitlines(),
+ output.splitlines(),
+ fromfile=filename,
+ tofile="output",
+ lineterm="",
+ ):
+ log("{}", line)
+
+ log("------")
+ log("--- Full output ---")
+ log(output)
+ log("------")
+
+ return False
+
+ log("** Tests ran successfully")
+ return True
+
+
+def main(args):
+ DIR = os.path.dirname(args[0])
+
+ clang_bin_dir = os.getenv("CLANG_BIN")
+ clang_plugins_dir = os.getenv("CLANG_PLUGINS")
+
+ if not clang_bin_dir or clang_bin_dir == "":
+ fatal("CLANG_BIN not set")
+
+ if not clang_plugins_dir or clang_plugins_dir == "":
+ clang_plugins_dir = DIR
+
+ flags = {
+ #: not build gcsuspects file and reuse previously generated one.
+ "reuse_gcsuspects": False,
+ #:n't use parallel python runner.
+ "sequential": False,
+ # Print commands to console before executing them.
+ "verbose": True,
+ # Perform dead variable analysis.
+ "dead_vars": True,
+ # Enable verbose tracing from the plugin itself.
+ "verbose_trace": False,
+ # When building gcsuspects allowlist certain functions as if they can be
+ # causing GC. Currently used to reduce number of false positives in dead
+ # variables analysis. See TODO for ALLOWLIST
+ "allowlist": True,
+ }
+ pos_args = []
+
+ flag_regexp = re.compile("^--(no[-_]?)?([\w\-_]+)$")
+ for arg in args[1:]:
+ m = flag_regexp.match(arg)
+ if m:
+ no, flag = m.groups()
+ flag = flag.replace("-", "_")
+ if flag in flags:
+ flags[flag] = no is None
+ else:
+ fatal("Unknown flag: {}", flag)
+ else:
+ pos_args.append(arg)
+
+ archs = pos_args if len(pos_args) > 0 else ["ia32", "arm", "x64", "arm64"]
+
+ any_errors_found = False
+ if not TestRun(flags, clang_bin_dir, clang_plugins_dir):
+ any_errors_found = True
+ else:
+ for arch in archs:
+ if not ARCHITECTURES[arch]:
+ fatal("Unknown arch: {}", arch)
+
+ errors_found, output = CheckCorrectnessForArch(arch, False, flags,
+ clang_bin_dir,
+ clang_plugins_dir)
+ any_errors_found = any_errors_found or errors_found
+
+ sys.exit(1 if any_errors_found else 0)
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/deps/v8/tools/gcmole/package.sh b/deps/v8/tools/gcmole/package.sh
index 6206e7bb2e..7178de5c11 100755
--- a/deps/v8/tools/gcmole/package.sh
+++ b/deps/v8/tools/gcmole/package.sh
@@ -10,14 +10,22 @@
THIS_DIR="$(readlink -f "$(dirname "${0}")")"
-PACKAGE_DIR="${THIS_DIR}/../../tools/gcmole/gcmole-tools"
-PACKAGE_FILE="${THIS_DIR}/../../tools/gcmole/gcmole-tools.tar.gz"
-PACKAGE_SUM="${THIS_DIR}/../../tools/gcmole/gcmole-tools.tar.gz.sha1"
-BUILD_DIR="${THIS_DIR}/../../third_party/llvm+clang-build"
+PACKAGE_DIR="${THIS_DIR}/gcmole-tools"
+PACKAGE_FILE="${THIS_DIR}/gcmole-tools.tar.gz"
+PACKAGE_SUM="${THIS_DIR}/gcmole-tools.tar.gz.sha1"
+BUILD_DIR="${THIS_DIR}/bootstrap/build"
# Echo all commands
set -x
+# Clean out any old files
+if [ -e "${PACKAGE_DIR:?}/bin" ] ; then
+ rm -rf "${PACKAGE_DIR:?}/bin"
+fi
+if [ -e "${PACKAGE_DIR:?}/lib" ] ; then
+ rm -rf "${PACKAGE_DIR:?}/lib"
+fi
+
# Copy all required files
mkdir -p "${PACKAGE_DIR}/bin"
cp "${BUILD_DIR}/bin/clang++" "${PACKAGE_DIR}/bin"
@@ -39,7 +47,22 @@ echo You can find a packaged version of gcmole here:
echo
echo $(readlink -f "${PACKAGE_FILE}")
echo
+echo Upload the update package to the chrome infra:
+echo
+echo 'gsutil.py cp tools/gcmole/gcmole-tools.tar.gz gs://chrome-v8-gcmole/$(cat tools/gcmole/gcmole-tools.tar.gz.sha1)'
+echo
+echo Run bootstrap.sh in chroot if glibc versions mismatch with bots:
+echo '# Create chroot'
+echo 'mkdir -p $CHROOT_DIR'
+echo 'sudo debootstrap $DEBIAN_VERSION $CHROOT_DIR'
+echo 'sudo chroot $CHROOT_DIR apt install g++ cmake python git'
+echo '# Mount ./depot_tools and ./v8 dirs in the chroot:'
+echo 'sudo chroot $CHROOT_DIR mkdir /docs'
+echo 'sudo mount --bind /path/to/workspace /docs'
+echo '# Build gcmole'
+echo "sudo chroot \$CHROOT_DIR bash -c 'PATH=/docs/depot_tools:\$PATH; /docs/v8/v8/tools/gcmole/bootstrap.sh'"
+echo
echo You can now run gcmole using this command:
echo
-echo CLANG_BIN="tools/gcmole/gcmole-tools/bin" lua tools/gcmole/gcmole.lua
+echo CLANG_BIN=\"tools/gcmole/gcmole-tools/bin\" python tools/gcmole/gcmole.py
echo
diff --git a/deps/v8/tools/gcmole/parallel.py b/deps/v8/tools/gcmole/parallel.py
deleted file mode 100755
index 7ff95ccadc..0000000000
--- a/deps/v8/tools/gcmole/parallel.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""
-This script calls the first argument for each of the following arguments in
-parallel. E.g.
-parallel.py "clang --opt" file1 file2
-calls
-clang --opt file1
-clang --opt file2
-
-The output (stdout and stderr) is concatenated sequentially in the form:
-______________ file1
-<output of clang --opt file1>
-______________ finish <exit code of clang --opt file1> ______________
-______________ file2
-<output of clang --opt file2>
-______________ finish <exit code of clang --opt file2> ______________
-"""
-
-# for py2/py3 compatibility
-from __future__ import print_function
-
-import itertools
-import multiprocessing
-import subprocess
-import sys
-
-def invoke(cmdline):
- try:
- return (subprocess.check_output(
- cmdline, shell=True, stderr=subprocess.STDOUT), 0)
- except subprocess.CalledProcessError as e:
- return (e.output, e.returncode)
-
-if __name__ == '__main__':
- assert len(sys.argv) > 2
- processes = multiprocessing.cpu_count()
- pool = multiprocessing.Pool(processes=processes)
- cmdlines = ["%s %s" % (sys.argv[1], filename) for filename in sys.argv[2:]]
- for filename, result in itertools.izip(
- sys.argv[2:], pool.imap(invoke, cmdlines)):
- print("______________ %s" % filename)
- print(result[0])
- print("______________ finish %d ______________" % result[1])
diff --git a/deps/v8/tools/gcmole/run-gcmole.py b/deps/v8/tools/gcmole/run-gcmole.py
index 02174b218a..cfcb2dd410 100755
--- a/deps/v8/tools/gcmole/run-gcmole.py
+++ b/deps/v8/tools/gcmole/run-gcmole.py
@@ -15,19 +15,18 @@ import sys
GCMOLE_PATH = os.path.dirname(os.path.abspath(__file__))
CLANG_BIN = os.path.join(GCMOLE_PATH, 'gcmole-tools', 'bin')
CLANG_PLUGINS = os.path.join(GCMOLE_PATH, 'gcmole-tools')
-LUA = os.path.join(GCMOLE_PATH, 'gcmole-tools', 'lua52')
-DRIVER = os.path.join(GCMOLE_PATH, 'gcmole.lua')
+DRIVER = os.path.join(GCMOLE_PATH, 'gcmole.py')
BASE_PATH = os.path.dirname(os.path.dirname(GCMOLE_PATH))
-assert len(sys.argv) == 2
+assert len(sys.argv) >= 2
if not os.path.isfile("out/build/gen/torque-generated/builtin-definitions.h"):
print("Expected generated headers in out/build/gen.")
- print("Either build v8 in out/build or change gcmole.lua:115")
+ print("Either build v8 in out/build or change the 'out/build/gen' location in gcmole.py")
sys.exit(-1)
proc = subprocess.Popen(
- [LUA, DRIVER, sys.argv[1]],
+ [sys.executable, DRIVER] + sys.argv[1:],
env={'CLANG_BIN': CLANG_BIN, 'CLANG_PLUGINS': CLANG_PLUGINS},
cwd=BASE_PATH,
)
diff --git a/deps/v8/tools/gcmole/test-expectations.txt b/deps/v8/tools/gcmole/test-expectations.txt
index f6c04e4a6c..92256b3e18 100644
--- a/deps/v8/tools/gcmole/test-expectations.txt
+++ b/deps/v8/tools/gcmole/test-expectations.txt
@@ -1,38 +1,73 @@
-
-tools/gcmole/gcmole-test.cc:27:10: warning: Possibly dead variable.
+tools/gcmole/gcmole-test.cc:30:10: warning: Possibly dead variable.
return obj;
^
-tools/gcmole/gcmole-test.cc:45:3: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:48:3: warning: Possible problem with evaluation order.
TwoArgumentsFunction(*CauseGC(obj1, isolate), *CauseGC(obj2, isolate));
^
-tools/gcmole/gcmole-test.cc:57:3: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:60:3: warning: Possible problem with evaluation order.
TwoSizeTArgumentsFunction(sizeof(*CauseGC(obj1, isolate)),
^
-tools/gcmole/gcmole-test.cc:82:7: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:85:7: warning: Possible problem with evaluation order.
so->Method(*CauseGC(obj1, isolate));
^
-tools/gcmole/gcmole-test.cc:84:7: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:87:7: warning: Possible problem with evaluation order.
so->Method(CauseGCRaw(*obj1, isolate));
^
-tools/gcmole/gcmole-test.cc:128:14: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:131:14: warning: Possible problem with evaluation order.
so_handle->Method(*derived.VirtualCauseGC(obj1, isolate));
^
-tools/gcmole/gcmole-test.cc:130:14: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:133:14: warning: Possible problem with evaluation order.
so_handle->Method(*base->VirtualCauseGC(obj1, isolate));
^
-tools/gcmole/gcmole-test.cc:151:14: warning: Possible problem with evaluation order.
+tools/gcmole/gcmole-test.cc:154:14: warning: Possible problem with evaluation order.
so_handle->Method(*SomeClass::StaticCauseGC(obj1, isolate));
^
-tools/gcmole/gcmole-test.cc:161:3: warning: Possibly dead variable.
+tools/gcmole/gcmole-test.cc:164:3: warning: Possibly dead variable.
raw_obj.Print();
^
-tools/gcmole/gcmole-test.cc:193:3: warning: Possibly dead variable.
+tools/gcmole/gcmole-test.cc:172:3: warning: Possibly dead variable.
raw_obj.Print();
^
-tools/gcmole/gcmole-test.cc:216:3: warning: Possibly dead variable.
+tools/gcmole/gcmole-test.cc:198:3: warning: Possibly dead variable.
raw_obj.Print();
^
-tools/gcmole/gcmole-test.cc:229:3: warning: Possibly dead variable.
+tools/gcmole/gcmole-test.cc:224:3: warning: Possibly dead variable.
raw_obj.Print();
^
-12 warnings generated.
+tools/gcmole/gcmole-test.cc:235:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:242:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:252:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:262:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:265:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:271:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:287:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:295:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:302:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:319:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:338:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+tools/gcmole/gcmole-test.cc:349:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+24 warnings generated.
diff --git a/deps/v8/tools/heap-stats/categories.js b/deps/v8/tools/heap-stats/categories.js
index 2bd08fad02..d3aa8480dc 100644
--- a/deps/v8/tools/heap-stats/categories.js
+++ b/deps/v8/tools/heap-stats/categories.js
@@ -94,8 +94,6 @@ export const CATEGORIES = new Map([
'SYMBOL_TYPE',
'THIN_ONE_BYTE_STRING_TYPE',
'THIN_STRING_TYPE',
- 'UNCACHED_EXTERNAL_INTERNALIZED_STRING_TYPE',
- 'UNCACHED_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE',
'UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE',
'UNCACHED_EXTERNAL_STRING_TYPE',
'WASM_INSTANCE_OBJECT_TYPE',
diff --git a/deps/v8/tools/ic-processor-driver.mjs b/deps/v8/tools/ic-processor-driver.mjs
index ef6d83e1e4..c8042736b0 100644
--- a/deps/v8/tools/ic-processor-driver.mjs
+++ b/deps/v8/tools/ic-processor-driver.mjs
@@ -78,11 +78,7 @@ const accumulator = {
StoreInArrayLiteralIC: 0,
}
for (const ic of processor.icTimeline.all) {
- print(
- ic.type + ' (' + ic.oldState + '->' + ic.newState + ic.modifier + ') at ' +
- ic.filePosition + ' ' + ic.key +
- ' (map 0x' + ic.map.toString(16) + ')' +
- (ic.reason ? ` ${ic.reason}` : '') + ' time: ' + ic.time);
+ print(Object.values(ic));
accumulator[ic.type]++;
}
diff --git a/deps/v8/tools/logreader.mjs b/deps/v8/tools/logreader.mjs
index 1bd9a4ba02..a46c4bc87d 100644
--- a/deps/v8/tools/logreader.mjs
+++ b/deps/v8/tools/logreader.mjs
@@ -28,9 +28,13 @@
/**
* @fileoverview Log Reader is used to process log file produced by V8.
*/
-
import { CsvParser } from "./csvparser.mjs";
+
+// Parses dummy variable for readability;
+export const parseString = 'parse-string';
+export const parseVarArgs = 'parse-var-args';
+
/**
* Base class for processing log files.
*
@@ -41,206 +45,200 @@
* markers.
* @constructor
*/
-export function LogReader(dispatchTable, timedRange, pairwiseTimedRange) {
- /**
- * @type {Array.<Object>}
- */
- this.dispatchTable_ = dispatchTable;
+export class LogReader {
+ constructor (dispatchTable, timedRange, pairwiseTimedRange) {
+ /**
+ * @type {Array.<Object>}
+ */
+ this.dispatchTable_ = dispatchTable;
+
+ /**
+ * @type {boolean}
+ */
+ this.timedRange_ = timedRange;
+
+ /**
+ * @type {boolean}
+ */
+ this.pairwiseTimedRange_ = pairwiseTimedRange;
+ if (pairwiseTimedRange) {
+ this.timedRange_ = true;
+ }
+
+ /**
+ * Current line.
+ * @type {number}
+ */
+ this.lineNum_ = 0;
+
+ /**
+ * CSV lines parser.
+ * @type {CsvParser}
+ */
+ this.csvParser_ = new CsvParser();
+
+ /**
+ * Keeps track of whether we've seen a "current-time" tick yet.
+ * @type {boolean}
+ */
+ this.hasSeenTimerMarker_ = false;
+
+ /**
+ * List of log lines seen since last "current-time" tick.
+ * @type {Array.<String>}
+ */
+ this.logLinesSinceLastTimerMarker_ = [];
+ }
/**
- * @type {boolean}
+ * Used for printing error messages.
+ *
+ * @param {string} str Error message.
*/
- this.timedRange_ = timedRange;
+ printError(str) {
+ // Do nothing.
+ }
/**
- * @type {boolean}
+ * Processes a portion of V8 profiler event log.
+ *
+ * @param {string} chunk A portion of log.
*/
- this.pairwiseTimedRange_ = pairwiseTimedRange;
- if (pairwiseTimedRange) {
- this.timedRange_ = true;
+ processLogChunk(chunk) {
+ this.processLog_(chunk.split('\n'));
}
/**
- * Current line.
- * @type {number}
+ * Processes a line of V8 profiler event log.
+ *
+ * @param {string} line A line of log.
*/
- this.lineNum_ = 0;
+ processLogLine(line) {
+ if (!this.timedRange_) {
+ this.processLogLine_(line);
+ return;
+ }
+ if (line.startsWith("current-time")) {
+ if (this.hasSeenTimerMarker_) {
+ this.processLog_(this.logLinesSinceLastTimerMarker_);
+ this.logLinesSinceLastTimerMarker_ = [];
+ // In pairwise mode, a "current-time" line ends the timed range.
+ if (this.pairwiseTimedRange_) {
+ this.hasSeenTimerMarker_ = false;
+ }
+ } else {
+ this.hasSeenTimerMarker_ = true;
+ }
+ } else {
+ if (this.hasSeenTimerMarker_) {
+ this.logLinesSinceLastTimerMarker_.push(line);
+ } else if (!line.startsWith("tick")) {
+ this.processLogLine_(line);
+ }
+ }
+ }
/**
- * CSV lines parser.
- * @type {CsvParser}
+ * Processes stack record.
+ *
+ * @param {number} pc Program counter.
+ * @param {number} func JS Function.
+ * @param {Array.<string>} stack String representation of a stack.
+ * @return {Array.<number>} Processed stack.
*/
- this.csvParser_ = new CsvParser();
+ processStack(pc, func, stack) {
+ const fullStack = func ? [pc, func] : [pc];
+ let prevFrame = pc;
+ for (let i = 0, n = stack.length; i < n; ++i) {
+ const frame = stack[i];
+ const firstChar = frame.charAt(0);
+ if (firstChar == '+' || firstChar == '-') {
+ // An offset from the previous frame.
+ prevFrame += parseInt(frame, 16);
+ fullStack.push(prevFrame);
+ // Filter out possible 'overflow' string.
+ } else if (firstChar != 'o') {
+ fullStack.push(parseInt(frame, 16));
+ } else {
+ this.printError(`dropping: ${frame}`);
+ }
+ }
+ return fullStack;
+ }
/**
- * Keeps track of whether we've seen a "current-time" tick yet.
- * @type {boolean}
+ * Returns whether a particular dispatch must be skipped.
+ *
+ * @param {!Object} dispatch Dispatch record.
+ * @return {boolean} True if dispatch must be skipped.
*/
- this.hasSeenTimerMarker_ = false;
+ skipDispatch(dispatch) {
+ return false;
+ }
/**
- * List of log lines seen since last "current-time" tick.
- * @type {Array.<String>}
+ * Does a dispatch of a log record.
+ *
+ * @param {Array.<string>} fields Log record.
+ * @private
*/
- this.logLinesSinceLastTimerMarker_ = [];
-};
-
-
-/**
- * Used for printing error messages.
- *
- * @param {string} str Error message.
- */
-LogReader.prototype.printError = function(str) {
- // Do nothing.
-};
-
-
-/**
- * Processes a portion of V8 profiler event log.
- *
- * @param {string} chunk A portion of log.
- */
-LogReader.prototype.processLogChunk = function(chunk) {
- this.processLog_(chunk.split('\n'));
-};
-
-
-/**
- * Processes a line of V8 profiler event log.
- *
- * @param {string} line A line of log.
- */
-LogReader.prototype.processLogLine = function(line) {
- if (!this.timedRange_) {
- this.processLogLine_(line);
- return;
- }
- if (line.startsWith("current-time")) {
- if (this.hasSeenTimerMarker_) {
- this.processLog_(this.logLinesSinceLastTimerMarker_);
- this.logLinesSinceLastTimerMarker_ = [];
- // In pairwise mode, a "current-time" line ends the timed range.
- if (this.pairwiseTimedRange_) {
- this.hasSeenTimerMarker_ = false;
- }
- } else {
- this.hasSeenTimerMarker_ = true;
+ dispatchLogRow_(fields) {
+ // Obtain the dispatch.
+ const command = fields[0];
+ const dispatch = this.dispatchTable_[command];
+ if (dispatch === undefined) return;
+ if (dispatch === null || this.skipDispatch(dispatch)) {
+ return;
}
- } else {
- if (this.hasSeenTimerMarker_) {
- this.logLinesSinceLastTimerMarker_.push(line);
- } else if (!line.startsWith("tick")) {
- this.processLogLine_(line);
- }
- }
-};
-
-/**
- * Processes stack record.
- *
- * @param {number} pc Program counter.
- * @param {number} func JS Function.
- * @param {Array.<string>} stack String representation of a stack.
- * @return {Array.<number>} Processed stack.
- */
-LogReader.prototype.processStack = function(pc, func, stack) {
- const fullStack = func ? [pc, func] : [pc];
- let prevFrame = pc;
- for (let i = 0, n = stack.length; i < n; ++i) {
- const frame = stack[i];
- const firstChar = frame.charAt(0);
- if (firstChar == '+' || firstChar == '-') {
- // An offset from the previous frame.
- prevFrame += parseInt(frame, 16);
- fullStack.push(prevFrame);
- // Filter out possible 'overflow' string.
- } else if (firstChar != 'o') {
- fullStack.push(parseInt(frame, 16));
- } else {
- this.printError(`dropping: ${frame}`);
+ // Parse fields.
+ const parsedFields = [];
+ for (let i = 0; i < dispatch.parsers.length; ++i) {
+ const parser = dispatch.parsers[i];
+ if (parser === parseString) {
+ parsedFields.push(fields[1 + i]);
+ } else if (typeof parser == 'function') {
+ parsedFields.push(parser(fields[1 + i]));
+ } else if (parser === parseVarArgs) {
+ // var-args
+ parsedFields.push(fields.slice(1 + i));
+ break;
+ } else {
+ throw new Error(`Invalid log field parser: ${parser}`);
+ }
}
- }
- return fullStack;
-};
-
-/**
- * Returns whether a particular dispatch must be skipped.
- *
- * @param {!Object} dispatch Dispatch record.
- * @return {boolean} True if dispatch must be skipped.
- */
-LogReader.prototype.skipDispatch = dispatch => false;
-
-// Parses dummy variable for readability;
-export const parseString = 'parse-string';
-export const parseVarArgs = 'parse-var-args';
-
-/**
- * Does a dispatch of a log record.
- *
- * @param {Array.<string>} fields Log record.
- * @private
- */
-LogReader.prototype.dispatchLogRow_ = function(fields) {
- // Obtain the dispatch.
- const command = fields[0];
- const dispatch = this.dispatchTable_[command];
- if (dispatch === undefined) return;
- if (dispatch === null || this.skipDispatch(dispatch)) {
- return;
+ // Run the processor.
+ dispatch.processor.apply(this, parsedFields);
}
- // Parse fields.
- const parsedFields = [];
- for (let i = 0; i < dispatch.parsers.length; ++i) {
- const parser = dispatch.parsers[i];
- if (parser === parseString) {
- parsedFields.push(fields[1 + i]);
- } else if (typeof parser == 'function') {
- parsedFields.push(parser(fields[1 + i]));
- } else if (parser === parseVarArgs) {
- // var-args
- parsedFields.push(fields.slice(1 + i));
- break;
- } else {
- throw new Error(`Invalid log field parser: ${parser}`);
+ /**
+ * Processes log lines.
+ *
+ * @param {Array.<string>} lines Log lines.
+ * @private
+ */
+ processLog_(lines) {
+ for (let i = 0, n = lines.length; i < n; ++i) {
+ this.processLogLine_(lines[i]);
}
}
- // Run the processor.
- dispatch.processor.apply(this, parsedFields);
-};
-
-
-/**
- * Processes log lines.
- *
- * @param {Array.<string>} lines Log lines.
- * @private
- */
-LogReader.prototype.processLog_ = function(lines) {
- for (let i = 0, n = lines.length; i < n; ++i) {
- this.processLogLine_(lines[i]);
- }
-}
-
-/**
- * Processes a single log line.
- *
- * @param {String} a log line
- * @private
- */
-LogReader.prototype.processLogLine_ = function(line) {
- if (line.length > 0) {
- try {
- const fields = this.csvParser_.parseLine(line);
- this.dispatchLogRow_(fields);
- } catch (e) {
- this.printError(`line ${this.lineNum_ + 1}: ${e.message || e}\n${e.stack}`);
+ /**
+ * Processes a single log line.
+ *
+ * @param {String} a log line
+ * @private
+ */
+ processLogLine_(line) {
+ if (line.length > 0) {
+ try {
+ const fields = this.csvParser_.parseLine(line);
+ this.dispatchLogRow_(fields);
+ } catch (e) {
+ this.printError(`line ${this.lineNum_ + 1}: ${e.message || e}\n${e.stack}`);
+ }
}
+ this.lineNum_++;
}
- this.lineNum_++;
-};
+}
diff --git a/deps/v8/tools/memory/asan/blacklist_win.txt b/deps/v8/tools/memory/asan/blacklist_win.txt
deleted file mode 100644
index 2bb1aa9714..0000000000
--- a/deps/v8/tools/memory/asan/blacklist_win.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# The rules in this file are only applied at compile time. If you can modify the
-# source in question, consider function attributes to disable instrumentation.
-#
-# Please think twice before you add or remove these rules. \ No newline at end of file
diff --git a/deps/v8/tools/memory/asan/blacklist.txt b/deps/v8/tools/memory/asan/blocklist_win.txt
index 2bb1aa9714..2bb1aa9714 100644
--- a/deps/v8/tools/memory/asan/blacklist.txt
+++ b/deps/v8/tools/memory/asan/blocklist_win.txt
diff --git a/deps/v8/tools/parse-processor.mjs b/deps/v8/tools/parse-processor.mjs
index f78c4c0261..debde68665 100644
--- a/deps/v8/tools/parse-processor.mjs
+++ b/deps/v8/tools/parse-processor.mjs
@@ -40,7 +40,7 @@ function BYTES(bytes, total) {
unitIndex++;
}
let result = formatNumber(value).padStart(10) + ' ' + units[unitIndex];
- if (total !== void 0 && total != 0) {
+ if (total !== undefined && total != 0) {
result += PERCENT(bytes, total).padStart(5);
}
return result;
@@ -161,7 +161,7 @@ class CompilationUnit {
class Script extends CompilationUnit {
constructor(id) {
super();
- if (id === void 0 || id <= 0) {
+ if (id === undefined || id <= 0) {
throw new Error(`Invalid id=${id} for script`);
}
this.file = '';
@@ -214,7 +214,7 @@ class Script extends CompilationUnit {
addMissingFunktions(list) {
if (this.finalized) throw 'script is finalized!';
list.forEach(fn => {
- if (this.funktions[fn.start] === void 0) {
+ if (this.funktions[fn.start] === undefined) {
this.addFunktion(fn);
}
});
@@ -222,8 +222,8 @@ class Script extends CompilationUnit {
addFunktion(fn) {
if (this.finalized) throw 'script is finalized!';
- if (fn.start === void 0) throw "Funktion has no start position";
- if (this.funktions[fn.start] !== void 0) {
+ if (fn.start === undefined) throw "Funktion has no start position";
+ if (this.funktions[fn.start] !== undefined) {
fn.print();
throw "adding same function twice to script";
}
@@ -441,7 +441,7 @@ class Script extends CompilationUnit {
for (let i = 1; i < metricProperties.length; i += kMetricIncrement) {
let timestampPropertyName = metricProperties[i];
let timestamp = funktionOrScript[timestampPropertyName];
- if (timestamp === void 0) continue;
+ if (timestamp === undefined) continue;
if (timestamp < start || end < timestamp) continue;
timestamp -= start;
let index = Math.floor(timestamp / delta);
@@ -906,7 +906,7 @@ export class ParseProcessor extends LogReader {
}
let script = this.lookupScript(scriptId);
let funktion = script.getFunktionAtStartPosition(startPosition);
- if (funktion === void 0) {
+ if (funktion === undefined) {
funktion = new Funktion(functionName, startPosition, endPosition, script);
}
return funktion;
diff --git a/deps/v8/tools/profile.mjs b/deps/v8/tools/profile.mjs
index b2e953f247..f443740324 100644
--- a/deps/v8/tools/profile.mjs
+++ b/deps/v8/tools/profile.mjs
@@ -28,6 +28,7 @@
import { CodeMap, CodeEntry } from "./codemap.mjs";
import { ConsArray } from "./consarray.mjs";
+// Used to associate log entries with source positions in scripts.
// TODO: move to separate modules
export class SourcePosition {
constructor(script, line, column) {
@@ -36,19 +37,43 @@ export class SourcePosition {
this.column = column;
this.entries = [];
}
+
addEntry(entry) {
this.entries.push(entry);
}
+
+ toString() {
+ return `${this.script.name}:${this.line}:${this.column}`;
+ }
+
+ toStringLong() {
+ return this.toString();
+ }
}
export class Script {
- constructor(id, name, source) {
+ name;
+ source;
+ // Map<line, Map<column, SourcePosition>>
+ lineToColumn = new Map();
+ _entries = [];
+
+ constructor(id) {
this.id = id;
+ this.sourcePositions = [];
+ }
+
+ update(name, source) {
this.name = name;
this.source = source;
- this.sourcePositions = [];
- // Map<line, Map<column, SourcePosition>>
- this.lineToColumn = new Map();
+ }
+
+ get length() {
+ return this.source.length;
+ }
+
+ get entries() {
+ return this._entries;
}
addSourcePosition(line, column, entry) {
@@ -58,6 +83,7 @@ export class Script {
this._addSourcePosition(line, column, sourcePosition);
}
sourcePosition.addEntry(entry);
+ this._entries.push(entry);
return sourcePosition;
}
@@ -72,6 +98,42 @@ export class Script {
this.sourcePositions.push(sourcePosition);
columnToSourcePosition.set(column, sourcePosition);
}
+
+ toString() {
+ return `Script(${this.id}): ${this.name}`;
+ }
+
+ toStringLong() {
+ return this.source;
+ }
+}
+
+
+class SourceInfo {
+ script;
+ start;
+ end;
+ positions;
+ inlined ;
+ fns;
+ disassemble;
+
+ setSourcePositionInfo(script, startPos, endPos, sourcePositionTable, inliningPositions, inlinedFunctions) {
+ this.script = script;
+ this.start = startPos;
+ this.end = endPos;
+ this.positions = sourcePositionTable;
+ this.inlined = inliningPositions;
+ this.fns = inlinedFunctions;
+ }
+
+ setDisassemble(code) {
+ this.disassemble = code;
+ }
+
+ getSourceCode() {
+ return this.script.source?.substring(this.start, this.end);
+ }
}
/**
@@ -118,8 +180,44 @@ export class Profile {
*/
static CodeState = {
COMPILED: 0,
- OPTIMIZABLE: 1,
- OPTIMIZED: 2
+ IGNITION: 1,
+ NATIVE_CONTEXT_INDEPENDENT: 2,
+ TURBOPROP: 3,
+ TURBOFAN: 4,
+ }
+
+ /**
+ * Parser for dynamic code optimization state.
+ */
+ static parseState(s) {
+ switch (s) {
+ case '':
+ return this.CodeState.COMPILED;
+ case '~':
+ return this.CodeState.IGNITION;
+ case '-':
+ return this.CodeState.NATIVE_CONTEXT_INDEPENDENT;
+ case '+':
+ return this.CodeState.TURBOPROP;
+ case '*':
+ return this.CodeState.TURBOFAN;
+ }
+ throw new Error(`unknown code state: ${s}`);
+ }
+
+ static getKindFromState(state) {
+ if (state === this.CodeState.COMPILED) {
+ return "Builtin";
+ } else if (state === this.CodeState.IGNITION) {
+ return "Unopt";
+ } else if (state === this.CodeState.NATIVE_CONTEXT_INDEPENDENT) {
+ return "NCI";
+ } else if (state === this.CodeState.TURBOPROP) {
+ return "Turboprop";
+ } else if (state === this.CodeState.TURBOFAN) {
+ return "Opt";
+ }
+ throw new Error(`unknown code state: ${state}`);
}
/**
@@ -228,7 +326,7 @@ export class Profile {
}
}
- deoptCode( timestamp, code, inliningId, scriptOffset, bailoutType,
+ deoptCode(timestamp, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) {
}
@@ -248,23 +346,59 @@ export class Profile {
/**
* Adds source positions for given code.
*/
- addSourcePositions(start, script, startPos, endPos, sourcePositions,
+ addSourcePositions(start, scriptId, startPos, endPos, sourcePositionTable,
inliningPositions, inlinedFunctions) {
- // CLI does not need source code => ignore.
+ const script = this.getOrCreateScript(scriptId);
+ const entry = this.codeMap_.findDynamicEntryByStartAddress(start);
+ if (!entry) return;
+ // Resolve the inlined functions list.
+ if (inlinedFunctions.length > 0) {
+ inlinedFunctions = inlinedFunctions.substring(1).split("S");
+ for (let i = 0; i < inlinedFunctions.length; i++) {
+ const funcAddr = parseInt(inlinedFunctions[i]);
+ const func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
+ if (!func || func.funcId === undefined) {
+ // TODO: fix
+ console.warn(`Could not find function ${inlinedFunctions[i]}`);
+ inlinedFunctions[i] = null;
+ } else {
+ inlinedFunctions[i] = func.funcId;
+ }
+ }
+ } else {
+ inlinedFunctions = [];
+ }
+
+ this.getOrCreateSourceInfo(entry).setSourcePositionInfo(
+ script, startPos, endPos, sourcePositionTable, inliningPositions,
+ inlinedFunctions);
+ }
+
+ addDisassemble(start, kind, disassemble) {
+ const entry = this.codeMap_.findDynamicEntryByStartAddress(start);
+ if (!entry) return;
+ this.getOrCreateSourceInfo(entry).setDisassemble(disassemble);
+ }
+
+ getOrCreateSourceInfo(entry) {
+ return entry.source ?? (entry.source = new SourceInfo());
}
- /**
- * Adds script source code.
- */
addScriptSource(id, url, source) {
- const script = new Script(id, url, source);
- this.scripts_[id] = script;
+ const script = this.getOrCreateScript(id);
+ script.update(url, source);
this.urlToScript_.set(url, script);
}
- /**
- * Adds script source code.
- */
+ getOrCreateScript(id) {
+ let script = this.scripts_[id];
+ if (!script) {
+ script = new Script(id);
+ this.scripts_[id] = script;
+ }
+ return script;
+ }
+
getScript(url) {
return this.urlToScript_.get(url);
}
@@ -547,10 +681,19 @@ class DynamicFuncCodeEntry extends CodeEntry {
constructor(size, type, func, state) {
super(size, '', type);
this.func = func;
+ func.addDynamicCode(this);
this.state = state;
}
- static STATE_PREFIX = ["", "~", "*"];
+ get functionName() {
+ return this.func.functionName;
+ }
+
+ getSourceCode() {
+ return this.source?.getSourceCode();
+ }
+
+ static STATE_PREFIX = ["", "~", "-", "+", "*"];
getState() {
return DynamicFuncCodeEntry.STATE_PREFIX[this.state];
}
@@ -583,8 +726,26 @@ class DynamicFuncCodeEntry extends CodeEntry {
* @constructor
*/
class FunctionEntry extends CodeEntry {
+
+ // Contains the list of generated code for this function.
+ _codeEntries = new Set();
+
constructor(name) {
super(0, name);
+ const index = name.lastIndexOf(' ');
+ this.functionName = 1 <= index ? name.substring(0, index) : '<anonymous>';
+ }
+
+ addDynamicCode(code) {
+ if (code.func != this) {
+ throw new Error("Adding dynamic code to wrong function");
+ }
+ this._codeEntries.add(code);
+ }
+
+ getSourceCode() {
+ // All code entries should map to the same source positions.
+ return this._codeEntries.values().next().value.getSourceCode();
}
/**
@@ -593,10 +754,10 @@ class FunctionEntry extends CodeEntry {
getName() {
let name = this.name;
if (name.length == 0) {
- name = '<anonymous>';
+ return '<anonymous>';
} else if (name.charAt(0) == ' ') {
// An anonymous function with location: " aaa.js:10".
- name = `<anonymous>${name}`;
+ return `<anonymous>${name}`;
}
return name;
}
@@ -947,13 +1108,7 @@ JsonProfile.prototype.addFuncCode = function (
this.functionEntries_[func.funcId].codes.push(entry.codeId);
- if (state === 0) {
- kind = "Builtin";
- } else if (state === 1) {
- kind = "Unopt";
- } else if (state === 2) {
- kind = "Opt";
- }
+ kind = Profile.getKindFromState(state);
this.codeEntries_.push({
name: entry.name,
diff --git a/deps/v8/tools/profview/index.html b/deps/v8/tools/profview/index.html
index 8695a41e3a..64f4e512c3 100644
--- a/deps/v8/tools/profview/index.html
+++ b/deps/v8/tools/profview/index.html
@@ -47,6 +47,25 @@ found in the LICENSE file. -->
To view the profile, click the <i>Choose file</i> button above and choose
the file in the dialog box.
+ <br>
+ <br>
+ For recording a profile from Chrome use:
+ <pre>
+ --no-sandbox --js-flags=--prof
+ </pre>
+
+ If running on Android use also use --single-process:
+ <pre>
+ --single-process --no-sandbox --js-flags=--prof
+ </pre>
+
+ If the profile is from Android pass the unstripped Chrome library to
+ resolve C++ symbols when processing the file using linux-tick-processor.
+ <pre>
+ &lt;v8-dir>/tools/linux-tick-processor --preprocess --apk-embedded-library=./out/Release/lib.unstripped/libchrome.so v8.log > v8.json
+ </pre>
+
+ More detailed instructions for Android here: https://v8.dev/docs/profile-chromium#android
</div>
<div id="timeline" style="display : none">
@@ -112,7 +131,7 @@ found in the LICENSE file. -->
<br>
<br>
<br>
-Copyright the V8 Authors - Last change to this page: 2018/08/13
+Copyright the V8 Authors - Last change to this page: 2020/12/04
</p>
</body>
diff --git a/deps/v8/tools/profview/profile-utils.js b/deps/v8/tools/profview/profile-utils.js
index 4be55893dd..9007855ea9 100644
--- a/deps/v8/tools/profview/profile-utils.js
+++ b/deps/v8/tools/profview/profile-utils.js
@@ -19,7 +19,9 @@ let codeKinds = [
"BUILTIN",
"REGEXP",
"JSOPT",
- "JSUNOPT"
+ "JSUNOPT",
+ "JSNCI",
+ "JSTURBOPROP"
];
function resolveCodeKind(code) {
@@ -55,6 +57,10 @@ function resolveCodeKind(code) {
return "JSOPT";
} else if (code.kind === "Unopt") {
return "JSUNOPT";
+ } else if (code.kind === "NCI") {
+ return "JSNCI";
+ } else if (code.kind === "Turboprop") {
+ return "JSTURBOPROP";
}
}
console.log("Unknown code type '" + type + "'.");
@@ -264,6 +270,8 @@ function buildCategoryTreeAndLookup() {
root.children.push(n);
}
addCategory("JS Optimized", [ "JSOPT" ]);
+ addCategory("JS NCI", [ "JSNCI" ]);
+ addCategory("JS Turboprop", [ "JSTURBOPROP" ]);
addCategory("JS Unoptimized", [ "JSUNOPT", "BC" ]);
addCategory("IC", [ "IC" ]);
addCategory("RegExp", [ "REGEXP" ]);
@@ -526,11 +534,15 @@ function computeOptimizationStats(file,
let functionCount = 0;
let optimizedFunctionCount = 0;
+ let turbopropOptimizedFunctionCount = 0;
let deoptimizedFunctionCount = 0;
let optimizations = newCollection();
+ let turbopropOptimizations = newCollection();
let eagerDeoptimizations = newCollection();
let softDeoptimizations = newCollection();
let lazyDeoptimizations = newCollection();
+ let softBailouts = newCollection();
+ let eagerBailouts = newCollection();
for (let i = 0; i < file.functions.length; i++) {
let f = file.functions[i];
@@ -541,6 +553,7 @@ function computeOptimizationStats(file,
functionCount++;
let optimized = false;
+ let turboprop_optimized = false;
let deoptimized = false;
for (let j = 0; j < f.codes.length; j++) {
@@ -552,19 +565,33 @@ function computeOptimizationStats(file,
addToCollection(optimizations, code);
}
}
+ if (code.kind === "Turboprop") {
+ turboprop_optimized = true;
+ if (code.tm >= timeStart && code.tm <= timeEnd) {
+ addToCollection(turbopropOptimizations, code);
+ }
+ }
if (code.deopt) {
- deoptimized = true;
+ if (code.deopt.bailoutType === "deopt-lazy" || code.deopt.bailoutType === "deopt-eager" || code.deopt.bailoutType === "deopt-lazy") {
+ deoptimized = true;
+ }
if (code.deopt.tm >= timeStart && code.deopt.tm <= timeEnd) {
switch (code.deopt.bailoutType) {
- case "lazy":
+ case "deopt-lazy":
addToCollection(lazyDeoptimizations, code);
break;
- case "eager":
+ case "deopt-eager":
addToCollection(eagerDeoptimizations, code);
break;
- case "soft":
+ case "deopt-soft":
addToCollection(softDeoptimizations, code);
break;
+ case "bailout-soft":
+ addToCollection(softBailouts, code);
+ break;
+ case "bailout":
+ addToCollection(eagerBailouts, code);
+ break;
}
}
}
@@ -572,6 +599,9 @@ function computeOptimizationStats(file,
if (optimized) {
optimizedFunctionCount++;
}
+ if (turboprop_optimized) {
+ turbopropOptimizedFunctionCount++;
+ }
if (deoptimized) {
deoptimizedFunctionCount++;
}
@@ -586,15 +616,20 @@ function computeOptimizationStats(file,
sortCollection(lazyDeoptimizations);
sortCollection(softDeoptimizations);
sortCollection(optimizations);
+ sortCollection(turbopropOptimizations);
return {
functionCount,
optimizedFunctionCount,
+ turbopropOptimizedFunctionCount,
deoptimizedFunctionCount,
optimizations,
+ turbopropOptimizations,
eagerDeoptimizations,
lazyDeoptimizations,
softDeoptimizations,
+ softBailouts,
+ eagerBailouts,
};
}
diff --git a/deps/v8/tools/profview/profview.js b/deps/v8/tools/profview/profview.js
index 210cec7618..248146f99f 100644
--- a/deps/v8/tools/profview/profview.js
+++ b/deps/v8/tools/profview/profview.js
@@ -216,6 +216,14 @@ const bucketDescriptors =
color : "#64dd17",
backgroundColor : "#80e27e",
text : "JS Optimized" },
+ { kinds : [ "JSNCI" ],
+ color : "#3289a8",
+ backgroundColor : "#3289a8",
+ text : "JS NCI" },
+ { kinds : [ "JSTURBOPROP" ],
+ color : "#693eb8",
+ backgroundColor : "#a6c452",
+ text : "JS Turboprop" },
{ kinds : [ "JSUNOPT", "BC" ],
color : "#dd2c00",
backgroundColor : "#ff9e80",
@@ -308,6 +316,10 @@ function codeTypeToText(type) {
return "RegExp";
case "JSOPT":
return "JS opt";
+ case "JSNCI":
+ return "JS NCI";
+ case "JSTURBOPROP":
+ return "JS Turboprop";
case "JSUNOPT":
return "JS unopt";
}
@@ -1275,15 +1287,27 @@ class SummaryView {
addRow("Total function count:", stats.functionCount);
addRow("Optimized function count:", stats.optimizedFunctionCount, 1);
+ if (stats.turbopropOptimizedFunctionCount != 0) {
+ addRow("Turboprop optimized function count:", stats.turbopropOptimizedFunctionCount, 1);
+ }
addRow("Deoptimized function count:", stats.deoptimizedFunctionCount, 2);
addExpandableRow("Optimization count:", stats.optimizations, 0, "opt");
+ if (stats.turbopropOptimizedFunctionCount != 0) {
+ addExpandableRow("Turboprop Optimization count:", stats.turbopropOptimizations, 0, "tp");
+ }
let deoptCount = stats.eagerDeoptimizations.count +
stats.softDeoptimizations.count + stats.lazyDeoptimizations.count;
addRow("Deoptimization count:", deoptCount);
addExpandableRow("Eager:", stats.eagerDeoptimizations, 1, "eager");
addExpandableRow("Lazy:", stats.lazyDeoptimizations, 1, "lazy");
addExpandableRow("Soft:", stats.softDeoptimizations, 1, "soft");
+ if (stats.softBailouts.count != 0) {
+ addExpandableRow("SoftBailout:", stats.softBailouts, 1, "softbailout");
+ }
+ if (stats.eagerBailouts.count != 0) {
+ addExpandableRow("EagerBailout:", stats.eagerBailouts, 1, "eagerbailout");
+ }
table.appendChild(rows);
this.element.appendChild(table);
@@ -1369,6 +1393,7 @@ class SourceData {
for (let i = 0; i < file.scripts.length; i++) {
const scriptBlock = file.scripts[i];
if (scriptBlock === null) continue; // Array may be sparse.
+ if (scriptBlock.source === undefined) continue;
let source = scriptBlock.source.split("\n");
this.scripts.set(i, source);
}
diff --git a/deps/v8/tools/splaytree.mjs b/deps/v8/tools/splaytree.mjs
index eaba4e4b57..d942d1f463 100644
--- a/deps/v8/tools/splaytree.mjs
+++ b/deps/v8/tools/splaytree.mjs
@@ -34,274 +34,250 @@
*
* @constructor
*/
-export function SplayTree() {
-};
-
-
-/**
- * Pointer to the root node of the tree.
- *
- * @type {SplayTree.Node}
- * @private
- */
-SplayTree.prototype.root_ = null;
-
-
-/**
- * @return {boolean} Whether the tree is empty.
- */
-SplayTree.prototype.isEmpty = function() {
- return !this.root_;
-};
-
-
-
-/**
- * Inserts a node into the tree with the specified key and value if
- * the tree does not already contain a node with the specified key. If
- * the value is inserted, it becomes the root of the tree.
- *
- * @param {number} key Key to insert into the tree.
- * @param {*} value Value to insert into the tree.
- */
-SplayTree.prototype.insert = function(key, value) {
- if (this.isEmpty()) {
- this.root_ = new SplayTree.Node(key, value);
- return;
+export class SplayTree {
+
+ /**
+ * Pointer to the root node of the tree.
+ *
+ * @type {SplayTreeNode}
+ * @private
+ */
+ root_ = null;
+
+
+ /**
+ * @return {boolean} Whether the tree is empty.
+ */
+ isEmpty() {
+ return !this.root_;
}
- // Splay on the key to move the last node on the search path for
- // the key to the root of the tree.
- this.splay_(key);
- if (this.root_.key == key) {
- return;
- }
- const node = new SplayTree.Node(key, value);
- if (key > this.root_.key) {
- node.left = this.root_;
- node.right = this.root_.right;
- this.root_.right = null;
- } else {
- node.right = this.root_;
- node.left = this.root_.left;
- this.root_.left = null;
- }
- this.root_ = node;
-};
+ /**
+ * Inserts a node into the tree with the specified key and value if
+ * the tree does not already contain a node with the specified key. If
+ * the value is inserted, it becomes the root of the tree.
+ *
+ * @param {number} key Key to insert into the tree.
+ * @param {*} value Value to insert into the tree.
+ */
+ insert(key, value) {
+ if (this.isEmpty()) {
+ this.root_ = new SplayTreeNode(key, value);
+ return;
+ }
+ // Splay on the key to move the last node on the search path for
+ // the key to the root of the tree.
+ this.splay_(key);
+ if (this.root_.key == key) return;
-/**
- * Removes a node with the specified key from the tree if the tree
- * contains a node with this key. The removed node is returned. If the
- * key is not found, an exception is thrown.
- *
- * @param {number} key Key to find and remove from the tree.
- * @return {SplayTree.Node} The removed node.
- */
-SplayTree.prototype.remove = function(key) {
- if (this.isEmpty()) {
- throw Error(`Key not found: ${key}`);
- }
- this.splay_(key);
- if (this.root_.key != key) {
- throw Error(`Key not found: ${key}`);
+ const node = new SplayTreeNode(key, value);
+ if (key > this.root_.key) {
+ node.left = this.root_;
+ node.right = this.root_.right;
+ this.root_.right = null;
+ } else {
+ node.right = this.root_;
+ node.left = this.root_.left;
+ this.root_.left = null;
+ }
+ this.root_ = node;
}
- const removed = this.root_;
- if (!this.root_.left) {
- this.root_ = this.root_.right;
- } else {
- const { right } = this.root_;
- this.root_ = this.root_.left;
- // Splay to make sure that the new root has an empty right child.
+
+ /**
+ * Removes a node with the specified key from the tree if the tree
+ * contains a node with this key. The removed node is returned. If the
+ * key is not found, an exception is thrown.
+ *
+ * @param {number} key Key to find and remove from the tree.
+ * @return {SplayTreeNode} The removed node.
+ */
+ remove(key) {
+ if (this.isEmpty()) {
+ throw Error(`Key not found: ${key}`);
+ }
this.splay_(key);
- // Insert the original right child as the right child of the new
- // root.
- this.root_.right = right;
+ if (this.root_.key != key) {
+ throw Error(`Key not found: ${key}`);
+ }
+ const removed = this.root_;
+ if (!this.root_.left) {
+ this.root_ = this.root_.right;
+ } else {
+ const { right } = this.root_;
+ this.root_ = this.root_.left;
+ // Splay to make sure that the new root has an empty right child.
+ this.splay_(key);
+ // Insert the original right child as the right child of the new
+ // root.
+ this.root_.right = right;
+ }
+ return removed;
}
- return removed;
-};
-
-/**
- * Returns the node having the specified key or null if the tree doesn't contain
- * a node with the specified key.
- *
- * @param {number} key Key to find in the tree.
- * @return {SplayTree.Node} Node having the specified key.
- */
-SplayTree.prototype.find = function(key) {
- if (this.isEmpty()) {
- return null;
+ /**
+ * Returns the node having the specified key or null if the tree doesn't contain
+ * a node with the specified key.
+ *
+ * @param {number} key Key to find in the tree.
+ * @return {SplayTreeNode} Node having the specified key.
+ */
+ find(key) {
+ if (this.isEmpty()) return null;
+ this.splay_(key);
+ return this.root_.key == key ? this.root_ : null;
}
- this.splay_(key);
- return this.root_.key == key ? this.root_ : null;
-};
-
-/**
- * @return {SplayTree.Node} Node having the minimum key value.
- */
-SplayTree.prototype.findMin = function() {
- if (this.isEmpty()) {
- return null;
- }
- let current = this.root_;
- while (current.left) {
- current = current.left;
+ /**
+ * @return {SplayTreeNode} Node having the minimum key value.
+ */
+ findMin() {
+ if (this.isEmpty()) return null;
+ let current = this.root_;
+ while (current.left) {
+ current = current.left;
+ }
+ return current;
}
- return current;
-};
-
-/**
- * @return {SplayTree.Node} Node having the maximum key value.
- */
-SplayTree.prototype.findMax = function(opt_startNode) {
- if (this.isEmpty()) {
- return null;
- }
- let current = opt_startNode || this.root_;
- while (current.right) {
- current = current.right;
+ /**
+ * @return {SplayTreeNode} Node having the maximum key value.
+ */
+ findMax(opt_startNode) {
+ if (this.isEmpty()) return null;
+ let current = opt_startNode || this.root_;
+ while (current.right) {
+ current = current.right;
+ }
+ return current;
}
- return current;
-};
-
-/**
- * @return {SplayTree.Node} Node having the maximum key value that
- * is less or equal to the specified key value.
- */
-SplayTree.prototype.findGreatestLessThan = function(key) {
- if (this.isEmpty()) {
- return null;
- }
- // Splay on the key to move the node with the given key or the last
- // node on the search path to the top of the tree.
- this.splay_(key);
- // Now the result is either the root node or the greatest node in
- // the left subtree.
- if (this.root_.key <= key) {
- return this.root_;
- } else if (this.root_.left) {
- return this.findMax(this.root_.left);
- } else {
- return null;
+ /**
+ * @return {SplayTreeNode} Node having the maximum key value that
+ * is less or equal to the specified key value.
+ */
+ findGreatestLessThan(key) {
+ if (this.isEmpty()) return null;
+ // Splay on the key to move the node with the given key or the last
+ // node on the search path to the top of the tree.
+ this.splay_(key);
+ // Now the result is either the root node or the greatest node in
+ // the left subtree.
+ if (this.root_.key <= key) {
+ return this.root_;
+ } else if (this.root_.left) {
+ return this.findMax(this.root_.left);
+ } else {
+ return null;
+ }
}
-};
-
-
-/**
- * @return {Array<*>} An array containing all the values of tree's nodes paired
- * with keys.
- */
-SplayTree.prototype.exportKeysAndValues = function() {
- const result = [];
- this.traverse_(function(node) { result.push([node.key, node.value]); });
- return result;
-};
-
-
-/**
- * @return {Array<*>} An array containing all the values of tree's nodes.
- */
-SplayTree.prototype.exportValues = function() {
- const result = [];
- this.traverse_(function(node) { result.push(node.value); });
- return result;
-};
+ /**
+ * @return {Array<*>} An array containing all the values of tree's nodes paired
+ * with keys.
+ */
+ exportKeysAndValues() {
+ const result = [];
+ this.traverse_(function(node) { result.push([node.key, node.value]); });
+ return result;
+ }
-/**
- * Perform the splay operation for the given key. Moves the node with
- * the given key to the top of the tree. If no node has the given
- * key, the last node on the search path is moved to the top of the
- * tree. This is the simplified top-down splaying algorithm from:
- * "Self-adjusting Binary Search Trees" by Sleator and Tarjan
- *
- * @param {number} key Key to splay the tree on.
- * @private
- */
-SplayTree.prototype.splay_ = function(key) {
- if (this.isEmpty()) {
- return;
+ /**
+ * @return {Array<*>} An array containing all the values of tree's nodes.
+ */
+ exportValues() {
+ const result = [];
+ this.traverse_(function(node) { result.push(node.value); });
+ return result;
}
- // Create a dummy node. The use of the dummy node is a bit
- // counter-intuitive: The right child of the dummy node will hold
- // the L tree of the algorithm. The left child of the dummy node
- // will hold the R tree of the algorithm. Using a dummy node, left
- // and right will always be nodes and we avoid special cases.
- let dummy, left, right;
- dummy = left = right = new SplayTree.Node(null, null);
- let current = this.root_;
- while (true) {
- if (key < current.key) {
- if (!current.left) {
- break;
- }
- if (key < current.left.key) {
- // Rotate right.
- const tmp = current.left;
- current.left = tmp.right;
- tmp.right = current;
- current = tmp;
+
+ /**
+ * Perform the splay operation for the given key. Moves the node with
+ * the given key to the top of the tree. If no node has the given
+ * key, the last node on the search path is moved to the top of the
+ * tree. This is the simplified top-down splaying algorithm from:
+ * "Self-adjusting Binary Search Trees" by Sleator and Tarjan
+ *
+ * @param {number} key Key to splay the tree on.
+ * @private
+ */
+ splay_(key) {
+ if (this.isEmpty()) return;
+ // Create a dummy node. The use of the dummy node is a bit
+ // counter-intuitive: The right child of the dummy node will hold
+ // the L tree of the algorithm. The left child of the dummy node
+ // will hold the R tree of the algorithm. Using a dummy node, left
+ // and right will always be nodes and we avoid special cases.
+ let dummy, left, right;
+ dummy = left = right = new SplayTreeNode(null, null);
+ let current = this.root_;
+ while (true) {
+ if (key < current.key) {
if (!current.left) {
break;
}
- }
- // Link right.
- right.left = current;
- right = current;
- current = current.left;
- } else if (key > current.key) {
- if (!current.right) {
- break;
- }
- if (key > current.right.key) {
- // Rotate left.
- const tmp = current.right;
- current.right = tmp.left;
- tmp.left = current;
- current = tmp;
+ if (key < current.left.key) {
+ // Rotate right.
+ const tmp = current.left;
+ current.left = tmp.right;
+ tmp.right = current;
+ current = tmp;
+ if (!current.left) {
+ break;
+ }
+ }
+ // Link right.
+ right.left = current;
+ right = current;
+ current = current.left;
+ } else if (key > current.key) {
if (!current.right) {
break;
}
+ if (key > current.right.key) {
+ // Rotate left.
+ const tmp = current.right;
+ current.right = tmp.left;
+ tmp.left = current;
+ current = tmp;
+ if (!current.right) {
+ break;
+ }
+ }
+ // Link left.
+ left.right = current;
+ left = current;
+ current = current.right;
+ } else {
+ break;
}
- // Link left.
- left.right = current;
- left = current;
- current = current.right;
- } else {
- break;
}
+ // Assemble.
+ left.right = current.left;
+ right.left = current.right;
+ current.left = dummy.right;
+ current.right = dummy.left;
+ this.root_ = current;
}
- // Assemble.
- left.right = current.left;
- right.left = current.right;
- current.left = dummy.right;
- current.right = dummy.left;
- this.root_ = current;
-};
-
-/**
- * Performs a preorder traversal of the tree.
- *
- * @param {function(SplayTree.Node)} f Visitor function.
- * @private
- */
-SplayTree.prototype.traverse_ = function(f) {
- const nodesToVisit = [this.root_];
- while (nodesToVisit.length > 0) {
- const node = nodesToVisit.shift();
- if (node == null) {
- continue;
+ /**
+ * Performs a preorder traversal of the tree.
+ *
+ * @param {function(SplayTreeNode)} f Visitor function.
+ * @private
+ */
+ traverse_(f) {
+ const nodesToVisit = [this.root_];
+ while (nodesToVisit.length > 0) {
+ const node = nodesToVisit.shift();
+ if (node == null) {
+ continue;
+ }
+ f(node);
+ nodesToVisit.push(node.left);
+ nodesToVisit.push(node.right);
}
- f(node);
- nodesToVisit.push(node.left);
- nodesToVisit.push(node.right);
}
-};
-
+}
/**
* Constructs a Splay tree node.
@@ -309,19 +285,17 @@ SplayTree.prototype.traverse_ = function(f) {
* @param {number} key Key.
* @param {*} value Value.
*/
-SplayTree.Node = function(key, value) {
- this.key = key;
- this.value = value;
-};
-
-
-/**
- * @type {SplayTree.Node}
- */
-SplayTree.Node.prototype.left = null;
-
-
-/**
- * @type {SplayTree.Node}
- */
-SplayTree.Node.prototype.right = null;
+class SplayTreeNode {
+ constructor(key, value) {
+ this.key = key;
+ this.value = value;
+ /**
+ * @type {SplayTreeNode}
+ */
+ this.left = null;
+ /**
+ * @type {SplayTreeNode}
+ */
+ this.right = null;
+ }
+}; \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/app-model.mjs b/deps/v8/tools/system-analyzer/app-model.mjs
index a0b176c170..5d558e248b 100644
--- a/deps/v8/tools/system-analyzer/app-model.mjs
+++ b/deps/v8/tools/system-analyzer/app-model.mjs
@@ -9,17 +9,22 @@ class State {
_selectedMapLogEntries;
_selectedIcLogEntries;
_selectedDeoptLogEntries;
+ _selecteCodeLogEntries;
_selectedSourcePositions;
_nofChunks;
_chunks;
_icTimeline;
_mapTimeline;
_deoptTimeline;
+ _codeTimeline;
+ _apiTimeline;
_minStartTime = Number.POSITIVE_INFINITY;
_maxEndTime = Number.NEGATIVE_INFINITY;
+
get minStartTime() {
return this._minStartTime;
}
+
get maxEndTime() {
return this._maxEndTime;
}
@@ -27,46 +32,68 @@ class State {
selectTimeRange(start, end) {
this.timeSelection.start = start;
this.timeSelection.end = end;
- this._icTimeline.selectTimeRange(start, end);
- this._mapTimeline.selectTimeRange(start, end);
- this._deoptTimeline.selectTimeRange(start, end);
+ if (start == 0 && end == Infinity) {
+ this.timelines.forEach(each => each.clearSelection());
+ } else {
+ this.timelines.forEach(each => each.selectTimeRange(start, end));
+ }
}
- _updateTimeRange(timeline) {
- this._minStartTime = Math.min(this._minStartTime, timeline.startTime);
- this._maxEndTime = Math.max(this._maxEndTime, timeline.endTime);
- timeline.startTime = this._minStartTime;
- timeline.endTime = this._maxEndTime;
+ setTimelines(
+ mapTimeline, icTimeline, deoptTimeline, codeTimeline, apiTimeline) {
+ this._mapTimeline = mapTimeline;
+ this._icTimeline = icTimeline;
+ this._deoptTimeline = deoptTimeline;
+ this._codeTimeline = codeTimeline;
+ this._apiTimeline = apiTimeline;
+ for (let timeline of arguments) {
+ if (timeline === undefined) return;
+ this._minStartTime = Math.min(this._minStartTime, timeline.startTime);
+ this._maxEndTime = Math.max(this._maxEndTime, timeline.endTime);
+ }
+ for (let timeline of arguments) {
+ timeline.startTime = this._minStartTime;
+ timeline.endTime = this._maxEndTime;
+ }
}
+
get mapTimeline() {
return this._mapTimeline;
}
- set mapTimeline(timeline) {
- this._updateTimeRange(timeline);
- this._mapTimeline = timeline;
- }
+
get icTimeline() {
return this._icTimeline;
}
- set icTimeline(timeline) {
- this._updateTimeRange(timeline);
- this._icTimeline = timeline;
- }
+
get deoptTimeline() {
return this._deoptTimeline;
}
- set deoptTimeline(timeline) {
- this._updateTimeRange(timeline);
- this._deoptTimeline = timeline;
+
+ get codeTimeline() {
+ return this._codeTimeline;
}
+
+ get apiTimeline() {
+ return this._apiTimeline;
+ }
+
+ get timelines() {
+ return [
+ this._mapTimeline, this._icTimeline, this._deoptTimeline,
+ this._codeTimeline, this._apiTimeline
+ ];
+ }
+
set chunks(value) {
// TODO(zcankara) split up between maps and ics, and every timeline track
this._chunks = value;
}
+
get chunks() {
// TODO(zcankara) split up between maps and ics, and every timeline track
return this._chunks;
}
+
get nofChunks() {
return this._nofChunks;
}
diff --git a/deps/v8/tools/system-analyzer/events.mjs b/deps/v8/tools/system-analyzer/events.mjs
deleted file mode 100644
index 69529233b4..0000000000
--- a/deps/v8/tools/system-analyzer/events.mjs
+++ /dev/null
@@ -1,51 +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.
-
-class SelectionEvent extends CustomEvent {
- // TODO: turn into static class fields once Safari supports it.
- static get name() {
- return 'showentries';
- }
- constructor(entries) {
- super(SelectionEvent.name, {bubbles: true, composed: true});
- if (!Array.isArray(entries) || entries.length == 0) {
- throw new Error('No valid entries selected!');
- }
- this.entries = entries;
- }
-}
-
-class FocusEvent extends CustomEvent {
- static get name() {
- return 'showentrydetail';
- }
- constructor(entry) {
- super(FocusEvent.name, {bubbles: true, composed: true});
- this.entry = entry;
- }
-}
-
-class SelectTimeEvent extends CustomEvent {
- static get name() {
- return 'timerangeselect';
- }
- constructor(start, end) {
- super(SelectTimeEvent.name, {bubbles: true, composed: true});
- this.start = start;
- this.end = end;
- }
-}
-
-class SynchronizeSelectionEvent extends CustomEvent {
- static get name() {
- return 'syncselection';
- }
- constructor(start, end) {
- super(SynchronizeSelectionEvent.name, {bubbles: true, composed: true});
- this.start = start;
- this.end = end;
- }
-}
-
-export {SelectionEvent, FocusEvent, SelectTimeEvent, SynchronizeSelectionEvent};
diff --git a/deps/v8/tools/system-analyzer/helper.mjs b/deps/v8/tools/system-analyzer/helper.mjs
index 854a51fcf3..1eccfbdc93 100644
--- a/deps/v8/tools/system-analyzer/helper.mjs
+++ b/deps/v8/tools/system-analyzer/helper.mjs
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-const KB = 1024;
-const MB = KB * KB;
-const GB = MB * KB;
-const kMillis2Seconds = 1 / 1000;
+export const KB = 1024;
+export const MB = KB * KB;
+export const GB = MB * KB;
+export const kMicro2Milli = 1 / 1000;
-function formatBytes(bytes) {
+export function formatBytes(bytes) {
const units = ['B', 'KiB', 'MiB', 'GiB'];
const divisor = 1024;
let index = 0;
@@ -18,230 +18,57 @@ function formatBytes(bytes) {
return bytes.toFixed(2) + units[index];
}
-function formatSeconds(millis) {
- return (millis * kMillis2Seconds).toFixed(2) + 's';
+export function formatMicroSeconds(millis) {
+ return (millis * kMicro2Milli).toFixed(1) + 'ms';
}
-class CSSColor {
- static getColor(name) {
- const style = getComputedStyle(document.body);
- return style.getPropertyValue(`--${name}`);
- }
- static get backgroundColor() {
- return CSSColor.getColor('backgroud-color');
- }
- static get surfaceColor() {
- return CSSColor.getColor('surface-color');
- }
- static get primaryColor() {
- return CSSColor.getColor('primary-color');
- }
- static get secondaryColor() {
- return CSSColor.getColor('secondary-color');
- }
- static get onSurfaceColor() {
- return CSSColor.getColor('on-surface-color');
- }
- static get onBackgroundColor() {
- return CSSColor.getColor('on-background-color');
- }
- static get onPrimaryColor() {
- return CSSColor.getColor('on-primary-color');
- }
- static get onSecondaryColor() {
- return CSSColor.getColor('on-secondary-color');
- }
- static get defaultColor() {
- return CSSColor.getColor('default-color');
- }
- static get errorColor() {
- return CSSColor.getColor('error-color');
- }
- static get mapBackgroundColor() {
- return CSSColor.getColor('map-background-color');
- }
- static get timelineBackgroundColor() {
- return CSSColor.getColor('timeline-background-color');
- }
- static get red() {
- return CSSColor.getColor('red');
- }
- static get green() {
- return CSSColor.getColor('green');
- }
- static get yellow() {
- return CSSColor.getColor('yellow');
- }
- static get blue() {
- return CSSColor.getColor('blue');
- }
- static get orange() {
- return CSSColor.getColor('orange');
- }
- static get violet() {
- return CSSColor.getColor('violet');
- }
-}
-
-function typeToColor(type) {
- switch (type) {
- case 'new':
- return CSSColor.green;
- case 'Normalize':
- return CSSColor.violet;
- case 'SlowToFast':
- return CSSColor.orange;
- case 'InitialMap':
- return CSSColor.yellow;
- case 'Transition':
- return CSSColor.primaryColor;
- case 'ReplaceDescriptors':
- return CSSColor.red;
- case 'LoadGlobalIC':
- return CSSColor.green;
- case 'LoadIC':
- return CSSColor.primaryColor;
- case 'StoreInArrayLiteralIC':
- return CSSColor.violet;
- case 'StoreGlobalIC':
- return CSSColor.blue;
- case 'StoreIC':
- return CSSColor.orange;
- case 'KeyedLoadIC':
- return CSSColor.red;
- case 'KeyedStoreIC':
- return CSSColor.yellow;
- }
- return CSSColor.secondaryColor;
-}
-
-class DOM {
- static div(classes) {
- const node = document.createElement('div');
- if (classes !== void 0) {
- if (typeof classes === 'string') {
- node.classList.add(classes);
- } else {
- classes.forEach(cls => node.classList.add(cls));
- }
- }
- return node;
- }
-
- static table(className) {
- const node = document.createElement('table');
- if (className) node.classList.add(className);
- return node;
- }
-
- static td(textOrNode, className) {
- const node = document.createElement('td');
- if (typeof textOrNode === 'object') {
- node.appendChild(textOrNode);
- } else if (textOrNode) {
- node.innerText = textOrNode;
- }
- if (className) node.classList.add(className);
- return node;
- }
-
- static tr(className) {
- const node = document.createElement('tr');
- if (className) node.classList.add(className);
- return node;
- }
-
- static text(string) {
- return document.createTextNode(string);
- }
-
- static removeAllChildren(node) {
- let range = document.createRange();
- range.selectNodeContents(node);
- range.deleteContents();
- }
-
- static defineCustomElement(path, generator) {
- let name = path.substring(path.lastIndexOf('/') + 1, path.length);
- path = path + '-template.html';
- fetch(path)
- .then(stream => stream.text())
- .then(
- templateText =>
- customElements.define(name, generator(templateText)));
- }
-}
-
-function $(id) {
- return document.querySelector(id)
+export function delay(time) {
+ return new Promise(resolver => setTimeout(resolver, time));
}
-class V8CustomElement extends HTMLElement {
- _updateTimeoutId;
- _updateCallback = this._update.bind(this);
-
- constructor(templateText) {
- super();
- const shadowRoot = this.attachShadow({mode: 'open'});
- shadowRoot.innerHTML = templateText;
- }
-
- $(id) {
- return this.shadowRoot.querySelector(id);
+export class Group {
+ constructor(key, id, parentTotal, entries) {
+ this.key = key;
+ this.id = id;
+ this.count = 1;
+ this.entries = entries;
+ this.parentTotal = parentTotal;
}
- querySelectorAll(query) {
- return this.shadowRoot.querySelectorAll(query);
+ get percent() {
+ return this.count / this.parentTotal * 100;
}
- update() {
- // Use timeout tasks to asynchronously update the UI without blocking.
- clearTimeout(this._updateTimeoutId);
- const kDelayMs = 5;
- this._updateTimeoutId = setTimeout(this._updateCallback, kDelayMs);
+ add() {
+ this.count++;
}
- _update() {
- throw Error('Subclass responsibility');
+ addEntry(entry) {
+ this.count++;
+ this.entries.push(entry);
}
}
-class LazyTable {
- constructor(table, rowData, rowElementCreator) {
- this._table = table;
- this._rowData = rowData;
- this._rowElementCreator = rowElementCreator;
- const tbody = table.querySelector('tbody');
- table.replaceChild(document.createElement('tbody'), tbody);
- table.querySelector('tfoot td').onclick = (e) => this._addMoreRows();
- this._addMoreRows();
- }
-
- _nextRowDataSlice() {
- return this._rowData.splice(0, 100);
- }
-
- _addMoreRows() {
- const fragment = new DocumentFragment();
- for (let row of this._nextRowDataSlice()) {
- const tr = this._rowElementCreator(row);
- fragment.appendChild(tr);
+export function groupBy(array, keyFunction, collect = false) {
+ if (array.length === 0) return [];
+ if (keyFunction === undefined) keyFunction = each => each;
+ const keyToGroup = new Map();
+ const groups = [];
+ let id = 0;
+ // This is performance critical, resorting to for-loop
+ for (let each of array) {
+ const key = keyFunction(each);
+ let group = keyToGroup.get(key);
+ if (group !== undefined) {
+ collect ? group.addEntry(each) : group.add();
+ continue;
}
- this._table.querySelector('tbody').appendChild(fragment);
- }
-}
-
-function delay(time) {
- return new Promise(resolver => setTimeout(resolver, time));
-}
-
-export {
- DOM,
- $,
- V8CustomElement,
- formatBytes,
- typeToColor,
- CSSColor,
- delay,
- LazyTable,
-};
+ let entries = undefined;
+ if (collect) entries = [each];
+ group = new Group(key, id++, array.length, entries);
+ groups.push(group);
+ keyToGroup.set(key, group);
+ }
+ // Sort by count
+ return groups.sort((a, b) => b.count - a.count);
+} \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/ic-model.mjs b/deps/v8/tools/system-analyzer/ic-model.mjs
deleted file mode 100644
index 2bb40b6853..0000000000
--- a/deps/v8/tools/system-analyzer/ic-model.mjs
+++ /dev/null
@@ -1,57 +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.
-
-import {IcLogEntry} from './log/ic.mjs';
-
-// For compatibility with console scripts:
-print = console.log;
-
-export class Group {
- constructor(property, key, entry) {
- this.property = property;
- this.key = key;
- this.count = 1;
- this.entries = [entry];
- this.percentage = undefined;
- this.groups = undefined;
- }
-
- add(entry) {
- this.count++;
- this.entries.push(entry)
- }
-
- createSubGroups() {
- // TODO: use Map
- this.groups = {};
- for (const propertyName of IcLogEntry.propertyNames) {
- if (this.property == propertyName) continue;
- this.groups[propertyName] = Group.groupBy(this.entries, propertyName);
- }
- }
-
- static groupBy(entries, property) {
- let accumulator = Object.create(null);
- let length = entries.length;
- for (let i = 0; i < length; i++) {
- let entry = entries[i];
- let key = entry[property];
- if (accumulator[key] == undefined) {
- accumulator[key] = new Group(property, key, entry);
- } else {
- let group = accumulator[key];
- if (group.entries == undefined) console.log([group, entry]);
- group.add(entry)
- }
- }
- let result = [];
- for (let key in accumulator) {
- let group = accumulator[key];
- group.percentage = Math.round(group.count / length * 100 * 100) / 100;
- result.push(group);
- }
- result.sort((a, b) => {return b.count - a.count});
- return result;
- }
-}
diff --git a/deps/v8/tools/system-analyzer/ic-panel-template.html b/deps/v8/tools/system-analyzer/ic-panel-template.html
deleted file mode 100644
index ee08901fb0..0000000000
--- a/deps/v8/tools/system-analyzer/ic-panel-template.html
+++ /dev/null
@@ -1,98 +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. -->
-
-<head>
- <link href="./index.css" rel="stylesheet">
-</head>
-<style>
- .count {
- text-align: right;
- width: 5em;
- }
-
- .percentage {
- text-align: right;
- width: 5em;
- }
-
- .key {
- padding-left: 1em;
- }
-
- .drilldown-group-title {
- font-weight: bold;
- padding: 0.5em 0 0.2em 0;
- }
-
- .toggle {
- width: 1em;
- text-align: center;
- cursor: -webkit-zoom-in;
- color: rgba(var(--border-color), 1);
- }
- .toggle::before {
- content: "â–¶";
- }
- .open .toggle::before {
- content: "â–¼";
- }
-
- .panel {
- position: relative;
- min-height: 200px;
- }
-
- #legend {
- position: absolute;
- right: 10px;
- top: 10px;
- background-color: var(--surface-color);
- border-radius: 5px;
- border: 3px solid rgba(var(--border-color), 0.2);
- padding: 0 10px 0 10px;
- }
-
- #legend dt {
- font-family: monospace;
- }
- #legend h3 {
- margin-top: 10px;
- }
- .scroller {
- max-height: 800px;
- overflow-y: scroll;
- }
-</style>
-<div class="panel">
- <h2>IC Panel <span id="count"></span></h2>
- <div id="legend">
- <h3>Legend</h3>
- <dl>
- <dt>0</dt>
- <dd>uninitialized</dd>
- <dt>X</dt>
- <dd>no feedback</dd>
- <dt>1</dt>
- <dd>monomorphic</dd>
- <dt>^</dt>
- <dd>recompute handler</dd>
- <dt>P</dt>
- <dd>polymorphic</dd>
- <dt>N</dt>
- <dd>megamorphic</dd>
- <dt>G</dt>
- <dd>generic</dd>
- </dl>
- </div>
- <p>
- Group by IC-property:
- <select id="group-key"></select>
- </p>
- <div class="panelBody">
- <table id="table" width="100%">
- <tbody id="table-body">
- </tbody>
- </table>
- </div>
-</div>
diff --git a/deps/v8/tools/system-analyzer/ic-panel.mjs b/deps/v8/tools/system-analyzer/ic-panel.mjs
deleted file mode 100644
index d81d06d0d6..0000000000
--- a/deps/v8/tools/system-analyzer/ic-panel.mjs
+++ /dev/null
@@ -1,191 +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.
-
-import {FocusEvent, SelectionEvent, SelectTimeEvent} from './events.mjs';
-import {delay, DOM, V8CustomElement} from './helper.mjs';
-import {Group} from './ic-model.mjs';
-import {IcLogEntry} from './log/ic.mjs';
-import {MapLogEntry} from './log/map.mjs';
-
-DOM.defineCustomElement(
- 'ic-panel', (templateText) => class ICPanel extends V8CustomElement {
- _selectedLogEntries;
- _timeline;
- constructor() {
- super(templateText);
- this.initGroupKeySelect();
- this.groupKey.addEventListener('change', e => this.updateTable(e));
- }
- set timeline(value) {
- console.assert(value !== undefined, 'timeline undefined!');
- this._timeline = value;
- this.selectedLogEntries = this._timeline.all;
- this.update();
- }
- get groupKey() {
- return this.$('#group-key');
- }
-
- get table() {
- return this.$('#table');
- }
-
- get tableBody() {
- return this.$('#table-body');
- }
-
- get count() {
- return this.$('#count');
- }
-
- get spanSelectAll() {
- return this.querySelectorAll('span');
- }
-
- set selectedLogEntries(value) {
- this._selectedLogEntries = value;
- this.update();
- }
-
- _update() {
- this._updateCount();
- this._updateTable();
- }
-
- _updateCount() {
- this.count.innerHTML = `length=${this._selectedLogEntries.length}`;
- }
-
- _updateTable(event) {
- let select = this.groupKey;
- let key = select.options[select.selectedIndex].text;
- DOM.removeAllChildren(this.tableBody);
- let groups = Group.groupBy(this._selectedLogEntries, key, true);
- this._render(groups, this.tableBody);
- }
-
- escapeHtml(unsafe) {
- if (!unsafe) return '';
- return unsafe.toString()
- .replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;')
- .replace(/'/g, '&#039;');
- }
-
- handleMapClick(e) {
- const group = e.target.parentNode.entry;
- const id = group.key;
- const selectedMapLogEntries =
- this.searchIcLogEntryToMapLogEntry(id, group.entries);
- this.dispatchEvent(new SelectionEvent(selectedMapLogEntries));
- }
-
- searchIcLogEntryToMapLogEntry(id, icLogEntries) {
- // searches for mapLogEntries using the id, time
- const selectedMapLogEntriesSet = new Set();
- for (const icLogEntry of icLogEntries) {
- const selectedMap = MapLogEntry.get(id, icLogEntry.time);
- selectedMapLogEntriesSet.add(selectedMap);
- }
- return Array.from(selectedMapLogEntriesSet);
- }
-
- // TODO(zcankara) Handle in the processor for events with source
- // positions.
- handleFilePositionClick(e) {
- const tr = e.target.parentNode;
- const sourcePosition = tr.group.entries[0].sourcePosition;
- this.dispatchEvent(new FocusEvent(sourcePosition));
- }
-
- _render(groups, parent) {
- const fragment = document.createDocumentFragment();
- const max = Math.min(1000, groups.length)
- const detailsClickHandler = this.handleDetailsClick.bind(this);
- const mapClickHandler = this.handleMapClick.bind(this);
- const fileClickHandler = this.handleFilePositionClick.bind(this);
- for (let i = 0; i < max; i++) {
- const group = groups[i];
- const tr = DOM.tr();
- tr.group = group;
- const details = tr.appendChild(DOM.td('', 'toggle'));
- details.onclick = detailsClickHandler;
- tr.appendChild(DOM.td(group.percentage + '%', 'percentage'));
- tr.appendChild(DOM.td(group.count, 'count'));
- const valueTd = tr.appendChild(DOM.td(group.key, 'key'));
- if (group.property === 'map') {
- valueTd.onclick = mapClickHandler;
- valueTd.classList.add('clickable');
- } else if (group.property == 'filePosition') {
- valueTd.classList.add('clickable');
- valueTd.onclick = fileClickHandler;
- }
- fragment.appendChild(tr);
- }
- const omitted = groups.length - max;
- if (omitted > 0) {
- const tr = DOM.tr();
- const tdNode = tr.appendChild(DOM.td(`Omitted ${omitted} entries.`));
- tdNode.colSpan = 4;
- fragment.appendChild(tr);
- }
- parent.appendChild(fragment);
- }
-
- handleDetailsClick(event) {
- const tr = event.target.parentNode;
- const group = tr.group;
- // Create subgroup in-place if the don't exist yet.
- if (group.groups === undefined) {
- group.createSubGroups();
- this.renderDrilldown(group, tr);
- }
- let detailsTr = tr.nextSibling;
- if (tr.classList.contains('open')) {
- tr.classList.remove('open');
- detailsTr.style.display = 'none';
- } else {
- tr.classList.add('open');
- detailsTr.style.display = 'table-row';
- }
- }
-
- renderDrilldown(group, previousSibling) {
- let tr = DOM.tr('entry-details');
- tr.style.display = 'none';
- // indent by one td.
- tr.appendChild(DOM.td());
- let td = DOM.td();
- td.colSpan = 3;
- for (let key in group.groups) {
- this.renderDrilldownGroup(td, group.groups[key], key);
- }
- tr.appendChild(td);
- // Append the new TR after previousSibling.
- previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling)
- }
-
- renderDrilldownGroup(td, children, key) {
- const max = 20;
- const div = DOM.div('drilldown-group-title');
- div.textContent =
- `Grouped by ${key} [top ${max} out of ${children.length}]`;
- td.appendChild(div);
- const table = DOM.table();
- this._render(children.slice(0, max), table, false)
- td.appendChild(table);
- }
-
- initGroupKeySelect() {
- const select = this.groupKey;
- select.options.length = 0;
- for (const propertyName of IcLogEntry.propertyNames) {
- const option = document.createElement('option');
- option.text = propertyName;
- select.add(option);
- }
- }
- });
diff --git a/deps/v8/tools/system-analyzer/index.css b/deps/v8/tools/system-analyzer/index.css
index 5b55182f68..27b07531bf 100644
--- a/deps/v8/tools/system-analyzer/index.css
+++ b/deps/v8/tools/system-analyzer/index.css
@@ -18,7 +18,8 @@
--blue: #6e77dc;
--orange: #dc9b6e;
--violet: #d26edc;
- --border-color: 128, 128, 128;
+ --border-color-rgb: 128, 128, 128;
+ --border-color: rgba(var(--border-color-rgb), 0.2);
}
[data-theme="light"] {
@@ -110,19 +111,62 @@ dd {
.panel {
background-color: var(--surface-color);
color: var(--on-surface-color);
- padding: 10px 10px 10px 10px;
+ padding: 10px;
border-radius: 10px;
- border: 3px solid rgba(var(--border-color), 0.2);
+ border: 3px solid var(--border-color);
+ overflow: hidden;
}
.panelBody {
+ position: relative;
max-height: 800px;
overflow-y: scroll;
margin: 0 -10px -10px 0;
}
-.panel > h2 {
- margin-top: 5px;
+.panel > h2, .panelTitle {
+ margin: -10px -10px 0 -10px;
+ padding: 5px 10px 5px 10px;
+ background-color: var(--border-color);
+ border-radius: 7px 7px 0 0;
+ font-weight: 400;
+}
+
+.panel > select{
+ width: calc(100% + 20px);
+ margin: 0 -10px 10px -10px;
+}
+
+.panel > .selection {
+ display: flex;
+ margin: 0 -10px 0 -10px;
+}
+.panel > .selection input {
+ display: none;
+}
+
+.panel > .selection label {
+ flex: 1;
+ padding: 5px;
+ cursor: pointer;
+ background-color: var( --surface-color);
+ font-weight: normal;
+ text-align: center;
+}
+.panel > .selection label ~ label {
+ border-left: 2px var(--border-color) solid;
+}
+
+.panel > .selection label:hover {
+ background-color: var(--primary-color);
+}
+.panel > .selection [type=radio]:checked + label {
+ background-color: var(--border-color);
+}
+
+.panel > .selection select {
+ flex: 1;
+ width: 50%;
}
button {
@@ -133,17 +177,18 @@ select,
button {
background-color: var(--surface-color);
color: var(--on-surface-color);
- border: 2px solid rgba(var(--border-color), 0.4);
+ border: 2px solid rgba(var(--border-color-rgb), 0.4);
border-radius: 5px;
padding: 2px;
}
input:hover,
select:hover,
button:hover {
- border: 2px solid rgba(var(--border-color), 0.6);
+ border: 2px solid rgba(var(--border-color-rgb), 0.6);
}
.colorbox {
+ display: inline-block;
width: 10px;
height: 10px;
border: 1px var(--background-color) solid;
@@ -192,6 +237,8 @@ button:hover {
background-color: var(--primary-color);
color: var(--on-primary-color);
}
+
+button:hover,
.clickable:hover,
.mark:hover,
.clickable:active,
@@ -199,4 +246,48 @@ button:hover {
background-color: var(--primary-color);
color: var(--on-primary-color);
cursor: pointer;
+}
+
+
+.legend {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ background-color: var(--surface-color);
+ border-radius: 5px;
+ border: 3px solid var(--border-color);
+ padding: 0 10px 0 10px;
+}
+.legend dt {
+ font-family: monospace;
+}
+.legend h3 {
+ margin-top: 10px;
+}
+
+
+.panelCloserLabel {
+ float: left;
+ cursor: zoom-out;
+ margin: 0 10px 0 0;
+ transition: transform 0.2s ease-out;
+ user-select: none;
+}
+.panelCloserInput {
+ display: none;
+}
+.panel .panelCloserInput:checked ~ .panelCloserLabel,
+.panelCloserInput:checked ~ .panelCloserLabel {
+ cursor: zoom-in;
+ transform: rotate(-90deg);
+ display: inherit;
+}
+.panel .panelCloserInput:checked ~ h2 {
+ display: inherit;
+ border-radius: 7px;
+ margin-bottom: -20px;
+ padding-bottom: 10px;
+}
+.panelCloserInput:checked ~ * {
+ display: none;
} \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/index.html b/deps/v8/tools/system-analyzer/index.html
index a861300f91..fa09830240 100644
--- a/deps/v8/tools/system-analyzer/index.html
+++ b/deps/v8/tools/system-analyzer/index.html
@@ -8,33 +8,27 @@ found in the LICENSE file. -->
<title>Indicium</title>
<!-- <link rel="icon" type="image/png" href="/images/favicon.png"/> -->
- <link rel="modulepreload" href="./log-file-reader.mjs" >
<link rel="modulepreload" href="./helper.mjs" >
- <link rel="preload" href="./log-file-reader-template.html" as="fetch" crossorigin="anonymous">
+ <link rel="modulepreload" href="./view/log-file-reader.mjs" >
+ <link rel="modulepreload" href="./view/helper.mjs" >
+ <link rel="preload" href="./view/log-file-reader-template.html" as="fetch" crossorigin="anonymous">
<script type="module">
// Force instatiating the log-reader before anything else.
- import "./log-file-reader.mjs";
+ import "./view/log-file-reader.mjs";
// Delay loading of the main App
(async function() {
let module = await import('./index.mjs');
- globalThis.app = new module.App("#log-file-reader", "#map-panel", "#map-stats-panel",
- "#timeline-panel", "#ic-panel", "#map-track", "#ic-track", "#deopt-track",
- "#source-panel");
+ globalThis.app = new module.App();
})();
</script>
-
<link rel="stylesheet" type="text/css" href="./index.css">
<style>
- .theme-switch-wrapper {
- display: inline-block;
- align-items: center;
- }
-
.theme-switch {
display: inline-block;
height: 16px;
position: relative;
width: 38px;
+ vertical-align: middle;
}
.theme-switch input {
@@ -75,7 +69,7 @@ found in the LICENSE file. -->
width: 100%;
}
- .panels{
+ .panels {
display: grid;
align-content: center;
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
@@ -91,31 +85,60 @@ found in the LICENSE file. -->
</head>
<body>
+ <tool-tip id="tool-tip"></tool-tip>
+
<section id="file-reader">
<log-file-reader id="log-file-reader"></log-file-reader>
</section>
<section id="container" class="initial">
<timeline-panel id="timeline-panel">
- <timeline-track id="map-track"></timeline-track>
- <timeline-track id="ic-track"></timeline-track>
- <timeline-track id="deopt-track"></timeline-track>
+ <timeline-track id="map-track" title="Map"></timeline-track>
+ <timeline-track id="ic-track" title="IC"></timeline-track>
+ <timeline-track id="deopt-track" title="Deopt"></timeline-track>
+ <timeline-track id="code-track" title="Code"></timeline-track>
+ <timeline-track id="api-track" title="API"></timeline-track>
</timeline-panel>
+
<div class="panels">
<map-panel id="map-panel"></map-panel>
- <stats-panel id="map-stats-panel"></stats-panel>
- <ic-panel id="ic-panel" onchange="app.handleSelectIc(event)"></ic-panel>
- <source-panel id="source-panel"></source-panel>
+ <list-panel id="ic-list" title="IC List">
+ <div class="legend">
+ <h3>Legend</h3>
+ <dl>
+ <dt>0</dt>
+ <dd>uninitialized</dd>
+ <dt>X</dt>
+ <dd>no feedback</dd>
+ <dt>1</dt>
+ <dd>monomorphic</dd>
+ <dt>^</dt>
+ <dd>recompute handler</dd>
+ <dt>P</dt>
+ <dd>polymorphic</dd>
+ <dt>N</dt>
+ <dd>megamorphic</dd>
+ <dt>G</dt>
+ <dd>generic</dd>
+ </dl>
+ </div>
+ </list-panel>
+ <list-panel id="map-list" title="Map Events"></list-panel>
+ <list-panel id="deopt-list" title="Deopt Events"></list-panel>
+ <list-panel id="code-list" title="Code Events"></list-panel>
+ <list-panel id="api-list" title="API Events"></list-panel>
+ <script-panel id="script-panel"></script-panel>
+ <code-panel id="code-panel"></code-panel>
</div>
</section>
<div class="panels">
<section id="settings" class="panel">
<h2>Settings</h2>
- <span>Theme:</span>
- <div class="theme-switch-wrapper">
+ <div class="panelBody">
+ <span>Theme:</span>
<label class="theme-switch" for="theme-switch-input">
- <input type="checkbox" id="theme-switch-input" />
+ <input type="checkbox" id="theme-switch-input" >
<div class="slider"></div>
</label>
</div>
@@ -123,63 +146,96 @@ found in the LICENSE file. -->
<section id="instructions" class="panel">
<h2>Instructions</h2>
- <p>
- Unified web interface to analyse runtime information stored in the v8 log.
- </p>
- For generating a v8.log file from <a href="https://v8.dev/docs/build">d8</a>:
- <ul>
- <li>
- <code>/path/do/d8 --trace-maps --trace_ic --log-source-code $FILE</code>
- </li>
- </ul>
- For generating a v8.log file from Chrome:
- <ul>
- <li>
- <code>/path/to/chrome --user-data-dir=/var/tmp/chr$RANDOM --no-sandbox
- --js-flags='--trace-ic --trace-maps --log-source-code’
- $WEBSITE_URL</code>
- </li>
- </ul>
-
- <h3>Log Options:</h3>
- <dl class="d8-options">
- <dt><code>--trace-maps</code></dt>
- <dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank">
- Maps</a></dd>
- <dt><code>--trace-ic</code></dt>
- <dd>Log
- <a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank">
- ICs</a></dd>
- <dt><code>--log-source-code</code></dt>
- <dd>Log source code</dd>
- </dl>
-
- <h3>Keyboard Shortcuts for Navigation</h3>
- <dl>
- <dt><kbd>SHIFT</kbd> + <kbd>Arrow Up</kbd></dt>
- <dd>Follow Map transition forward (first child)</dd>
-
- <dt><kbd>SHIFT</kbd> + <kbd>Arrow Down</kbd></dt>
- <dd>Follow Map transition backwards</dd>
-
- <dt><kbd>Arrow Up</kbd></dt>
- <dd>Go to previous Map chunk</dd>
-
- <dt><kbd>Arrow Down</kbd></dt>
- <dd>Go to next Map in chunk</dd>
-
- <dt><kbd>Arrow Left</kbd></dt>
- <dd>Go to previous chunk</dd>
-
- <dt><kbd>Arrow Right</kbd></dt>
- <dd>Go to next chunk</dd>
-
- <dt><kbd>+</kbd></dt>
- <dd>Timeline zoom in</dd>
-
- <dt><kbd>-</kbd></dt>
- <dd>Timeline zoom out</dd>
- </dl>
+ <div class="panelBody">
+ <p>
+ Unified web interface to analyse runtime information stored in the v8 log.
+ </p>
+ For generating a v8.log file from <a href="https://v8.dev/docs/build">d8</a>:
+ <ul>
+ <li>
+ <code>/path/do/d8 $LOG_FLAGS $FILE</code>
+ </li>
+ </ul>
+ For generating a v8.log file from Chrome:
+ <ul>
+ <li>
+ <code>/path/to/chrome --user-data-dir=/var/tmp/chr$RANDOM --no-sandbox
+ --js-flags='$LOG_FLAGS’
+ $WEBSITE_URL</code>
+ </li>
+ </ul>
+
+ <h3><code>LOG_FLAGS</code>:</h3>
+ <dl class="d8-options">
+ <dt>
+ <a href="https://source.chromium.org/search?q=FLAG_log_all">
+ <code>--log-all</code>
+ </a>
+ </dt>
+ <dd>Enable all V8 logging options.</dd>
+ <dt>
+ <a href="https://source.chromium.org/search?q=FLAG_trace_maps">
+ <code>--trace-maps</code>
+ </a>
+ </dt>
+ <dd>
+ Log<a href="https://v8.dev/blog/fast-properties">Maps</a>
+ </dd>
+ <dt>
+ <a href="https://source.chromium.org/search?q=FLAG_trace_ic">
+ <code>--trace-ic</code>
+ </a>
+ </dt>
+ <dd>
+ Log <a href="https://mathiasbynens.be/notes/shapes-ics">ICs</a>
+ </dd>
+ <dt>
+ <a href="https://source.chromium.org/search?q=FLAG_log_source_code">
+ <code>--log-source-code</code>
+ </a>
+ </dt>
+ <dd>Log source code</dd>
+ <dt>
+ <a href="https://source.chromium.org/search?q=FLAG_log_code_disassemble">
+ <code>--log-code-disassemble</code>
+ </a>
+ </dt>
+ <dd>Log detailed generated generated code</dd>
+ <dt>
+ <a href="https://source.chromium.org/search?q=FLAG_log_api">
+ <code>--log-api</code>
+ </a>
+ </dt>
+ <dd>Log various API uses.</dd>
+ </dl>
+
+ <h3>Keyboard Shortcuts for Navigation</h3>
+ <dl>
+ <dt><kbd>SHIFT</kbd> + <kbd>Arrow Up</kbd></dt>
+ <dd>Follow Map transition forward (first child)</dd>
+
+ <dt><kbd>SHIFT</kbd> + <kbd>Arrow Down</kbd></dt>
+ <dd>Follow Map transition backwards</dd>
+
+ <dt><kbd>Arrow Up</kbd></dt>
+ <dd>Go to previous Map chunk</dd>
+
+ <dt><kbd>Arrow Down</kbd></dt>
+ <dd>Go to next Map in chunk</dd>
+
+ <dt><kbd>Arrow Left</kbd></dt>
+ <dd>Go to previous chunk</dd>
+
+ <dt><kbd>Arrow Right</kbd></dt>
+ <dd>Go to next chunk</dd>
+
+ <dt><kbd>+</kbd></dt>
+ <dd>Timeline zoom in</dd>
+
+ <dt><kbd>-</kbd></dt>
+ <dd>Timeline zoom out</dd>
+ </dl>
+ </div>
</section>
</div>
</body>
diff --git a/deps/v8/tools/system-analyzer/index.mjs b/deps/v8/tools/system-analyzer/index.mjs
index dfc858e5d6..531ae79138 100644
--- a/deps/v8/tools/system-analyzer/index.mjs
+++ b/deps/v8/tools/system-analyzer/index.mjs
@@ -2,34 +2,46 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import {SourcePosition} from '../profile.mjs';
+import {Script, SourcePosition} from '../profile.mjs';
import {State} from './app-model.mjs';
-import {FocusEvent, SelectionEvent, SelectTimeEvent} from './events.mjs';
-import {$} from './helper.mjs';
+import {ApiLogEntry} from './log/api.mjs';
+import {DeoptLogEntry} from './log/code.mjs';
+import {CodeLogEntry} from './log/code.mjs';
import {IcLogEntry} from './log/ic.mjs';
import {MapLogEntry} from './log/map.mjs';
import {Processor} from './processor.mjs';
+import {FocusEvent, SelectionEvent, SelectRelatedEvent, SelectTimeEvent, ToolTipEvent,} from './view/events.mjs';
+import {$, CSSColor, groupBy} from './view/helper.mjs';
class App {
_state;
_view;
_navigation;
_startupPromise;
- constructor(
- fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId,
- mapTrackId, icTrackId, deoptTrackId, sourcePanelId) {
+ constructor() {
this._view = {
__proto__: null,
- logFileReader: $(fileReaderId),
- icPanel: $(icPanelId),
- mapPanel: $(mapPanelId),
- mapStatsPanel: $(mapStatsPanelId),
- timelinePanel: $(timelinePanelId),
- mapTrack: $(mapTrackId),
- icTrack: $(icTrackId),
- deoptTrack: $(deoptTrackId),
- sourcePanel: $(sourcePanelId)
+ logFileReader: $('#log-file-reader'),
+
+ timelinePanel: $('#timeline-panel'),
+ mapTrack: $('#map-track'),
+ icTrack: $('#ic-track'),
+ deoptTrack: $('#deopt-track'),
+ codeTrack: $('#code-track'),
+ apiTrack: $('#api-track'),
+
+ icList: $('#ic-list'),
+ mapList: $('#map-list'),
+ codeList: $('#code-list'),
+ deoptList: $('#deopt-list'),
+ apiList: $('#api-list'),
+
+ mapPanel: $('#map-panel'),
+ codePanel: $('#code-panel'),
+ scriptPanel: $('#script-panel'),
+
+ toolTip: $('#tool-tip'),
};
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
this.toggleSwitch.addEventListener('change', (e) => this.switchTheme(e));
@@ -40,90 +52,208 @@ class App {
this._startupPromise = this.runAsyncInitialize();
}
+ static get allEventTypes() {
+ return new Set([
+ SourcePosition, MapLogEntry, IcLogEntry, ApiLogEntry, CodeLogEntry,
+ DeoptLogEntry
+ ]);
+ }
+
async runAsyncInitialize() {
await Promise.all([
- import('./ic-panel.mjs'),
- import('./timeline-panel.mjs'),
- import('./stats-panel.mjs'),
- import('./map-panel.mjs'),
- import('./source-panel.mjs'),
+ import('./view/list-panel.mjs'),
+ import('./view/timeline-panel.mjs'),
+ import('./view/map-panel.mjs'),
+ import('./view/script-panel.mjs'),
+ import('./view/code-panel.mjs'),
+ import('./view/tool-tip.mjs'),
]);
document.addEventListener(
'keydown', e => this._navigation?.handleKeyDown(e));
document.addEventListener(
- SelectionEvent.name, e => this.handleShowEntries(e));
+ SelectRelatedEvent.name, e => this.handleSelectRelatedEntries(e));
document.addEventListener(
- FocusEvent.name, e => this.handleShowEntryDetail(e));
+ SelectionEvent.name, e => this.handleSelectEntries(e))
+ document.addEventListener(
+ FocusEvent.name, e => this.handleFocusLogEntryl(e));
document.addEventListener(
SelectTimeEvent.name, e => this.handleTimeRangeSelect(e));
+ document.addEventListener(ToolTipEvent.name, e => this.handleToolTip(e));
}
- handleShowEntries(e) {
- if (e.entries[0] instanceof MapLogEntry) {
- this.showMapEntries(e.entries);
- } else if (e.entries[0] instanceof IcLogEntry) {
- this.showIcEntries(e.entries);
- } else if (e.entries[0] instanceof SourcePosition) {
- this.showSourcePositionEntries(e.entries);
- } else {
- throw new Error('Unknown selection type!');
+ handleSelectRelatedEntries(e) {
+ e.stopImmediatePropagation();
+ this.selectRelatedEntries(e.entry);
+ }
+
+ selectRelatedEntries(entry) {
+ let entries = [entry];
+ switch (entry.constructor) {
+ case SourcePosition:
+ entries = entries.concat(entry.entries);
+ break;
+ case MapLogEntry:
+ entries = this._state.icTimeline.filter(each => each.map === entry);
+ break;
+ case IcLogEntry:
+ if (entry.map) entries.push(entry.map);
+ break;
+ case ApiLogEntry:
+ break;
+ case CodeLogEntry:
+ break;
+ case DeoptLogEntry:
+ // TODO select map + code entries
+ if (entry.fileSourcePosition) entries.push(entry.fileSourcePosition);
+ break;
+ case Script:
+ entries = entry.entries.concat(entry.sourcePositions);
+ break;
+ default:
+ throw new Error('Unknown selection type!');
+ }
+ if (entry.sourcePosition) {
+ entries.push(entry.sourcePosition);
+ // TODO: find the matching Code log entries.
+ }
+ this.selectEntries(entries);
+ }
+
+ handleSelectEntries(e) {
+ e.stopImmediatePropagation();
+ this.showEntries(e.entries);
+ }
+
+ selectEntries(entries) {
+ const missingTypes = App.allEventTypes;
+ groupBy(entries, each => each.constructor, true).forEach(group => {
+ this.selectEntriesOfSingleType(group.entries);
+ missingTypes.delete(group.key);
+ });
+ missingTypes.forEach(type => this.selectEntriesOfSingleType([], type));
+ }
+
+ selectEntriesOfSingleType(entries, type) {
+ switch (entries[0]?.constructor ?? type) {
+ case SourcePosition:
+ return this.showSourcePositions(entries);
+ case MapLogEntry:
+ return this.showMapEntries(entries);
+ case IcLogEntry:
+ return this.showIcEntries(entries);
+ case ApiLogEntry:
+ return this.showApiEntries(entries);
+ case CodeLogEntry:
+ return this.showCodeEntries(entries);
+ case DeoptLogEntry:
+ return this.showDeoptEntries(entries);
+ default:
+ throw new Error('Unknown selection type!');
}
- e.stopPropagation();
}
+
showMapEntries(entries) {
this._state.selectedMapLogEntries = entries;
- this._view.mapPanel.selectedMapLogEntries = entries;
- this._view.mapStatsPanel.selectedLogEntries = entries;
+ this._view.mapPanel.selectedLogEntries = entries;
+ this._view.mapList.selectedLogEntries = entries;
}
+
showIcEntries(entries) {
this._state.selectedIcLogEntries = entries;
- this._view.icPanel.selectedLogEntries = entries;
+ this._view.icList.selectedLogEntries = entries;
}
+
showDeoptEntries(entries) {
this._state.selectedDeoptLogEntries = entries;
+ this._view.deoptList.selectedLogEntries = entries;
}
- showSourcePositionEntries(entries) {
- // TODO: Handle multiple source position selection events
- this._view.sourcePanel.selectedSourcePositions = entries
+
+ showCodeEntries(entries) {
+ this._state.selectedCodeLogEntries = entries;
+ this._view.codePanel.selectedEntries = entries;
+ this._view.codeList.selectedLogEntries = entries;
+ }
+
+ showApiEntries(entries) {
+ this._state.selectedApiLogEntries = entries;
+ this._view.apiList.selectedLogEntries = entries;
+ }
+
+ showSourcePositions(entries) {
+ this._view.scriptPanel.selectedSourcePositions = entries
}
handleTimeRangeSelect(e) {
+ e.stopImmediatePropagation();
this.selectTimeRange(e.start, e.end);
- e.stopPropagation();
}
selectTimeRange(start, end) {
this._state.selectTimeRange(start, end);
- this.showMapEntries(this._state.mapTimeline.selection);
- this.showIcEntries(this._state.icTimeline.selection);
- this.showDeoptEntries(this._state.deoptTimeline.selection);
+ this.showMapEntries(this._state.mapTimeline.selectionOrSelf);
+ this.showIcEntries(this._state.icTimeline.selectionOrSelf);
+ this.showDeoptEntries(this._state.deoptTimeline.selectionOrSelf);
+ this.showCodeEntries(this._state.codeTimeline.selectionOrSelf);
+ this.showApiEntries(this._state.apiTimeline.selectionOrSelf);
this._view.timelinePanel.timeSelection = {start, end};
}
- handleShowEntryDetail(e) {
- if (e.entry instanceof MapLogEntry) {
- this.selectMapLogEntry(e.entry);
- } else if (e.entry instanceof IcLogEntry) {
- this.selectICLogEntry(e.entry);
- } else if (e.entry instanceof SourcePosition) {
- this.selectSourcePosition(e.entry);
- } else {
- throw new Error('Unknown selection type!');
+ handleFocusLogEntryl(e) {
+ e.stopImmediatePropagation();
+ this.focusLogEntry(e.entry);
+ }
+
+ focusLogEntry(entry) {
+ switch (entry.constructor) {
+ case SourcePosition:
+ return this.focusSourcePosition(entry);
+ case MapLogEntry:
+ return this.focusMapLogEntry(entry);
+ case IcLogEntry:
+ return this.focusIcLogEntry(entry);
+ case ApiLogEntry:
+ return this.focusApiLogEntry(entry);
+ case CodeLogEntry:
+ return this.focusCodeLogEntry(entry);
+ case DeoptLogEntry:
+ return this.focusDeoptLogEntry(entry);
+ default:
+ throw new Error('Unknown selection type!');
}
- e.stopPropagation();
}
- selectMapLogEntry(entry) {
+
+ focusMapLogEntry(entry) {
this._state.map = entry;
- this._view.mapTrack.selectedEntry = entry;
+ this._view.mapTrack.focusedEntry = entry;
this._view.mapPanel.map = entry;
}
- selectICLogEntry(entry) {
+
+ focusIcLogEntry(entry) {
this._state.ic = entry;
- this._view.icPanel.selectedLogEntries = [entry];
}
- selectSourcePosition(sourcePositions) {
- if (!sourcePositions.script) return;
- this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
+
+ focusCodeLogEntry(entry) {
+ this._state.code = entry;
+ this._view.codePanel.entry = entry;
+ }
+
+ focusDeoptLogEntry(entry) {
+ this._view.deoptList.focusedLogEntry = entry;
+ }
+
+ focusApiLogEntry(entry) {
+ this._state.apiLogEntry = entry;
+ this._view.apiTrack.focusedEntry = entry;
+ }
+
+ focusSourcePosition(sourcePosition) {
+ if (!sourcePosition) return;
+ this._view.sourcePanel.focusedSourcePositions = [sourcePosition];
+ }
+
+ handleToolTip(event) {
+ this._view.toolTip.positionOrTargetNode = event.positionOrTargetNode;
+ this._view.toolTip.content = event.content;
}
handleFileUploadStart(e) {
@@ -140,22 +270,23 @@ class App {
await this._startupPromise;
try {
const processor = new Processor(e.detail);
+ this._state.profile = processor.profile;
const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline;
const deoptTimeline = processor.deoptTimeline;
- this._state.mapTimeline = mapTimeline;
- this._state.icTimeline = icTimeline;
- this._state.deoptTimeline = deoptTimeline;
- // Transitions must be set before timeline for stats panel.
+ const codeTimeline = processor.codeTimeline;
+ const apiTimeline = processor.apiTimeline;
+ this._state.setTimelines(
+ mapTimeline, icTimeline, deoptTimeline, codeTimeline, apiTimeline);
this._view.mapPanel.timeline = mapTimeline;
- this._view.mapTrack.data = mapTimeline;
- this._view.mapStatsPanel.transitions =
- this._state.mapTimeline.transitions;
- this._view.mapStatsPanel.timeline = mapTimeline;
- this._view.icPanel.timeline = icTimeline;
- this._view.icTrack.data = icTimeline;
- this._view.deoptTrack.data = deoptTimeline;
- this._view.sourcePanel.data = processor.scripts
+ this._view.icList.timeline = icTimeline;
+ this._view.mapList.timeline = mapTimeline;
+ this._view.deoptList.timeline = deoptTimeline;
+ this._view.codeList.timeline = codeTimeline;
+ this._view.apiList.timeline = apiTimeline;
+ this._view.scriptPanel.scripts = processor.scripts;
+ this._view.codePanel.timeline = codeTimeline;
+ this.refreshTimelineTrackView();
} catch (e) {
this._view.logFileReader.error = 'Log file contains errors!'
throw (e);
@@ -169,14 +300,16 @@ class App {
this._view.mapTrack.data = this._state.mapTimeline;
this._view.icTrack.data = this._state.icTimeline;
this._view.deoptTrack.data = this._state.deoptTimeline;
+ this._view.codeTrack.data = this._state.codeTimeline;
+ this._view.apiTrack.data = this._state.apiTimeline;
}
switchTheme(event) {
document.documentElement.dataset.theme =
event.target.checked ? 'light' : 'dark';
- if (this.fileLoaded) {
- this.refreshTimelineTrackView();
- }
+ CSSColor.reset();
+ if (!this.fileLoaded) return;
+ this.refreshTimelineTrackView();
}
}
diff --git a/deps/v8/tools/system-analyzer/log/api.mjs b/deps/v8/tools/system-analyzer/log/api.mjs
new file mode 100644
index 0000000000..760ac54914
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/log/api.mjs
@@ -0,0 +1,32 @@
+// 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.
+import {LogEntry} from './log.mjs';
+
+export class ApiLogEntry extends LogEntry {
+ constructor(type, time, name, argument) {
+ super(type, time);
+ this._name = name;
+ this._argument = argument;
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ get argument() {
+ return this._argument;
+ }
+
+ toString() {
+ return `Api(${this.type})`;
+ }
+
+ toStringLong() {
+ return `Api(${this.type}): ${this._name}`;
+ }
+
+ static get propertyNames() {
+ return ['type', 'name', 'argument'];
+ }
+}
diff --git a/deps/v8/tools/system-analyzer/log/code.mjs b/deps/v8/tools/system-analyzer/log/code.mjs
new file mode 100644
index 0000000000..4f69f16c64
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/log/code.mjs
@@ -0,0 +1,95 @@
+// 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.
+import {LogEntry} from './log.mjs';
+
+export class DeoptLogEntry extends LogEntry {
+ constructor(
+ type, time, entry, deoptReason, deoptLocation, scriptOffset,
+ instructionStart, codeSize, inliningId) {
+ super(type, time);
+ this._entry = entry;
+ this._reason = deoptReason;
+ this._location = deoptLocation;
+ this._scriptOffset = scriptOffset;
+ this._instructionStart = instructionStart;
+ this._codeSize = codeSize;
+ this._inliningId = inliningId;
+ this.fileSourcePosition = undefined;
+ }
+
+ get reason() {
+ return this._reason;
+ }
+
+ get location() {
+ return this._location;
+ }
+
+ get entry() {
+ return this._entry;
+ }
+
+ get functionName() {
+ return this._entry.functionName;
+ }
+
+ toString() {
+ return `Deopt(${this.type})`;
+ }
+
+ toStringLong() {
+ return `Deopt(${this.type})${this._reason}: ${this._location}`;
+ }
+
+ static get propertyNames() {
+ return [
+ 'type', 'reason', 'functionName', 'sourcePosition',
+ 'functionSourcePosition', 'script'
+ ];
+ }
+}
+
+export class CodeLogEntry extends LogEntry {
+ constructor(type, time, kind, entry) {
+ super(type, time);
+ this._kind = kind;
+ this._entry = entry;
+ }
+
+ get kind() {
+ return this._kind;
+ }
+
+ get entry() {
+ return this._entry;
+ }
+
+ get functionName() {
+ return this._entry.functionName;
+ }
+
+ get size() {
+ return this._entry.size;
+ }
+
+ get source() {
+ return this._entry?.getSourceCode() ?? '';
+ }
+
+ get disassemble() {
+ return this._entry?.source?.disassemble;
+ }
+
+ toString() {
+ return `Code(${this.type})`;
+ }
+
+ toStringLong() {
+ return `Code(${this.type}): ${this._entry.toString()}`;
+ }
+
+ static get propertyNames() {
+ return ['type', 'kind', 'functionName', 'sourcePosition', 'script'];
+ }
+}
diff --git a/deps/v8/tools/system-analyzer/log/deopt.mjs b/deps/v8/tools/system-analyzer/log/deopt.mjs
deleted file mode 100644
index f3ff1a71a2..0000000000
--- a/deps/v8/tools/system-analyzer/log/deopt.mjs
+++ /dev/null
@@ -1,10 +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.
-import {LogEntry} from './log.mjs';
-
-export class DeoptLogEntry extends LogEntry {
- constructor(type, time) {
- super(type, time);
- }
-}
diff --git a/deps/v8/tools/system-analyzer/log/ic.mjs b/deps/v8/tools/system-analyzer/log/ic.mjs
index b6c7ec5553..68078ccc68 100644
--- a/deps/v8/tools/system-analyzer/log/ic.mjs
+++ b/deps/v8/tools/system-analyzer/log/ic.mjs
@@ -6,7 +6,7 @@ import {LogEntry} from './log.mjs';
export class IcLogEntry extends LogEntry {
constructor(
type, fn_file, time, line, column, key, oldState, newState, map, reason,
- script, modifier, additional) {
+ modifier, additional) {
super(type, time);
this.category = 'other';
if (this.type.indexOf('Store') !== -1) {
@@ -14,11 +14,10 @@ export class IcLogEntry extends LogEntry {
} else if (this.type.indexOf('Load') !== -1) {
this.category = 'Load';
}
- let parts = fn_file.split(' ');
+ const parts = fn_file.split(' ');
this.functionName = parts[0];
this.file = parts[1];
let position = line + ':' + column;
- this.filePosition = this.file + ':' + position;
this.oldState = oldState;
this.newState = newState;
this.state = this.oldState + ' → ' + this.newState;
@@ -26,10 +25,17 @@ export class IcLogEntry extends LogEntry {
this.map = map;
this.reason = reason;
this.additional = additional;
- this.script = script;
this.modifier = modifier;
}
+ toString() {
+ return `IC(${this.type})`;
+ }
+
+ toStringLong() {
+ return `IC(${this.type}):\n${this.state}`;
+ }
+
parseMapProperties(parts, offset) {
let next = parts[++offset];
if (!next.startsWith('dict')) return offset;
@@ -58,8 +64,8 @@ export class IcLogEntry extends LogEntry {
static get propertyNames() {
return [
- 'type', 'category', 'functionName', 'filePosition', 'state', 'key', 'map',
- 'reason', 'file'
+ 'type', 'category', 'functionName', 'script', 'sourcePosition', 'state',
+ 'key', 'map', 'reason', 'file'
];
}
}
diff --git a/deps/v8/tools/system-analyzer/log/log.mjs b/deps/v8/tools/system-analyzer/log/log.mjs
index 69195d7853..5339d88432 100644
--- a/deps/v8/tools/system-analyzer/log/log.mjs
+++ b/deps/v8/tools/system-analyzer/log/log.mjs
@@ -3,19 +3,32 @@
// found in the LICENSE file.
export class LogEntry {
- _time;
- _type;
constructor(type, time) {
- // TODO(zcankara) remove type and add empty getters to override
this._time = time;
this._type = type;
+ this.sourcePosition = undefined;
}
+
get time() {
return this._time;
}
+
get type() {
return this._type;
}
+
+ get script() {
+ return this.sourcePosition?.script;
+ }
+
+ toString() {
+ return `${this.constructor.name}(${this._type})`;
+ }
+
+ toStringLong() {
+ return this.toString();
+ }
+
// Returns an Array of all possible #type values.
static get allTypes() {
throw new Error('Not implemented.');
diff --git a/deps/v8/tools/system-analyzer/log/map.mjs b/deps/v8/tools/system-analyzer/log/map.mjs
index 4df6fb847c..d97f340ca1 100644
--- a/deps/v8/tools/system-analyzer/log/map.mjs
+++ b/deps/v8/tools/system-analyzer/log/map.mjs
@@ -34,21 +34,34 @@ define(Array.prototype, 'last', function() {
// Map Log Events
class MapLogEntry extends LogEntry {
- edge = void 0;
- children = [];
- depth = 0;
- _isDeprecated = false;
- deprecatedTargets = null;
- leftId = 0;
- rightId = 0;
- filePosition = '';
- script = '';
- id = -1;
constructor(id, time) {
if (!time) throw new Error('Invalid time');
- super(id, time);
- MapLogEntry.set(id, this);
+ // Use MapLogEntry.type getter instead of property, since we only know the
+ // type lazily from the incoming transition.
+ super(undefined, time);
this.id = id;
+ MapLogEntry.set(id, this);
+ this.edge = undefined;
+ this.children = [];
+ this.depth = 0;
+ this._isDeprecated = false;
+ this.deprecatedTargets = null;
+ this.leftId = 0;
+ this.rightId = 0;
+ this.entry = undefined;
+ this.description = '';
+ }
+
+ get functionName() {
+ return this.entry?.functionName;
+ }
+
+ toString() {
+ return `Map(${this.id})`;
+ }
+
+ toStringLong() {
+ return `Map(${this.id}):\n${this.description}`;
}
finalizeRootMap(id) {
@@ -59,9 +72,9 @@ class MapLogEntry extends LogEntry {
console.warn('Skipping potential parent loop between maps:', current)
continue;
}
- current.finalize(id)
+ current.finalize(id);
id += 1;
- current.children.forEach(edge => stack.push(edge.to))
+ current.children.forEach(edge => stack.push(edge.to));
// TODO implement rightId
}
return id;
@@ -75,8 +88,7 @@ class MapLogEntry extends LogEntry {
}
parent() {
- if (this.edge === void 0) return void 0;
- return this.edge.from;
+ return this.edge?.from;
}
isDeprecated() {
@@ -88,7 +100,7 @@ class MapLogEntry extends LogEntry {
}
isRoot() {
- return this.edge === void 0 || this.edge.from === void 0;
+ return this.edge === undefined || this.edge.from === undefined;
}
contains(map) {
@@ -111,9 +123,10 @@ class MapLogEntry extends LogEntry {
}
position(chunks) {
- let index = this.chunkIndex(chunks);
- let xFrom = (index + 1.5) * kChunkWidth;
- let yFrom = kChunkHeight - chunks[index].yOffset(this);
+ const index = this.chunkIndex(chunks);
+ if (index === -1) return [0, 0];
+ const xFrom = (index + 1.5) * kChunkWidth;
+ const yFrom = kChunkHeight - chunks[index].yOffset(this);
return [xFrom, yFrom];
}
@@ -131,11 +144,19 @@ class MapLogEntry extends LogEntry {
}
get type() {
- return this.edge === void 0 ? 'new' : this.edge.type;
+ return this.edge?.type ?? 'new';
+ }
+
+ get reason() {
+ return this.edge?.reason;
+ }
+
+ get property() {
+ return this.edge?.name;
}
isBootstrapped() {
- return this.edge === void 0;
+ return this.edge === undefined;
}
getParents() {
@@ -150,15 +171,16 @@ class MapLogEntry extends LogEntry {
static get(id, time = undefined) {
let maps = this.cache.get(id);
- if (maps) {
+ if (maps === undefined) return undefined;
+ if (time !== undefined) {
for (let i = 1; i < maps.length; i++) {
if (maps[i].time > time) {
return maps[i - 1];
}
}
- // default return the latest
- return (maps.length > 0) ? maps[maps.length - 1] : undefined;
}
+ // default return the latest
+ return maps[maps.length - 1];
}
static set(id, map) {
@@ -168,6 +190,13 @@ class MapLogEntry extends LogEntry {
this.cache.set(id, [map]);
}
}
+
+ static get propertyNames() {
+ return [
+ 'type', 'reason', 'property', 'functionName', 'sourcePosition', 'script',
+ 'id'
+ ];
+ }
}
MapLogEntry.cache = new Map();
@@ -183,17 +212,29 @@ class Edge {
this.to = to;
}
+ updateFrom(edge) {
+ if (this.to !== edge.to || this.from !== edge.from) {
+ throw new Error('Invalid Edge updated', this, to);
+ }
+ this.type = edge.type;
+ this.name = edge.name;
+ this.reason = edge.reason;
+ this.time = edge.time;
+ }
+
finishSetup() {
const from = this.from;
- if (from) from.addEdge(this);
const to = this.to;
+ if (to?.time < from?.time) {
+ // This happens for map deprecation where the transition tree is converted
+ // in reverse order.
+ console.warn('Invalid time order');
+ }
+ if (from) from.addEdge(this);
if (to === undefined) return;
to.edge = this;
if (from === undefined) return;
if (to === from) throw 'From and to must be distinct.';
- if (to.time < from.time) {
- console.warn('invalid time order');
- }
let newDepth = from.depth + 1;
if (to.depth > 0 && to.depth != newDepth) {
console.warn('Depth has already been initialized');
diff --git a/deps/v8/tools/system-analyzer/map-panel-template.html b/deps/v8/tools/system-analyzer/map-panel-template.html
deleted file mode 100644
index 12d6ec5a14..0000000000
--- a/deps/v8/tools/system-analyzer/map-panel-template.html
+++ /dev/null
@@ -1,21 +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. -->
-
-<head>
- <link href="./index.css" rel="stylesheet">
-</head>
-<style>
- #searchBarInput {
- width: 200px;
- }
-</style>
-<div class="panel">
- <h2>Map Panel</h2>
- <map-transitions id="map-transitions"></map-transitions>
- <h3>Search Map by Address</h3>
- <section id="searchBar"></section>
- <input type="search" id="searchBarInput"></input>
- <button id="searchBarBtn">Search</button>
- <map-details id="map-details"></map-details>
-</div>
diff --git a/deps/v8/tools/system-analyzer/map-panel.mjs b/deps/v8/tools/system-analyzer/map-panel.mjs
deleted file mode 100644
index 1516038a2d..0000000000
--- a/deps/v8/tools/system-analyzer/map-panel.mjs
+++ /dev/null
@@ -1,72 +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.
-import './stats-panel.mjs';
-import './map-panel/map-details.mjs';
-import './map-panel/map-transitions.mjs';
-
-import {FocusEvent} from './events.mjs';
-import {DOM, V8CustomElement} from './helper.mjs';
-import {MapLogEntry} from './log/map.mjs';
-
-DOM.defineCustomElement('map-panel',
- (templateText) =>
- class MapPanel extends V8CustomElement {
- _map;
- constructor() {
- super(templateText);
- this.searchBarBtn.addEventListener('click', e => this.handleSearchBar(e));
- this.addEventListener(FocusEvent.name, e => this.handleUpdateMapDetails(e));
- }
-
- handleUpdateMapDetails(e) {
- if (e.entry instanceof MapLogEntry) {
- this.mapDetailsPanel.map = e.entry;
- }
- }
-
- get mapTransitionsPanel() {
- return this.$('#map-transitions');
- }
-
- get mapDetailsPanel() {
- return this.$('#map-details');
- }
-
- get searchBarBtn() {
- return this.$('#searchBarBtn');
- }
-
- get searchBar() {
- return this.$('#searchBar');
- }
-
- set timeline(timeline) {
- this._timeline = timeline;
- }
-
- set map(value) {
- this._map = value;
- this.mapTransitionsPanel.map = this._map;
- }
-
- handleSearchBar(e) {
- let searchBar = this.$('#searchBarInput');
- let searchBarInput = searchBar.value;
- // access the map from model cache
- let selectedMap = MapLogEntry.get(parseInt(searchBarInput));
- if (selectedMap) {
- searchBar.className = 'success';
- } else {
- searchBar.className = 'failure';
- }
- this.dispatchEvent(new FocusEvent(selectedMap));
- }
-
- set selectedMapLogEntries(list) {
- this.mapTransitionsPanel.selectedMapLogEntries = list;
- }
- get selectedMapLogEntries() {
- return this.mapTransitionsPanel.selectedMapLogEntries;
- }
-});
diff --git a/deps/v8/tools/system-analyzer/map-panel/map-transitions.mjs b/deps/v8/tools/system-analyzer/map-panel/map-transitions.mjs
deleted file mode 100644
index 60462a1db2..0000000000
--- a/deps/v8/tools/system-analyzer/map-panel/map-transitions.mjs
+++ /dev/null
@@ -1,184 +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.
-import {FocusEvent, SelectionEvent} from '../events.mjs';
-import {DOM, typeToColor, V8CustomElement} from '../helper.mjs';
-
-DOM.defineCustomElement('./map-panel/map-transitions',
- (templateText) =>
- class MapTransitions extends V8CustomElement {
- _map;
- _selectedMapLogEntries;
- _displayedMapsInTree;
-
- constructor() {
- super(templateText);
- this.transitionView.addEventListener(
- 'mousemove', (e) => this.handleTransitionViewChange(e));
- this.currentNode = this.transitionView;
- this.currentMap = undefined;
- }
-
- get transitionView() {
- return this.$('#transitionView');
- }
-
- get tooltip() {
- return this.$('#tooltip');
- }
-
- get tooltipContents() {
- return this.$('#tooltipContents');
- }
-
- set map(value) {
- this._map = value;
- this.showMap();
- }
-
- handleTransitionViewChange(e) {
- this.tooltip.style.left = e.pageX + 'px';
- this.tooltip.style.top = e.pageY + 'px';
- const map = e.target.map;
- if (map) {
- this.tooltipContents.innerText = map.description;
- }
- }
-
- _selectMap(map) {
- this.dispatchEvent(new SelectionEvent([map]));
- }
-
- showMap() {
- if (this.currentMap === this._map) return;
- this.currentMap = this._map;
- this.selectedMapLogEntries = [this._map];
- this.update();
- }
-
- _update() {
- this.transitionView.style.display = 'none';
- DOM.removeAllChildren(this.transitionView);
- this._displayedMapsInTree = new Set();
- // Limit view to 200 maps for performance reasons.
- this.selectedMapLogEntries.slice(0, 200).forEach(
- (map) => this.addMapAndParentTransitions(map));
- this._displayedMapsInTree = undefined;
- this.transitionView.style.display = '';
- }
-
- set selectedMapLogEntries(list) {
- this._selectedMapLogEntries = list;
- this.update();
- }
-
- get selectedMapLogEntries() {
- return this._selectedMapLogEntries;
- }
-
- addMapAndParentTransitions(map) {
- if (map === void 0) return;
- if (this._displayedMapsInTree.has(map)) return;
- this._displayedMapsInTree.add(map);
- this.currentNode = this.transitionView;
- let parents = map.getParents();
- if (parents.length > 0) {
- this.addTransitionTo(parents.pop());
- parents.reverse().forEach((each) => this.addTransitionTo(each));
- }
- let mapNode = this.addSubtransitions(map);
- // Mark and show the selected map.
- mapNode.classList.add('selected');
- if (this.selectedMap == map) {
- setTimeout(
- () => mapNode.scrollIntoView({
- behavior: 'smooth',
- block: 'nearest',
- inline: 'nearest',
- }),
- 1);
- }
- }
-
- addSubtransitions(map) {
- let mapNode = this.addTransitionTo(map);
- // Draw outgoing linear transition line.
- let current = map;
- while (current.children.length == 1) {
- current = current.children[0].to;
- this.addTransitionTo(current);
- }
- return mapNode;
- }
-
- addTransitionEdge(map) {
- let classes = ['transitionEdge'];
- let edge = DOM.div(classes);
- edge.style.backgroundColor = typeToColor(map.edge);
- let labelNode = DOM.div('transitionLabel');
- labelNode.innerText = map.edge.toString();
- edge.appendChild(labelNode);
- return edge;
- }
-
- addTransitionTo(map) {
- // transition[ transitions[ transition[...], transition[...], ...]];
- this._displayedMapsInTree?.add(map);
- let transition = DOM.div('transition');
- if (map.isDeprecated()) transition.classList.add('deprecated');
- if (map.edge) {
- transition.appendChild(this.addTransitionEdge(map));
- }
- let mapNode = this.addMapNode(map);
- transition.appendChild(mapNode);
-
- let subtree = DOM.div('transitions');
- transition.appendChild(subtree);
-
- this.currentNode.appendChild(transition);
- this.currentNode = subtree;
-
- return mapNode;
- }
-
- addMapNode(map) {
- let node = DOM.div('map');
- if (map.edge) node.style.backgroundColor = typeToColor(map.edge);
- node.map = map;
- node.addEventListener('click', () => this._selectMap(map));
- if (map.children.length > 1) {
- node.innerText = map.children.length;
- let showSubtree = DOM.div('showSubtransitions');
- showSubtree.addEventListener('click', (e) => this.toggleSubtree(e, node));
- node.appendChild(showSubtree);
- } else if (map.children.length == 0) {
- node.innerHTML = '&#x25CF;';
- }
- this.currentNode.appendChild(node);
- return node;
- }
-
- toggleSubtree(event, node) {
- let map = node.map;
- event.target.classList.toggle('opened');
- let transitionsNode = node.parentElement.querySelector('.transitions');
- let subtransitionNodes = transitionsNode.children;
- if (subtransitionNodes.length <= 1) {
- // Add subtransitions excepth the one that's already shown.
- let visibleTransitionMap = subtransitionNodes.length == 1 ?
- transitionsNode.querySelector('.map').map :
- void 0;
- map.children.forEach((edge) => {
- if (edge.to != visibleTransitionMap) {
- this.currentNode = transitionsNode;
- this.addSubtransitions(edge.to);
- }
- });
- } else {
- // remove all but the first (currently selected) subtransition
- for (let i = subtransitionNodes.length - 1; i > 0; i--) {
- transitionsNode.removeChild(subtransitionNodes[i]);
- }
- }
- }
-});
diff --git a/deps/v8/tools/system-analyzer/processor.mjs b/deps/v8/tools/system-analyzer/processor.mjs
index 49448bb9da..9685e09ad6 100644
--- a/deps/v8/tools/system-analyzer/processor.mjs
+++ b/deps/v8/tools/system-analyzer/processor.mjs
@@ -5,7 +5,8 @@
import {LogReader, parseString, parseVarArgs} from '../logreader.mjs';
import {Profile} from '../profile.mjs';
-import {DeoptLogEntry} from './log/deopt.mjs';
+import {ApiLogEntry} from './log/api.mjs';
+import {CodeLogEntry, DeoptLogEntry} from './log/code.mjs';
import {IcLogEntry} from './log/ic.mjs';
import {Edge, MapLogEntry} from './log/map.mjs';
import {Timeline} from './timeline.mjs';
@@ -17,17 +18,28 @@ export class Processor extends LogReader {
_mapTimeline = new Timeline();
_icTimeline = new Timeline();
_deoptTimeline = new Timeline();
+ _codeTimeline = new Timeline();
+ _apiTimeline = new Timeline();
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
+ _lastTimestamp = 0;
+ _lastCodeLogEntry;
MAJOR_VERSION = 7;
MINOR_VERSION = 6;
constructor(logString) {
super();
- this.propertyICParser = [
+ const propertyICParser = [
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
parseString, parseString, parseString, parseString
];
this.dispatchTable_ = {
__proto__: null,
+ 'v8-version': {
+ parsers: [
+ parseInt,
+ parseInt,
+ ],
+ processor: this.processV8Version
+ },
'code-creation': {
parsers: [
parseString, parseInt, parseInt, parseInt, parseInt, parseString,
@@ -42,20 +54,28 @@ export class Processor extends LogReader {
],
processor: this.processCodeDeopt
},
- 'v8-version': {
+ 'code-move':
+ {parsers: [parseInt, parseInt], processor: this.processCodeMove},
+ 'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
+ 'code-source-info': {
+ parsers: [
+ parseInt, parseInt, parseInt, parseInt, parseString, parseString,
+ parseString
+ ],
+ processor: this.processCodeSourceInfo
+ },
+ 'code-disassemble': {
parsers: [
parseInt,
- parseInt,
+ parseString,
+ parseString,
],
- processor: this.processV8Version
+ processor: this.processCodeDisassemble
},
'script-source': {
parsers: [parseInt, parseString, parseString],
processor: this.processScriptSource
},
- 'code-move':
- {parsers: [parseInt, parseInt], processor: this.processCodeMove},
- 'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
'sfi-move':
{parsers: [parseInt, parseInt], processor: this.processFunctionMove},
'map-create':
@@ -72,33 +92,37 @@ export class Processor extends LogReader {
processor: this.processMapDetails
},
'LoadGlobalIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'LoadGlobalIC')
},
'StoreGlobalIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreGlobalIC')
},
'LoadIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'LoadIC')
},
'StoreIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreIC')
},
'KeyedLoadIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'KeyedLoadIC')
},
'KeyedStoreIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'KeyedStoreIC')
},
'StoreInArrayLiteralIC': {
- parsers: this.propertyICParser,
+ parsers: propertyICParser,
processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
},
+ 'api': {
+ parsers: [parseString, parseVarArgs],
+ processor: this.processApiEvent
+ },
};
if (logString) this.processString(logString);
}
@@ -166,45 +190,56 @@ export class Processor extends LogReader {
});
}
- /**
- * Parser for dynamic code optimization state.
- */
- parseState(s) {
- switch (s) {
- case '':
- return Profile.CodeState.COMPILED;
- case '~':
- return Profile.CodeState.OPTIMIZABLE;
- case '*':
- return Profile.CodeState.OPTIMIZED;
+ processV8Version(majorVersion, minorVersion) {
+ if ((majorVersion == this.MAJOR_VERSION &&
+ minorVersion <= this.MINOR_VERSION) ||
+ (majorVersion < this.MAJOR_VERSION)) {
+ window.alert(
+ `Unsupported version ${majorVersion}.${minorVersion}. \n` +
+ `Please use the matching tool for given the V8 version.`);
}
- throw new Error(`unknown code state: ${s}`);
}
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
+ this._lastTimestamp = timestamp;
+ let entry;
+ let stateName = '';
if (maybe_func.length) {
const funcAddr = parseInt(maybe_func[0]);
- const state = this.parseState(maybe_func[1]);
- this._profile.addFuncCode(
+ stateName = maybe_func[1] ?? '';
+ const state = Profile.parseState(maybe_func[1]);
+ entry = this._profile.addFuncCode(
type, name, timestamp, start, size, funcAddr, state);
} else {
- this._profile.addCode(type, name, timestamp, start, size);
+ entry = this._profile.addCode(type, name, timestamp, start, size);
}
+ this._lastCodeLogEntry =
+ new CodeLogEntry(type + stateName, timestamp, kind, entry);
+ this._codeTimeline.push(this._lastCodeLogEntry);
}
processCodeDeopt(
timestamp, codeSize, instructionStart, inliningId, scriptOffset,
deoptKind, deoptLocation, deoptReason) {
- this._deoptTimeline.push(new DeoptLogEntry(deoptKind, timestamp));
- }
-
- processV8Version(majorVersion, minorVersion) {
- if ((majorVersion == this.MAJOR_VERSION &&
- minorVersion <= this.MINOR_VERSION) ||
- (majorVersion < this.MAJOR_VERSION)) {
- window.alert(
- `Unsupported version ${majorVersion}.${minorVersion}. \n` +
- `Please use the matching tool for given the V8 version.`);
+ this._lastTimestamp = timestamp;
+ const codeEntry = this._profile.findEntry(instructionStart);
+ const logEntry = new DeoptLogEntry(
+ deoptKind, timestamp, codeEntry, deoptReason, deoptLocation,
+ scriptOffset, instructionStart, codeSize, inliningId);
+ this._deoptTimeline.push(logEntry);
+ this.addSourcePosition(codeEntry, logEntry);
+ logEntry.functionSourcePosition = logEntry.sourcePosition;
+ // custom parse deopt location
+ if (deoptLocation !== '<unknown>') {
+ const colSeparator = deoptLocation.lastIndexOf(':');
+ const rowSeparator = deoptLocation.lastIndexOf(':', colSeparator - 1);
+ const script = this.getScript(deoptLocation.substring(1, rowSeparator));
+ const line =
+ parseInt(deoptLocation.substring(rowSeparator + 1, colSeparator));
+ const column = parseInt(
+ deoptLocation.substring(colSeparator + 1, deoptLocation.length - 1));
+ logEntry.sourcePosition =
+ script.addSourcePosition(line, column, logEntry);
}
}
@@ -224,111 +259,138 @@ export class Processor extends LogReader {
this._profile.moveFunc(from, to);
}
- formatName(entry) {
- if (!entry) return '<unknown>';
- let name = entry.func.getName();
- let re = /(.*):[0-9]+:[0-9]+$/;
- let array = re.exec(name);
- if (!array) return name;
- return entry.getState() + array[1];
+ processCodeSourceInfo(
+ start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
+ inlinedFunctions) {
+ this._profile.addSourcePositions(
+ start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
+ inlinedFunctions);
+ let profileEntry = this._profile.findEntry(start);
+ if (profileEntry !== this._lastCodeLogEntry._entry) return;
+ this.addSourcePosition(profileEntry, this._lastCodeLogEntry);
+ this._lastCodeLogEntry = undefined;
+ }
+
+ addSourcePosition(profileEntry, logEntry) {
+ let script = this.getProfileEntryScript(profileEntry);
+ const parts = profileEntry.getRawName().split(':');
+ if (parts.length < 3) return;
+ const line = parseInt(parts[parts.length - 2]);
+ const column = parseInt(parts[parts.length - 1]);
+ logEntry.sourcePosition = script.addSourcePosition(line, column, logEntry);
+ }
+
+ processCodeDisassemble(start, kind, disassemble) {
+ this._profile.addDisassemble(start, kind, disassemble);
}
processPropertyIC(
- type, pc, time, line, column, old_state, new_state, map, key, modifier,
+ type, pc, time, line, column, old_state, new_state, mapId, key, modifier,
slow_reason) {
- let fnName = this.functionName(pc);
- let parts = fnName.split(' ');
- let fileName = parts[parts.length - 1];
- let script = this.getScript(fileName);
+ this._lastTimestamp = time;
+ const profileEntry = this._profile.findEntry(pc);
+ const fnName = this.formatProfileEntry(profileEntry);
+ const script = this.getProfileEntryScript(profileEntry);
+ const map = this.getOrCreateMapEntry(mapId, time);
// TODO: Use SourcePosition here directly
let entry = new IcLogEntry(
type, fnName, time, line, column, key, old_state, new_state, map,
- slow_reason, script, modifier);
+ slow_reason, modifier);
if (script) {
entry.sourcePosition = script.addSourcePosition(line, column, entry);
}
this._icTimeline.push(entry);
}
- functionName(pc) {
- let entry = this._profile.findEntry(pc);
- return this.formatName(entry);
- }
- formatPC(pc, line, column) {
- let entry = this._profile.findEntry(pc);
- if (!entry) return '<unknown>'
- if (entry.type === 'Builtin') {
- return entry.name;
- }
- let name = entry.func.getName();
- let array = this._formatPCRegexp.exec(name);
- if (array === null) {
- entry = name;
- } else {
- entry = entry.getState() + array[1];
- }
- return entry + ':' + line + ':' + column;
+ formatProfileEntry(profileEntry, line, column) {
+ if (!profileEntry) return '<unknown>';
+ if (profileEntry.type === 'Builtin') return profileEntry.name;
+ const name = profileEntry.func.getName();
+ const array = this._formatPCRegexp.exec(name);
+ const formatted =
+ (array === null) ? name : profileEntry.getState() + array[1];
+ if (line === undefined || column === undefined) return formatted;
+ return `${formatted}:${line}:${column}`;
}
- processFileName(filePositionLine) {
- if (!filePositionLine.includes(' ')) return;
- // Try to handle urls with file positions: https://foo.bar.com/:17:330"
- filePositionLine = filePositionLine.split(' ');
- let parts = filePositionLine[1].split(':');
- if (parts[0].length <= 5) return parts[0] + ':' + parts[1];
- return parts[1];
+ getProfileEntryScript(profileEntry) {
+ if (!profileEntry) return undefined;
+ if (profileEntry.type === 'Builtin') return undefined;
+ const script = profileEntry.source?.script;
+ if (script !== undefined) return script;
+ // Slow path, try to get the script from the url:
+ const fnName = this.formatProfileEntry(profileEntry);
+ let parts = fnName.split(' ');
+ let fileName = parts[parts.length - 1];
+ return this.getScript(fileName);
}
processMap(type, time, from, to, pc, line, column, reason, name) {
- let time_ = parseInt(time);
+ this._lastTimestamp = time;
+ const time_ = parseInt(time);
if (type === 'Deprecate') return this.deprecateMap(type, time_, from);
- let from_ = this.getExistingMapEntry(from, time_);
- let to_ = this.getExistingMapEntry(to, time_);
+ // Skip normalized maps that were cached so we don't introduce multiple
+ // edges with the same source and target map.
+ if (type === 'NormalizeCached') return;
+ const from_ = this.getOrCreateMapEntry(from, time_);
+ const to_ = this.getOrCreateMapEntry(to, time_);
+ if (type === 'Normalize') {
+ // Fix a bug where we log "Normalize" transitions for maps created from
+ // the NormalizedMapCache.
+ if (to_.parent()?.id === from || to_.time < from_.time || to_.depth > 0) {
+ console.log(`Skipping transition to cached normalized map`);
+ return;
+ }
+ }
// TODO: use SourcePosition directly.
let edge = new Edge(type, name, reason, time, from_, to_);
- to_.filePosition = this.formatPC(pc, line, column);
- let fileName = this.processFileName(to_.filePosition);
- // TODO: avoid undefined source positions.
- if (fileName !== undefined) {
- to_.script = this.getScript(fileName);
+ const profileEntry = this._profile.findEntry(pc)
+ to_.entry = profileEntry;
+ let script = this.getProfileEntryScript(profileEntry);
+ if (script) {
+ to_.sourcePosition = script.addSourcePosition(line, column, to_)
}
- if (to_.script) {
- to_.sourcePosition = to_.script.addSourcePosition(line, column, to_)
+ if (to_.parent() !== undefined && to_.parent() === from_) {
+ // Fix bug where we double log transitions.
+ console.warn('Fixing up double transition');
+ to_.edge.updateFrom(edge);
+ } else {
+ edge.finishSetup();
}
- edge.finishSetup();
}
deprecateMap(type, time, id) {
- this.getExistingMapEntry(id, time).deprecate();
+ this._lastTimestamp = time;
+ this.getOrCreateMapEntry(id, time).deprecate();
}
processMapCreate(time, id) {
// map-create events might override existing maps if the addresses get
// recycled. Hence we do not check for existing maps.
- let map = this.createMapEntry(id, time);
+ this._lastTimestamp = time;
+ this.createMapEntry(id, time);
}
processMapDetails(time, id, string) {
// TODO(cbruni): fix initial map logging.
- let map = this.getExistingMapEntry(id, time);
+ const map = this.getOrCreateMapEntry(id, time);
map.description = string;
}
createMapEntry(id, time) {
- let map = new MapLogEntry(id, time);
+ this._lastTimestamp = time;
+ const map = new MapLogEntry(id, time);
this._mapTimeline.push(map);
return map;
}
- getExistingMapEntry(id, time) {
+ getOrCreateMapEntry(id, time) {
if (id === '0x000000000000') return undefined;
- let map = MapLogEntry.get(id, time);
- if (map === undefined) {
- console.error(`No map details provided: id=${id}`);
- // Manually patch in a map to continue running.
- return this.createMapEntry(id, time);
- };
- return map;
+ const map = MapLogEntry.get(id, time);
+ if (map !== undefined) return map;
+ console.warn(`No map details provided: id=${id}`);
+ // Manually patch in a map to continue running.
+ return this.createMapEntry(id, time);
}
getScript(url) {
@@ -340,6 +402,22 @@ export class Processor extends LogReader {
return script;
}
+ processApiEvent(type, varArgs) {
+ let name, arg1;
+ if (varArgs.length == 0) {
+ const index = type.indexOf(':');
+ if (index > 0) {
+ name = type;
+ type = type.substr(0, index);
+ }
+ } else {
+ name = varArgs[0];
+ arg1 = varArgs[1];
+ }
+ this._apiTimeline.push(
+ new ApiLogEntry(type, this._lastTimestamp, name, arg1));
+ }
+
get icTimeline() {
return this._icTimeline;
}
@@ -352,7 +430,19 @@ export class Processor extends LogReader {
return this._deoptTimeline;
}
+ get codeTimeline() {
+ return this._codeTimeline;
+ }
+
+ get apiTimeline() {
+ return this._apiTimeline;
+ }
+
get scripts() {
return this._profile.scripts_.filter(script => script !== undefined);
}
+
+ get profile() {
+ return this._profile;
+ }
}
diff --git a/deps/v8/tools/system-analyzer/source-panel-template.html b/deps/v8/tools/system-analyzer/source-panel-template.html
deleted file mode 100644
index 01b777042f..0000000000
--- a/deps/v8/tools/system-analyzer/source-panel-template.html
+++ /dev/null
@@ -1,54 +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. -->
-
-<head>
- <link href="./index.css" rel="stylesheet">
-</head>
-<style>
- pre.scriptNode {
- white-space: pre-wrap;
- }
-
- pre.scriptNode:before {
- counter-reset: sourceLineCounter;
- }
-
- pre.scriptNode span {
- counter-increment: sourceLineCounter;
- }
-
- pre.scriptNode span::before {
- content: counter(sourceLineCounter) ": ";
- display: inline-block;
- width: 4em;
- padding-left: auto;
- margin-left: auto;
- text-align: right;
- }
-
- mark {
- width: 1ch;
- border-radius: 2px;
- border: 0.5px var(--background-color) solid;
- cursor: pointer;
- background-color: var(--primary-color);
- color: var(--on-primary-color);
- }
-
- .marked {
- background-color: var(--secondary-color);
- }
-
- #script-dropdown {
- width: 100%;
- margin-bottom: 10px;
- }
-</style>
-<div class="panel">
- <h2>Source Panel</h2>
- <select id="script-dropdown"></select>
- <div id="script" class="panelBody">
- <pre class="scripNode"></pre>
- </div>
-</div>
diff --git a/deps/v8/tools/system-analyzer/stats-panel-template.html b/deps/v8/tools/system-analyzer/stats-panel-template.html
deleted file mode 100644
index fb91fad1cf..0000000000
--- a/deps/v8/tools/system-analyzer/stats-panel-template.html
+++ /dev/null
@@ -1,73 +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. -->
-
-<head>
- <link href="./index.css" rel="stylesheet">
-</head>
-<style>
- #stats {
- display: flex;
- height: 250px;
- background-color: var(--surface-color);
- padding: 10px 10px 10px 10px;
- margin: auto;
- }
-
- table {
- flex: 1;
- max-height: 250px;
- display: inline-block;
- overflow-y: scroll;
- border-collapse: collapse;
- }
- table td {
- padding: 2px;
- }
-
- table thead td {
- border-bottom: 1px var(--on-surface-color) dotted;
- }
-
- table tbody td {
- cursor: pointer;
- }
-
- #nameTable tr {
- max-width: 200px;
-
- }
-
- #nameTable tr td:nth-child(1) {
- text-align: right;
- }
-
- #typeTable {
- text-align: right;
- max-width: 380px;
- }
-
- #typeTable tr td:nth-child(2) {
- text-align: left;
- }
-</style>
-<div class="panel">
- <h2>Map Stats</h2>
- <section id="stats">
- <table id="typeTable" class="statsTable">
- <thead>
- <tr><td></td><td>Type</td><td>Count</td><td>Percent</td></tr>
- </thead>
- <tbody></tbody>
- </table>
- <table id="nameTable">
- <thead>
- <tr><td>Count</td><td>Propery Name</td></tr>
- </thead>
- <tbody></tbody>
- <tfoot>
- <tr><td colspan="2" class="clickable">Show more...</td></tr>
- </tfoo>
- </table>
- </section>
-</div>
diff --git a/deps/v8/tools/system-analyzer/stats-panel.mjs b/deps/v8/tools/system-analyzer/stats-panel.mjs
deleted file mode 100644
index dd0ac78489..0000000000
--- a/deps/v8/tools/system-analyzer/stats-panel.mjs
+++ /dev/null
@@ -1,129 +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.
-import {SelectionEvent} from './events.mjs';
-import {DOM, V8CustomElement} from './helper.mjs';
-import {delay, LazyTable} from './helper.mjs';
-
-DOM.defineCustomElement(
- 'stats-panel', (templateText) => class StatsPanel extends V8CustomElement {
- _timeline;
- _transitions;
- _selectedLogEntries;
- constructor() {
- super(templateText);
- }
-
- get stats() {
- return this.$('#stats');
- }
-
- set timeline(timeline) {
- this._timeline = timeline;
- this.selectedLogEntries = timeline.all
- }
-
- set selectedLogEntries(entries) {
- this._selectedLogEntries = entries;
- this.update();
- }
-
- set transitions(value) {
- this._transitions = value;
- }
-
- _filterUniqueTransitions(filter) {
- // Returns a list of Maps whose parent is not in the list.
- return this._selectedLogEntries.filter((map) => {
- if (filter(map) === false) return false;
- let parent = map.parent();
- if (parent === undefined) return true;
- return filter(parent) === false;
- });
- }
-
- _update() {
- this._updateGeneralStats();
- this._updateNamedTransitionsStats();
- }
-
- _updateGeneralStats() {
- console.assert(this._timeline !== undefined, 'Timeline not set yet!');
- let pairs = [
- ['Transitions', 'primary', (e) => e.edge && e.edge.isTransition()],
- ['Fast to Slow', 'violet', (e) => e.edge && e.edge.isFastToSlow()],
- ['Slow to Fast', 'orange', (e) => e.edge && e.edge.isSlowToFast()],
- ['Initial Map', 'yellow', (e) => e.edge && e.edge.isInitial()],
- [
- 'Replace Descriptors',
- 'red',
- (e) => e.edge && e.edge.isReplaceDescriptors(),
- ],
- [
- 'Copy as Prototype',
- 'red',
- (e) => e.edge && e.edge.isCopyAsPrototype(),
- ],
- [
- 'Optimize as Prototype',
- null,
- (e) => e.edge && e.edge.isOptimizeAsPrototype(),
- ],
- ['Deprecated', null, (e) => e.isDeprecated()],
- ['Bootstrapped', 'green', (e) => e.isBootstrapped()],
- ['Total', null, (e) => true],
- ];
-
- let tbody = document.createElement('tbody');
- let total = this._selectedLogEntries.length;
- pairs.forEach(([name, color, filter]) => {
- let row = DOM.tr();
- if (color !== null) {
- row.appendChild(DOM.td(DOM.div(['colorbox', color])));
- } else {
- row.appendChild(DOM.td(''));
- }
- row.classList.add('clickable');
- row.onclick = (e) => {
- // lazily compute the stats
- let node = e.target.parentNode;
- if (node.maps == undefined) {
- node.maps = this._filterUniqueTransitions(filter);
- }
- this.dispatchEvent(new SelectionEvent(node.maps));
- };
- row.appendChild(DOM.td(name));
- let count = this._count(filter);
- row.appendChild(DOM.td(count));
- let percent = Math.round((count / total) * 1000) / 10;
- row.appendChild(DOM.td(percent.toFixed(1) + '%'));
- tbody.appendChild(row);
- });
- this.$('#typeTable').replaceChild(tbody, this.$('#typeTable tbody'));
- }
-
- _count(filter) {
- let count = 0;
- for (const map of this._selectedLogEntries) {
- if (filter(map)) count++;
- }
- return count;
- }
-
- _updateNamedTransitionsStats() {
- let rowData = Array.from(this._transitions.entries());
- rowData.sort((a, b) => b[1].length - a[1].length);
- new LazyTable(this.$('#nameTable'), rowData, ([name, maps]) => {
- let row = DOM.tr();
- row.maps = maps;
- row.classList.add('clickable');
- row.addEventListener(
- 'click',
- (e) => this.dispatchEvent(new SelectionEvent(
- e.target.parentNode.maps.map((map) => map.to))));
- row.appendChild(DOM.td(maps.length));
- row.appendChild(DOM.td(name));
- return row;
- });
- }
- });
diff --git a/deps/v8/tools/system-analyzer/timeline-panel-template.html b/deps/v8/tools/system-analyzer/timeline-panel-template.html
deleted file mode 100644
index 2641c71441..0000000000
--- a/deps/v8/tools/system-analyzer/timeline-panel-template.html
+++ /dev/null
@@ -1,13 +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. -->
-
-<head>
- <link href="./index.css" rel="stylesheet">
-</head>
-<div class="panel">
- <h2>Timeline Panel</h2>
- <div>
- <slot></slot>
- </div>
-</div>
diff --git a/deps/v8/tools/system-analyzer/timeline.mjs b/deps/v8/tools/system-analyzer/timeline.mjs
index 996f108b6a..13e97553e6 100644
--- a/deps/v8/tools/system-analyzer/timeline.mjs
+++ b/deps/v8/tools/system-analyzer/timeline.mjs
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import {groupBy} from './helper.mjs'
+
class Timeline {
// Class:
_model;
@@ -9,13 +11,13 @@ class Timeline {
_values;
// Current selection, subset of #values:
_selection;
- _uniqueTypes;
+ _breakdown;
- constructor(model) {
+ constructor(model, values = [], startTime = 0, endTime = 0) {
this._model = model;
- this._values = [];
- this.startTime = 0;
- this.endTime = 0;
+ this._values = values;
+ this.startTime = startTime;
+ this.endTime = endTime;
}
get model() {
@@ -30,21 +32,28 @@ class Timeline {
return this._selection;
}
+ get selectionOrSelf() {
+ return this._selection ?? this;
+ }
+
set selection(value) {
this._selection = value;
}
- selectTimeRange(start, end) {
- this._selection = this.filter(e => e.time >= start && e.time <= end);
+ selectTimeRange(startTime, endTime) {
+ const items = this.range(startTime, endTime);
+ this._selection = new Timeline(this._model, items, startTime, endTime);
+ }
+
+ clearSelection() {
+ this._selection = undefined;
}
getChunks(windowSizeMs) {
- // TODO(zcankara) Fill this one
return this.chunkSizes(windowSizeMs);
}
get values() {
- // TODO(zcankara) Not to break something delete later
return this._values;
}
@@ -94,6 +103,10 @@ class Timeline {
return this._values.length;
}
+ slice(startIndex, endIndex) {
+ return this._values.slice(startIndex, endIndex);
+ }
+
first() {
return this._values[0];
}
@@ -102,17 +115,23 @@ class Timeline {
return this._values[this._values.length - 1];
}
+ * [Symbol.iterator]() {
+ yield* this._values;
+ }
+
duration() {
+ if (this.isEmpty()) return 0;
return this.last().time - this.first().time;
}
forEachChunkSize(count, fn) {
+ if (this.isEmpty()) return;
const increment = this.duration() / count;
let currentTime = this.first().time + increment;
let index = 0;
for (let i = 0; i < count; i++) {
- let nextIndex = this.find(currentTime, index);
- let nextTime = currentTime + increment;
+ const nextIndex = this.find(currentTime, index);
+ const nextTime = currentTime + increment;
fn(index, nextIndex, currentTime, nextTime);
index = nextIndex;
currentTime = nextTime;
@@ -120,56 +139,55 @@ class Timeline {
}
chunkSizes(count) {
- let chunks = [];
+ const chunks = [];
this.forEachChunkSize(count, (start, end) => chunks.push(end - start));
return chunks;
}
- chunks(count) {
- let chunks = [];
+ chunks(count, predicate = undefined) {
+ const chunks = [];
this.forEachChunkSize(count, (start, end, startTime, endTime) => {
let items = this._values.slice(start, end);
+ if (predicate !== undefined) items = items.filter(predicate);
chunks.push(new Chunk(chunks.length, startTime, endTime, items));
});
return chunks;
}
- range(start, end) {
- const first = this.find(start);
- if (first < 0) return [];
- const last = this.find(end, first);
- return this._values.slice(first, last);
+ // Return all entries in ({startTime}, {endTime}]
+ range(startTime, endTime) {
+ const firstIndex = this.find(startTime);
+ if (firstIndex < 0) return [];
+ const lastIndex = this.find(endTime, firstIndex + 1);
+ return this._values.slice(firstIndex, lastIndex);
}
+ // Return the first index for the first element at {time}.
find(time, offset = 0) {
return this._find(this._values, each => each.time - time, offset);
}
- _find(array, cmp, offset = 0) {
- let min = offset;
- let max = array.length;
- while (min < max) {
- let mid = min + Math.floor((max - min) / 2);
- let result = cmp(array[mid]);
- if (result > 0) {
- max = mid - 1;
+ // Return the first index for which compareFn(item) is >= 0;
+ _find(array, compareFn, offset = 0) {
+ let minIndex = offset;
+ let maxIndex = array.length - 1;
+ while (minIndex < maxIndex) {
+ const midIndex = minIndex + (((maxIndex - minIndex) / 2) | 0);
+ if (compareFn(array[midIndex]) < 0) {
+ minIndex = midIndex + 1;
} else {
- min = mid + 1;
+ maxIndex = midIndex;
}
}
- return min;
+ return minIndex;
}
- initializeTypes() {
- const types = new Map();
- for (const entry of this.all) {
- types.get(entry.type)?.push(entry) ?? types.set(entry.type, [entry])
+ getBreakdown(keyFunction) {
+ if (keyFunction) return groupBy(this._values, keyFunction);
+ if (this._breakdown === undefined) {
+ this._breakdown = groupBy(this._values, each => each.type);
}
- return this._uniqueTypes = types;
- }
-
- get uniqueTypes() {
- return this._uniqueTypes ?? this.initializeTypes();
+ return this._breakdown;
}
depthHistogram() {
@@ -215,6 +233,10 @@ class Chunk {
return this.items.length;
}
+ get length() {
+ return this.items.length;
+ }
+
yOffset(event) {
// items[0] == oldest event, displayed at the top of the chunk
// items[n-1] == youngest event, displayed at the bottom of the chunk
@@ -248,17 +270,8 @@ class Chunk {
return chunk;
}
- getBreakdown(event_fn) {
- if (event_fn === void 0) {
- event_fn = each => each;
- }
- let breakdown = {__proto__: null};
- this.items.forEach(each => {
- const type = event_fn(each);
- const v = breakdown[type];
- breakdown[type] = (v | 0) + 1;
- });
- return Object.entries(breakdown).sort((a, b) => a[1] - b[1]);
+ getBreakdown(keyFunction) {
+ return groupBy(this.items, keyFunction);
}
filter() {
diff --git a/deps/v8/tools/system-analyzer/timeline/timeline-track-template.html b/deps/v8/tools/system-analyzer/timeline/timeline-track-template.html
deleted file mode 100644
index e14b927e4b..0000000000
--- a/deps/v8/tools/system-analyzer/timeline/timeline-track-template.html
+++ /dev/null
@@ -1,138 +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. -->
-
-<head>
- <link href="./index.css" rel="stylesheet">
-</head>
-<style>
- #timeline {
- position: relative;
- height: calc(200px + 12px);
- overflow-y: hidden;
- overflow-x: scroll;
- user-select: none;
- }
-
- #timelineLabel {
- transform: rotate(90deg);
- transform-origin: left bottom 0;
- position: absolute;
- left: 0;
- width: 200px;
- text-align: center;
- font-size: 10px;
- opacity: 0.5;
- }
-
- #timelineChunks {
- height: 200px;
- position: absolute;
- margin-right: 100px;
- }
-
- #timelineCanvas {
- height: 200px;
- position: relative;
- overflow: visible;
- pointer-events: none;
- }
-
- .chunk {
- width: 6px;
- position: absolute;
- background-size: 100% 100%;
- image-rendering: pixelated;
- bottom: 0px;
- background-color: var(--on-surface-color);
- cursor: pointer;
- }
- .chunk:hover {
- border-radius: 2px 2px 0 0;
- margin: 0 0 -2px -2px;
- border: 2px var(--primary-color) solid;
- }
-
- .timestamp {
- height: 200px;
- width: 100px;
- border-left: 1px var(--on-surface-color) dashed;
- padding-left: 4px;
- position: absolute;
- pointer-events: none;
- font-size: 10px;
- }
-
- #legend {
- position: relative;
- float: right;
- width: 100%;
- max-width: 280px;
- padding-left: 20px;
- padding-top: 10px;
- border-collapse: collapse;
- }
-
- th,
- td {
- width: 200px;
- text-align: left;
- padding-bottom: 3px;
- }
-
- /* right align numbers */
- #legend td:nth-of-type(4n+3),
- #legend td:nth-of-type(4n+4) {
- text-align: right;
- }
-
- .legendTypeColumn {
- width: 100%;
- }
-
- .timeline {
- background-color: var(--timeline-background-color);
- }
-
- #timeline .rightHandle,
- #timeline .leftHandle {
- background-color: rgba(200, 200, 200, 0.5);
- height: 100%;
- width: 5px;
- position: absolute;
- z-index: 3;
- cursor: col-resize;
- }
- #timeline .leftHandle {
- border-left: 1px solid var(--on-surface-color);
- }
- #timeline .rightHandle {
- border-right: 1px solid var(--on-surface-color);
- }
-
- #timeline .selection {
- background-color: rgba(133, 68, 163, 0.5);
- height: 100%;
- position: absolute;
- }
-</style>
-<table id="legend" class="typeStatsTable">
- <thead>
- <tr>
- <td></td>
- <td>Type</td>
- <td>Count</td>
- <td>Percent</td>
- </tr>
- </thead>
- <tbody id="legendContent">
- </tbody>
-</table>
-<div id="timeline">
- <div class="leftHandle"></div>
- <div class="selection"></div>
- <div class="rightHandle"></div>
- <div id="timelineLabel">Frequency</div>
- <div id="timelineChunks"></div>
- <canvas id="timelineCanvas"></canvas>
-</div> \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/timeline/timeline-track.mjs b/deps/v8/tools/system-analyzer/timeline/timeline-track.mjs
deleted file mode 100644
index a37bcce2c5..0000000000
--- a/deps/v8/tools/system-analyzer/timeline/timeline-track.mjs
+++ /dev/null
@@ -1,518 +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.
-
-import {FocusEvent, SelectionEvent, SelectTimeEvent, SynchronizeSelectionEvent} from '../events.mjs';
-import {CSSColor, delay, DOM, V8CustomElement} from '../helper.mjs';
-import {kChunkHeight, kChunkWidth} from '../log/map.mjs';
-
-const kColors = [
- CSSColor.green,
- CSSColor.violet,
- CSSColor.orange,
- CSSColor.yellow,
- CSSColor.primaryColor,
- CSSColor.red,
- CSSColor.blue,
- CSSColor.yellow,
- CSSColor.secondaryColor,
-];
-
-DOM.defineCustomElement('./timeline/timeline-track',
- (templateText) =>
- class TimelineTrack extends V8CustomElement {
- // TODO turn into static field once Safari supports it.
- static get SELECTION_OFFSET() {
- return 10
- };
- _timeline;
- _nofChunks = 400;
- _chunks;
- _selectedEntry;
- _timeToPixel;
- _timeSelection = {start: -1, end: Infinity};
- _timeStartOffset;
- _selectionOriginTime;
- _typeToColor;
- constructor() {
- super(templateText);
- this.timeline.addEventListener('scroll', e => this.handleTimelineScroll(e));
- this.timeline.addEventListener(
- 'mousedown', e => this.handleTimeSelectionMouseDown(e));
- this.timeline.addEventListener(
- 'mouseup', e => this.handleTimeSelectionMouseUp(e));
- this.timeline.addEventListener(
- 'mousemove', e => this.handleTimeSelectionMouseMove(e));
- this.backgroundCanvas = document.createElement('canvas');
- this.isLocked = false;
- }
-
- handleTimeSelectionMouseDown(e) {
- let xPosition = e.clientX
- // Update origin time in case we click on a handle.
- if (this.isOnLeftHandle(xPosition)) {
- xPosition = this.rightHandlePosX;
- }
- else if (this.isOnRightHandle(xPosition)) {
- xPosition = this.leftHandlePosX;
- }
- this._selectionOriginTime = this.positionToTime(xPosition);
- }
-
- isOnLeftHandle(posX) {
- return (
- Math.abs(this.leftHandlePosX - posX) <= TimelineTrack.SELECTION_OFFSET);
- }
-
- isOnRightHandle(posX) {
- return (
- Math.abs(this.rightHandlePosX - posX) <=
- TimelineTrack.SELECTION_OFFSET);
- }
-
- handleTimeSelectionMouseMove(e) {
- if (!this._isSelecting) return;
- const currentTime = this.positionToTime(e.clientX);
- this.dispatchEvent(new SynchronizeSelectionEvent(
- Math.min(this._selectionOriginTime, currentTime),
- Math.max(this._selectionOriginTime, currentTime)));
- }
-
- handleTimeSelectionMouseUp(e) {
- this._selectionOriginTime = -1;
- const delta = this._timeSelection.end - this._timeSelection.start;
- if (delta <= 1 || isNaN(delta)) return;
- this.dispatchEvent(new SelectTimeEvent(
- this._timeSelection.start, this._timeSelection.end));
- }
-
- set timeSelection(selection) {
- this._timeSelection.start = selection.start;
- this._timeSelection.end = selection.end;
- this.updateSelection();
- }
-
- get _isSelecting() {
- return this._selectionOriginTime >= 0;
- }
-
- updateSelection() {
- const startPosition = this.timeToPosition(this._timeSelection.start);
- const endPosition = this.timeToPosition(this._timeSelection.end);
- const delta = endPosition - startPosition;
- this.leftHandle.style.left = startPosition + 'px';
- this.selection.style.left = startPosition + 'px';
- this.rightHandle.style.left = endPosition + 'px';
- this.selection.style.width = delta + 'px';
- }
-
- get leftHandlePosX() {
- return this.leftHandle.getBoundingClientRect().x;
- }
-
- get rightHandlePosX() {
- return this.rightHandle.getBoundingClientRect().x;
- }
-
- // Maps the clicked x position to the x position on timeline canvas
- positionOnTimeline(posX) {
- let rect = this.timeline.getBoundingClientRect();
- let posClickedX = posX - rect.left + this.timeline.scrollLeft;
- return posClickedX;
- }
-
- positionToTime(posX) {
- let posTimelineX = this.positionOnTimeline(posX) + this._timeStartOffset;
- return posTimelineX / this._timeToPixel;
- }
-
- timeToPosition(time) {
- let posX = time * this._timeToPixel;
- posX -= this._timeStartOffset
- return posX;
- }
-
- get leftHandle() {
- return this.$('.leftHandle');
- }
-
- get rightHandle() {
- return this.$('.rightHandle');
- }
-
- get selection() {
- return this.$('.selection');
- }
-
- get timelineCanvas() {
- return this.$('#timelineCanvas');
- }
-
- get timelineChunks() {
- return this.$('#timelineChunks');
- }
-
- get timeline() {
- return this.$('#timeline');
- }
-
- get timelineLegend() {
- return this.$('#legend');
- }
-
- get timelineLegendContent() {
- return this.$('#legendContent');
- }
-
- set data(value) {
- this._timeline = value;
- this._resetTypeToColorCache();
- this.update();
- }
-
- _update() {
- this._updateChunks();
- this._updateTimeline();
- this._renderLegend();
- }
-
- _resetTypeToColorCache() {
- this._typeToColor = new Map();
- let lastIndex = 0;
- for (const type of this.data.uniqueTypes.keys()) {
- this._typeToColor.set(type, kColors[lastIndex++]);
- }
- }
-
- get data() {
- return this._timeline;
- }
-
- set nofChunks(count) {
- this._nofChunks = count;
- this.update();
- }
-
- get nofChunks() {
- return this._nofChunks;
- }
-
- _updateChunks() {
- this._chunks = this.data.chunks(this.nofChunks);
- }
-
- get chunks() {
- return this._chunks;
- }
-
- set selectedEntry(value) {
- this._selectedEntry = value;
- if (value.edge) this.redraw();
- }
-
- get selectedEntry() {
- return this._selectedEntry;
- }
-
- set scrollLeft(offset) {
- this.timeline.scrollLeft = offset;
- }
-
- typeToColor(type) {
- return this._typeToColor.get(type);
- }
-
- _renderLegend() {
- let timelineLegendContent = this.timelineLegendContent;
- DOM.removeAllChildren(timelineLegendContent);
- this._timeline.uniqueTypes.forEach((entries, type) => {
- let row = DOM.tr('clickable');
- row.entries = entries;
- row.addEventListener('dblclick', e => this.handleEntryTypeDblClick(e));
- let color = this.typeToColor(type);
- if (color !== null) {
- let div = DOM.div('colorbox');
- div.style.backgroundColor = color;
- row.appendChild(DOM.td(div));
- } else {
- row.appendChild(DOM.td());
- }
- let td = DOM.td(type);
- row.appendChild(td);
- row.appendChild(DOM.td(entries.length));
- let percent = (entries.length / this.data.all.length) * 100;
- row.appendChild(DOM.td(percent.toFixed(1) + '%'));
- timelineLegendContent.appendChild(row);
- });
- // Add Total row.
- let row = DOM.tr();
- row.appendChild(DOM.td(''));
- row.appendChild(DOM.td('All'));
- row.appendChild(DOM.td(this.data.all.length));
- row.appendChild(DOM.td('100%'));
- timelineLegendContent.appendChild(row);
- this.timelineLegend.appendChild(timelineLegendContent);
- }
-
- handleEntryTypeDblClick(e) {
- this.dispatchEvent(new SelectionEvent(e.target.parentNode.entries));
- }
-
- timelineIndicatorMove(offset) {
- this.timeline.scrollLeft += offset;
- }
-
- handleTimelineScroll(e) {
- let horizontal = e.currentTarget.scrollLeft;
- this.dispatchEvent(new CustomEvent(
- 'scrolltrack', {bubbles: true, composed: true, detail: horizontal}));
- }
-
- async setChunkBackgrounds(backgroundTodo) {
- const kMaxDuration = 50;
- let lastTime = 0;
- for (let [chunk, node] of backgroundTodo) {
- const current = performance.now();
- if (current - lastTime > kMaxDuration) {
- await delay(25);
- lastTime = current;
- }
- this.setChunkBackground(chunk, node);
- }
- }
-
- setChunkBackground(chunk, node) {
- // Render the types of transitions as bar charts
- const kHeight = chunk.height;
- const kWidth = 1;
- this.backgroundCanvas.width = kWidth;
- this.backgroundCanvas.height = kHeight;
- let ctx = this.backgroundCanvas.getContext('2d');
- ctx.clearRect(0, 0, kWidth, kHeight);
- let y = 0;
- let total = chunk.size();
- let type, count;
- if (true) {
- chunk.getBreakdown(map => map.type).forEach(([type, count]) => {
- ctx.fillStyle = this.typeToColor(type);
- let height = count / total * kHeight;
- ctx.fillRect(0, y, kWidth, y + height);
- y += height;
- });
- } else {
- chunk.items.forEach(map => {
- ctx.fillStyle = this.typeToColor(map.type);
- let y = chunk.yOffset(map);
- ctx.fillRect(0, y, kWidth, y + 1);
- });
- }
-
- let imageData = this.backgroundCanvas.toDataURL('image/webp', 0.2);
- node.style.backgroundImage = `url(${imageData})`;
- }
-
- _updateTimeline() {
- let chunksNode = this.timelineChunks;
- DOM.removeAllChildren(chunksNode);
- let chunks = this.chunks;
- let max = chunks.max(each => each.size());
- let start = this.data.startTime;
- let end = this.data.endTime;
- let duration = end - start;
- this._timeToPixel = chunks.length * kChunkWidth / duration;
- this._timeStartOffset = start * this._timeToPixel;
- let addTimestamp = (time, name) => {
- let timeNode = DOM.div('timestamp');
- timeNode.innerText = name;
- timeNode.style.left = ((time - start) * this._timeToPixel) + 'px';
- chunksNode.appendChild(timeNode);
- };
- let backgroundTodo = [];
- for (let i = 0; i < chunks.length; i++) {
- let chunk = chunks[i];
- let height = (chunk.size() / max * kChunkHeight);
- chunk.height = height;
- if (chunk.isEmpty()) continue;
- let node = DOM.div();
- node.className = 'chunk';
- node.style.left = ((chunks[i].start - start) * this._timeToPixel) + 'px';
- node.style.height = height + 'px';
- node.chunk = chunk;
- node.addEventListener('mousemove', e => this.handleChunkMouseMove(e));
- node.addEventListener('click', e => this.handleChunkClick(e));
- node.addEventListener('dblclick', e => this.handleChunkDoubleClick(e));
- backgroundTodo.push([chunk, node])
- chunksNode.appendChild(node);
- }
- this.setChunkBackgrounds(backgroundTodo);
-
- // Put a time marker roughly every 20 chunks.
- let expected = duration / chunks.length * 20;
- let interval = (10 ** Math.floor(Math.log10(expected)));
- let correction = Math.log10(expected / interval);
- correction = (correction < 0.33) ? 1 : (correction < 0.75) ? 2.5 : 5;
- interval *= correction;
-
- let time = start;
- while (time < end) {
- addTimestamp(time, ((time - start) / 1000) + ' ms');
- time += interval;
- }
- this.redraw();
- }
-
- handleChunkMouseMove(event) {
- if (this.isLocked) return false;
- if (this._isSelecting) return false;
- let chunk = event.target.chunk;
- if (!chunk) return;
- // topmost map (at chunk.height) == map #0.
- let relativeIndex =
- Math.round(event.layerY / event.target.offsetHeight * chunk.size());
- let map = chunk.at(relativeIndex);
- this.dispatchEvent(new FocusEvent(map));
- }
-
- handleChunkClick(event) {
- this.isLocked = !this.isLocked;
- }
-
- handleChunkDoubleClick(event) {
- let chunk = event.target.chunk;
- if (!chunk) return;
- this.dispatchEvent(new SelectTimeEvent(chunk.start, chunk.end));
- }
-
- redraw() {
- let canvas = this.timelineCanvas;
- canvas.width = (this.chunks.length + 1) * kChunkWidth;
- canvas.height = kChunkHeight;
- let ctx = canvas.getContext('2d');
- ctx.clearRect(0, 0, canvas.width, kChunkHeight);
- if (!this.selectedEntry || !this.selectedEntry.edge) return;
- this.drawEdges(ctx);
- }
- setMapStyle(map, ctx) {
- ctx.fillStyle = map.edge && map.edge.from ? CSSColor.onBackgroundColor :
- CSSColor.onPrimaryColor;
- }
-
- setEdgeStyle(edge, ctx) {
- let color = this.typeToColor(edge.type);
- ctx.strokeStyle = color;
- ctx.fillStyle = color;
- }
-
- markMap(ctx, map) {
- let [x, y] = map.position(this.chunks);
- ctx.beginPath();
- this.setMapStyle(map, ctx);
- ctx.arc(x, y, 3, 0, 2 * Math.PI);
- ctx.fill();
- ctx.beginPath();
- ctx.fillStyle = CSSColor.onBackgroundColor;
- ctx.arc(x, y, 2, 0, 2 * Math.PI);
- ctx.fill();
- }
-
- markSelectedMap(ctx, map) {
- let [x, y] = map.position(this.chunks);
- ctx.beginPath();
- this.setMapStyle(map, ctx);
- ctx.arc(x, y, 6, 0, 2 * Math.PI);
- ctx.strokeStyle = CSSColor.onBackgroundColor;
- ctx.stroke();
- }
-
- drawEdges(ctx) {
- // Draw the trace of maps in reverse order to make sure the outgoing
- // transitions of previous maps aren't drawn over.
- const kMaxOutgoingEdges = 100;
- let nofEdges = 0;
- let stack = [];
- let current = this.selectedEntry;
- while (current && nofEdges < kMaxOutgoingEdges) {
- nofEdges += current.children.length;
- stack.push(current);
- current = current.parent();
- }
- ctx.save();
- this.drawOutgoingEdges(ctx, this.selectedEntry, 3);
- ctx.restore();
-
- let labelOffset = 15;
- let xPrev = 0;
- while (current = stack.pop()) {
- if (current.edge) {
- this.setEdgeStyle(current.edge, ctx);
- let [xTo, yTo] = this.drawEdge(ctx, current.edge, true, labelOffset);
- if (xTo == xPrev) {
- labelOffset += 8;
- } else {
- labelOffset = 15
- }
- xPrev = xTo;
- }
- this.markMap(ctx, current);
- current = current.parent();
- ctx.save();
- // this.drawOutgoingEdges(ctx, current, 1);
- ctx.restore();
- }
- // Mark selected map
- this.markSelectedMap(ctx, this.selectedEntry);
- }
-
- drawEdge(ctx, edge, showLabel = true, labelOffset = 20) {
- if (!edge.from || !edge.to) return [-1, -1];
- let [xFrom, yFrom] = edge.from.position(this.chunks);
- let [xTo, yTo] = edge.to.position(this.chunks);
- let sameChunk = xTo == xFrom;
- if (sameChunk) labelOffset += 8;
-
- ctx.beginPath();
- ctx.moveTo(xFrom, yFrom);
- let offsetX = 20;
- let offsetY = 20;
- let midX = xFrom + (xTo - xFrom) / 2;
- let midY = (yFrom + yTo) / 2 - 100;
- if (!sameChunk) {
- ctx.quadraticCurveTo(midX, midY, xTo, yTo);
- } else {
- ctx.lineTo(xTo, yTo);
- }
- if (!showLabel) {
- ctx.stroke();
- } else {
- let centerX, centerY;
- if (!sameChunk) {
- centerX = (xFrom / 2 + midX + xTo / 2) / 2;
- centerY = (yFrom / 2 + midY + yTo / 2) / 2;
- } else {
- centerX = xTo;
- centerY = yTo;
- }
- ctx.moveTo(centerX, centerY);
- ctx.lineTo(centerX + offsetX, centerY - labelOffset);
- ctx.stroke();
- ctx.textAlign = 'left';
- ctx.fillStyle = this.typeToColor(edge.type);
- ctx.fillText(
- edge.toString(), centerX + offsetX + 2, centerY - labelOffset);
- }
- return [xTo, yTo];
- }
-
- drawOutgoingEdges(ctx, map, max = 10, depth = 0) {
- if (!map) return;
- if (depth >= max) return;
- ctx.globalAlpha = 0.5 - depth * (0.3 / max);
- ctx.strokeStyle = CSSColor.timelineBackgroundColor;
- const limit = Math.min(map.children.length, 100)
- for (let i = 0; i < limit; i++) {
- let edge = map.children[i];
- this.drawEdge(ctx, edge, true);
- this.drawOutgoingEdges(ctx, edge.to, max, depth + 1);
- }
- }
-});
diff --git a/deps/v8/tools/system-analyzer/view/code-panel-template.html b/deps/v8/tools/system-analyzer/view/code-panel-template.html
new file mode 100644
index 0000000000..e04c6be8c1
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/code-panel-template.html
@@ -0,0 +1,25 @@
+<!-- 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. -->
+
+<head>
+ <link href="./index.css" rel="stylesheet">
+</head>
+<style>
+ #sourceCode {
+ white-space: pre-line;
+ }
+</style>
+<div class="panel">
+ <h2>Code Panel</h2>
+ <div class="selection">
+ <select id="codeSelect"></select>
+ <button id="selectedRelatedButton">Select Related Events</button>
+ </div>
+ <div class="panelBody">
+ <h3>Disassembly</h3>
+ <pre id="disassembly"></pre>
+ <h3>Source Code</h3>
+ <pre id="sourceCode"></pre>
+ </div>
+</div>
diff --git a/deps/v8/tools/system-analyzer/view/code-panel.mjs b/deps/v8/tools/system-analyzer/view/code-panel.mjs
new file mode 100644
index 0000000000..3b5261e03c
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/code-panel.mjs
@@ -0,0 +1,82 @@
+// 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.
+import {IcLogEntry} from '../log/ic.mjs';
+import {MapLogEntry} from '../log/map.mjs';
+
+import {FocusEvent, SelectionEvent, ToolTipEvent} from './events.mjs';
+import {delay, DOM, formatBytes, formatMicroSeconds, V8CustomElement} from './helper.mjs';
+
+DOM.defineCustomElement('view/code-panel',
+ (templateText) =>
+ class CodePanel extends V8CustomElement {
+ _timeline;
+ _selectedEntries;
+ _entry;
+
+ constructor() {
+ super(templateText);
+ this._codeSelectNode.onchange = this._handleSelectCode.bind(this);
+ this.$('#selectedRelatedButton').onclick =
+ this._handleSelectRelated.bind(this)
+ }
+
+ set timeline(timeline) {
+ this._timeline = timeline;
+ this.$('.panel').style.display = timeline.isEmpty() ? 'none' : 'inherit';
+ this.update();
+ }
+
+ set selectedEntries(entries) {
+ this._selectedEntries = entries;
+ // TODO: add code selection dropdown
+ this._updateSelect();
+ this.entry = entries.first();
+ }
+
+ set entry(entry) {
+ this._entry = entry;
+ this.update();
+ }
+
+ get _disassemblyNode() {
+ return this.$('#disassembly');
+ }
+
+ get _sourceNode() {
+ return this.$('#sourceCode');
+ }
+
+ get _codeSelectNode() {
+ return this.$('#codeSelect');
+ }
+
+ _update() {
+ this._disassemblyNode.innerText = this._entry?.disassemble ?? '';
+ this._sourceNode.innerText = this._entry?.source ?? '';
+ }
+
+ _updateSelect() {
+ const select = this._codeSelectNode;
+ select.options.length = 0;
+ const sorted =
+ this._selectedEntries.slice().sort((a, b) => a.time - b.time);
+ for (const code of this._selectedEntries) {
+ const option = DOM.element('option');
+ option.text =
+ `${code.name}(...) t=${formatMicroSeconds(code.time)} size=${
+ formatBytes(code.size)} script=${code.script?.toString()}`;
+ option.data = code;
+ select.add(option);
+ }
+ }
+
+ _handleSelectCode() {
+ this.entry = this._codeSelectNode.selectedOptions[0].data;
+ }
+
+ _handleSelectRelated(e) {
+ if (!this._entry) return;
+ this.dispatchEvent(new SelectRelatedEvent(this._entry));
+ }
+}); \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/view/events.mjs b/deps/v8/tools/system-analyzer/view/events.mjs
new file mode 100644
index 0000000000..4204973f8f
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/events.mjs
@@ -0,0 +1,93 @@
+// 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.
+
+class AppEvent extends CustomEvent {
+ constructor(name) {
+ super(name, {bubbles: true, composed: true});
+ }
+}
+
+export class SelectionEvent extends AppEvent {
+ // TODO: turn into static class fields once Safari supports it.
+ static get name() {
+ return 'select';
+ }
+
+ constructor(entries) {
+ super(SelectionEvent.name);
+ if (!Array.isArray(entries) || entries.length == 0) {
+ throw new Error('No valid entries selected!');
+ }
+ this.entries = entries;
+ }
+}
+
+export class SelectRelatedEvent extends AppEvent {
+ static get name() {
+ return 'selectrelated';
+ }
+
+ constructor(entry) {
+ super(SelectRelatedEvent.name);
+ this.entry = entry;
+ }
+}
+
+export class FocusEvent extends AppEvent {
+ static get name() {
+ return 'showentrydetail';
+ }
+
+ constructor(entry) {
+ super(FocusEvent.name);
+ this.entry = entry;
+ }
+}
+
+export class SelectTimeEvent extends AppEvent {
+ static get name() {
+ return 'timerangeselect';
+ }
+
+ constructor(start = 0, end = Infinity) {
+ super(SelectTimeEvent.name);
+ this.start = start;
+ this.end = end;
+ }
+}
+
+export class SynchronizeSelectionEvent extends AppEvent {
+ static get name() {
+ return 'syncselection';
+ }
+
+ constructor(start, end) {
+ super(SynchronizeSelectionEvent.name);
+ this.start = start;
+ this.end = end;
+ }
+}
+
+export class ToolTipEvent extends AppEvent {
+ static get name() {
+ return 'showtooltip';
+ }
+
+ constructor(content, positionOrTargetNode) {
+ super(ToolTipEvent.name);
+ this._content = content;
+ if (!positionOrTargetNode && !node) {
+ throw Error('Either provide a valid position or targetNode');
+ }
+ this._positionOrTargetNode = positionOrTargetNode;
+ }
+
+ get content() {
+ return this._content;
+ }
+
+ get positionOrTargetNode() {
+ return this._positionOrTargetNode;
+ }
+}
diff --git a/deps/v8/tools/system-analyzer/view/helper.mjs b/deps/v8/tools/system-analyzer/view/helper.mjs
new file mode 100644
index 0000000000..780864ef5a
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/helper.mjs
@@ -0,0 +1,314 @@
+// 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.
+
+class CSSColor {
+ static _cache = new Map();
+
+ static get(name) {
+ let color = this._cache.get(name);
+ if (color !== undefined) return color;
+ const style = getComputedStyle(document.body);
+ color = style.getPropertyValue(`--${name}`);
+ if (color === undefined) {
+ throw new Error(`CSS color does not exist: ${name}`);
+ }
+ color = color.trim();
+ this._cache.set(name, color);
+ return color;
+ }
+ static reset() {
+ this._cache.clear();
+ }
+
+ static get backgroundColor() {
+ return this.get('background-color');
+ }
+ static get surfaceColor() {
+ return this.get('surface-color');
+ }
+ static get primaryColor() {
+ return this.get('primary-color');
+ }
+ static get secondaryColor() {
+ return this.get('secondary-color');
+ }
+ static get onSurfaceColor() {
+ return this.get('on-surface-color');
+ }
+ static get onBackgroundColor() {
+ return this.get('on-background-color');
+ }
+ static get onPrimaryColor() {
+ return this.get('on-primary-color');
+ }
+ static get onSecondaryColor() {
+ return this.get('on-secondary-color');
+ }
+ static get defaultColor() {
+ return this.get('default-color');
+ }
+ static get errorColor() {
+ return this.get('error-color');
+ }
+ static get mapBackgroundColor() {
+ return this.get('map-background-color');
+ }
+ static get timelineBackgroundColor() {
+ return this.get('timeline-background-color');
+ }
+ static get red() {
+ return this.get('red');
+ }
+ static get green() {
+ return this.get('green');
+ }
+ static get yellow() {
+ return this.get('yellow');
+ }
+ static get blue() {
+ return this.get('blue');
+ }
+
+ static get orange() {
+ return this.get('orange');
+ }
+
+ static get violet() {
+ return this.get('violet');
+ }
+
+ static at(index) {
+ return this.list[index % this.list.length];
+ }
+
+ static darken(hexColorString, amount = -40) {
+ if (hexColorString[0] !== '#') {
+ throw new Error(`Unsupported color: ${hexColorString}`);
+ }
+ let color = parseInt(hexColorString.substring(1), 16);
+ let b = Math.min(Math.max((color & 0xFF) + amount, 0), 0xFF);
+ let g = Math.min(Math.max(((color >> 8) & 0xFF) + amount, 0), 0xFF);
+ let r = Math.min(Math.max(((color >> 16) & 0xFF) + amount, 0), 0xFF);
+ color = (r << 16) + (g << 8) + b;
+ return `#${color.toString(16).padStart(6, '0')}`;
+ }
+
+ static get list() {
+ if (!this._colors) {
+ this._colors = [
+ this.green,
+ this.violet,
+ this.orange,
+ this.yellow,
+ this.primaryColor,
+ this.red,
+ this.blue,
+ this.yellow,
+ this.secondaryColor,
+ this.darken(this.green),
+ this.darken(this.violet),
+ this.darken(this.orange),
+ this.darken(this.yellow),
+ this.darken(this.primaryColor),
+ this.darken(this.red),
+ this.darken(this.blue),
+ this.darken(this.yellow),
+ this.darken(this.secondaryColor),
+ ];
+ }
+ return this._colors;
+ }
+}
+
+class DOM {
+ static element(type, classes) {
+ const node = document.createElement(type);
+ if (classes === undefined) return node;
+ if (typeof classes === 'string') {
+ node.className = classes;
+ } else {
+ classes.forEach(cls => node.classList.add(cls));
+ }
+ return node;
+ }
+
+ static text(string) {
+ return document.createTextNode(string);
+ }
+
+ static div(classes) {
+ return this.element('div', classes);
+ }
+
+ static span(classes) {
+ return this.element('span', classes);
+ }
+
+ static table(classes) {
+ return this.element('table', classes);
+ }
+
+ static tbody(classes) {
+ return this.element('tbody', classes);
+ }
+
+ static td(textOrNode, className) {
+ const node = this.element('td');
+ if (typeof textOrNode === 'object') {
+ node.appendChild(textOrNode);
+ } else if (textOrNode) {
+ node.innerText = textOrNode;
+ }
+ if (className) node.className = className;
+ return node;
+ }
+
+ static tr(classes) {
+ return this.element('tr', classes);
+ }
+
+ static removeAllChildren(node) {
+ let range = document.createRange();
+ range.selectNodeContents(node);
+ range.deleteContents();
+ }
+
+ static defineCustomElement(path, generator) {
+ let name = path.substring(path.lastIndexOf('/') + 1, path.length);
+ path = path + '-template.html';
+ fetch(path)
+ .then(stream => stream.text())
+ .then(
+ templateText =>
+ customElements.define(name, generator(templateText)));
+ }
+}
+
+function $(id) {
+ return document.querySelector(id)
+}
+
+class V8CustomElement extends HTMLElement {
+ _updateTimeoutId;
+ _updateCallback = this._update.bind(this);
+
+ constructor(templateText) {
+ super();
+ const shadowRoot = this.attachShadow({mode: 'open'});
+ shadowRoot.innerHTML = templateText;
+ this._updateCallback = this._update.bind(this);
+ }
+
+ $(id) {
+ return this.shadowRoot.querySelector(id);
+ }
+
+ querySelectorAll(query) {
+ return this.shadowRoot.querySelectorAll(query);
+ }
+
+ update(useAnimation = false) {
+ if (useAnimation) {
+ window.cancelAnimationFrame(this._updateTimeoutId);
+ this._updateTimeoutId =
+ window.requestAnimationFrame(this._updateCallback);
+ } else {
+ // Use timeout tasks to asynchronously update the UI without blocking.
+ clearTimeout(this._updateTimeoutId);
+ const kDelayMs = 5;
+ this._updateTimeoutId = setTimeout(this._updateCallback, kDelayMs);
+ }
+ }
+
+ _update() {
+ throw Error('Subclass responsibility');
+ }
+}
+
+class Chunked {
+ constructor(iterable, limit) {
+ this._iterator = iterable[Symbol.iterator]();
+ this._limit = limit;
+ }
+
+ * next(limit = undefined) {
+ for (let i = 0; i < (limit ?? this._limit); i++) {
+ const {value, done} = this._iterator.next();
+ if (done) {
+ this._iterator = undefined;
+ return;
+ };
+ yield value;
+ }
+ }
+
+ get hasMore() {
+ return this._iterator !== undefined;
+ }
+}
+
+class LazyTable {
+ constructor(table, rowData, rowElementCreator, limit = 100) {
+ this._table = table;
+ this._chunkedRowData = new Chunked(rowData, limit);
+ this._rowElementCreator = rowElementCreator;
+ if (table.tBodies.length == 0) {
+ table.appendChild(DOM.tbody());
+ } else {
+ table.replaceChild(DOM.tbody(), table.tBodies[0]);
+ }
+ if (!table.tFoot) {
+ const td = table.appendChild(DOM.element('tfoot'))
+ .appendChild(DOM.tr())
+ .appendChild(DOM.td());
+ for (let count of [10, 100]) {
+ const button = DOM.element('button');
+ button.innerText = `+${count}`;
+ button.onclick = (e) => this._addMoreRows(count);
+ td.appendChild(button);
+ }
+ td.setAttribute('colspan', 100);
+ }
+ table.tFoot.addEventListener('click', this._clickHandler);
+ this._addMoreRows();
+ }
+
+ _addMoreRows(count = undefined) {
+ const fragment = new DocumentFragment();
+ for (let row of this._chunkedRowData.next(count)) {
+ const tr = this._rowElementCreator(row);
+ fragment.appendChild(tr);
+ }
+ this._table.tBodies[0].appendChild(fragment);
+ if (!this._chunkedRowData.hasMore) {
+ DOM.removeAllChildren(this._table.tFoot);
+ }
+ }
+}
+
+export function gradientStopsFromGroups(
+ totalLength, maxHeight, groups, colorFn) {
+ const kMaxHeight = maxHeight === '%' ? 100 : maxHeight;
+ const kUnit = maxHeight === '%' ? '%' : 'px';
+ let increment = 0;
+ let lastHeight = 0.0;
+ const stops = [];
+ for (let group of groups) {
+ const color = colorFn(group.key);
+ increment += group.count;
+ let height = (increment / totalLength * kMaxHeight) | 0;
+ stops.push(`${color} ${lastHeight}${kUnit} ${height}${kUnit}`)
+ lastHeight = height;
+ }
+ return stops;
+}
+
+export * from '../helper.mjs';
+export {
+ DOM,
+ $,
+ V8CustomElement,
+ CSSColor,
+ LazyTable,
+};
diff --git a/deps/v8/tools/system-analyzer/view/list-panel-template.html b/deps/v8/tools/system-analyzer/view/list-panel-template.html
new file mode 100644
index 0000000000..4714f97c02
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/list-panel-template.html
@@ -0,0 +1,78 @@
+<!-- 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. -->
+
+<head>
+ <link href="./index.css" rel="stylesheet">
+</head>
+<style>
+ .count {
+ text-align: right;
+ width: 5em;
+ }
+
+ .percentage {
+ text-align: right;
+ width: 4em;
+ }
+
+ .key {
+ padding-left: 1em;
+ }
+
+ .drilldown-group-title {
+ font-weight: bold;
+ padding: 0.5em 0 0.2em 0;
+ }
+
+ .toggle {
+ width: 1em;
+ text-align: left;
+ cursor: -webkit-zoom-in;
+ color: rgba(var(--border-color), 1);
+ }
+
+ .toggle::before {
+ content: "â–¶";
+ }
+ .open .toggle::before {
+ content: "â–¼";
+ }
+
+ .panel {
+ position: relative;
+ }
+
+ .panelBody {
+ height: 400px;
+ }
+
+ .scroller {
+ max-height: 800px;
+ overflow-y: scroll;
+ }
+
+ .legend {
+ top: 40px;
+ }
+</style>
+
+<div class="panel">
+ <input type="checkbox" id="closer" class="panelCloserInput">
+ <label class="panelCloserLabel" for="closer">â–¼</label>
+ <h2 id="title"></h2>
+ <div class="selection">
+ <input type="radio" id="show-all" name="selectionType" value="all">
+ <label for="show-all">All</label>
+ <input type="radio" id="show-timerange" name="selectionType" value="timerange">
+ <label for="show-timerange">Time Range</label>
+ <input type="radio" id="show-selection" name="selectionType" value="selection">
+ <label for="show-selection">Last Selection</label>
+ </div>
+ <select id="group-key"></select>
+ <div id="content" class="panelBody">
+ <slot></slot>
+ <table id="table" width="100%">
+ </table>
+ </div>
+</div>
diff --git a/deps/v8/tools/system-analyzer/view/list-panel.mjs b/deps/v8/tools/system-analyzer/view/list-panel.mjs
new file mode 100644
index 0000000000..85e3cd47e2
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/list-panel.mjs
@@ -0,0 +1,198 @@
+// 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.
+
+import {Script, SourcePosition} from '../../profile.mjs';
+import {LogEntry} from '../log/log.mjs';
+
+import {FocusEvent} from './events.mjs';
+import {groupBy, LazyTable} from './helper.mjs';
+import {DOM, V8CustomElement} from './helper.mjs';
+
+DOM.defineCustomElement('view/list-panel',
+ (templateText) =>
+ class ListPanel extends V8CustomElement {
+ _selectedLogEntries = [];
+ _displayedLogEntries = [];
+ _timeline;
+
+ _detailsClickHandler = this._handleDetailsClick.bind(this);
+ _logEntryClickHandler = this._handleLogEntryClick.bind(this);
+
+ constructor() {
+ super(templateText);
+ this.groupKey.addEventListener('change', e => this.update());
+ this.showAllRadio.onclick = _ => this._showEntries(this._timeline);
+ this.showTimerangeRadio.onclick = _ =>
+ this._showEntries(this._timeline.selectionOrSelf);
+ this.showSelectionRadio.onclick = _ =>
+ this._showEntries(this._selectedLogEntries);
+ }
+
+ static get observedAttributes() {
+ return ['title'];
+ }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ if (name == 'title') {
+ this.$('#title').innerHTML = newValue;
+ }
+ }
+
+ set timeline(timeline) {
+ console.assert(timeline !== undefined, 'timeline undefined!');
+ this._timeline = timeline;
+ this.$('.panel').style.display = timeline.isEmpty() ? 'none' : 'inherit';
+ this._initGroupKeySelect();
+ }
+
+ set selectedLogEntries(entries) {
+ if (entries === this._timeline) {
+ this.showAllRadio.click();
+ } else if (entries === this._timeline.selection) {
+ this.showTimerangeRadio.click();
+ } else {
+ this._selectedLogEntries = entries;
+ this.showSelectionRadio.click();
+ }
+ }
+
+ get entryClass() {
+ return this._timeline.at(0)?.constructor;
+ }
+
+ get groupKey() {
+ return this.$('#group-key');
+ }
+
+ get table() {
+ return this.$('#table');
+ }
+
+ get showAllRadio() {
+ return this.$('#show-all');
+ }
+ get showTimerangeRadio() {
+ return this.$('#show-timerange');
+ }
+ get showSelectionRadio() {
+ return this.$('#show-selection');
+ }
+
+ get _propertyNames() {
+ return this.entryClass?.propertyNames ?? [];
+ }
+
+ _initGroupKeySelect() {
+ const select = this.groupKey;
+ select.options.length = 0;
+ for (const propertyName of this._propertyNames) {
+ const option = DOM.element('option');
+ option.text = propertyName;
+ select.add(option);
+ }
+ }
+
+ _showEntries(entries) {
+ this._displayedLogEntries = entries;
+ this.update();
+ }
+
+ _update() {
+ if (this._timeline.isEmpty()) return;
+ DOM.removeAllChildren(this.table);
+ if (this._displayedLogEntries.length == 0) return;
+ const propertyName = this.groupKey.selectedOptions[0].text;
+ const groups =
+ groupBy(this._displayedLogEntries, each => each[propertyName], true);
+ this._render(groups, this.table);
+ }
+
+ createSubgroups(group) {
+ const map = new Map();
+ for (let propertyName of this._propertyNames) {
+ map.set(
+ propertyName,
+ groupBy(group.entries, each => each[propertyName], true));
+ }
+ return map;
+ }
+
+ _handleLogEntryClick(e) {
+ const group = e.currentTarget.group;
+ this.dispatchEvent(new FocusEvent(group.key));
+ }
+
+ _handleDetailsClick(event) {
+ event.stopPropagation();
+ const tr = event.target.parentNode;
+ const group = tr.group;
+ // Create subgroup in-place if the don't exist yet.
+ if (tr.groups === undefined) {
+ const groups = tr.groups = this.createSubgroups(group);
+ this.renderDrilldown(groups, tr);
+ }
+ const detailsTr = tr.nextSibling;
+ if (tr.classList.contains('open')) {
+ tr.classList.remove('open');
+ detailsTr.style.display = 'none';
+ } else {
+ tr.classList.add('open');
+ detailsTr.style.display = 'table-row';
+ }
+ }
+
+ renderDrilldown(groups, previousSibling) {
+ const tr = DOM.tr('entry-details');
+ tr.style.display = 'none';
+ // indent by one td.
+ tr.appendChild(DOM.td());
+ const td = DOM.td();
+ td.colSpan = 3;
+ groups.forEach((group, key) => {
+ this.renderDrilldownGroup(td, group, key);
+ });
+ tr.appendChild(td);
+ // Append the new TR after previousSibling.
+ previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling);
+ }
+
+ renderDrilldownGroup(td, groups, key) {
+ const div = DOM.div('drilldown-group-title');
+ div.textContent = `Grouped by ${key}: ${groups[0]?.parentTotal ?? 0}#`;
+ td.appendChild(div);
+ const table = DOM.table();
+ this._render(groups, table, false)
+ td.appendChild(table);
+ }
+
+ _render(groups, table) {
+ let last;
+ new LazyTable(table, groups, group => {
+ if (last && last.count < group.count) {
+ console.log(last, group);
+ }
+ last = group;
+ const tr = DOM.tr();
+ tr.group = group;
+ const details = tr.appendChild(DOM.td('', 'toggle'));
+ details.onclick = this._detailsClickHandler;
+ tr.appendChild(DOM.td(`${group.percent.toFixed(2)}%`, 'percentage'));
+ tr.appendChild(DOM.td(group.count, 'count'));
+ const valueTd = tr.appendChild(DOM.td(`${group.key}`, 'key'));
+ if (this._isClickable(group.key)) {
+ tr.onclick = this._logEntryClickHandler;
+ valueTd.classList.add('clickable');
+ }
+ return tr;
+ }, 10);
+ }
+
+ _isClickable(object) {
+ if (typeof object !== 'object') return false;
+ if (object instanceof LogEntry) return true;
+ if (object instanceof SourcePosition) return true;
+ if (object instanceof Script) return true;
+ return false;
+ }
+});
diff --git a/deps/v8/tools/system-analyzer/log-file-reader-template.html b/deps/v8/tools/system-analyzer/view/log-file-reader-template.html
index e54d45990a..e54d45990a 100644
--- a/deps/v8/tools/system-analyzer/log-file-reader-template.html
+++ b/deps/v8/tools/system-analyzer/view/log-file-reader-template.html
diff --git a/deps/v8/tools/system-analyzer/log-file-reader.mjs b/deps/v8/tools/system-analyzer/view/log-file-reader.mjs
index c46d792d00..fd935f2f83 100644
--- a/deps/v8/tools/system-analyzer/log-file-reader.mjs
+++ b/deps/v8/tools/system-analyzer/view/log-file-reader.mjs
@@ -3,7 +3,7 @@
// found in the LICENSE file.
import {DOM, V8CustomElement} from './helper.mjs';
-DOM.defineCustomElement('log-file-reader',
+DOM.defineCustomElement('view/log-file-reader',
(templateText) =>
class LogFileReader extends V8CustomElement {
constructor() {
diff --git a/deps/v8/tools/system-analyzer/view/map-panel-template.html b/deps/v8/tools/system-analyzer/view/map-panel-template.html
new file mode 100644
index 0000000000..8a2b23ee3d
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/map-panel-template.html
@@ -0,0 +1,36 @@
+<!-- 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. -->
+
+<head>
+ <link href="./index.css" rel="stylesheet">
+</head>
+<style>
+ #searchBarInput {
+ width: 200px;
+ }
+</style>
+<div class="panel">
+ <input type="checkbox" id="closer" class="panelCloserInput">
+ <label class="panelCloserLabel" for="closer">â–¼</label>
+ <h2>Map Panel</h2>
+ <div class="selection">
+ <input type="radio" id="show-all" name="selectionType" value="all">
+ <label for="show-all">All</label>
+ <input type="radio" id="show-timerange" name="selectionType" value="timerange">
+ <label for="show-timerange">Time Range</label>
+ <input type="radio" id="show-selection" name="selectionType" value="selection">
+ <label for="show-selection">Last Selection</label>
+ </div>
+ <h3>All Transitions</h3>
+ <map-transitions id="map-transitions"></map-transitions>
+ <h3>Search Map by Address</h3>
+ <section id="searchBar"></section>
+ <input type="search" id="searchBarInput"></input>
+ <button id="searchBarBtn">Search</button>
+
+ <h3>Details Transitions</h3>
+ <map-transitions id="map-details-transitions"></map-transitions>
+ <h3>Details</h3>
+ <map-details id="map-details"></map-details>
+</div>
diff --git a/deps/v8/tools/system-analyzer/view/map-panel.mjs b/deps/v8/tools/system-analyzer/view/map-panel.mjs
new file mode 100644
index 0000000000..7ee2325f34
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/map-panel.mjs
@@ -0,0 +1,106 @@
+// 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.
+import './map-panel/map-details.mjs';
+import './map-panel/map-transitions.mjs';
+
+import {MapLogEntry} from '../log/map.mjs';
+
+import {FocusEvent} from './events.mjs';
+import {DOM, V8CustomElement} from './helper.mjs';
+
+DOM.defineCustomElement(
+ 'view/map-panel', (templateText) => class MapPanel extends V8CustomElement {
+ _map;
+ _timeline;
+ _selectedLogEntries = [];
+ _displayedLogEntries = [];
+
+ constructor() {
+ super(templateText);
+ this.searchBarBtn.addEventListener('click', e => this._handleSearch(e));
+ this.showAllRadio.onclick = _ => this._showEntries(this._timeline);
+ this.showTimerangeRadio.onclick = _ =>
+ this._showEntries(this._timeline.selectionOrSelf);
+ this.showSelectionRadio.onclick = _ =>
+ this._showEntries(this._selectedLogEntries);
+ }
+
+ get showAllRadio() {
+ return this.$('#show-all');
+ }
+ get showTimerangeRadio() {
+ return this.$('#show-timerange');
+ }
+ get showSelectionRadio() {
+ return this.$('#show-selection');
+ }
+
+ get mapTransitionsPanel() {
+ return this.$('#map-transitions');
+ }
+
+ get mapDetailsTransitionsPanel() {
+ return this.$('#map-details-transitions');
+ }
+
+ get mapDetailsPanel() {
+ return this.$('#map-details');
+ }
+
+ get searchBarBtn() {
+ return this.$('#searchBarBtn');
+ }
+
+ get searchBar() {
+ return this.$('#searchBar');
+ }
+
+ set timeline(timeline) {
+ console.assert(timeline !== undefined, 'timeline undefined!');
+ this._timeline = timeline;
+ this.$('.panel').style.display =
+ timeline.isEmpty() ? 'none' : 'inherit';
+ this.mapTransitionsPanel.timeline = timeline;
+ this.mapDetailsTransitionsPanel.timeline = timeline;
+ }
+
+ set selectedLogEntries(entries) {
+ if (entries === this._timeline.selection) {
+ this.showTimerangeRadio.click();
+ } else if (entries == this._timeline) {
+ this.showAllRadio.click();
+ } else {
+ this._selectedLogEntries = entries;
+ this.showSelectionRadio.click();
+ }
+ }
+
+ set map(map) {
+ this._map = map;
+ this.mapDetailsTransitionsPanel.selectedLogEntries = [map];
+ this.mapDetailsPanel.map = map;
+ }
+
+ _showEntries(entries) {
+ this._displayedLogEntries = entries;
+ this.mapTransitionsPanel.selectedLogEntries = entries;
+ }
+
+ update() {
+ // nothing to do
+ }
+
+ _handleSearch(e) {
+ let searchBar = this.$('#searchBarInput');
+ let searchBarInput = searchBar.value;
+ // access the map from model cache
+ let selectedMap = MapLogEntry.get(searchBarInput);
+ if (selectedMap) {
+ searchBar.className = 'success';
+ this.dispatchEvent(new FocusEvent(selectedMap));
+ } else {
+ searchBar.className = 'failure';
+ }
+ }
+ });
diff --git a/deps/v8/tools/system-analyzer/map-panel/map-details-template.html b/deps/v8/tools/system-analyzer/view/map-panel/map-details-template.html
index 6d1b268c5d..b109d4c8ac 100644
--- a/deps/v8/tools/system-analyzer/map-panel/map-details-template.html
+++ b/deps/v8/tools/system-analyzer/view/map-panel/map-details-template.html
@@ -8,16 +8,12 @@ found in the LICENSE file. -->
<style>
#mapDetails,
#filePositionNode {
- overflow-x: scroll;
+ overflow: scroll;
}
-
- #mapDetails::-webkit-scrollbar {
- width: 0;
- background-color: transparent;
+ #mapDetails {
+ font-family: monospace;
+ white-space: pre;
}
</style>
-<div class="panel">
- <h4>Map Details</h4>
- <section id="filePositionNode"></section>
- <section id="mapDetails"></section>
-</div>
+<section id="filePositionNode"></section>
+<section id="mapDetails"></section>
diff --git a/deps/v8/tools/system-analyzer/map-panel/map-details.mjs b/deps/v8/tools/system-analyzer/view/map-panel/map-details.mjs
index bcf8f9c9aa..446475a5b0 100644
--- a/deps/v8/tools/system-analyzer/map-panel/map-details.mjs
+++ b/deps/v8/tools/system-analyzer/view/map-panel/map-details.mjs
@@ -5,7 +5,7 @@ import {FocusEvent} from '../events.mjs';
import {DOM, V8CustomElement} from '../helper.mjs';
DOM.defineCustomElement(
- './map-panel/map-details',
+ './view/map-panel/map-details',
(templateText) => class MapDetails extends V8CustomElement {
_map;
diff --git a/deps/v8/tools/system-analyzer/map-panel/map-transitions-template.html b/deps/v8/tools/system-analyzer/view/map-panel/map-transitions-template.html
index c4cab2bf46..d5dcca07a7 100644
--- a/deps/v8/tools/system-analyzer/map-panel/map-transitions-template.html
+++ b/deps/v8/tools/system-analyzer/view/map-panel/map-transitions-template.html
@@ -137,12 +137,4 @@ found in the LICENSE file. -->
padding-bottom: 10px;
}
</style>
-<div class="panel">
- <div id="title">
- <h4>Transitions</h4>
- </div>
- <section id="transitionView"></section>
- <div id="tooltip">
- <div id="tooltipContents"></div>
- </div>
-</div>
+<section id="transitionView"></section>
diff --git a/deps/v8/tools/system-analyzer/view/map-panel/map-transitions.mjs b/deps/v8/tools/system-analyzer/view/map-panel/map-transitions.mjs
new file mode 100644
index 0000000000..f60bd37d39
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/map-panel/map-transitions.mjs
@@ -0,0 +1,181 @@
+// 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.
+import {FocusEvent, SelectRelatedEvent, ToolTipEvent} from '../events.mjs';
+import {CSSColor} from '../helper.mjs';
+import {DOM, V8CustomElement} from '../helper.mjs';
+
+DOM.defineCustomElement(
+ './view/map-panel/map-transitions',
+ (templateText) => class MapTransitions extends V8CustomElement {
+ _timeline;
+ _map;
+ _edgeToColor = new Map();
+ _selectedLogEntries;
+ _displayedMapsInTree;
+ _toggleSubtreeHandler = this._handleToggleSubtree.bind(this);
+ _mapClickHandler = this._handleMapClick.bind(this);
+ _mapDoubleClickHandler = this._handleMapDoubleClick.bind(this);
+ _mouseoverMapHandler = this._handleMouseoverMap.bind(this);
+
+ constructor() {
+ super(templateText);
+ this.currentNode = this.transitionView;
+ }
+
+ get transitionView() {
+ return this.$('#transitionView');
+ }
+
+ set timeline(timeline) {
+ this._timeline = timeline;
+ this._edgeToColor.clear();
+ timeline.getBreakdown().forEach(breakdown => {
+ this._edgeToColor.set(breakdown.key, CSSColor.at(breakdown.id));
+ });
+ }
+
+ set selectedLogEntries(list) {
+ this._selectedLogEntries = list;
+ this.update();
+ }
+
+ _update() {
+ this.transitionView.style.display = 'none';
+ DOM.removeAllChildren(this.transitionView);
+ if (this._selectedLogEntries.length == 0) return;
+ this._displayedMapsInTree = new Set();
+ // Limit view to 200 maps for performance reasons.
+ this._selectedLogEntries.slice(0, 200).forEach(
+ (map) => this._addMapAndParentTransitions(map));
+ this._displayedMapsInTree = undefined;
+ this.transitionView.style.display = '';
+ }
+
+ _addMapAndParentTransitions(map) {
+ if (map === undefined) return;
+ if (this._displayedMapsInTree.has(map)) return;
+ this._displayedMapsInTree.add(map);
+ this.currentNode = this.transitionView;
+ let parents = map.getParents();
+ if (parents.length > 0) {
+ this._addTransitionTo(parents.pop());
+ parents.reverse().forEach((each) => this._addTransitionTo(each));
+ }
+ let mapNode = this._addSubtransitions(map);
+ // Mark and show the selected map.
+ mapNode.classList.add('selected');
+ if (this.selectedMap == map) {
+ setTimeout(
+ () => mapNode.scrollIntoView({
+ behavior: 'smooth',
+ block: 'nearest',
+ inline: 'nearest',
+ }),
+ 1);
+ }
+ }
+
+ _addSubtransitions(map) {
+ let mapNode = this._addTransitionTo(map);
+ // Draw outgoing linear transition line.
+ let current = map;
+ while (current.children.length == 1) {
+ current = current.children[0].to;
+ this._addTransitionTo(current);
+ }
+ return mapNode;
+ }
+
+ _addTransitionEdge(map) {
+ let classes = ['transitionEdge'];
+ let edge = DOM.div(classes);
+ edge.style.backgroundColor = this._edgeToColor.get(map.edge.type);
+ let labelNode = DOM.div('transitionLabel');
+ labelNode.innerText = map.edge.toString();
+ edge.appendChild(labelNode);
+ return edge;
+ }
+
+ _addTransitionTo(map) {
+ // transition[ transitions[ transition[...], transition[...], ...]];
+ this._displayedMapsInTree?.add(map);
+ let transition = DOM.div('transition');
+ if (map.isDeprecated()) transition.classList.add('deprecated');
+ if (map.edge) {
+ transition.appendChild(this._addTransitionEdge(map));
+ }
+ let mapNode = this._addMapNode(map);
+ transition.appendChild(mapNode);
+
+ let subtree = DOM.div('transitions');
+ transition.appendChild(subtree);
+
+ this.currentNode.appendChild(transition);
+ this.currentNode = subtree;
+
+ return mapNode;
+ }
+
+ _addMapNode(map) {
+ let node = DOM.div('map');
+ if (map.edge)
+ node.style.backgroundColor = this._edgeToColor.get(map.edge.type);
+ node.map = map;
+ node.onclick = this._mapClickHandler
+ node.ondblclick = this._mapDoubleClickHandler
+ node.onmouseover = this._mouseoverMapHandler
+ if (map.children.length > 1) {
+ node.innerText = map.children.length;
+ const showSubtree = DOM.div('showSubtransitions');
+ showSubtree.onclick = this._toggleSubtreeHandler
+ node.appendChild(showSubtree);
+ }
+ else if (map.children.length == 0) {
+ node.innerHTML = '&#x25CF;';
+ }
+ this.currentNode.appendChild(node);
+ return node;
+ }
+
+ _handleMapClick(event) {
+ const map = event.currentTarget.map;
+ this.dispatchEvent(new FocusEvent(map));
+ }
+
+ _handleMapDoubleClick(event) {
+ this.dispatchEvent(new SelectRelatedEvent(event.currentTarget.map));
+ }
+
+ _handleMouseoverMap(event) {
+ this.dispatchEvent(new ToolTipEvent(
+ event.currentTarget.map.toStringLong(), event.currentTarget));
+ }
+
+ _handleToggleSubtree(event) {
+ event.preventDefault();
+ const node = event.currentTarget.parentElement;
+ let map = node.map;
+ event.target.classList.toggle('opened');
+ let transitionsNode = node.parentElement.querySelector('.transitions');
+ let subtransitionNodes = transitionsNode.children;
+ if (subtransitionNodes.length <= 1) {
+ // Add subtransitions except the one that's already shown.
+ let visibleTransitionMap = subtransitionNodes.length == 1 ?
+ transitionsNode.querySelector('.map').map :
+ undefined;
+ map.children.forEach((edge) => {
+ if (edge.to != visibleTransitionMap) {
+ this.currentNode = transitionsNode;
+ this._addSubtransitions(edge.to);
+ }
+ });
+ } else {
+ // remove all but the first (currently selected) subtransition
+ for (let i = subtransitionNodes.length - 1; i > 0; i--) {
+ transitionsNode.removeChild(subtransitionNodes[i]);
+ }
+ }
+ return false;
+ }
+ });
diff --git a/deps/v8/tools/system-analyzer/view/script-panel-template.html b/deps/v8/tools/system-analyzer/view/script-panel-template.html
new file mode 100644
index 0000000000..27fd3d83eb
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/script-panel-template.html
@@ -0,0 +1,72 @@
+<!-- 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. -->
+
+<head>
+ <link href="./index.css" rel="stylesheet">
+</head>
+<style>
+ .scriptNode {
+ font-family: Consolas, monospace;
+ }
+
+ .scriptNode:before {
+ counter-reset: sourceLineCounter;
+ }
+
+ .scriptNode span {
+ counter-increment: sourceLineCounter 1;
+ text-indent: -3.5em;
+ padding-left: 3.5em;
+ display: block;
+ }
+
+ .scriptNode span::before {
+ content: counter(sourceLineCounter) ": ";
+ width: 3.5em;
+ display: inline-block;
+ white-space: pre;
+ text-align: right;
+ }
+
+ mark {
+ width: 1ch;
+ border-radius: 2px;
+ border: 0.5px var(--background-color) solid;
+ cursor: pointer;
+ background-color: var(--primary-color);
+ color: var(--on-primary-color);
+ }
+
+ .marked {
+ background-color: var(--secondary-color);
+ }
+
+ @keyframes pulse {
+ 0% {
+ box-shadow: 0px 0px 0px 0px var(--secondary-color);
+ }
+ 5% {
+ box-shadow: 0px 0px 0px 10px var(--secondary-color);
+ }
+ 10% {
+ box-shadow: 0px 0px 0px 0px var(--secondary-color);
+ }
+ 15% {
+ box-shadow: 0px 0px 0px 10px var(--secondary-color);
+ }
+ 20% {
+ box-shadow: 0px 0px 0px 0px var(--secondary-color);
+ }
+ }
+</style>
+<div class="panel">
+ <h2>Source Panel</h2>
+ <div class="selection">
+ <select id="script-dropdown"></select>
+ <button id="selectedRelatedButton">Select Related Events</button>
+ </div>
+ <div id="script" class="panelBody">
+ <div class="scriptNode"></div>
+ </div>
+</div>
diff --git a/deps/v8/tools/system-analyzer/source-panel.mjs b/deps/v8/tools/system-analyzer/view/script-panel.mjs
index a4dc07fb45..b0dac6960c 100644
--- a/deps/v8/tools/system-analyzer/source-panel.mjs
+++ b/deps/v8/tools/system-analyzer/view/script-panel.mjs
@@ -1,22 +1,26 @@
// 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.
-import {FocusEvent, SelectionEvent} from './events.mjs';
-import {delay, DOM, formatBytes, V8CustomElement} from './helper.mjs';
-import {IcLogEntry} from './log/ic.mjs';
-import {MapLogEntry} from './log/map.mjs';
+import {groupBy} from '../helper.mjs';
+import {App} from '../index.mjs'
-DOM.defineCustomElement('source-panel',
+import {SelectRelatedEvent, ToolTipEvent} from './events.mjs';
+import {CSSColor, delay, DOM, formatBytes, gradientStopsFromGroups, V8CustomElement} from './helper.mjs';
+
+DOM.defineCustomElement('view/script-panel',
(templateText) =>
class SourcePanel extends V8CustomElement {
_selectedSourcePositions = [];
- _sourcePositionsToMarkNodes;
+ _sourcePositionsToMarkNodes = [];
_scripts = [];
_script;
+
constructor() {
super(templateText);
this.scriptDropdown.addEventListener(
'change', e => this._handleSelectScript(e));
+ this.$('#selectedRelatedButton').onclick =
+ this._handleSelectRelated.bind(this);
}
get script() {
@@ -41,7 +45,11 @@ DOM.defineCustomElement('source-panel',
this._focusSelectedMarkers();
}
- set data(scripts) {
+ set focusedSourcePositions(sourcePositions) {
+ this.selectedSourcePositions = sourcePositions;
+ }
+
+ set scripts(scripts) {
this._scripts = scripts;
this._initializeScriptDropdown();
}
@@ -71,13 +79,13 @@ DOM.defineCustomElement('source-panel',
let scriptNode;
if (this._script) {
await delay(1);
- const builder =
- new LineBuilder(this, this._script, this._selectedSourcePositions);
+ const builder = new LineBuilder(this, this._script);
scriptNode = builder.createScriptNode();
this._sourcePositionsToMarkNodes = builder.sourcePositionToMarkers;
} else {
- scriptNode = document.createElement('pre');
+ scriptNode = DOM.div();
this._selectedMarkNodes = undefined;
+ this._sourcePositionsToMarkNodes = new Map();
}
const oldScriptNode = this.script.childNodes[1];
this.script.replaceChild(scriptNode, oldScriptNode);
@@ -90,9 +98,15 @@ DOM.defineCustomElement('source-panel',
markNode.className = '';
}
for (let sourcePosition of this._selectedSourcePositions) {
+ if (sourcePosition.script !== this._script) continue;
this._sourcePositionsToMarkNodes.get(sourcePosition).className = 'marked';
}
- const sourcePosition = this._selectedSourcePositions[0];
+ this._scrollToFirstSourcePosition()
+ }
+
+ _scrollToFirstSourcePosition() {
+ const sourcePosition = this._selectedSourcePositions.find(
+ each => each.script === this._script);
if (!sourcePosition) return;
const markNode = this._sourcePositionsToMarkNodes.get(sourcePosition);
markNode.scrollIntoView(
@@ -103,29 +117,32 @@ DOM.defineCustomElement('source-panel',
const option =
this.scriptDropdown.options[this.scriptDropdown.selectedIndex];
this.script = option.script;
- this.selectLogEntries(this._script.entries());
+ }
+
+ _handleSelectRelated(e) {
+ if (!this._script) return;
+ this.dispatchEvent(new SelectRelatedEvent(this._script));
}
handleSourcePositionClick(e) {
- this.selectLogEntries(e.target.sourcePosition.entries)
- }
-
- selectLogEntries(logEntries) {
- let icLogEntries = [];
- let mapLogEntries = [];
- for (const entry of logEntries) {
- if (entry instanceof MapLogEntry) {
- mapLogEntries.push(entry);
- } else if (entry instanceof IcLogEntry) {
- icLogEntries.push(entry);
- }
- }
- if (icLogEntries.length > 0) {
- this.dispatchEvent(new SelectionEvent(icLogEntries));
- }
- if (mapLogEntries.length > 0) {
- this.dispatchEvent(new SelectionEvent(mapLogEntries));
- }
+ const sourcePosition = e.target.sourcePosition;
+ this.dispatchEvent(new SelectRelatedEvent(sourcePosition));
+ }
+
+ handleSourcePositionMouseOver(e) {
+ const entries = e.target.sourcePosition.entries;
+ let text = groupBy(entries, each => each.constructor, true)
+ .map(group => {
+ let text = `${group.key.name}: ${group.count}\n`
+ text += groupBy(group.entries, each => each.type, true)
+ .map(group => {
+ return ` - ${group.key}: ${group.count}`;
+ })
+ .join('\n');
+ return text;
+ })
+ .join('\n');
+ this.dispatchEvent(new ToolTipEvent(text, e.target));
}
});
@@ -177,16 +194,28 @@ function* lineIterator(source) {
}
class LineBuilder {
+ static _colorMap = (function() {
+ const map = new Map();
+ let i = 0;
+ for (let type of App.allEventTypes) {
+ map.set(type, CSSColor.at(i++));
+ }
+ return map;
+ })();
+ static get colorMap() {
+ return this._colorMap;
+ }
+
_script;
_clickHandler;
+ _mouseoverHandler;
_sourcePositions;
- _selection;
_sourcePositionToMarkers = new Map();
- constructor(panel, script, highlightPositions) {
+ constructor(panel, script) {
this._script = script;
- this._selection = new Set(highlightPositions);
this._clickHandler = panel.handleSourcePositionClick.bind(panel);
+ this._mouseoverHandler = panel.handleSourcePositionMouseOver.bind(panel);
// TODO: sort on script finalization.
script.sourcePositions.sort((a, b) => {
if (a.line === b.line) return a.column - b.column;
@@ -200,8 +229,7 @@ class LineBuilder {
}
createScriptNode() {
- const scriptNode = document.createElement('pre');
- scriptNode.classList.add('scriptNode');
+ const scriptNode = DOM.div('scriptNode');
for (let [lineIndex, line] of lineIterator(this._script.source)) {
scriptNode.appendChild(this._createLineNode(lineIndex, line));
}
@@ -209,7 +237,7 @@ class LineBuilder {
}
_createLineNode(lineIndex, line) {
- const lineNode = document.createElement('span');
+ const lineNode = DOM.span();
let columnIndex = 0;
for (const sourcePosition of this._sourcePositions.forLine(lineIndex)) {
const nextColumnIndex = sourcePosition.column - 1;
@@ -232,6 +260,14 @@ class LineBuilder {
marker.textContent = text;
marker.sourcePosition = sourcePosition;
marker.onclick = this._clickHandler;
+ marker.onmouseover = this._mouseoverHandler;
+
+ const entries = sourcePosition.entries;
+ const stops = gradientStopsFromGroups(
+ entries.length, '%', groupBy(entries, entry => entry.constructor),
+ type => LineBuilder.colorMap.get(type));
+ marker.style.backgroundImage = `linear-gradient(0deg,${stops.join(',')})`
+
return marker;
}
-} \ No newline at end of file
+}
diff --git a/deps/v8/tools/system-analyzer/view/timeline-panel-template.html b/deps/v8/tools/system-analyzer/view/timeline-panel-template.html
new file mode 100644
index 0000000000..da0ce26380
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/timeline-panel-template.html
@@ -0,0 +1,29 @@
+<!-- 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. -->
+
+<head>
+ <link href="./index.css" rel="stylesheet">
+ <style>
+ .panel {
+ padding-bottom: 0px;
+ position: relative;
+ }
+ .titleBackground {
+ position: absolute;
+ left: 0px;
+ top: 34px;
+ border-radius: 0 0 0 7px;
+ height: calc(100% - 34px);
+ width: 30px;
+ background-color: var(--border-color);
+ }
+ </style>
+</head>
+<div class="panel">
+ <h2>Timeline Panel</h2>
+ <div class="titleBackground"></div>
+ <div>
+ <slot></slot>
+ </div>
+</div>
diff --git a/deps/v8/tools/system-analyzer/timeline-panel.mjs b/deps/v8/tools/system-analyzer/view/timeline-panel.mjs
index a61d2efc90..331db401e9 100644
--- a/deps/v8/tools/system-analyzer/timeline-panel.mjs
+++ b/deps/v8/tools/system-analyzer/view/timeline-panel.mjs
@@ -8,7 +8,7 @@ import {SynchronizeSelectionEvent} from './events.mjs';
import {DOM, V8CustomElement} from './helper.mjs';
DOM.defineCustomElement(
- 'timeline-panel',
+ 'view/timeline-panel',
(templateText) => class TimelinePanel extends V8CustomElement {
constructor() {
super(templateText);
diff --git a/deps/v8/tools/system-analyzer/view/timeline/timeline-track-template.html b/deps/v8/tools/system-analyzer/view/timeline/timeline-track-template.html
new file mode 100644
index 0000000000..b27ad66b59
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/timeline/timeline-track-template.html
@@ -0,0 +1,205 @@
+<!-- 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. -->
+
+<head>
+ <link href="./index.css" rel="stylesheet">
+</head>
+<style>
+ #timeline {
+ position: relative;
+ height: calc(200px + 12px);
+ overflow-y: hidden;
+ overflow-x: scroll;
+ user-select: none;
+ }
+
+ #timelineLabel {
+ transform: rotate(90deg);
+ transform-origin: left bottom 0;
+ position: absolute;
+ left: 0;
+ width: 200px;
+ text-align: center;
+ font-size: 10px;
+ opacity: 0.5;
+ }
+
+ #timelineChunks {
+ height: 200px;
+ position: absolute;
+ margin-right: 100px;
+ }
+
+ #timelineCanvas {
+ height: 200px;
+ position: relative;
+ overflow: visible;
+ pointer-events: none;
+ }
+
+ .chunk {
+ width: 6px;
+ position: absolute;
+ background-size: 100% 100%;
+ image-rendering: pixelated;
+ bottom: 0px;
+ background-color: var(--on-surface-color);
+ cursor: pointer;
+ }
+ .chunk:hover {
+ border-radius: 2px 2px 0 0;
+ margin: 0 0 -2px -2px;
+ border: 2px var(--primary-color) solid;
+ }
+
+ .timestamp {
+ height: 200px;
+ width: 100px;
+ border-left: 1px var(--on-surface-color) dashed;
+ padding-left: 4px;
+ position: absolute;
+ pointer-events: none;
+ font-size: 10px;
+ }
+
+ .title {
+ position: relative;
+ float: left;
+ width: 20px;
+ writing-mode: vertical-rl;
+ text-orientation: mixed;
+ margin: 20px 0 0 -10px;
+ padding: 5px 5px 0px 5px;
+ overflow: hidden;
+ border-radius: 7px;
+ font-weight: 400;
+ }
+
+ .panelCloserInput:checked ~ h3 {
+ display: inherit;
+ flex: 1;
+ writing-mode: unset;
+ text-orientation: unset;
+ background-color: var(--border-color);
+ border-radius: 0px;
+ padding: 5px;
+ margin: 0 -10px 0 20px;
+ }
+
+ .timelineLegend {
+ position: relative;
+ float: right;
+ height: calc(200px + 12px);
+ overflow-y: scroll;
+ margin-right: -10px;
+ padding-right: 2px;
+ }
+
+ #legendTable {
+ width: 280px;
+ border-collapse: collapse;
+ }
+
+ th,
+ td {
+ padding: 1px 3px 2px 3px;
+ }
+
+ /* Center colors */
+ #legendTable td:nth-of-type(4n+1) {
+ text-align: center;
+ padding-top: 3px;
+ }
+ /* Left align text*/
+ #legendTable td:nth-of-type(4n+2) {
+ text-align: left;
+ width: 100%;
+ }
+ /* right align numbers */
+ #legendTable td:nth-of-type(4n+3),
+ #legendTable td:nth-of-type(4n+4) {
+ text-align: right;
+ }
+
+ .timeline {
+ background-color: var(--timeline-background-color);
+ }
+
+ #selection {
+ display: none;
+ }
+
+ #rightHandle,
+ #leftHandle {
+ background-color: rgba(200, 200, 200, 0.5);
+ height: 100%;
+ width: 5px;
+ position: absolute;
+ z-index: 3;
+ cursor: col-resize;
+ }
+ #leftHandle {
+ border-left: 1px solid var(--on-surface-color);
+ }
+ #rightHandle {
+ border-right: 1px solid var(--on-surface-color);
+ }
+
+ #selectionBackground {
+ background-color: rgba(133, 68, 163, 0.5);
+ height: 100%;
+ position: absolute;
+ }
+
+
+ .content {
+ display: flex;
+ position: relative;
+ }
+ .panelCloserLabel {
+ position: absolute;
+ top: 5px;
+ left: 0px;
+ }
+ .title {
+ flex: initial;
+ }
+ #timeline {
+ flex: 1;
+ }
+ .legend {
+ flex: initial;
+ }
+
+</style>
+
+<div class="content">
+ <input type="checkbox" id="closer" class="panelCloserInput">
+ <label class="panelCloserLabel" for="closer">â–¼</label>
+ <h3 class="title" id="title"></h3>
+
+ <div id="timeline">
+ <div id="selection">
+ <div id="leftHandle"></div>
+ <div id="selectionBackground"></div>
+ <div id="rightHandle"></div>
+ </div>
+ <div id="timelineLabel">Frequency</div>
+ <div id="timelineChunks"></div>
+ <canvas id="timelineCanvas"></canvas>
+ </div>
+
+ <div class="timelineLegend">
+ <table id="legendTable">
+ <thead>
+ <tr>
+ <td>Type</td>
+ <td>Count</td>
+ <td>Percent</td>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
+</div> \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/view/timeline/timeline-track.mjs b/deps/v8/tools/system-analyzer/view/timeline/timeline-track.mjs
new file mode 100644
index 0000000000..60216af2ee
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/timeline/timeline-track.mjs
@@ -0,0 +1,605 @@
+// 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.
+
+import {kChunkHeight, kChunkWidth} from '../../log/map.mjs';
+import {MapLogEntry} from '../../log/map.mjs';
+import {FocusEvent, SelectionEvent, SelectTimeEvent, SynchronizeSelectionEvent, ToolTipEvent,} from '../events.mjs';
+import {CSSColor, DOM, gradientStopsFromGroups, V8CustomElement} from '../helper.mjs';
+
+DOM.defineCustomElement('view/timeline/timeline-track',
+ (templateText) =>
+ class TimelineTrack extends V8CustomElement {
+ _timeline;
+ _nofChunks = 400;
+ _chunks;
+ _selectedEntry;
+ _timeToPixel;
+ _timeStartOffset;
+ _legend;
+
+ _chunkMouseMoveHandler = this._handleChunkMouseMove.bind(this);
+ _chunkClickHandler = this._handleChunkClick.bind(this);
+ _chunkDoubleClickHandler = this._handleChunkDoubleClick.bind(this);
+
+ constructor() {
+ super(templateText);
+ this._selectionHandler = new SelectionHandler(this);
+ this._legend = new Legend(this.$('#legendTable'));
+ this._legend.onFilter = (type) => this._handleFilterTimeline();
+ this.timelineNode.addEventListener(
+ 'scroll', e => this._handleTimelineScroll(e));
+ this.timelineNode.ondblclick = (e) =>
+ this._selectionHandler.clearSelection();
+ this.isLocked = false;
+ }
+
+ static get observedAttributes() {
+ return ['title'];
+ }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ if (name == 'title') {
+ this.$('#title').innerHTML = newValue;
+ }
+ }
+
+ _handleFilterTimeline(type) {
+ this._updateChunks();
+ }
+
+ set data(timeline) {
+ this._timeline = timeline;
+ this._legend.timeline = timeline;
+ this.$('.content').style.display = timeline.isEmpty() ? 'none' : 'relative';
+ this._updateChunks();
+ }
+
+ set timeSelection(selection) {
+ this._selectionHandler.timeSelection = selection;
+ this.updateSelection();
+ }
+
+ updateSelection() {
+ this._selectionHandler.update();
+ this._legend.update();
+ }
+
+ // Maps the clicked x position to the x position on timeline canvas
+ positionOnTimeline(posX) {
+ let rect = this.timelineNode.getBoundingClientRect();
+ let posClickedX = posX - rect.left + this.timelineNode.scrollLeft;
+ return posClickedX;
+ }
+
+ positionToTime(posX) {
+ let posTimelineX = this.positionOnTimeline(posX) + this._timeStartOffset;
+ return posTimelineX / this._timeToPixel;
+ }
+
+ timeToPosition(time) {
+ let posX = time * this._timeToPixel;
+ posX -= this._timeStartOffset;
+ return posX;
+ }
+
+ get timelineCanvas() {
+ return this.$('#timelineCanvas');
+ }
+
+ get timelineChunks() {
+ return this.$('#timelineChunks');
+ }
+
+ get timelineNode() {
+ return this.$('#timeline');
+ }
+
+ _update() {
+ this._updateTimeline();
+ this._legend.update();
+ }
+
+ set nofChunks(count) {
+ this._nofChunks = count;
+ this._updateChunks();
+ }
+
+ get nofChunks() {
+ return this._nofChunks;
+ }
+
+ _updateChunks() {
+ this._chunks =
+ this._timeline.chunks(this.nofChunks, this._legend.filterPredicate);
+ this.update();
+ }
+
+ get chunks() {
+ return this._chunks;
+ }
+
+ set selectedEntry(value) {
+ this._selectedEntry = value;
+ if (value.edge) this.redraw();
+ }
+
+ get selectedEntry() {
+ return this._selectedEntry;
+ }
+
+ set scrollLeft(offset) {
+ this.timelineNode.scrollLeft = offset;
+ }
+
+ handleEntryTypeDoubleClick(e) {
+ this.dispatchEvent(new SelectionEvent(e.target.parentNode.entries));
+ }
+
+ timelineIndicatorMove(offset) {
+ this.timelineNode.scrollLeft += offset;
+ }
+
+ _handleTimelineScroll(e) {
+ let horizontal = e.currentTarget.scrollLeft;
+ this.dispatchEvent(new CustomEvent(
+ 'scrolltrack', {bubbles: true, composed: true, detail: horizontal}));
+ }
+
+ _createBackgroundImage(chunk) {
+ const stops = gradientStopsFromGroups(
+ chunk.length, chunk.height, chunk.getBreakdown(event => event.type),
+ type => this._legend.colorForType(type));
+ return `linear-gradient(0deg,${stops.join(',')})`;
+ }
+
+ _updateTimeline() {
+ const reusableNodes = Array.from(this.timelineChunks.childNodes).reverse();
+ let fragment = new DocumentFragment();
+ let chunks = this.chunks;
+ let max = chunks.max(each => each.size());
+ let start = this._timeline.startTime;
+ let end = this._timeline.endTime;
+ let duration = end - start;
+ this._timeToPixel = chunks.length * kChunkWidth / duration;
+ this._timeStartOffset = start * this._timeToPixel;
+ for (let i = 0; i < chunks.length; i++) {
+ let chunk = chunks[i];
+ let height = (chunk.size() / max * kChunkHeight);
+ chunk.height = height;
+ if (chunk.isEmpty()) continue;
+ let node = reusableNodes[reusableNodes.length - 1];
+ let reusedNode = false;
+ if (node?.className == 'chunk') {
+ reusableNodes.pop();
+ reusedNode = true;
+ } else {
+ node = DOM.div('chunk');
+ node.onmousemove = this._chunkMouseMoveHandler;
+ node.onclick = this._chunkClickHandler;
+ node.ondblclick = this._chunkDoubleClickHandler;
+ }
+ const style = node.style;
+ style.left = `${((chunk.start - start) * this._timeToPixel) | 0}px`;
+ style.height = `${height | 0}px`;
+ style.backgroundImage = this._createBackgroundImage(chunk);
+ node.chunk = chunk;
+ if (!reusedNode) fragment.appendChild(node);
+ }
+
+ // Put a time marker roughly every 20 chunks.
+ let expected = duration / chunks.length * 20;
+ let interval = (10 ** Math.floor(Math.log10(expected)));
+ let correction = Math.log10(expected / interval);
+ correction = (correction < 0.33) ? 1 : (correction < 0.75) ? 2.5 : 5;
+ interval *= correction;
+
+ let time = start;
+ while (time < end) {
+ let timeNode = DOM.div('timestamp');
+ timeNode.innerText = `${((time - start) / 1000) | 0} ms`;
+ timeNode.style.left = `${((time - start) * this._timeToPixel) | 0}px`;
+ fragment.appendChild(timeNode);
+ time += interval;
+ }
+
+ // Remove superfluos nodes lazily, for Chrome this is a very expensive
+ // operation.
+ if (reusableNodes.length > 0) {
+ for (const node of reusableNodes) {
+ node.style.display = 'none';
+ }
+ setTimeout(() => {
+ const range = document.createRange();
+ const first = reusableNodes[reusableNodes.length - 1];
+ const last = reusableNodes[0];
+ range.setStartBefore(first);
+ range.setEndAfter(last);
+ range.deleteContents();
+ }, 100);
+ }
+ this.timelineChunks.appendChild(fragment);
+ this.redraw();
+ }
+
+ _handleChunkMouseMove(event) {
+ if (this.isLocked) return false;
+ if (this._selectionHandler.isSelecting) return false;
+ let chunk = event.target.chunk;
+ if (!chunk) return;
+ if (chunk.isEmpty()) return;
+ // topmost map (at chunk.height) == map #0.
+ let relativeIndex = Math.round(
+ event.layerY / event.target.offsetHeight * (chunk.size() - 1));
+ let logEntry = chunk.at(relativeIndex);
+ this.dispatchEvent(new FocusEvent(logEntry));
+ this.dispatchEvent(new ToolTipEvent(logEntry.toStringLong(), event.target));
+ }
+
+ _handleChunkClick(event) {
+ this.isLocked = !this.isLocked;
+ }
+
+ _handleChunkDoubleClick(event) {
+ let chunk = event.target.chunk;
+ if (!chunk) return;
+ event.stopPropagation();
+ this.dispatchEvent(new SelectTimeEvent(chunk.start, chunk.end));
+ }
+
+ redraw() {
+ window.requestAnimationFrame(() => this._redraw());
+ }
+
+ _redraw() {
+ if (!(this._timeline.at(0) instanceof MapLogEntry)) return;
+ let canvas = this.timelineCanvas;
+ let width = (this.chunks.length + 1) * kChunkWidth;
+ if (width > 32767) width = 32767;
+ canvas.width = width;
+ canvas.height = kChunkHeight;
+ let ctx = canvas.getContext('2d');
+ ctx.clearRect(0, 0, canvas.width, kChunkHeight);
+ if (!this.selectedEntry || !this.selectedEntry.edge) return;
+ this.drawEdges(ctx);
+ }
+
+ setMapStyle(map, ctx) {
+ ctx.fillStyle = map.edge && map.edge.from ? CSSColor.onBackgroundColor :
+ CSSColor.onPrimaryColor;
+ }
+
+ setEdgeStyle(edge, ctx) {
+ let color = this._legend.colorForType(edge.type);
+ ctx.strokeStyle = color;
+ ctx.fillStyle = color;
+ }
+
+ markMap(ctx, map) {
+ let [x, y] = map.position(this.chunks);
+ ctx.beginPath();
+ this.setMapStyle(map, ctx);
+ ctx.arc(x, y, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.fillStyle = CSSColor.onBackgroundColor;
+ ctx.arc(x, y, 2, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+
+ markSelectedMap(ctx, map) {
+ let [x, y] = map.position(this.chunks);
+ ctx.beginPath();
+ this.setMapStyle(map, ctx);
+ ctx.arc(x, y, 6, 0, 2 * Math.PI);
+ ctx.strokeStyle = CSSColor.onBackgroundColor;
+ ctx.stroke();
+ }
+
+ drawEdges(ctx) {
+ // Draw the trace of maps in reverse order to make sure the outgoing
+ // transitions of previous maps aren't drawn over.
+ const kMaxOutgoingEdges = 100;
+ let nofEdges = 0;
+ let stack = [];
+ let current = this.selectedEntry;
+ while (current && nofEdges < kMaxOutgoingEdges) {
+ nofEdges += current.children.length;
+ stack.push(current);
+ current = current.parent();
+ }
+ ctx.save();
+ this.drawOutgoingEdges(ctx, this.selectedEntry, 3);
+ ctx.restore();
+
+ let labelOffset = 15;
+ let xPrev = 0;
+ while (current = stack.pop()) {
+ if (current.edge) {
+ this.setEdgeStyle(current.edge, ctx);
+ let [xTo, yTo] = this.drawEdge(ctx, current.edge, true, labelOffset);
+ if (xTo == xPrev) {
+ labelOffset += 8;
+ } else {
+ labelOffset = 15
+ }
+ xPrev = xTo;
+ }
+ this.markMap(ctx, current);
+ current = current.parent();
+ ctx.save();
+ // this.drawOutgoingEdges(ctx, current, 1);
+ ctx.restore();
+ }
+ // Mark selected map
+ this.markSelectedMap(ctx, this.selectedEntry);
+ }
+
+ drawEdge(ctx, edge, showLabel = true, labelOffset = 20) {
+ if (!edge.from || !edge.to) return [-1, -1];
+ let [xFrom, yFrom] = edge.from.position(this.chunks);
+ let [xTo, yTo] = edge.to.position(this.chunks);
+ let sameChunk = xTo == xFrom;
+ if (sameChunk) labelOffset += 8;
+
+ ctx.beginPath();
+ ctx.moveTo(xFrom, yFrom);
+ let offsetX = 20;
+ let offsetY = 20;
+ let midX = xFrom + (xTo - xFrom) / 2;
+ let midY = (yFrom + yTo) / 2 - 100;
+ if (!sameChunk) {
+ ctx.quadraticCurveTo(midX, midY, xTo, yTo);
+ } else {
+ ctx.lineTo(xTo, yTo);
+ }
+ if (!showLabel) {
+ ctx.stroke();
+ } else {
+ let centerX, centerY;
+ if (!sameChunk) {
+ centerX = (xFrom / 2 + midX + xTo / 2) / 2;
+ centerY = (yFrom / 2 + midY + yTo / 2) / 2;
+ } else {
+ centerX = xTo;
+ centerY = yTo;
+ }
+ ctx.moveTo(centerX, centerY);
+ ctx.lineTo(centerX + offsetX, centerY - labelOffset);
+ ctx.stroke();
+ ctx.textAlign = 'left';
+ ctx.fillStyle = this._legend.colorForType(edge.type);
+ ctx.fillText(
+ edge.toString(), centerX + offsetX + 2, centerY - labelOffset);
+ }
+ return [xTo, yTo];
+ }
+
+ drawOutgoingEdges(ctx, map, max = 10, depth = 0) {
+ if (!map) return;
+ if (depth >= max) return;
+ ctx.globalAlpha = 0.5 - depth * (0.3 / max);
+ ctx.strokeStyle = CSSColor.timelineBackgroundColor;
+ const limit = Math.min(map.children.length, 100)
+ for (let i = 0; i < limit; i++) {
+ let edge = map.children[i];
+ this.drawEdge(ctx, edge, true);
+ this.drawOutgoingEdges(ctx, edge.to, max, depth + 1);
+ }
+ }
+});
+
+class SelectionHandler {
+ // TODO turn into static field once Safari supports it.
+ static get SELECTION_OFFSET() {
+ return 10
+ };
+
+ _timeSelection = {start: -1, end: Infinity};
+ _selectionOriginTime = -1;
+
+ constructor(timeline) {
+ this._timeline = timeline;
+ this._timelineNode.addEventListener(
+ 'mousedown', e => this._handleTimeSelectionMouseDown(e));
+ this._timelineNode.addEventListener(
+ 'mouseup', e => this._handleTimeSelectionMouseUp(e));
+ this._timelineNode.addEventListener(
+ 'mousemove', e => this._handleTimeSelectionMouseMove(e));
+ }
+
+ update() {
+ if (!this.hasSelection) {
+ this._selectionNode.style.display = 'none';
+ return;
+ }
+ this._selectionNode.style.display = 'inherit';
+ const startPosition = this.timeToPosition(this._timeSelection.start);
+ const endPosition = this.timeToPosition(this._timeSelection.end);
+ this._leftHandleNode.style.left = startPosition + 'px';
+ this._rightHandleNode.style.left = endPosition + 'px';
+ const delta = endPosition - startPosition;
+ const selectionNode = this._selectionBackgroundNode;
+ selectionNode.style.left = startPosition + 'px';
+ selectionNode.style.width = delta + 'px';
+ }
+
+ set timeSelection(selection) {
+ this._timeSelection.start = selection.start;
+ this._timeSelection.end = selection.end;
+ }
+
+ clearSelection() {
+ this._timeline.dispatchEvent(new SelectTimeEvent());
+ }
+
+ timeToPosition(posX) {
+ return this._timeline.timeToPosition(posX);
+ }
+
+ positionToTime(posX) {
+ return this._timeline.positionToTime(posX);
+ }
+
+ get isSelecting() {
+ return this._selectionOriginTime >= 0;
+ }
+
+ get hasSelection() {
+ return this._timeSelection.start >= 0 &&
+ this._timeSelection.end != Infinity;
+ }
+
+ get _timelineNode() {
+ return this._timeline.$('#timeline');
+ }
+
+ get _selectionNode() {
+ return this._timeline.$('#selection');
+ }
+
+ get _selectionBackgroundNode() {
+ return this._timeline.$('#selectionBackground');
+ }
+
+ get _leftHandleNode() {
+ return this._timeline.$('#leftHandle');
+ }
+
+ get _rightHandleNode() {
+ return this._timeline.$('#rightHandle');
+ }
+
+ get _leftHandlePosX() {
+ return this._leftHandleNode.getBoundingClientRect().x;
+ }
+
+ get _rightHandlePosX() {
+ return this._rightHandleNode.getBoundingClientRect().x;
+ }
+
+ _isOnLeftHandle(posX) {
+ return Math.abs(this._leftHandlePosX - posX) <=
+ SelectionHandler.SELECTION_OFFSET;
+ }
+
+ _isOnRightHandle(posX) {
+ return Math.abs(this._rightHandlePosX - posX) <=
+ SelectionHandler.SELECTION_OFFSET;
+ }
+
+ _handleTimeSelectionMouseDown(e) {
+ let xPosition = e.clientX
+ // Update origin time in case we click on a handle.
+ if (this._isOnLeftHandle(xPosition)) {
+ xPosition = this._rightHandlePosX;
+ }
+ else if (this._isOnRightHandle(xPosition)) {
+ xPosition = this._leftHandlePosX;
+ }
+ this._selectionOriginTime = this.positionToTime(xPosition);
+ }
+
+ _handleTimeSelectionMouseMove(e) {
+ if (!this.isSelecting) return;
+ const currentTime = this.positionToTime(e.clientX);
+ this._timeline.dispatchEvent(new SynchronizeSelectionEvent(
+ Math.min(this._selectionOriginTime, currentTime),
+ Math.max(this._selectionOriginTime, currentTime)));
+ }
+
+ _handleTimeSelectionMouseUp(e) {
+ this._selectionOriginTime = -1;
+ const delta = this._timeSelection.end - this._timeSelection.start;
+ if (delta <= 1 || isNaN(delta)) return;
+ this._timeline.dispatchEvent(new SelectTimeEvent(
+ this._timeSelection.start, this._timeSelection.end));
+ }
+}
+
+class Legend {
+ _timeline;
+ _typesFilters = new Map();
+ _typeClickHandler = this._handleTypeClick.bind(this);
+ _filterPredicate = this.filter.bind(this);
+ onFilter = () => {};
+
+ constructor(table) {
+ this._table = table;
+ }
+
+ set timeline(timeline) {
+ this._timeline = timeline;
+ const groups = timeline.getBreakdown();
+ this._typesFilters = new Map(groups.map(each => [each.key, true]));
+ this._colors =
+ new Map(groups.map(each => [each.key, CSSColor.at(each.id)]));
+ }
+
+ get selection() {
+ return this._timeline.selectionOrSelf;
+ }
+
+ get filterPredicate() {
+ for (let visible of this._typesFilters.values()) {
+ if (!visible) return this._filterPredicate;
+ }
+ return undefined;
+ }
+
+ colorForType(type) {
+ return this._colors.get(type);
+ }
+
+ filter(logEntry) {
+ return this._typesFilters.get(logEntry.type);
+ }
+
+ update() {
+ const tbody = DOM.tbody();
+ const missingTypes = new Set(this._typesFilters.keys());
+ this.selection.getBreakdown().forEach(group => {
+ tbody.appendChild(this._addTypeRow(group));
+ missingTypes.delete(group.key);
+ });
+ missingTypes.forEach(key => tbody.appendChild(this._row('', key, 0, '0%')));
+ if (this._timeline.selection) {
+ tbody.appendChild(
+ this._row('', 'Selection', this.selection.length, '100%'));
+ }
+ tbody.appendChild(this._row('', 'All', this._timeline.length, ''));
+ this._table.tBodies[0].replaceWith(tbody);
+ }
+
+ _row(color, type, count, percent) {
+ const row = DOM.tr();
+ row.appendChild(DOM.td(color));
+ row.appendChild(DOM.td(type));
+ row.appendChild(DOM.td(count.toString()));
+ row.appendChild(DOM.td(percent));
+ return row
+ }
+
+ _addTypeRow(group) {
+ const color = this.colorForType(group.key);
+ const colorDiv = DOM.div('colorbox');
+ if (this._typesFilters.get(group.key)) {
+ colorDiv.style.backgroundColor = color;
+ } else {
+ colorDiv.style.borderColor = color;
+ colorDiv.style.backgroundColor = CSSColor.backgroundImage;
+ }
+ let percent = `${(group.count / this.selection.length * 100).toFixed(1)}%`;
+ const row = this._row(colorDiv, group.key, group.count, percent);
+ row.className = 'clickable';
+ row.onclick = this._typeClickHandler;
+ row.data = group.key;
+ return row;
+ }
+
+ _handleTypeClick(e) {
+ const type = e.currentTarget.data;
+ this._typesFilters.set(type, !this._typesFilters.get(type));
+ this.onFilter(type);
+ }
+} \ No newline at end of file
diff --git a/deps/v8/tools/system-analyzer/view/tool-tip-template.html b/deps/v8/tools/system-analyzer/view/tool-tip-template.html
new file mode 100644
index 0000000000..b0e9c72c45
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/tool-tip-template.html
@@ -0,0 +1,81 @@
+<!-- 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. -->
+<head>
+ <link href="./index.css" rel="stylesheet">
+</head>
+<style>
+ :host {
+ position: absolute;
+ z-index: 100;
+ }
+
+ #content {
+ background-color: var(--surface-color);
+ border: 3px var(--primary-color) solid;
+ border-radius: 10px;
+ min-width: 100px;
+ min-height: 100px;
+ padding: 10px;
+ box-shadow: 0px 0px 10px rgba(0,0,0,0.5);
+ width: auto;
+ }
+
+ .textContent {
+ font-family: monospace;
+ white-space: pre;
+ overflow-x: hidden;
+ max-width: 500px;
+ }
+
+ #body {
+ display: none;
+ position: absolute;
+ --tip-offset: 10px;
+ --tip-width: 10px;
+ --tip-height: 15px;
+ }
+
+ #body.top {
+ bottom: var(--tip-height);
+ }
+ #body.bottom {
+ top: var(--tip-height);
+ }
+ #body.left {
+ right: calc(var(--tip-offset) * -1 - var(--tip-width));
+ }
+ #body.right {
+ left: calc(var(--tip-offset) * -1 - var(--tip-width));
+ }
+
+ .tip {
+ width: 0;
+ height: 0;
+ border-style: solid;
+ position: absolute;
+ border-width: var(--tip-height) var(--tip-width) 0 var(--tip-width);
+ border-color: var(--primary-color) transparent transparent transparent;
+ pointer-events: none;
+ }
+
+ .top > .tip {
+ bottom: calc(var(--tip-height) * -1);
+ }
+ .bottom > .tip {
+ top: calc(var(--tip-height) * -1);
+ transform: scaleY(-1);
+ }
+ .left > .tip {
+ right: var(--tip-offset);
+ }
+ .right > .tip {
+ left: var(--tip-offset);
+ }
+</style>
+
+<div id="body">
+ <div id="content">
+ </div>
+ <div class="tip"></div>
+</div>
diff --git a/deps/v8/tools/system-analyzer/view/tool-tip.mjs b/deps/v8/tools/system-analyzer/view/tool-tip.mjs
new file mode 100644
index 0000000000..896c04dd29
--- /dev/null
+++ b/deps/v8/tools/system-analyzer/view/tool-tip.mjs
@@ -0,0 +1,110 @@
+// 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.
+
+import {DOM, V8CustomElement} from './helper.mjs';
+
+DOM.defineCustomElement(
+ 'view/tool-tip', (templateText) => class Tooltip extends V8CustomElement {
+ _targetNode;
+ _content;
+ _isHidden = true;
+ constructor() {
+ super(templateText);
+ this._intersectionObserver = new IntersectionObserver((entries) => {
+ if (entries[0].intersectionRatio <= 0) {
+ this.hide();
+ } else {
+ this.show();
+ this.update(true);
+ }
+ });
+ }
+
+ _update() {
+ if (!this._targetNode || this._isHidden) return;
+ const rect = this._targetNode.getBoundingClientRect();
+ rect.x += rect.width / 2;
+ let atRight = this._useRight(rect.x);
+ let atBottom = this._useBottom(rect.y);
+ if (atBottom) {
+ rect.y += rect.height;
+ }
+ this._setPosition(rect, atRight, atBottom);
+ this.update(true);
+ }
+
+ set positionOrTargetNode(positionOrTargetNode) {
+ if (positionOrTargetNode.nodeType === undefined) {
+ this.position = positionOrTargetNode;
+ } else {
+ this.targetNode = positionOrTargetNode;
+ }
+ }
+
+ set targetNode(targetNode) {
+ this._intersectionObserver.disconnect();
+ this._targetNode = targetNode;
+ if (targetNode) {
+ this._intersectionObserver.observe(targetNode);
+ this.update(true);
+ }
+ }
+
+ set position(position) {
+ this._targetNode = undefined;
+ this._setPosition(
+ position, this._useRight(position.x), this._useBottom(position.y));
+ }
+
+ _setPosition(viewportPosition, atRight, atBottom) {
+ const horizontalMode = atRight ? 'right' : 'left';
+ const verticalMode = atBottom ? 'bottom' : 'top';
+ this.bodyNode.className = horizontalMode + ' ' + verticalMode;
+ const pageX = viewportPosition.x + window.scrollX;
+ this.style.left = `${pageX}px`;
+ const pageY = viewportPosition.y + window.scrollY;
+ this.style.top = `${pageY}px`;
+ }
+
+ _useBottom(viewportY) {
+ return viewportY <= 400;
+ }
+
+ _useRight(viewportX) {
+ return viewportX < document.documentElement.clientWidth / 2;
+ }
+
+ set content(content) {
+ if (!content) return this.hide();
+ this.show();
+ if (typeof content === 'string') {
+ this.contentNode.innerHTML = content;
+ this.contentNode.className = 'textContent';
+ } else {
+ const newContent = DOM.div();
+ newContent.appendChild(content);
+ this.contentNode.replaceWith(newContent);
+ newContent.id = 'content';
+ }
+ }
+
+ hide() {
+ this._isHidden = true;
+ this.bodyNode.style.display = 'none';
+ this.targetNode = undefined;
+ }
+
+ show() {
+ this.bodyNode.style.display = 'block';
+ this._isHidden = false;
+ }
+
+ get bodyNode() {
+ return this.$('#body');
+ }
+
+ get contentNode() {
+ return this.$('#content');
+ }
+ });
diff --git a/deps/v8/tools/testrunner/base_runner.py b/deps/v8/tools/testrunner/base_runner.py
index d3674a4f8b..54a9e61b16 100644
--- a/deps/v8/tools/testrunner/base_runner.py
+++ b/deps/v8/tools/testrunner/base_runner.py
@@ -351,9 +351,6 @@ class BaseTestRunner(object):
help="Path to a file for storing json results.")
parser.add_option('--slow-tests-cutoff', type="int", default=100,
help='Collect N slowest tests')
- parser.add_option("--junitout", help="File name of the JUnit output")
- parser.add_option("--junittestsuite", default="v8tests",
- help="The testsuite name in the JUnit output file")
parser.add_option("--exit-after-n-failures", type="int", default=100,
help="Exit after the first N failures instead of "
"running all tests. Pass 0 to disable this feature.")
@@ -760,9 +757,6 @@ class BaseTestRunner(object):
def _create_progress_indicators(self, test_count, options):
procs = [PROGRESS_INDICATORS[options.progress]()]
- if options.junitout:
- procs.append(progress.JUnitTestProgressIndicator(options.junitout,
- options.junittestsuite))
if options.json_test_results:
procs.append(progress.JsonTestProgressIndicator(self.framework_name))
diff --git a/deps/v8/tools/testrunner/local/junit_output.py b/deps/v8/tools/testrunner/local/junit_output.py
deleted file mode 100644
index 52f31ec422..0000000000
--- a/deps/v8/tools/testrunner/local/junit_output.py
+++ /dev/null
@@ -1,49 +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.
-
-
-import xml.etree.ElementTree as xml
-
-
-class JUnitTestOutput:
- def __init__(self, test_suite_name):
- self.root = xml.Element("testsuite")
- self.root.attrib["name"] = test_suite_name
-
- def HasRunTest(self, test_name, test_cmd, test_duration, test_failure):
- testCaseElement = xml.Element("testcase")
- testCaseElement.attrib["name"] = test_name
- testCaseElement.attrib["cmd"] = test_cmd
- testCaseElement.attrib["time"] = str(round(test_duration, 3))
- if len(test_failure):
- failureElement = xml.Element("failure")
- failureElement.text = test_failure
- testCaseElement.append(failureElement)
- self.root.append(testCaseElement)
-
- def FinishAndWrite(self, f):
- xml.ElementTree(self.root).write(f, "UTF-8")
diff --git a/deps/v8/tools/testrunner/local/utils.py b/deps/v8/tools/testrunner/local/utils.py
index a6b92dc756..8fdc16b4bb 100644
--- a/deps/v8/tools/testrunner/local/utils.py
+++ b/deps/v8/tools/testrunner/local/utils.py
@@ -90,7 +90,8 @@ def GuessOS():
return 'solaris'
elif system == 'NetBSD':
return 'netbsd'
- elif system == 'AIX':
+ elif system in ['AIX', 'OS400']:
+ # OS400 runs an AIX emulator called PASE
return 'aix'
else:
return None
diff --git a/deps/v8/tools/testrunner/local/variants.py b/deps/v8/tools/testrunner/local/variants.py
index 4236c1678a..69ca853de3 100644
--- a/deps/v8/tools/testrunner/local/variants.py
+++ b/deps/v8/tools/testrunner/local/variants.py
@@ -53,12 +53,14 @@ ALL_VARIANT_FLAGS = {
# implications defined in flag-definitions.h.
INCOMPATIBLE_FLAGS_PER_VARIANT = {
"assert_types": ["--no-assert-types"],
- "jitless": ["--opt", "--liftoff", "--track-field-types", "--validate-asm"],
+ "jitless": ["--opt", "--always-opt", "--liftoff", "--track-field-types", "--validate-asm"],
"no_wasm_traps": ["--wasm-trap-handler"],
- "nooptimization": ["--opt", "--no-liftoff", "--predictable", "--wasm-tier-up"],
+ "nooptimization": ["--opt", "--always-opt", "--no-liftoff", "--wasm-tier-up"],
"slow_path": ["--no-force-slow-path"],
+ "stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"stress_incremental_marking": ["--no-stress-incremental-marking"],
- "stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile"],
+ "future": ["--parallel-compile-tasks"],
+ "stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile", "--parallel-compile-tasks"],
"stress": ["--no-stress-opt", "--always-opt", "--no-always-opt", "--liftoff", "--max-inlined-bytecode-size=*",
"--max-inlined-bytecode-size-cumulative=*", "--stress-inline"],
"turboprop": ["--interrupt-budget=*", "--no-turboprop"],
@@ -77,7 +79,8 @@ INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE = {
+ INCOMPATIBLE_FLAGS_PER_VARIANT["jitless"],
"predictable": ["--liftoff", "--parallel-compile-tasks",
"--concurrent-recompilation",
- "--wasm-num-compilation-tasks=*"],
+ "--wasm-num-compilation-tasks=*",
+ "--stress-concurrent-allocation"],
}
# Flags that lead to a contradiction when a certain extra-flag is present.
@@ -92,7 +95,9 @@ INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = {
"--no-enable-sse3": ["--enable-sse3"],
"--no-enable-sse4-1": ["--enable-sse4-1"],
"--optimize-for-size": ["--max-semi-space-size=*"],
+ "--stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"--stress-flush-bytecode": ["--no-stress-flush-bytecode"],
+ "--future": ["--parallel-compile-tasks"],
"--stress-incremental-marking": INCOMPATIBLE_FLAGS_PER_VARIANT["stress_incremental_marking"],
}
diff --git a/deps/v8/tools/testrunner/testproc/progress.py b/deps/v8/tools/testrunner/testproc/progress.py
index 634ef7c2f2..9ff943a5c2 100644
--- a/deps/v8/tools/testrunner/testproc/progress.py
+++ b/deps/v8/tools/testrunner/testproc/progress.py
@@ -15,7 +15,6 @@ import time
from . import base
from . import util
-from ..local import junit_output
def print_failure_header(test):
@@ -349,45 +348,6 @@ class MonochromeProgressIndicator(CompactProgressIndicator):
print(("\r" + (" " * last_length) + "\r"), end='')
-class JUnitTestProgressIndicator(ProgressIndicator):
- def __init__(self, junitout, junittestsuite):
- super(JUnitTestProgressIndicator, self).__init__()
- self._requirement = base.DROP_PASS_STDOUT
-
- self.outputter = junit_output.JUnitTestOutput(junittestsuite)
- if junitout:
- self.outfile = open(junitout, "w")
- else:
- self.outfile = sys.stdout
-
- def _on_result_for(self, test, result):
- # TODO(majeski): Support for dummy/grouped results
- fail_text = ""
- output = result.output
- if result.has_unexpected_output:
- stdout = output.stdout.strip()
- if len(stdout):
- fail_text += "stdout:\n%s\n" % stdout
- stderr = output.stderr.strip()
- if len(stderr):
- fail_text += "stderr:\n%s\n" % stderr
- fail_text += "Command: %s" % result.cmd.to_string()
- if output.HasCrashed():
- fail_text += "exit code: %d\n--- CRASHED ---" % output.exit_code
- if output.HasTimedOut():
- fail_text += "--- TIMEOUT ---"
- self.outputter.HasRunTest(
- test_name=str(test),
- test_cmd=result.cmd.to_string(relative=True),
- test_duration=output.duration,
- test_failure=fail_text)
-
- def finished(self):
- self.outputter.FinishAndWrite(self.outfile)
- if self.outfile != sys.stdout:
- self.outfile.close()
-
-
class JsonTestProgressIndicator(ProgressIndicator):
def __init__(self, framework_name):
super(JsonTestProgressIndicator, self).__init__()
diff --git a/deps/v8/tools/tickprocessor.mjs b/deps/v8/tools/tickprocessor.mjs
index 5b746d943a..54c37e68e0 100644
--- a/deps/v8/tools/tickprocessor.mjs
+++ b/deps/v8/tools/tickprocessor.mjs
@@ -31,11 +31,6 @@ import { Profile, JsonProfile } from "./profile.mjs";
import { ViewBuilder } from "./profile_view.mjs";
-export function inherits(childCtor, parentCtor) {
- childCtor.prototype.__proto__ = parentCtor.prototype;
-};
-
-
class V8Profile extends Profile {
static IC_RE =
/^(LoadGlobalIC: )|(Handler: )|(?:CallIC|LoadIC|StoreIC)|(?:Builtin: (?:Keyed)?(?:Load|Store)IC_)/;
@@ -75,20 +70,8 @@ export function readFile(fileName) {
}
-/**
- * Parser for dynamic code optimization state.
- */
-function parseState(s) {
- switch (s) {
- case "": return Profile.CodeState.COMPILED;
- case "~": return Profile.CodeState.OPTIMIZABLE;
- case "*": return Profile.CodeState.OPTIMIZED;
- }
- throw new Error(`unknown code state: ${s}`);
-}
-
-
-export function TickProcessor(
+export class TickProcessor extends LogReader {
+ constructor(
cppEntriesProvider,
separateIc,
separateBytecodes,
@@ -105,8 +88,10 @@ export function TickProcessor(
onlySummary,
runtimeTimerFilter,
preprocessJson) {
- this.preprocessJson = preprocessJson;
- LogReader.call(this, {
+ super({},
+ timedRange,
+ pairwiseTimedRange);
+ this.dispatchTable_ = {
'shared-library': { parsers: [parseString, parseInt, parseInt, parseInt],
processor: this.processSharedLibrary },
'code-creation': {
@@ -155,10 +140,10 @@ export function TickProcessor(
// Obsolete row types.
'code-allocate': null,
'begin-code-region': null,
- 'end-code-region': null },
- timedRange,
- pairwiseTimedRange);
+ 'end-code-region': null
+ };
+ this.preprocessJson = preprocessJson;
this.cppEntriesProvider_ = cppEntriesProvider;
this.callGraphSize_ = callGraphSize;
this.ignoreUnknown_ = ignoreUnknown;
@@ -214,11 +199,10 @@ export function TickProcessor(
this.generation_ = 1;
this.currentProducerProfile_ = null;
this.onlySummary_ = onlySummary;
-};
-inherits(TickProcessor, LogReader);
+}
-TickProcessor.VmStates = {
+static VmStates = {
JS: 0,
GC: 1,
PARSER: 2,
@@ -230,7 +214,7 @@ TickProcessor.VmStates = {
};
-TickProcessor.CodeTypes = {
+static CodeTypes = {
CPP: 0,
SHARED_LIB: 1
};
@@ -238,56 +222,56 @@ TickProcessor.CodeTypes = {
// codeTypes_ map because there can be zillions of them.
-TickProcessor.CALL_PROFILE_CUTOFF_PCT = 1.0;
+static CALL_PROFILE_CUTOFF_PCT = 1.0;
-TickProcessor.CALL_GRAPH_SIZE = 5;
+static CALL_GRAPH_SIZE = 5;
/**
* @override
*/
-TickProcessor.prototype.printError = function(str) {
+printError(str) {
printErr(str);
-};
+}
-TickProcessor.prototype.setCodeType = function(name, type) {
+setCodeType(name, type) {
this.codeTypes_[name] = TickProcessor.CodeTypes[type];
-};
+}
-TickProcessor.prototype.isSharedLibrary = function(name) {
+isSharedLibrary(name) {
return this.codeTypes_[name] == TickProcessor.CodeTypes.SHARED_LIB;
-};
+}
-TickProcessor.prototype.isCppCode = function(name) {
+isCppCode(name) {
return this.codeTypes_[name] == TickProcessor.CodeTypes.CPP;
-};
+}
-TickProcessor.prototype.isJsCode = function(name) {
+isJsCode(name) {
return name !== "UNKNOWN" && !(name in this.codeTypes_);
-};
+}
-TickProcessor.prototype.processLogFile = function(fileName) {
+processLogFile(fileName) {
this.lastLogFileName_ = fileName;
let line;
while (line = readline()) {
this.processLogLine(line);
}
-};
+}
-TickProcessor.prototype.processLogFileInTest = function(fileName) {
+processLogFileInTest(fileName) {
// Hack file name to avoid dealing with platform specifics.
this.lastLogFileName_ = 'v8.log';
const contents = readFile(fileName);
this.processLogChunk(contents);
-};
+}
-TickProcessor.prototype.processSharedLibrary = function(
+processSharedLibrary(
name, startAddr, endAddr, aslrSlide) {
const entry = this.profile_.addLibrary(name, startAddr, endAddr, aslrSlide);
this.setCodeType(entry.getName(), 'SHARED_LIB');
@@ -298,67 +282,67 @@ TickProcessor.prototype.processSharedLibrary = function(
self.profile_.addStaticCode(fName, fStart, fEnd);
self.setCodeType(fName, 'CPP');
});
-};
+}
-TickProcessor.prototype.processCodeCreation = function(
+processCodeCreation(
type, kind, timestamp, start, size, name, maybe_func) {
if (maybe_func.length) {
const funcAddr = parseInt(maybe_func[0]);
- const state = parseState(maybe_func[1]);
+ const state = Profile.parseState(maybe_func[1]);
this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
} else {
this.profile_.addCode(type, name, timestamp, start, size);
}
-};
+}
-TickProcessor.prototype.processCodeDeopt = function(
+processCodeDeopt(
timestamp, size, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) {
this.profile_.deoptCode(timestamp, code, inliningId, scriptOffset,
bailoutType, sourcePositionText, deoptReasonText);
-};
+}
-TickProcessor.prototype.processCodeMove = function(from, to) {
+processCodeMove(from, to) {
this.profile_.moveCode(from, to);
-};
+}
-TickProcessor.prototype.processCodeDelete = function(start) {
+processCodeDelete(start) {
this.profile_.deleteCode(start);
-};
+}
-TickProcessor.prototype.processCodeSourceInfo = function(
+processCodeSourceInfo(
start, script, startPos, endPos, sourcePositions, inliningPositions,
inlinedFunctions) {
this.profile_.addSourcePositions(start, script, startPos,
endPos, sourcePositions, inliningPositions, inlinedFunctions);
-};
+}
-TickProcessor.prototype.processScriptSource = function(script, url, source) {
+processScriptSource(script, url, source) {
this.profile_.addScriptSource(script, url, source);
-};
+}
-TickProcessor.prototype.processFunctionMove = function(from, to) {
+processFunctionMove(from, to) {
this.profile_.moveFunc(from, to);
-};
+}
-TickProcessor.prototype.includeTick = function(vmState) {
+includeTick(vmState) {
if (this.stateFilter_ !== null) {
return this.stateFilter_ == vmState;
} else if (this.runtimeTimerFilter_ !== null) {
return this.currentRuntimeTimer == this.runtimeTimerFilter_;
}
return true;
-};
+}
-TickProcessor.prototype.processRuntimeTimerEvent = function(name) {
+processRuntimeTimerEvent(name) {
this.currentRuntimeTimer = name;
}
-TickProcessor.prototype.processTick = function(pc,
+processTick(pc,
ns_since_start,
is_external_callback,
tos_or_external_callback,
@@ -394,21 +378,21 @@ TickProcessor.prototype.processTick = function(pc,
this.profile_.recordTick(
ns_since_start, vmState,
this.processStack(pc, tos_or_external_callback, stack));
-};
+}
-TickProcessor.prototype.advanceDistortion = function() {
+advanceDistortion() {
this.distortion += this.distortion_per_entry;
}
-TickProcessor.prototype.processHeapSampleBegin = function(space, state, ticks) {
+processHeapSampleBegin(space, state, ticks) {
if (space != 'Heap') return;
this.currentProducerProfile_ = new CallTree();
-};
+}
-TickProcessor.prototype.processHeapSampleEnd = function(space, state) {
+processHeapSampleEnd(space, state) {
if (space != 'Heap' || !this.currentProducerProfile_) return;
print(`Generation ${this.generation_}:`);
@@ -423,10 +407,10 @@ TickProcessor.prototype.processHeapSampleEnd = function(space, state) {
this.currentProducerProfile_ = null;
this.generation_++;
-};
+}
-TickProcessor.prototype.printStatistics = function() {
+printStatistics() {
if (this.preprocessJson) {
this.profile_.writeJson();
return;
@@ -505,29 +489,16 @@ TickProcessor.prototype.printStatistics = function() {
(rec2.internalFuncName < rec1.internalFuncName ? -1 : 1) );
this.printHeavyProfile(heavyView.head.children);
}
-};
-
-
-function padLeft(s, len) {
- s = s.toString();
- if (s.length < len) {
- const padLength = len - s.length;
- if (!(padLength in padLeft)) {
- padLeft[padLength] = new Array(padLength + 1).join(' ');
- }
- s = padLeft[padLength] + s;
- }
- return s;
-};
+}
-TickProcessor.prototype.printHeader = function(headerTitle) {
+printHeader(headerTitle) {
print(`\n [${headerTitle}]:`);
print(' ticks total nonlib name');
-};
+}
-TickProcessor.prototype.printLine = function(
+printLine(
entry, ticks, totalTicks, nonLibTicks) {
const pct = ticks * 100 / totalTicks;
const nonLibPct = nonLibTicks != null
@@ -539,7 +510,7 @@ TickProcessor.prototype.printLine = function(
entry);
}
-TickProcessor.prototype.printHeavyProfHeader = function() {
+printHeavyProfHeader() {
print('\n [Bottom up (heavy) profile]:');
print(' Note: percentage shows a share of a particular caller in the ' +
'total\n' +
@@ -548,10 +519,10 @@ TickProcessor.prototype.printHeavyProfHeader = function() {
TickProcessor.CALL_PROFILE_CUTOFF_PCT.toFixed(1) +
'% are not shown.\n');
print(' ticks parent name');
-};
+}
-TickProcessor.prototype.processProfile = function(
+processProfile(
profile, filterP, func) {
for (let i = 0, n = profile.length; i < n; ++i) {
const rec = profile[i];
@@ -562,7 +533,7 @@ TickProcessor.prototype.processProfile = function(
}
};
-TickProcessor.prototype.getLineAndColumn = function(name) {
+getLineAndColumn(name) {
const re = /:([0-9]+):([0-9]+)$/;
const array = re.exec(name);
if (!array) {
@@ -571,12 +542,12 @@ TickProcessor.prototype.getLineAndColumn = function(name) {
return {line: array[1], column: array[2]};
}
-TickProcessor.prototype.hasSourceMap = function() {
+hasSourceMap() {
return this.sourceMap != null;
-};
+}
-TickProcessor.prototype.formatFunctionName = function(funcName) {
+formatFunctionName(funcName) {
if (!this.hasSourceMap()) {
return funcName;
}
@@ -593,9 +564,9 @@ TickProcessor.prototype.formatFunctionName = function(funcName) {
const sourceColumn = entry[4] + 1;
return sourceFile + ':' + sourceLine + ':' + sourceColumn + ' -> ' + funcName;
-};
+}
-TickProcessor.prototype.printEntries = function(
+printEntries(
profile, totalTicks, nonLibTicks, filterP, callback, printAllTicks) {
const that = this;
this.processProfile(profile, filterP, function (rec) {
@@ -606,10 +577,9 @@ TickProcessor.prototype.printEntries = function(
that.printLine(funcName, rec.selfTime, totalTicks, nonLibTicks);
}
});
-};
-
+}
-TickProcessor.prototype.printHeavyProfile = function(profile, opt_indent) {
+ printHeavyProfile(profile, opt_indent) {
const self = this;
const indent = opt_indent || 0;
const indentStr = padLeft('', indent);
@@ -629,14 +599,27 @@ TickProcessor.prototype.printHeavyProfile = function(profile, opt_indent) {
print('');
}
});
-};
+}
+}
-function CppEntriesProvider() {
+
+function padLeft(s, len) {
+ s = s.toString();
+ if (s.length < len) {
+ const padLength = len - s.length;
+ if (!(padLength in padLeft)) {
+ padLeft[padLength] = new Array(padLength + 1).join(' ');
+ }
+ s = padLeft[padLength] + s;
+ }
+ return s;
};
-CppEntriesProvider.prototype.parseVmSymbols = function(
+class CppEntriesProvider {
+
+parseVmSymbols(
libName, libStart, libEnd, libASLRSlide, processorFunc) {
this.loadSymbols(libName);
@@ -699,17 +682,20 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
addEntry(funcInfo);
}
addEntry({name: '', start: libEnd});
-};
+}
-CppEntriesProvider.prototype.loadSymbols = function(libName) {
-};
+loadSymbols(libName) {
+}
+parseNextLine() { return false }
-CppEntriesProvider.prototype.parseNextLine = () => false;
+}
-export function UnixCppEntriesProvider(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
+export class UnixCppEntriesProvider extends CppEntriesProvider {
+ constructor(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
+ super();
this.symbols = [];
// File offset of a symbol minus the virtual address of a symbol found in
// the symbol table.
@@ -720,11 +706,10 @@ export function UnixCppEntriesProvider(nmExec, objdumpExec, targetRootFS, apkEmb
this.targetRootFS = targetRootFS;
this.apkEmbeddedLibrary = apkEmbeddedLibrary;
this.FUNC_RE = /^([0-9a-fA-F]{8,16}) ([0-9a-fA-F]{8,16} )?[tTwW] (.*)$/;
-};
-inherits(UnixCppEntriesProvider, CppEntriesProvider);
+}
-UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
+loadSymbols(libName) {
this.parsePos = 0;
if (this.apkEmbeddedLibrary && libName.endsWith('.apk')) {
libName = this.apkEmbeddedLibrary;
@@ -750,10 +735,10 @@ UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
// If the library cannot be found on this system let's not panic.
this.symbols = ['', ''];
}
-};
+}
-UnixCppEntriesProvider.prototype.parseNextLine = function() {
+parseNextLine() {
if (this.symbols.length == 0) {
return false;
}
@@ -775,18 +760,18 @@ UnixCppEntriesProvider.prototype.parseNextLine = function() {
}
}
return funcInfo;
-};
-
+}
+}
-export function MacCppEntriesProvider(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
- UnixCppEntriesProvider.call(this, nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary);
+export class MacCppEntriesProvider extends UnixCppEntriesProvider {
+ constructor(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
+ super(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary);
// Note an empty group. It is required, as UnixCppEntriesProvider expects 3 groups.
this.FUNC_RE = /^([0-9a-fA-F]{8,16})() (.*)$/;
-};
-inherits(MacCppEntriesProvider, UnixCppEntriesProvider);
+}
-MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+loadSymbols(libName) {
this.parsePos = 0;
libName = this.targetRootFS + libName;
@@ -798,34 +783,36 @@ MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
// If the library cannot be found on this system let's not panic.
this.symbols = '';
}
-};
+}
+}
-export function WindowsCppEntriesProvider(_ignored_nmExec, _ignored_objdumpExec, targetRootFS,
+export class WindowsCppEntriesProvider extends CppEntriesProvider {
+ constructor(_ignored_nmExec, _ignored_objdumpExec, targetRootFS,
_ignored_apkEmbeddedLibrary) {
+ super();
this.targetRootFS = targetRootFS;
this.symbols = '';
this.parsePos = 0;
};
-inherits(WindowsCppEntriesProvider, CppEntriesProvider);
-WindowsCppEntriesProvider.FILENAME_RE = /^(.*)\.([^.]+)$/;
+static FILENAME_RE = /^(.*)\.([^.]+)$/;
-WindowsCppEntriesProvider.FUNC_RE =
+static FUNC_RE =
/^\s+0001:[0-9a-fA-F]{8}\s+([_\?@$0-9a-zA-Z]+)\s+([0-9a-fA-F]{8}).*$/;
-WindowsCppEntriesProvider.IMAGE_BASE_RE =
+static IMAGE_BASE_RE =
/^\s+0000:00000000\s+___ImageBase\s+([0-9a-fA-F]{8}).*$/;
// This is almost a constant on Windows.
-WindowsCppEntriesProvider.EXE_IMAGE_BASE = 0x00400000;
+static EXE_IMAGE_BASE = 0x00400000;
-WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
+loadSymbols(libName) {
libName = this.targetRootFS + libName;
const fileNameFields = libName.match(WindowsCppEntriesProvider.FILENAME_RE);
if (!fileNameFields) return;
@@ -840,7 +827,7 @@ WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
};
-WindowsCppEntriesProvider.prototype.parseNextLine = function() {
+parseNextLine() {
const lineEndPos = this.symbols.indexOf('\r\n', this.parsePos);
if (lineEndPos == -1) {
return false;
@@ -875,14 +862,15 @@ WindowsCppEntriesProvider.prototype.parseNextLine = function() {
*
* ?LookupInDescriptor@JSObject@internal@v8@@...arguments info...
*/
-WindowsCppEntriesProvider.prototype.unmangleName = function(name) {
+ unmangleName(name) {
// Empty or non-mangled name.
if (name.length < 1 || name.charAt(0) != '?') return name;
const nameEndPos = name.indexOf('@@');
const components = name.substring(1, nameEndPos).split('@');
components.reverse();
return components.join('::');
-};
+}
+}
export class ArgumentsProcessor extends BaseArgumentsProcessor {
diff --git a/deps/v8/tools/v8heapconst.py b/deps/v8/tools/v8heapconst.py
index 0dd31d4ad2..cfd41e6bbd 100644
--- a/deps/v8/tools/v8heapconst.py
+++ b/deps/v8/tools/v8heapconst.py
@@ -11,8 +11,6 @@ INSTANCE_TYPES = {
2: "EXTERNAL_INTERNALIZED_STRING_TYPE",
8: "ONE_BYTE_INTERNALIZED_STRING_TYPE",
10: "EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE",
- 18: "UNCACHED_EXTERNAL_INTERNALIZED_STRING_TYPE",
- 26: "UNCACHED_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE",
32: "STRING_TYPE",
33: "CONS_STRING_TYPE",
34: "EXTERNAL_STRING_TYPE",
@@ -77,294 +75,301 @@ INSTANCE_TYPES = {
113: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
114: "WASM_INDIRECT_FUNCTION_TABLE_TYPE",
115: "WASM_JS_FUNCTION_DATA_TYPE",
- 116: "WASM_VALUE_TYPE",
- 117: "FIXED_ARRAY_TYPE",
- 118: "HASH_TABLE_TYPE",
- 119: "EPHEMERON_HASH_TABLE_TYPE",
- 120: "GLOBAL_DICTIONARY_TYPE",
- 121: "NAME_DICTIONARY_TYPE",
- 122: "NUMBER_DICTIONARY_TYPE",
- 123: "ORDERED_HASH_MAP_TYPE",
- 124: "ORDERED_HASH_SET_TYPE",
- 125: "ORDERED_NAME_DICTIONARY_TYPE",
- 126: "SIMPLE_NUMBER_DICTIONARY_TYPE",
- 127: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE",
- 128: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
- 129: "SCOPE_INFO_TYPE",
- 130: "SCRIPT_CONTEXT_TABLE_TYPE",
- 131: "BYTE_ARRAY_TYPE",
- 132: "BYTECODE_ARRAY_TYPE",
- 133: "FIXED_DOUBLE_ARRAY_TYPE",
- 134: "INTERNAL_CLASS_WITH_SMI_ELEMENTS_TYPE",
- 135: "SLOPPY_ARGUMENTS_ELEMENTS_TYPE",
- 136: "AWAIT_CONTEXT_TYPE",
- 137: "BLOCK_CONTEXT_TYPE",
- 138: "CATCH_CONTEXT_TYPE",
- 139: "DEBUG_EVALUATE_CONTEXT_TYPE",
- 140: "EVAL_CONTEXT_TYPE",
- 141: "FUNCTION_CONTEXT_TYPE",
- 142: "MODULE_CONTEXT_TYPE",
- 143: "NATIVE_CONTEXT_TYPE",
- 144: "SCRIPT_CONTEXT_TYPE",
- 145: "WITH_CONTEXT_TYPE",
- 146: "EXPORTED_SUB_CLASS_BASE_TYPE",
- 147: "EXPORTED_SUB_CLASS_TYPE",
- 148: "EXPORTED_SUB_CLASS2_TYPE",
- 149: "SMALL_ORDERED_HASH_MAP_TYPE",
- 150: "SMALL_ORDERED_HASH_SET_TYPE",
- 151: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
- 152: "DESCRIPTOR_ARRAY_TYPE",
- 153: "STRONG_DESCRIPTOR_ARRAY_TYPE",
- 154: "SOURCE_TEXT_MODULE_TYPE",
- 155: "SYNTHETIC_MODULE_TYPE",
- 156: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
- 157: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
- 158: "WEAK_FIXED_ARRAY_TYPE",
- 159: "TRANSITION_ARRAY_TYPE",
- 160: "CELL_TYPE",
- 161: "CODE_TYPE",
- 162: "CODE_DATA_CONTAINER_TYPE",
- 163: "COVERAGE_INFO_TYPE",
- 164: "EMBEDDER_DATA_ARRAY_TYPE",
- 165: "FEEDBACK_METADATA_TYPE",
- 166: "FEEDBACK_VECTOR_TYPE",
- 167: "FILLER_TYPE",
- 168: "FREE_SPACE_TYPE",
- 169: "INTERNAL_CLASS_TYPE",
- 170: "INTERNAL_CLASS_WITH_STRUCT_ELEMENTS_TYPE",
- 171: "MAP_TYPE",
- 172: "ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE",
- 173: "PREPARSE_DATA_TYPE",
- 174: "PROPERTY_ARRAY_TYPE",
- 175: "PROPERTY_CELL_TYPE",
- 176: "SHARED_FUNCTION_INFO_TYPE",
- 177: "SMI_BOX_TYPE",
- 178: "SMI_PAIR_TYPE",
- 179: "SORT_STATE_TYPE",
- 180: "WASM_ARRAY_TYPE",
- 181: "WASM_CAPI_FUNCTION_DATA_TYPE",
- 182: "WASM_STRUCT_TYPE",
- 183: "WEAK_ARRAY_LIST_TYPE",
- 184: "WEAK_CELL_TYPE",
- 185: "JS_PROXY_TYPE",
+ 116: "FIXED_ARRAY_TYPE",
+ 117: "HASH_TABLE_TYPE",
+ 118: "EPHEMERON_HASH_TABLE_TYPE",
+ 119: "GLOBAL_DICTIONARY_TYPE",
+ 120: "NAME_DICTIONARY_TYPE",
+ 121: "NUMBER_DICTIONARY_TYPE",
+ 122: "ORDERED_HASH_MAP_TYPE",
+ 123: "ORDERED_HASH_SET_TYPE",
+ 124: "ORDERED_NAME_DICTIONARY_TYPE",
+ 125: "SIMPLE_NUMBER_DICTIONARY_TYPE",
+ 126: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE",
+ 127: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
+ 128: "SCOPE_INFO_TYPE",
+ 129: "SCRIPT_CONTEXT_TABLE_TYPE",
+ 130: "BYTE_ARRAY_TYPE",
+ 131: "BYTECODE_ARRAY_TYPE",
+ 132: "FIXED_DOUBLE_ARRAY_TYPE",
+ 133: "INTERNAL_CLASS_WITH_SMI_ELEMENTS_TYPE",
+ 134: "SLOPPY_ARGUMENTS_ELEMENTS_TYPE",
+ 135: "AWAIT_CONTEXT_TYPE",
+ 136: "BLOCK_CONTEXT_TYPE",
+ 137: "CATCH_CONTEXT_TYPE",
+ 138: "DEBUG_EVALUATE_CONTEXT_TYPE",
+ 139: "EVAL_CONTEXT_TYPE",
+ 140: "FUNCTION_CONTEXT_TYPE",
+ 141: "MODULE_CONTEXT_TYPE",
+ 142: "NATIVE_CONTEXT_TYPE",
+ 143: "SCRIPT_CONTEXT_TYPE",
+ 144: "WITH_CONTEXT_TYPE",
+ 145: "EXPORTED_SUB_CLASS_BASE_TYPE",
+ 146: "EXPORTED_SUB_CLASS_TYPE",
+ 147: "EXPORTED_SUB_CLASS2_TYPE",
+ 148: "SMALL_ORDERED_HASH_MAP_TYPE",
+ 149: "SMALL_ORDERED_HASH_SET_TYPE",
+ 150: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
+ 151: "DESCRIPTOR_ARRAY_TYPE",
+ 152: "STRONG_DESCRIPTOR_ARRAY_TYPE",
+ 153: "SOURCE_TEXT_MODULE_TYPE",
+ 154: "SYNTHETIC_MODULE_TYPE",
+ 155: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
+ 156: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
+ 157: "WEAK_FIXED_ARRAY_TYPE",
+ 158: "TRANSITION_ARRAY_TYPE",
+ 159: "CELL_TYPE",
+ 160: "CODE_TYPE",
+ 161: "CODE_DATA_CONTAINER_TYPE",
+ 162: "COVERAGE_INFO_TYPE",
+ 163: "EMBEDDER_DATA_ARRAY_TYPE",
+ 164: "FEEDBACK_METADATA_TYPE",
+ 165: "FEEDBACK_VECTOR_TYPE",
+ 166: "FILLER_TYPE",
+ 167: "FREE_SPACE_TYPE",
+ 168: "INTERNAL_CLASS_TYPE",
+ 169: "INTERNAL_CLASS_WITH_STRUCT_ELEMENTS_TYPE",
+ 170: "MAP_TYPE",
+ 171: "ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE",
+ 172: "PREPARSE_DATA_TYPE",
+ 173: "PROPERTY_ARRAY_TYPE",
+ 174: "PROPERTY_CELL_TYPE",
+ 175: "SHARED_FUNCTION_INFO_TYPE",
+ 176: "SMI_BOX_TYPE",
+ 177: "SMI_PAIR_TYPE",
+ 178: "SORT_STATE_TYPE",
+ 179: "WASM_ARRAY_TYPE",
+ 180: "WASM_CAPI_FUNCTION_DATA_TYPE",
+ 181: "WASM_STRUCT_TYPE",
+ 182: "WEAK_ARRAY_LIST_TYPE",
+ 183: "WEAK_CELL_TYPE",
+ 184: "JS_PROXY_TYPE",
1057: "JS_OBJECT_TYPE",
- 186: "JS_GLOBAL_OBJECT_TYPE",
- 187: "JS_GLOBAL_PROXY_TYPE",
- 188: "JS_MODULE_NAMESPACE_TYPE",
+ 185: "JS_GLOBAL_OBJECT_TYPE",
+ 186: "JS_GLOBAL_PROXY_TYPE",
+ 187: "JS_MODULE_NAMESPACE_TYPE",
1040: "JS_SPECIAL_API_OBJECT_TYPE",
1041: "JS_PRIMITIVE_WRAPPER_TYPE",
- 1042: "JS_MAP_KEY_ITERATOR_TYPE",
- 1043: "JS_MAP_KEY_VALUE_ITERATOR_TYPE",
- 1044: "JS_MAP_VALUE_ITERATOR_TYPE",
- 1045: "JS_SET_KEY_VALUE_ITERATOR_TYPE",
- 1046: "JS_SET_VALUE_ITERATOR_TYPE",
- 1047: "JS_GENERATOR_OBJECT_TYPE",
- 1048: "JS_ASYNC_FUNCTION_OBJECT_TYPE",
- 1049: "JS_ASYNC_GENERATOR_OBJECT_TYPE",
- 1050: "JS_DATA_VIEW_TYPE",
- 1051: "JS_TYPED_ARRAY_TYPE",
- 1052: "JS_MAP_TYPE",
- 1053: "JS_SET_TYPE",
- 1054: "JS_WEAK_MAP_TYPE",
- 1055: "JS_WEAK_SET_TYPE",
+ 1042: "JS_ARRAY_ITERATOR_PROTOTYPE_TYPE",
+ 1043: "JS_ITERATOR_PROTOTYPE_TYPE",
+ 1044: "JS_MAP_ITERATOR_PROTOTYPE_TYPE",
+ 1045: "JS_OBJECT_PROTOTYPE_TYPE",
+ 1046: "JS_PROMISE_PROTOTYPE_TYPE",
+ 1047: "JS_REG_EXP_PROTOTYPE_TYPE",
+ 1048: "JS_SET_ITERATOR_PROTOTYPE_TYPE",
+ 1049: "JS_SET_PROTOTYPE_TYPE",
+ 1050: "JS_STRING_ITERATOR_PROTOTYPE_TYPE",
+ 1051: "JS_TYPED_ARRAY_PROTOTYPE_TYPE",
+ 1052: "JS_GENERATOR_OBJECT_TYPE",
+ 1053: "JS_ASYNC_FUNCTION_OBJECT_TYPE",
+ 1054: "JS_ASYNC_GENERATOR_OBJECT_TYPE",
+ 1055: "JS_ARGUMENTS_OBJECT_TYPE",
1056: "JS_API_OBJECT_TYPE",
- 1058: "JS_ARGUMENTS_OBJECT_TYPE",
- 1059: "JS_ARRAY_TYPE",
- 1060: "JS_ARRAY_BUFFER_TYPE",
- 1061: "JS_ARRAY_ITERATOR_TYPE",
- 1062: "JS_ASYNC_FROM_SYNC_ITERATOR_TYPE",
- 1063: "JS_COLLATOR_TYPE",
- 1064: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
- 1065: "JS_DATE_TYPE",
- 1066: "JS_DATE_TIME_FORMAT_TYPE",
- 1067: "JS_DISPLAY_NAMES_TYPE",
- 1068: "JS_ERROR_TYPE",
- 1069: "JS_FINALIZATION_REGISTRY_TYPE",
- 1070: "JS_LIST_FORMAT_TYPE",
- 1071: "JS_LOCALE_TYPE",
- 1072: "JS_MESSAGE_OBJECT_TYPE",
- 1073: "JS_NUMBER_FORMAT_TYPE",
- 1074: "JS_PLURAL_RULES_TYPE",
- 1075: "JS_PROMISE_TYPE",
- 1076: "JS_REG_EXP_TYPE",
- 1077: "JS_REG_EXP_STRING_ITERATOR_TYPE",
- 1078: "JS_RELATIVE_TIME_FORMAT_TYPE",
- 1079: "JS_SEGMENT_ITERATOR_TYPE",
- 1080: "JS_SEGMENTER_TYPE",
- 1081: "JS_SEGMENTS_TYPE",
- 1082: "JS_STRING_ITERATOR_TYPE",
- 1083: "JS_V8_BREAK_ITERATOR_TYPE",
- 1084: "JS_WEAK_REF_TYPE",
- 1085: "WASM_EXCEPTION_OBJECT_TYPE",
- 1086: "WASM_GLOBAL_OBJECT_TYPE",
- 1087: "WASM_INSTANCE_OBJECT_TYPE",
- 1088: "WASM_MEMORY_OBJECT_TYPE",
- 1089: "WASM_MODULE_OBJECT_TYPE",
- 1090: "WASM_TABLE_OBJECT_TYPE",
- 1091: "JS_BOUND_FUNCTION_TYPE",
- 1092: "JS_FUNCTION_TYPE",
+ 1058: "JS_MAP_KEY_ITERATOR_TYPE",
+ 1059: "JS_MAP_KEY_VALUE_ITERATOR_TYPE",
+ 1060: "JS_MAP_VALUE_ITERATOR_TYPE",
+ 1061: "JS_SET_KEY_VALUE_ITERATOR_TYPE",
+ 1062: "JS_SET_VALUE_ITERATOR_TYPE",
+ 1063: "JS_DATA_VIEW_TYPE",
+ 1064: "JS_TYPED_ARRAY_TYPE",
+ 1065: "JS_MAP_TYPE",
+ 1066: "JS_SET_TYPE",
+ 1067: "JS_BOUND_FUNCTION_TYPE",
+ 1068: "JS_FUNCTION_TYPE",
+ 1069: "JS_WEAK_MAP_TYPE",
+ 1070: "JS_WEAK_SET_TYPE",
+ 1071: "JS_ARRAY_TYPE",
+ 1072: "JS_ARRAY_BUFFER_TYPE",
+ 1073: "JS_ARRAY_ITERATOR_TYPE",
+ 1074: "JS_ASYNC_FROM_SYNC_ITERATOR_TYPE",
+ 1075: "JS_COLLATOR_TYPE",
+ 1076: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
+ 1077: "JS_DATE_TYPE",
+ 1078: "JS_DATE_TIME_FORMAT_TYPE",
+ 1079: "JS_DISPLAY_NAMES_TYPE",
+ 1080: "JS_ERROR_TYPE",
+ 1081: "JS_FINALIZATION_REGISTRY_TYPE",
+ 1082: "JS_LIST_FORMAT_TYPE",
+ 1083: "JS_LOCALE_TYPE",
+ 1084: "JS_MESSAGE_OBJECT_TYPE",
+ 1085: "JS_NUMBER_FORMAT_TYPE",
+ 1086: "JS_PLURAL_RULES_TYPE",
+ 1087: "JS_PROMISE_TYPE",
+ 1088: "JS_REG_EXP_TYPE",
+ 1089: "JS_REG_EXP_STRING_ITERATOR_TYPE",
+ 1090: "JS_RELATIVE_TIME_FORMAT_TYPE",
+ 1091: "JS_SEGMENT_ITERATOR_TYPE",
+ 1092: "JS_SEGMENTER_TYPE",
+ 1093: "JS_SEGMENTS_TYPE",
+ 1094: "JS_STRING_ITERATOR_TYPE",
+ 1095: "JS_V8_BREAK_ITERATOR_TYPE",
+ 1096: "JS_WEAK_REF_TYPE",
+ 1097: "WASM_EXCEPTION_OBJECT_TYPE",
+ 1098: "WASM_GLOBAL_OBJECT_TYPE",
+ 1099: "WASM_INSTANCE_OBJECT_TYPE",
+ 1100: "WASM_MEMORY_OBJECT_TYPE",
+ 1101: "WASM_MODULE_OBJECT_TYPE",
+ 1102: "WASM_TABLE_OBJECT_TYPE",
}
# List of known V8 maps.
KNOWN_MAPS = {
- ("read_only_space", 0x02115): (171, "MetaMap"),
+ ("read_only_space", 0x02115): (170, "MetaMap"),
("read_only_space", 0x0213d): (67, "NullMap"),
- ("read_only_space", 0x02165): (153, "StrongDescriptorArrayMap"),
- ("read_only_space", 0x0218d): (158, "WeakFixedArrayMap"),
+ ("read_only_space", 0x02165): (152, "StrongDescriptorArrayMap"),
+ ("read_only_space", 0x0218d): (157, "WeakFixedArrayMap"),
("read_only_space", 0x021cd): (96, "EnumCacheMap"),
- ("read_only_space", 0x02201): (117, "FixedArrayMap"),
+ ("read_only_space", 0x02201): (116, "FixedArrayMap"),
("read_only_space", 0x0224d): (8, "OneByteInternalizedStringMap"),
- ("read_only_space", 0x02299): (168, "FreeSpaceMap"),
- ("read_only_space", 0x022c1): (167, "OnePointerFillerMap"),
- ("read_only_space", 0x022e9): (167, "TwoPointerFillerMap"),
+ ("read_only_space", 0x02299): (167, "FreeSpaceMap"),
+ ("read_only_space", 0x022c1): (166, "OnePointerFillerMap"),
+ ("read_only_space", 0x022e9): (166, "TwoPointerFillerMap"),
("read_only_space", 0x02311): (67, "UninitializedMap"),
("read_only_space", 0x02389): (67, "UndefinedMap"),
("read_only_space", 0x023cd): (66, "HeapNumberMap"),
("read_only_space", 0x02401): (67, "TheHoleMap"),
("read_only_space", 0x02461): (67, "BooleanMap"),
- ("read_only_space", 0x02505): (131, "ByteArrayMap"),
- ("read_only_space", 0x0252d): (117, "FixedCOWArrayMap"),
- ("read_only_space", 0x02555): (118, "HashTableMap"),
+ ("read_only_space", 0x02505): (130, "ByteArrayMap"),
+ ("read_only_space", 0x0252d): (116, "FixedCOWArrayMap"),
+ ("read_only_space", 0x02555): (117, "HashTableMap"),
("read_only_space", 0x0257d): (64, "SymbolMap"),
("read_only_space", 0x025a5): (40, "OneByteStringMap"),
- ("read_only_space", 0x025cd): (129, "ScopeInfoMap"),
- ("read_only_space", 0x025f5): (176, "SharedFunctionInfoMap"),
- ("read_only_space", 0x0261d): (161, "CodeMap"),
- ("read_only_space", 0x02645): (160, "CellMap"),
- ("read_only_space", 0x0266d): (175, "GlobalPropertyCellMap"),
+ ("read_only_space", 0x025cd): (128, "ScopeInfoMap"),
+ ("read_only_space", 0x025f5): (175, "SharedFunctionInfoMap"),
+ ("read_only_space", 0x0261d): (160, "CodeMap"),
+ ("read_only_space", 0x02645): (159, "CellMap"),
+ ("read_only_space", 0x0266d): (174, "GlobalPropertyCellMap"),
("read_only_space", 0x02695): (70, "ForeignMap"),
- ("read_only_space", 0x026bd): (159, "TransitionArrayMap"),
+ ("read_only_space", 0x026bd): (158, "TransitionArrayMap"),
("read_only_space", 0x026e5): (45, "ThinOneByteStringMap"),
- ("read_only_space", 0x0270d): (166, "FeedbackVectorMap"),
- ("read_only_space", 0x0273d): (67, "ArgumentsMarkerMap"),
- ("read_only_space", 0x0279d): (67, "ExceptionMap"),
- ("read_only_space", 0x027f9): (67, "TerminationExceptionMap"),
- ("read_only_space", 0x02861): (67, "OptimizedOutMap"),
- ("read_only_space", 0x028c1): (67, "StaleRegisterMap"),
- ("read_only_space", 0x02921): (130, "ScriptContextTableMap"),
- ("read_only_space", 0x02949): (127, "ClosureFeedbackCellArrayMap"),
- ("read_only_space", 0x02971): (165, "FeedbackMetadataArrayMap"),
- ("read_only_space", 0x02999): (117, "ArrayListMap"),
- ("read_only_space", 0x029c1): (65, "BigIntMap"),
- ("read_only_space", 0x029e9): (128, "ObjectBoilerplateDescriptionMap"),
- ("read_only_space", 0x02a11): (132, "BytecodeArrayMap"),
- ("read_only_space", 0x02a39): (162, "CodeDataContainerMap"),
- ("read_only_space", 0x02a61): (163, "CoverageInfoMap"),
- ("read_only_space", 0x02a89): (133, "FixedDoubleArrayMap"),
- ("read_only_space", 0x02ab1): (120, "GlobalDictionaryMap"),
- ("read_only_space", 0x02ad9): (97, "ManyClosuresCellMap"),
- ("read_only_space", 0x02b01): (117, "ModuleInfoMap"),
- ("read_only_space", 0x02b29): (121, "NameDictionaryMap"),
- ("read_only_space", 0x02b51): (97, "NoClosuresCellMap"),
- ("read_only_space", 0x02b79): (122, "NumberDictionaryMap"),
- ("read_only_space", 0x02ba1): (97, "OneClosureCellMap"),
- ("read_only_space", 0x02bc9): (123, "OrderedHashMapMap"),
- ("read_only_space", 0x02bf1): (124, "OrderedHashSetMap"),
- ("read_only_space", 0x02c19): (125, "OrderedNameDictionaryMap"),
- ("read_only_space", 0x02c41): (173, "PreparseDataMap"),
- ("read_only_space", 0x02c69): (174, "PropertyArrayMap"),
- ("read_only_space", 0x02c91): (93, "SideEffectCallHandlerInfoMap"),
- ("read_only_space", 0x02cb9): (93, "SideEffectFreeCallHandlerInfoMap"),
- ("read_only_space", 0x02ce1): (93, "NextCallSideEffectFreeCallHandlerInfoMap"),
- ("read_only_space", 0x02d09): (126, "SimpleNumberDictionaryMap"),
- ("read_only_space", 0x02d31): (149, "SmallOrderedHashMapMap"),
- ("read_only_space", 0x02d59): (150, "SmallOrderedHashSetMap"),
- ("read_only_space", 0x02d81): (151, "SmallOrderedNameDictionaryMap"),
- ("read_only_space", 0x02da9): (154, "SourceTextModuleMap"),
- ("read_only_space", 0x02dd1): (155, "SyntheticModuleMap"),
- ("read_only_space", 0x02df9): (157, "UncompiledDataWithoutPreparseDataMap"),
- ("read_only_space", 0x02e21): (156, "UncompiledDataWithPreparseDataMap"),
- ("read_only_space", 0x02e49): (71, "WasmTypeInfoMap"),
- ("read_only_space", 0x02e71): (183, "WeakArrayListMap"),
- ("read_only_space", 0x02e99): (119, "EphemeronHashTableMap"),
- ("read_only_space", 0x02ec1): (164, "EmbedderDataArrayMap"),
- ("read_only_space", 0x02ee9): (184, "WeakCellMap"),
- ("read_only_space", 0x02f11): (32, "StringMap"),
- ("read_only_space", 0x02f39): (41, "ConsOneByteStringMap"),
- ("read_only_space", 0x02f61): (33, "ConsStringMap"),
- ("read_only_space", 0x02f89): (37, "ThinStringMap"),
- ("read_only_space", 0x02fb1): (35, "SlicedStringMap"),
- ("read_only_space", 0x02fd9): (43, "SlicedOneByteStringMap"),
- ("read_only_space", 0x03001): (34, "ExternalStringMap"),
- ("read_only_space", 0x03029): (42, "ExternalOneByteStringMap"),
- ("read_only_space", 0x03051): (50, "UncachedExternalStringMap"),
- ("read_only_space", 0x03079): (0, "InternalizedStringMap"),
- ("read_only_space", 0x030a1): (2, "ExternalInternalizedStringMap"),
- ("read_only_space", 0x030c9): (10, "ExternalOneByteInternalizedStringMap"),
- ("read_only_space", 0x030f1): (18, "UncachedExternalInternalizedStringMap"),
- ("read_only_space", 0x03119): (26, "UncachedExternalOneByteInternalizedStringMap"),
- ("read_only_space", 0x03141): (58, "UncachedExternalOneByteStringMap"),
- ("read_only_space", 0x03169): (67, "SelfReferenceMarkerMap"),
- ("read_only_space", 0x03191): (67, "BasicBlockCountersMarkerMap"),
- ("read_only_space", 0x031d5): (87, "ArrayBoilerplateDescriptionMap"),
- ("read_only_space", 0x032bd): (99, "InterceptorInfoMap"),
- ("read_only_space", 0x053c9): (72, "PromiseFulfillReactionJobTaskMap"),
- ("read_only_space", 0x053f1): (73, "PromiseRejectReactionJobTaskMap"),
- ("read_only_space", 0x05419): (74, "CallableTaskMap"),
- ("read_only_space", 0x05441): (75, "CallbackTaskMap"),
- ("read_only_space", 0x05469): (76, "PromiseResolveThenableJobTaskMap"),
- ("read_only_space", 0x05491): (79, "FunctionTemplateInfoMap"),
- ("read_only_space", 0x054b9): (80, "ObjectTemplateInfoMap"),
- ("read_only_space", 0x054e1): (81, "AccessCheckInfoMap"),
- ("read_only_space", 0x05509): (82, "AccessorInfoMap"),
- ("read_only_space", 0x05531): (83, "AccessorPairMap"),
- ("read_only_space", 0x05559): (84, "AliasedArgumentsEntryMap"),
- ("read_only_space", 0x05581): (85, "AllocationMementoMap"),
- ("read_only_space", 0x055a9): (88, "AsmWasmDataMap"),
- ("read_only_space", 0x055d1): (89, "AsyncGeneratorRequestMap"),
- ("read_only_space", 0x055f9): (90, "BreakPointMap"),
- ("read_only_space", 0x05621): (91, "BreakPointInfoMap"),
- ("read_only_space", 0x05649): (92, "CachedTemplateObjectMap"),
- ("read_only_space", 0x05671): (94, "ClassPositionsMap"),
- ("read_only_space", 0x05699): (95, "DebugInfoMap"),
- ("read_only_space", 0x056c1): (98, "FunctionTemplateRareDataMap"),
- ("read_only_space", 0x056e9): (100, "InterpreterDataMap"),
- ("read_only_space", 0x05711): (101, "ModuleRequestMap"),
- ("read_only_space", 0x05739): (102, "PromiseCapabilityMap"),
- ("read_only_space", 0x05761): (103, "PromiseReactionMap"),
- ("read_only_space", 0x05789): (104, "PropertyDescriptorObjectMap"),
- ("read_only_space", 0x057b1): (105, "PrototypeInfoMap"),
- ("read_only_space", 0x057d9): (106, "ScriptMap"),
- ("read_only_space", 0x05801): (107, "SourceTextModuleInfoEntryMap"),
- ("read_only_space", 0x05829): (108, "StackFrameInfoMap"),
- ("read_only_space", 0x05851): (109, "StackTraceFrameMap"),
- ("read_only_space", 0x05879): (110, "TemplateObjectDescriptionMap"),
- ("read_only_space", 0x058a1): (111, "Tuple2Map"),
- ("read_only_space", 0x058c9): (112, "WasmExceptionTagMap"),
- ("read_only_space", 0x058f1): (113, "WasmExportedFunctionDataMap"),
- ("read_only_space", 0x05919): (114, "WasmIndirectFunctionTableMap"),
- ("read_only_space", 0x05941): (115, "WasmJSFunctionDataMap"),
- ("read_only_space", 0x05969): (116, "WasmValueMap"),
- ("read_only_space", 0x05991): (135, "SloppyArgumentsElementsMap"),
- ("read_only_space", 0x059b9): (152, "DescriptorArrayMap"),
- ("read_only_space", 0x059e1): (172, "OnHeapBasicBlockProfilerDataMap"),
- ("read_only_space", 0x05a09): (181, "WasmCapiFunctionDataMap"),
- ("read_only_space", 0x05a31): (169, "InternalClassMap"),
- ("read_only_space", 0x05a59): (178, "SmiPairMap"),
- ("read_only_space", 0x05a81): (177, "SmiBoxMap"),
- ("read_only_space", 0x05aa9): (146, "ExportedSubClassBaseMap"),
- ("read_only_space", 0x05ad1): (147, "ExportedSubClassMap"),
- ("read_only_space", 0x05af9): (68, "AbstractInternalClassSubclass1Map"),
- ("read_only_space", 0x05b21): (69, "AbstractInternalClassSubclass2Map"),
- ("read_only_space", 0x05b49): (134, "InternalClassWithSmiElementsMap"),
- ("read_only_space", 0x05b71): (170, "InternalClassWithStructElementsMap"),
- ("read_only_space", 0x05b99): (148, "ExportedSubClass2Map"),
- ("read_only_space", 0x05bc1): (179, "SortStateMap"),
- ("read_only_space", 0x05be9): (86, "AllocationSiteWithWeakNextMap"),
- ("read_only_space", 0x05c11): (86, "AllocationSiteWithoutWeakNextMap"),
- ("read_only_space", 0x05c39): (77, "LoadHandler1Map"),
- ("read_only_space", 0x05c61): (77, "LoadHandler2Map"),
- ("read_only_space", 0x05c89): (77, "LoadHandler3Map"),
- ("read_only_space", 0x05cb1): (78, "StoreHandler0Map"),
- ("read_only_space", 0x05cd9): (78, "StoreHandler1Map"),
- ("read_only_space", 0x05d01): (78, "StoreHandler2Map"),
- ("read_only_space", 0x05d29): (78, "StoreHandler3Map"),
+ ("read_only_space", 0x0270d): (165, "FeedbackVectorMap"),
+ ("read_only_space", 0x02749): (67, "ArgumentsMarkerMap"),
+ ("read_only_space", 0x027a9): (67, "ExceptionMap"),
+ ("read_only_space", 0x02805): (67, "TerminationExceptionMap"),
+ ("read_only_space", 0x0286d): (67, "OptimizedOutMap"),
+ ("read_only_space", 0x028cd): (67, "StaleRegisterMap"),
+ ("read_only_space", 0x0292d): (129, "ScriptContextTableMap"),
+ ("read_only_space", 0x02955): (126, "ClosureFeedbackCellArrayMap"),
+ ("read_only_space", 0x0297d): (164, "FeedbackMetadataArrayMap"),
+ ("read_only_space", 0x029a5): (116, "ArrayListMap"),
+ ("read_only_space", 0x029cd): (65, "BigIntMap"),
+ ("read_only_space", 0x029f5): (127, "ObjectBoilerplateDescriptionMap"),
+ ("read_only_space", 0x02a1d): (131, "BytecodeArrayMap"),
+ ("read_only_space", 0x02a45): (161, "CodeDataContainerMap"),
+ ("read_only_space", 0x02a6d): (162, "CoverageInfoMap"),
+ ("read_only_space", 0x02a95): (132, "FixedDoubleArrayMap"),
+ ("read_only_space", 0x02abd): (119, "GlobalDictionaryMap"),
+ ("read_only_space", 0x02ae5): (97, "ManyClosuresCellMap"),
+ ("read_only_space", 0x02b0d): (116, "ModuleInfoMap"),
+ ("read_only_space", 0x02b35): (120, "NameDictionaryMap"),
+ ("read_only_space", 0x02b5d): (97, "NoClosuresCellMap"),
+ ("read_only_space", 0x02b85): (121, "NumberDictionaryMap"),
+ ("read_only_space", 0x02bad): (97, "OneClosureCellMap"),
+ ("read_only_space", 0x02bd5): (122, "OrderedHashMapMap"),
+ ("read_only_space", 0x02bfd): (123, "OrderedHashSetMap"),
+ ("read_only_space", 0x02c25): (124, "OrderedNameDictionaryMap"),
+ ("read_only_space", 0x02c4d): (172, "PreparseDataMap"),
+ ("read_only_space", 0x02c75): (173, "PropertyArrayMap"),
+ ("read_only_space", 0x02c9d): (93, "SideEffectCallHandlerInfoMap"),
+ ("read_only_space", 0x02cc5): (93, "SideEffectFreeCallHandlerInfoMap"),
+ ("read_only_space", 0x02ced): (93, "NextCallSideEffectFreeCallHandlerInfoMap"),
+ ("read_only_space", 0x02d15): (125, "SimpleNumberDictionaryMap"),
+ ("read_only_space", 0x02d3d): (148, "SmallOrderedHashMapMap"),
+ ("read_only_space", 0x02d65): (149, "SmallOrderedHashSetMap"),
+ ("read_only_space", 0x02d8d): (150, "SmallOrderedNameDictionaryMap"),
+ ("read_only_space", 0x02db5): (153, "SourceTextModuleMap"),
+ ("read_only_space", 0x02ddd): (154, "SyntheticModuleMap"),
+ ("read_only_space", 0x02e05): (71, "WasmTypeInfoMap"),
+ ("read_only_space", 0x02e2d): (182, "WeakArrayListMap"),
+ ("read_only_space", 0x02e55): (118, "EphemeronHashTableMap"),
+ ("read_only_space", 0x02e7d): (163, "EmbedderDataArrayMap"),
+ ("read_only_space", 0x02ea5): (183, "WeakCellMap"),
+ ("read_only_space", 0x02ecd): (32, "StringMap"),
+ ("read_only_space", 0x02ef5): (41, "ConsOneByteStringMap"),
+ ("read_only_space", 0x02f1d): (33, "ConsStringMap"),
+ ("read_only_space", 0x02f45): (37, "ThinStringMap"),
+ ("read_only_space", 0x02f6d): (35, "SlicedStringMap"),
+ ("read_only_space", 0x02f95): (43, "SlicedOneByteStringMap"),
+ ("read_only_space", 0x02fbd): (34, "ExternalStringMap"),
+ ("read_only_space", 0x02fe5): (42, "ExternalOneByteStringMap"),
+ ("read_only_space", 0x0300d): (50, "UncachedExternalStringMap"),
+ ("read_only_space", 0x03035): (0, "InternalizedStringMap"),
+ ("read_only_space", 0x0305d): (2, "ExternalInternalizedStringMap"),
+ ("read_only_space", 0x03085): (10, "ExternalOneByteInternalizedStringMap"),
+ ("read_only_space", 0x030ad): (58, "UncachedExternalOneByteStringMap"),
+ ("read_only_space", 0x030d5): (67, "SelfReferenceMarkerMap"),
+ ("read_only_space", 0x030fd): (67, "BasicBlockCountersMarkerMap"),
+ ("read_only_space", 0x03141): (87, "ArrayBoilerplateDescriptionMap"),
+ ("read_only_space", 0x03229): (99, "InterceptorInfoMap"),
+ ("read_only_space", 0x05355): (72, "PromiseFulfillReactionJobTaskMap"),
+ ("read_only_space", 0x0537d): (73, "PromiseRejectReactionJobTaskMap"),
+ ("read_only_space", 0x053a5): (74, "CallableTaskMap"),
+ ("read_only_space", 0x053cd): (75, "CallbackTaskMap"),
+ ("read_only_space", 0x053f5): (76, "PromiseResolveThenableJobTaskMap"),
+ ("read_only_space", 0x0541d): (79, "FunctionTemplateInfoMap"),
+ ("read_only_space", 0x05445): (80, "ObjectTemplateInfoMap"),
+ ("read_only_space", 0x0546d): (81, "AccessCheckInfoMap"),
+ ("read_only_space", 0x05495): (82, "AccessorInfoMap"),
+ ("read_only_space", 0x054bd): (83, "AccessorPairMap"),
+ ("read_only_space", 0x054e5): (84, "AliasedArgumentsEntryMap"),
+ ("read_only_space", 0x0550d): (85, "AllocationMementoMap"),
+ ("read_only_space", 0x05535): (88, "AsmWasmDataMap"),
+ ("read_only_space", 0x0555d): (89, "AsyncGeneratorRequestMap"),
+ ("read_only_space", 0x05585): (90, "BreakPointMap"),
+ ("read_only_space", 0x055ad): (91, "BreakPointInfoMap"),
+ ("read_only_space", 0x055d5): (92, "CachedTemplateObjectMap"),
+ ("read_only_space", 0x055fd): (94, "ClassPositionsMap"),
+ ("read_only_space", 0x05625): (95, "DebugInfoMap"),
+ ("read_only_space", 0x0564d): (98, "FunctionTemplateRareDataMap"),
+ ("read_only_space", 0x05675): (100, "InterpreterDataMap"),
+ ("read_only_space", 0x0569d): (101, "ModuleRequestMap"),
+ ("read_only_space", 0x056c5): (102, "PromiseCapabilityMap"),
+ ("read_only_space", 0x056ed): (103, "PromiseReactionMap"),
+ ("read_only_space", 0x05715): (104, "PropertyDescriptorObjectMap"),
+ ("read_only_space", 0x0573d): (105, "PrototypeInfoMap"),
+ ("read_only_space", 0x05765): (106, "ScriptMap"),
+ ("read_only_space", 0x0578d): (107, "SourceTextModuleInfoEntryMap"),
+ ("read_only_space", 0x057b5): (108, "StackFrameInfoMap"),
+ ("read_only_space", 0x057dd): (109, "StackTraceFrameMap"),
+ ("read_only_space", 0x05805): (110, "TemplateObjectDescriptionMap"),
+ ("read_only_space", 0x0582d): (111, "Tuple2Map"),
+ ("read_only_space", 0x05855): (112, "WasmExceptionTagMap"),
+ ("read_only_space", 0x0587d): (113, "WasmExportedFunctionDataMap"),
+ ("read_only_space", 0x058a5): (114, "WasmIndirectFunctionTableMap"),
+ ("read_only_space", 0x058cd): (115, "WasmJSFunctionDataMap"),
+ ("read_only_space", 0x058f5): (134, "SloppyArgumentsElementsMap"),
+ ("read_only_space", 0x0591d): (151, "DescriptorArrayMap"),
+ ("read_only_space", 0x05945): (156, "UncompiledDataWithoutPreparseDataMap"),
+ ("read_only_space", 0x0596d): (155, "UncompiledDataWithPreparseDataMap"),
+ ("read_only_space", 0x05995): (171, "OnHeapBasicBlockProfilerDataMap"),
+ ("read_only_space", 0x059bd): (180, "WasmCapiFunctionDataMap"),
+ ("read_only_space", 0x059e5): (168, "InternalClassMap"),
+ ("read_only_space", 0x05a0d): (177, "SmiPairMap"),
+ ("read_only_space", 0x05a35): (176, "SmiBoxMap"),
+ ("read_only_space", 0x05a5d): (145, "ExportedSubClassBaseMap"),
+ ("read_only_space", 0x05a85): (146, "ExportedSubClassMap"),
+ ("read_only_space", 0x05aad): (68, "AbstractInternalClassSubclass1Map"),
+ ("read_only_space", 0x05ad5): (69, "AbstractInternalClassSubclass2Map"),
+ ("read_only_space", 0x05afd): (133, "InternalClassWithSmiElementsMap"),
+ ("read_only_space", 0x05b25): (169, "InternalClassWithStructElementsMap"),
+ ("read_only_space", 0x05b4d): (147, "ExportedSubClass2Map"),
+ ("read_only_space", 0x05b75): (178, "SortStateMap"),
+ ("read_only_space", 0x05b9d): (86, "AllocationSiteWithWeakNextMap"),
+ ("read_only_space", 0x05bc5): (86, "AllocationSiteWithoutWeakNextMap"),
+ ("read_only_space", 0x05bed): (77, "LoadHandler1Map"),
+ ("read_only_space", 0x05c15): (77, "LoadHandler2Map"),
+ ("read_only_space", 0x05c3d): (77, "LoadHandler3Map"),
+ ("read_only_space", 0x05c65): (78, "StoreHandler0Map"),
+ ("read_only_space", 0x05c8d): (78, "StoreHandler1Map"),
+ ("read_only_space", 0x05cb5): (78, "StoreHandler2Map"),
+ ("read_only_space", 0x05cdd): (78, "StoreHandler3Map"),
("map_space", 0x02115): (1057, "ExternalMap"),
- ("map_space", 0x0213d): (1072, "JSMessageObjectMap"),
- ("map_space", 0x02165): (182, "WasmRttEqrefMap"),
- ("map_space", 0x0218d): (182, "WasmRttExternrefMap"),
- ("map_space", 0x021b5): (182, "WasmRttFuncrefMap"),
- ("map_space", 0x021dd): (182, "WasmRttI31refMap"),
+ ("map_space", 0x0213d): (1084, "JSMessageObjectMap"),
+ ("map_space", 0x02165): (181, "WasmRttEqrefMap"),
+ ("map_space", 0x0218d): (181, "WasmRttAnyrefMap"),
+ ("map_space", 0x021b5): (181, "WasmRttExternrefMap"),
+ ("map_space", 0x021dd): (181, "WasmRttFuncrefMap"),
+ ("map_space", 0x02205): (181, "WasmRttI31refMap"),
}
# List of known V8 objects.
@@ -383,37 +388,37 @@ KNOWN_OBJECTS = {
("read_only_space", 0x024c9): "FalseValue",
("read_only_space", 0x024f9): "empty_string",
("read_only_space", 0x02735): "EmptyScopeInfo",
- ("read_only_space", 0x02765): "ArgumentsMarker",
- ("read_only_space", 0x027c5): "Exception",
- ("read_only_space", 0x02821): "TerminationException",
- ("read_only_space", 0x02889): "OptimizedOut",
- ("read_only_space", 0x028e9): "StaleRegister",
- ("read_only_space", 0x031b9): "EmptyPropertyArray",
- ("read_only_space", 0x031c1): "EmptyByteArray",
- ("read_only_space", 0x031c9): "EmptyObjectBoilerplateDescription",
- ("read_only_space", 0x031fd): "EmptyArrayBoilerplateDescription",
- ("read_only_space", 0x03209): "EmptyClosureFeedbackCellArray",
- ("read_only_space", 0x03211): "EmptySlowElementDictionary",
- ("read_only_space", 0x03235): "EmptyOrderedHashMap",
- ("read_only_space", 0x03249): "EmptyOrderedHashSet",
- ("read_only_space", 0x0325d): "EmptyFeedbackMetadata",
- ("read_only_space", 0x03269): "EmptyPropertyCell",
- ("read_only_space", 0x0327d): "EmptyPropertyDictionary",
- ("read_only_space", 0x032a5): "EmptyOrderedPropertyDictionary",
- ("read_only_space", 0x032e5): "NoOpInterceptorInfo",
- ("read_only_space", 0x0330d): "EmptyWeakArrayList",
- ("read_only_space", 0x03319): "InfinityValue",
- ("read_only_space", 0x03325): "MinusZeroValue",
- ("read_only_space", 0x03331): "MinusInfinityValue",
- ("read_only_space", 0x0333d): "SelfReferenceMarker",
- ("read_only_space", 0x0337d): "BasicBlockCountersMarker",
- ("read_only_space", 0x033c1): "OffHeapTrampolineRelocationInfo",
- ("read_only_space", 0x033cd): "TrampolineTrivialCodeDataContainer",
- ("read_only_space", 0x033d9): "TrampolinePromiseRejectionCodeDataContainer",
- ("read_only_space", 0x033e5): "GlobalThisBindingScopeInfo",
- ("read_only_space", 0x0341d): "EmptyFunctionScopeInfo",
- ("read_only_space", 0x03445): "NativeScopeInfo",
- ("read_only_space", 0x03461): "HashSeed",
+ ("read_only_space", 0x02771): "ArgumentsMarker",
+ ("read_only_space", 0x027d1): "Exception",
+ ("read_only_space", 0x0282d): "TerminationException",
+ ("read_only_space", 0x02895): "OptimizedOut",
+ ("read_only_space", 0x028f5): "StaleRegister",
+ ("read_only_space", 0x03125): "EmptyPropertyArray",
+ ("read_only_space", 0x0312d): "EmptyByteArray",
+ ("read_only_space", 0x03135): "EmptyObjectBoilerplateDescription",
+ ("read_only_space", 0x03169): "EmptyArrayBoilerplateDescription",
+ ("read_only_space", 0x03175): "EmptyClosureFeedbackCellArray",
+ ("read_only_space", 0x0317d): "EmptySlowElementDictionary",
+ ("read_only_space", 0x031a1): "EmptyOrderedHashMap",
+ ("read_only_space", 0x031b5): "EmptyOrderedHashSet",
+ ("read_only_space", 0x031c9): "EmptyFeedbackMetadata",
+ ("read_only_space", 0x031d5): "EmptyPropertyCell",
+ ("read_only_space", 0x031e9): "EmptyPropertyDictionary",
+ ("read_only_space", 0x03211): "EmptyOrderedPropertyDictionary",
+ ("read_only_space", 0x03251): "NoOpInterceptorInfo",
+ ("read_only_space", 0x03279): "EmptyWeakArrayList",
+ ("read_only_space", 0x03285): "InfinityValue",
+ ("read_only_space", 0x03291): "MinusZeroValue",
+ ("read_only_space", 0x0329d): "MinusInfinityValue",
+ ("read_only_space", 0x032a9): "SelfReferenceMarker",
+ ("read_only_space", 0x032e9): "BasicBlockCountersMarker",
+ ("read_only_space", 0x0332d): "OffHeapTrampolineRelocationInfo",
+ ("read_only_space", 0x03339): "TrampolineTrivialCodeDataContainer",
+ ("read_only_space", 0x03345): "TrampolinePromiseRejectionCodeDataContainer",
+ ("read_only_space", 0x03351): "GlobalThisBindingScopeInfo",
+ ("read_only_space", 0x03389): "EmptyFunctionScopeInfo",
+ ("read_only_space", 0x033b1): "NativeScopeInfo",
+ ("read_only_space", 0x033cd): "HashSeed",
("old_space", 0x02115): "ArgumentsIteratorAccessor",
("old_space", 0x02159): "ArrayLengthAccessor",
("old_space", 0x0219d): "BoundFunctionLengthAccessor",
@@ -427,49 +432,49 @@ KNOWN_OBJECTS = {
("old_space", 0x023bd): "RegExpResultIndicesAccessor",
("old_space", 0x02401): "StringLengthAccessor",
("old_space", 0x02445): "InvalidPrototypeValidityCell",
- ("old_space", 0x024cd): "EmptyScript",
- ("old_space", 0x0250d): "ManyClosuresCell",
- ("old_space", 0x02519): "ArrayConstructorProtector",
- ("old_space", 0x0252d): "NoElementsProtector",
- ("old_space", 0x02541): "IsConcatSpreadableProtector",
- ("old_space", 0x02555): "ArraySpeciesProtector",
- ("old_space", 0x02569): "TypedArraySpeciesProtector",
- ("old_space", 0x0257d): "PromiseSpeciesProtector",
- ("old_space", 0x02591): "RegExpSpeciesProtector",
- ("old_space", 0x025a5): "StringLengthProtector",
- ("old_space", 0x025b9): "ArrayIteratorProtector",
- ("old_space", 0x025cd): "ArrayBufferDetachingProtector",
- ("old_space", 0x025e1): "PromiseHookProtector",
- ("old_space", 0x025f5): "PromiseResolveProtector",
- ("old_space", 0x02609): "MapIteratorProtector",
- ("old_space", 0x0261d): "PromiseThenProtector",
- ("old_space", 0x02631): "SetIteratorProtector",
- ("old_space", 0x02645): "StringIteratorProtector",
- ("old_space", 0x02659): "SingleCharacterStringCache",
- ("old_space", 0x02a61): "StringSplitCache",
- ("old_space", 0x02e69): "RegExpMultipleCache",
- ("old_space", 0x03271): "BuiltinsConstantsTable",
- ("old_space", 0x03651): "AsyncFunctionAwaitRejectSharedFun",
- ("old_space", 0x03679): "AsyncFunctionAwaitResolveSharedFun",
- ("old_space", 0x036a1): "AsyncGeneratorAwaitRejectSharedFun",
- ("old_space", 0x036c9): "AsyncGeneratorAwaitResolveSharedFun",
- ("old_space", 0x036f1): "AsyncGeneratorYieldResolveSharedFun",
- ("old_space", 0x03719): "AsyncGeneratorReturnResolveSharedFun",
- ("old_space", 0x03741): "AsyncGeneratorReturnClosedRejectSharedFun",
- ("old_space", 0x03769): "AsyncGeneratorReturnClosedResolveSharedFun",
- ("old_space", 0x03791): "AsyncIteratorValueUnwrapSharedFun",
- ("old_space", 0x037b9): "PromiseAllResolveElementSharedFun",
- ("old_space", 0x037e1): "PromiseAllSettledResolveElementSharedFun",
- ("old_space", 0x03809): "PromiseAllSettledRejectElementSharedFun",
- ("old_space", 0x03831): "PromiseAnyRejectElementSharedFun",
- ("old_space", 0x03859): "PromiseCapabilityDefaultRejectSharedFun",
- ("old_space", 0x03881): "PromiseCapabilityDefaultResolveSharedFun",
- ("old_space", 0x038a9): "PromiseCatchFinallySharedFun",
- ("old_space", 0x038d1): "PromiseGetCapabilitiesExecutorSharedFun",
- ("old_space", 0x038f9): "PromiseThenFinallySharedFun",
- ("old_space", 0x03921): "PromiseThrowerFinallySharedFun",
- ("old_space", 0x03949): "PromiseValueThunkFinallySharedFun",
- ("old_space", 0x03971): "ProxyRevokeSharedFun",
+ ("old_space", 0x02531): "EmptyScript",
+ ("old_space", 0x02571): "ManyClosuresCell",
+ ("old_space", 0x0257d): "ArrayConstructorProtector",
+ ("old_space", 0x02591): "NoElementsProtector",
+ ("old_space", 0x025a5): "IsConcatSpreadableProtector",
+ ("old_space", 0x025b9): "ArraySpeciesProtector",
+ ("old_space", 0x025cd): "TypedArraySpeciesProtector",
+ ("old_space", 0x025e1): "PromiseSpeciesProtector",
+ ("old_space", 0x025f5): "RegExpSpeciesProtector",
+ ("old_space", 0x02609): "StringLengthProtector",
+ ("old_space", 0x0261d): "ArrayIteratorProtector",
+ ("old_space", 0x02631): "ArrayBufferDetachingProtector",
+ ("old_space", 0x02645): "PromiseHookProtector",
+ ("old_space", 0x02659): "PromiseResolveProtector",
+ ("old_space", 0x0266d): "MapIteratorProtector",
+ ("old_space", 0x02681): "PromiseThenProtector",
+ ("old_space", 0x02695): "SetIteratorProtector",
+ ("old_space", 0x026a9): "StringIteratorProtector",
+ ("old_space", 0x026bd): "SingleCharacterStringCache",
+ ("old_space", 0x02ac5): "StringSplitCache",
+ ("old_space", 0x02ecd): "RegExpMultipleCache",
+ ("old_space", 0x032d5): "BuiltinsConstantsTable",
+ ("old_space", 0x036bd): "AsyncFunctionAwaitRejectSharedFun",
+ ("old_space", 0x036e1): "AsyncFunctionAwaitResolveSharedFun",
+ ("old_space", 0x03705): "AsyncGeneratorAwaitRejectSharedFun",
+ ("old_space", 0x03729): "AsyncGeneratorAwaitResolveSharedFun",
+ ("old_space", 0x0374d): "AsyncGeneratorYieldResolveSharedFun",
+ ("old_space", 0x03771): "AsyncGeneratorReturnResolveSharedFun",
+ ("old_space", 0x03795): "AsyncGeneratorReturnClosedRejectSharedFun",
+ ("old_space", 0x037b9): "AsyncGeneratorReturnClosedResolveSharedFun",
+ ("old_space", 0x037dd): "AsyncIteratorValueUnwrapSharedFun",
+ ("old_space", 0x03801): "PromiseAllResolveElementSharedFun",
+ ("old_space", 0x03825): "PromiseAllSettledResolveElementSharedFun",
+ ("old_space", 0x03849): "PromiseAllSettledRejectElementSharedFun",
+ ("old_space", 0x0386d): "PromiseAnyRejectElementSharedFun",
+ ("old_space", 0x03891): "PromiseCapabilityDefaultRejectSharedFun",
+ ("old_space", 0x038b5): "PromiseCapabilityDefaultResolveSharedFun",
+ ("old_space", 0x038d9): "PromiseCatchFinallySharedFun",
+ ("old_space", 0x038fd): "PromiseGetCapabilitiesExecutorSharedFun",
+ ("old_space", 0x03921): "PromiseThenFinallySharedFun",
+ ("old_space", 0x03945): "PromiseThrowerFinallySharedFun",
+ ("old_space", 0x03969): "PromiseValueThunkFinallySharedFun",
+ ("old_space", 0x0398d): "ProxyRevokeSharedFun",
}
# Lower 32 bits of first page addresses for various heap spaces.
diff --git a/deps/v8/tools/v8windbg/src/object-inspection.cc b/deps/v8/tools/v8windbg/src/object-inspection.cc
index b206dfa792..b682f5b1b9 100644
--- a/deps/v8/tools/v8windbg/src/object-inspection.cc
+++ b/deps/v8/tools/v8windbg/src/object-inspection.cc
@@ -17,6 +17,7 @@ V8CachedObject::V8CachedObject(Location location,
uncompressed_type_name_(std::move(uncompressed_type_name)),
context_(std::move(context)),
is_compressed_(is_compressed) {}
+
HRESULT V8CachedObject::Create(IModelObject* p_v8_object_instance,
IV8CachedObject** result) {
Location location;
@@ -25,15 +26,16 @@ HRESULT V8CachedObject::Create(IModelObject* p_v8_object_instance,
WRL::ComPtr<IDebugHostContext> context;
RETURN_IF_FAIL(p_v8_object_instance->GetContext(&context));
+ WRL::ComPtr<IDebugHostType> sp_type;
+ _bstr_t type_name;
+ RETURN_IF_FAIL(p_v8_object_instance->GetTypeInfo(&sp_type));
+ RETURN_IF_FAIL(sp_type->GetName(type_name.GetAddress()));
+
// If the object is of type v8::internal::TaggedValue, and this build uses
// compressed pointers, then the value is compressed. Other types such as
// v8::internal::Object represent uncompressed tagged values.
- WRL::ComPtr<IDebugHostType> sp_type;
- _bstr_t type_name;
bool is_compressed =
COMPRESS_POINTERS_BOOL &&
- SUCCEEDED(p_v8_object_instance->GetTypeInfo(&sp_type)) &&
- SUCCEEDED(sp_type->GetName(type_name.GetAddress())) &&
static_cast<const char*>(type_name) == std::string(kTaggedValue);
const char* uncompressed_type_name =
@@ -44,6 +46,7 @@ HRESULT V8CachedObject::Create(IModelObject* p_v8_object_instance,
.Detach();
return S_OK;
}
+
V8CachedObject::V8CachedObject(V8HeapObject heap_object)
: heap_object_(std::move(heap_object)), heap_object_initialized_(true) {}
diff --git a/deps/v8/tools/v8windbg/src/v8-debug-helper-interop.cc b/deps/v8/tools/v8windbg/src/v8-debug-helper-interop.cc
index 74d0a9df26..4433034237 100644
--- a/deps/v8/tools/v8windbg/src/v8-debug-helper-interop.cc
+++ b/deps/v8/tools/v8windbg/src/v8-debug-helper-interop.cc
@@ -16,7 +16,7 @@ namespace d = v8::debug_helper;
// We need a plain C function pointer for interop with v8_debug_helper. We can
// use this to get one as long as we never need two at once.
-class MemReaderScope {
+class V8_NODISCARD MemReaderScope {
public:
explicit MemReaderScope(WRL::ComPtr<IDebugHostContext> sp_context)
: sp_context_(sp_context) {
diff --git a/deps/v8/tools/v8windbg/test/v8windbg-test.cc b/deps/v8/tools/v8windbg/test/v8windbg-test.cc
index 59414f341d..6b40af0ff1 100644
--- a/deps/v8/tools/v8windbg/test/v8windbg-test.cc
+++ b/deps/v8/tools/v8windbg/test/v8windbg-test.cc
@@ -20,7 +20,7 @@ namespace {
// Loads a named extension library upon construction and unloads it upon
// destruction.
-class LoadExtensionScope {
+class V8_NODISCARD LoadExtensionScope {
public:
LoadExtensionScope(WRL::ComPtr<IDebugControl4> p_debug_control,
std::wstring extension_path)
@@ -49,7 +49,7 @@ class LoadExtensionScope {
};
// Initializes COM upon construction and uninitializes it upon destruction.
-class ComScope {
+class V8_NODISCARD ComScope {
public:
ComScope() { hr_ = CoInitializeEx(nullptr, COINIT_MULTITHREADED); }
~ComScope() {
diff --git a/deps/v8/tools/wasm/update-wasm-fuzzers.sh b/deps/v8/tools/wasm/update-wasm-fuzzers.sh
index ffd7e01633..d85b86700b 100755
--- a/deps/v8/tools/wasm/update-wasm-fuzzers.sh
+++ b/deps/v8/tools/wasm/update-wasm-fuzzers.sh
@@ -3,40 +3,29 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-set -e
+set -ex
-TOOLS_WASM_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cd "$( dirname "${BASH_SOURCE[0]}" )"
+cd ../..
-cd ${TOOLS_WASM_DIR}/../..
+BUILD_DIR=out/mk_wasm_fuzzer_corpus
+CORPUS_DIR=test/fuzzer/wasm_corpus
-rm -rf test/fuzzer/wasm_corpus
+rm -rf $BUILD_DIR $CORPUS_DIR
+mkdir -p $CORPUS_DIR
-tools/dev/gm.py x64.release all
+# Build optdebug such that the --dump-wasm-module flag is available.
+gn gen $BUILD_DIR --args='is_debug=true v8_optimized_debug=true target_cpu="x64" use_goma=true'
+autoninja -C $BUILD_DIR
-mkdir -p test/fuzzer/wasm_corpus
+./tools/run-tests.py --outdir=$BUILD_DIR --extra-flags="--dump-wasm-module \
+ --dump-wasm-module-path=./$CORPUS_DIR/"
-# wasm
-./tools/run-tests.py -j8 --variants=default --timeout=10 --arch=x64 \
- --mode=release --no-presubmit --extra-flags="--dump-wasm-module \
- --dump-wasm-module-path=./test/fuzzer/wasm_corpus/" unittests
-./tools/run-tests.py -j8 --variants=default --timeout=10 --arch=x64 \
- --mode=release --no-presubmit --extra-flags="--dump-wasm-module \
- --dump-wasm-module-path=./test/fuzzer/wasm_corpus/" wasm-spec-tests/*
-./tools/run-tests.py -j8 --variants=default --timeout=10 --arch=x64 \
- --mode=release --no-presubmit --extra-flags="--dump-wasm-module \
- --dump-wasm-module-path=./test/fuzzer/wasm_corpus/" mjsunit/wasm/*
-./tools/run-tests.py -j8 --variants=default --timeout=10 --arch=x64 \
- --mode=release --no-presubmit --extra-flags="--dump-wasm-module \
- --dump-wasm-module-path=./test/fuzzer/wasm_corpus/" \
- $(cd test/; ls cctest/wasm/test-*.cc | \
- sed -es/wasm\\///g | sed -es/[.]cc/\\/\\*/g)
+rm -rf $BUILD_DIR
# Delete items over 20k.
-for x in $(find ./test/fuzzer/wasm_corpus/ -type f -size +20k)
-do
- rm $x
-done
+find $CORPUS_DIR -type f -size +20k | xargs rm
# Upload changes.
-cd test/fuzzer
+cd $CORPUS_DIR/..
upload_to_google_storage.py -a -b v8-wasm-fuzzer wasm_corpus
diff --git a/deps/v8/tools/whitespace.txt b/deps/v8/tools/whitespace.txt
index d6024b5b7d..8fcce8dda7 100644
--- a/deps/v8/tools/whitespace.txt
+++ b/deps/v8/tools/whitespace.txt
@@ -8,7 +8,7 @@ The doubles heard this and started to unbox.
The Smi looked at them when a crazy v8-autoroll account showed up...
The autoroller bought a round of Himbeerbrause. Suddenly.....
The bartender starts to shake the bottles........................
-I can't add trailing whitespaces, so I'm adding this line.......
+I can't add trailing whitespaces, so I'm adding this line...........
I'm starting to think that just adding trailing whitespaces might not be bad.
Because whitespaces are not that funny.....
diff --git a/deps/v8/tools/windows-tick-processor.bat b/deps/v8/tools/windows-tick-processor.bat
index 56637e051c..ae74df9535 100755
--- a/deps/v8/tools/windows-tick-processor.bat
+++ b/deps/v8/tools/windows-tick-processor.bat
@@ -27,4 +27,4 @@ IF NOT %arg8:~0,2% == 8 (IF NOT %arg8:~0,2% == 8- SET log_file=%8)
SET arg9=9%9
IF NOT %arg9:~0,2% == 9 (IF NOT %arg9:~0,2% == 9- SET log_file=%9)
-type %log_file% | %D8_PATH%\d8 --module %tools_dir%tickprocessor-driver.js -- --windows %*
+type %log_file% | %D8_PATH%\d8 --module %tools_dir%tickprocessor-driver.mjs -- --windows %*
diff --git a/deps/v8/tools/wpr.wprp b/deps/v8/tools/wpr.wprp
new file mode 100644
index 0000000000..a6282490a8
--- /dev/null
+++ b/deps/v8/tools/wpr.wprp
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<WindowsPerformanceRecorder Version="1.0">
+ <!--
+Note: The following utilities are usually installed to: "C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit"
+See https://docs.microsoft.com/en-us/windows-hardware/test/wpt/ for an overview of the tools.
+
+Start and stop the trace:
+
+ wpr -start wpr.wprp!V8js
+...run scenario...
+ wpr -stop v8js.etl
+
+You can also run "wpr -status collectors details" while recording to check on status.
+
+Note: If you have issues with the command line, run WRPUI, and load this profile via the dialog.
+
+Run the below to open the trace:
+
+ wpa v8js.etl
+
+Set _NT_SYMBOL_PATH to a value such as "C:\src\v8\v8\out.gn\x64.debug;srv*c:\symbols*https://msdl.microsoft.com/download/symbols" first.
+Append "-symcacheonly" on the WPA command to save it trying to reload prior failed symbols on subsequent runs.
+
+For details on editing this file, see https://docs.microsoft.com/en-us/windows-hardware/test/wpt/authoring-recording-profiles
+ -->
+ <Profiles>
+ <SystemCollector Id="SystemCollector" Name="NT Kernel Logger">
+ <BufferSize Value="1024"/>
+ <Buffers Value="384"/>
+ </SystemCollector>
+ <EventCollector Id="EventCollector_V8js" Name="V8js Event Collector">
+ <BufferSize Value="1024"/>
+ <Buffers Value="256"/>
+ </EventCollector>
+ <SystemProvider Id="SystemProvider">
+ <Keywords>
+ <Keyword Value="ProcessThread"/>
+ <Keyword Value="Loader"/>
+ <Keyword Value="SampledProfile"/>
+ <Keyword Value="ReadyThread"/>
+ <Keyword Value="CSwitch"/>
+ <Keyword Value="DiskIOInit"/>
+ <Keyword Value="FileIOInit"/>
+ <Keyword Value="HardFaults"/>
+ </Keywords>
+ <Stacks>
+ <!-- See https://docs.microsoft.com/en-us/windows-hardware/test/wpt/stack-wpa for options -->
+ <Stack Value="SampledProfile"/>
+ <Stack Value="ReadyThread"/>
+ <Stack Value="CSwitch"/>
+ </Stacks>
+ </SystemProvider>
+ <EventProvider Id="Provider_V8js" Name="57277741-3638-4A4B-BDBA-0AC6E45DA56C" Level="5" Stack="true"></EventProvider>
+ <Profile Id="V8js.Verbose.File" Name="V8js" DetailLevel="Verbose" LoggingMode="File" Description="V8.js profile">
+ <Collectors>
+ <SystemCollectorId Value="SystemCollector">
+ <SystemProviderId Value="SystemProvider"></SystemProviderId>
+ </SystemCollectorId>
+ <EventCollectorId Value="EventCollector_V8js">
+ <EventProviders>
+ <EventProviderId Value="Provider_V8js"></EventProviderId>
+ </EventProviders>
+ </EventCollectorId>
+ </Collectors>
+ </Profile>
+ <Profile Id="V8js.Verbose.Memory" Base="V8js.Verbose.File" Name="V8js" DetailLevel="Verbose" LoggingMode="Memory" Description="V8.js profile"></Profile>
+ </Profiles>
+</WindowsPerformanceRecorder>