summaryrefslogtreecommitdiff
path: root/chromium/v8/tools
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-03-12 09:13:00 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-03-16 09:58:26 +0000
commit03561cae90f1d99b5c54b1ef3be69f10e882b25e (patch)
treecc5f0958e823c044e7ae51cc0117fe51432abe5e /chromium/v8/tools
parentfa98118a45f7e169f8846086dc2c22c49a8ba310 (diff)
downloadqtwebengine-chromium-03561cae90f1d99b5c54b1ef3be69f10e882b25e.tar.gz
BASELINE: Update Chromium to 88.0.4324.208
Change-Id: I3ae87d23e4eff4b4a469685658740a213600c667 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/tools')
-rwxr-xr-xchromium/v8/tools/android-sync.sh19
-rw-r--r--chromium/v8/tools/arguments.mjs22
-rw-r--r--chromium/v8/tools/clusterfuzz/js_fuzzer/DIR_METADATA11
-rw-r--r--chromium/v8/tools/clusterfuzz/js_fuzzer/OWNERS2
-rw-r--r--chromium/v8/tools/codemap.mjs433
-rw-r--r--chromium/v8/tools/consarray.mjs2
-rw-r--r--chromium/v8/tools/csvparser.mjs6
-rw-r--r--chromium/v8/tools/debug_helper/get-object-properties.cc7
-rw-r--r--chromium/v8/tools/dumpcpp-driver.mjs14
-rw-r--r--chromium/v8/tools/dumpcpp.mjs97
-rw-r--r--chromium/v8/tools/gcmole/gcmole-test.cc13
-rw-r--r--chromium/v8/tools/gcmole/gcmole-tools.tar.gz.sha12
-rw-r--r--chromium/v8/tools/gcmole/gcmole.cc37
-rw-r--r--chromium/v8/tools/gcmole/test-expectations.txt5
-rw-r--r--chromium/v8/tools/gen-postmortem-metadata.py22
-rw-r--r--chromium/v8/tools/ic-explorer.html389
-rw-r--r--chromium/v8/tools/ic-processor-driver.mjs74
-rw-r--r--chromium/v8/tools/ic-processor.mjs197
-rw-r--r--chromium/v8/tools/index.html17
-rwxr-xr-xchromium/v8/tools/linux-tick-processor2
-rw-r--r--chromium/v8/tools/logreader.mjs34
-rwxr-xr-xchromium/v8/tools/map-processor37
-rw-r--r--chromium/v8/tools/map-processor-driver.mjs38
-rw-r--r--chromium/v8/tools/map-processor.html1315
-rw-r--r--chromium/v8/tools/map-processor.mjs783
-rwxr-xr-xchromium/v8/tools/mb/mb_unittest.py8
-rw-r--r--chromium/v8/tools/parse-processor-driver.mjs12
-rw-r--r--chromium/v8/tools/parse-processor.mjs26
-rw-r--r--chromium/v8/tools/profile.mjs1434
-rw-r--r--chromium/v8/tools/profile_view.mjs32
-rw-r--r--chromium/v8/tools/sourcemap.mjs126
-rw-r--r--chromium/v8/tools/splaytree.mjs30
-rw-r--r--chromium/v8/tools/system-analyzer/app-model.mjs128
-rw-r--r--chromium/v8/tools/system-analyzer/events.mjs33
-rw-r--r--chromium/v8/tools/system-analyzer/helper.mjs148
-rw-r--r--chromium/v8/tools/system-analyzer/ic-model.mjs13
-rw-r--r--chromium/v8/tools/system-analyzer/ic-panel-template.html74
-rw-r--r--chromium/v8/tools/system-analyzer/ic-panel.mjs405
-rw-r--r--chromium/v8/tools/system-analyzer/index.css95
-rw-r--r--chromium/v8/tools/system-analyzer/index.html261
-rw-r--r--chromium/v8/tools/system-analyzer/index.mjs273
-rw-r--r--chromium/v8/tools/system-analyzer/log-file-reader-template.html24
-rw-r--r--chromium/v8/tools/system-analyzer/log-file-reader.mjs138
-rw-r--r--chromium/v8/tools/system-analyzer/log/deopt.mjs10
-rw-r--r--chromium/v8/tools/system-analyzer/log/ic.mjs19
-rw-r--r--chromium/v8/tools/system-analyzer/log/log.mjs25
-rw-r--r--chromium/v8/tools/system-analyzer/log/map.mjs45
-rw-r--r--chromium/v8/tools/system-analyzer/map-panel-template.html1
-rw-r--r--chromium/v8/tools/system-analyzer/map-panel.mjs130
-rw-r--r--chromium/v8/tools/system-analyzer/map-panel/map-details.mjs61
-rw-r--r--chromium/v8/tools/system-analyzer/map-panel/map-transitions-template.html2
-rw-r--r--chromium/v8/tools/system-analyzer/map-panel/map-transitions.mjs366
-rw-r--r--chromium/v8/tools/system-analyzer/processor.mjs185
-rw-r--r--chromium/v8/tools/system-analyzer/source-panel-template.html36
-rw-r--r--chromium/v8/tools/system-analyzer/source-panel.mjs300
-rw-r--r--chromium/v8/tools/system-analyzer/stats-panel-template.html47
-rw-r--r--chromium/v8/tools/system-analyzer/stats-panel.mjs152
-rw-r--r--chromium/v8/tools/system-analyzer/timeline-panel-template.html45
-rw-r--r--chromium/v8/tools/system-analyzer/timeline-panel.mjs118
-rw-r--r--chromium/v8/tools/system-analyzer/timeline.mjs106
-rw-r--r--chromium/v8/tools/system-analyzer/timeline/timeline-track-template.html90
-rw-r--r--chromium/v8/tools/system-analyzer/timeline/timeline-track.mjs904
-rw-r--r--chromium/v8/tools/testrunner/local/variants.py10
-rw-r--r--chromium/v8/tools/testrunner/objects/testcase.py39
-rw-r--r--chromium/v8/tools/testrunner/outproc/base.py3
-rw-r--r--chromium/v8/tools/tickprocessor-driver.mjs14
-rw-r--r--chromium/v8/tools/tickprocessor.mjs225
-rwxr-xr-xchromium/v8/tools/v8_presubmit.py63
-rw-r--r--chromium/v8/tools/v8heapconst.py343
-rw-r--r--chromium/v8/tools/whitespace.txt5
70 files changed, 3807 insertions, 6375 deletions
diff --git a/chromium/v8/tools/android-sync.sh b/chromium/v8/tools/android-sync.sh
index 709bbb7f7d3..66d7aed78d5 100755
--- a/chromium/v8/tools/android-sync.sh
+++ b/chromium/v8/tools/android-sync.sh
@@ -92,15 +92,16 @@ sync_file "$OUTDIR/$ARCH_MODE/snapshot_blob.bin"
sync_file "$OUTDIR/$ARCH_MODE/unittests"
echo ""
echo -n "sync to $ANDROID_V8/tools"
-sync_file tools/consarray.js
-sync_file tools/codemap.js
-sync_file tools/csvparser.js
-sync_file tools/profile.js
-sync_file tools/splaytree.js
-sync_file tools/profile_view.js
-sync_file tools/logreader.js
-sync_file tools/arguments.js
-sync_file tools/tickprocessor.js
+sync_file tools/arguments.mjs
+sync_file tools/codemap.mjs
+sync_file tools/consarray.mjs
+sync_file tools/csvparser.mjs
+sync_file tools/dumpcpp.mjs
+sync_file tools/logreader.mjs
+sync_file tools/profile.mjs
+sync_file tools/profile_view.mjs
+sync_file tools/splaytree.mjs
+sync_file tools/tickprocessor.mjs
echo ""
sync_dir test/intl
sync_dir test/message
diff --git a/chromium/v8/tools/arguments.mjs b/chromium/v8/tools/arguments.mjs
index 232ca6badb3..4e607b7ee9b 100644
--- a/chromium/v8/tools/arguments.mjs
+++ b/chromium/v8/tools/arguments.mjs
@@ -27,37 +27,37 @@ export class BaseArgumentsProcessor {
'Default log file name is "' +
this.result_.logFileName + '".\n');
print('Options:');
- for (var arg in this.argsDispatch_) {
- var synonyms = [arg];
- var dispatch = this.argsDispatch_[arg];
- for (var synArg in this.argsDispatch_) {
+ for (const arg in this.argsDispatch_) {
+ const synonyms = [arg];
+ const dispatch = this.argsDispatch_[arg];
+ for (const synArg in this.argsDispatch_) {
if (arg !== synArg && dispatch === this.argsDispatch_[synArg]) {
synonyms.push(synArg);
delete this.argsDispatch_[synArg];
}
}
- print(' ' + synonyms.join(', ').padEnd(20) + " " + dispatch[2]);
+ print(` ${synonyms.join(', ').padEnd(20)} ${dispatch[2]}`);
}
quit(2);
}
parse() {
while (this.args_.length) {
- var arg = this.args_.shift();
+ let arg = this.args_.shift();
if (arg.charAt(0) != '-') {
this.result_.logFileName = arg;
continue;
}
- var userValue = null;
- var eqPos = arg.indexOf('=');
+ let userValue = null;
+ const eqPos = arg.indexOf('=');
if (eqPos != -1) {
userValue = arg.substr(eqPos + 1);
arg = arg.substr(0, eqPos);
}
if (arg in this.argsDispatch_) {
- var dispatch = this.argsDispatch_[arg];
- var property = dispatch[0];
- var defaultValue = dispatch[1];
+ const dispatch = this.argsDispatch_[arg];
+ const property = dispatch[0];
+ const defaultValue = dispatch[1];
if (typeof defaultValue == "function") {
userValue = defaultValue(userValue);
} else if (userValue == null) {
diff --git a/chromium/v8/tools/clusterfuzz/js_fuzzer/DIR_METADATA b/chromium/v8/tools/clusterfuzz/js_fuzzer/DIR_METADATA
new file mode 100644
index 00000000000..9fc13203d74
--- /dev/null
+++ b/chromium/v8/tools/clusterfuzz/js_fuzzer/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+ component: "Infra>Client>V8"
+} \ No newline at end of file
diff --git a/chromium/v8/tools/clusterfuzz/js_fuzzer/OWNERS b/chromium/v8/tools/clusterfuzz/js_fuzzer/OWNERS
index 76eb9caefff..bc18f69af54 100644
--- a/chromium/v8/tools/clusterfuzz/js_fuzzer/OWNERS
+++ b/chromium/v8/tools/clusterfuzz/js_fuzzer/OWNERS
@@ -5,5 +5,3 @@ file:../../../INFRA_OWNERS
msarms@chromium.org
mslekova@chromium.org
ochang@chromium.org
-
-# COMPONENT: Infra>Client>V8
diff --git a/chromium/v8/tools/codemap.mjs b/chromium/v8/tools/codemap.mjs
index fd0fc808caa..245b6ba42eb 100644
--- a/chromium/v8/tools/codemap.mjs
+++ b/chromium/v8/tools/codemap.mjs
@@ -32,252 +32,232 @@ import { SplayTree } from "./splaytree.mjs";
*
* @constructor
*/
-export function CodeMap() {
+export class CodeMap {
/**
* Dynamic code entries. Used for JIT compiled code.
*/
- this.dynamics_ = new SplayTree();
+ dynamics_ = new SplayTree();
/**
* Name generator for entries having duplicate names.
*/
- this.dynamicsNameGen_ = new CodeMap.NameGenerator();
+ dynamicsNameGen_ = new NameGenerator();
/**
* Static code entries. Used for statically compiled code.
*/
- this.statics_ = new SplayTree();
+ statics_ = new SplayTree();
/**
* Libraries entries. Used for the whole static code libraries.
*/
- this.libraries_ = new SplayTree();
+ libraries_ = new SplayTree();
/**
* Map of memory pages occupied with static code.
*/
- this.pages_ = [];
-};
+ pages_ = [];
-/**
- * The number of alignment bits in a page address.
- */
-CodeMap.PAGE_ALIGNMENT = 12;
-
-
-/**
- * Page size in bytes.
- */
-CodeMap.PAGE_SIZE =
- 1 << CodeMap.PAGE_ALIGNMENT;
-
-
-/**
- * Adds a dynamic (i.e. moveable and discardable) code entry.
- *
- * @param {number} start The starting address.
- * @param {CodeMap.CodeEntry} codeEntry Code entry object.
- */
-CodeMap.prototype.addCode = function(start, codeEntry) {
- this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
- this.dynamics_.insert(start, codeEntry);
-};
-
-
-/**
- * Moves a dynamic code entry. Throws an exception if there is no dynamic
- * code entry with the specified starting address.
- *
- * @param {number} from The starting address of the entry being moved.
- * @param {number} to The destination address.
- */
-CodeMap.prototype.moveCode = function(from, to) {
- var removedNode = this.dynamics_.remove(from);
- this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
- this.dynamics_.insert(to, removedNode.value);
-};
-
-
-/**
- * Discards a dynamic code entry. Throws an exception if there is no dynamic
- * code entry with the specified starting address.
- *
- * @param {number} start The starting address of the entry being deleted.
- */
-CodeMap.prototype.deleteCode = function(start) {
- var removedNode = this.dynamics_.remove(start);
-};
-
-
-/**
- * Adds a library entry.
- *
- * @param {number} start The starting address.
- * @param {CodeMap.CodeEntry} codeEntry Code entry object.
- */
-CodeMap.prototype.addLibrary = function(
- start, codeEntry) {
- this.markPages_(start, start + codeEntry.size);
- this.libraries_.insert(start, codeEntry);
-};
+ /**
+ * The number of alignment bits in a page address.
+ */
+ static PAGE_ALIGNMENT = 12;
-/**
- * Adds a static code entry.
- *
- * @param {number} start The starting address.
- * @param {CodeMap.CodeEntry} codeEntry Code entry object.
- */
-CodeMap.prototype.addStaticCode = function(
- start, codeEntry) {
- this.statics_.insert(start, codeEntry);
-};
+ /**
+ * Page size in bytes.
+ */
+ static PAGE_SIZE = 1 << CodeMap.PAGE_ALIGNMENT;
-/**
- * @private
- */
-CodeMap.prototype.markPages_ = function(start, end) {
- for (var addr = start; addr <= end;
- addr += CodeMap.PAGE_SIZE) {
- this.pages_[(addr / CodeMap.PAGE_SIZE)|0] = 1;
+ /**
+ * Adds a dynamic (i.e. moveable and discardable) code entry.
+ *
+ * @param {number} start The starting address.
+ * @param {CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+ addCode(start, codeEntry) {
+ this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
+ this.dynamics_.insert(start, codeEntry);
}
-};
-
-/**
- * @private
- */
-CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
- var to_delete = [];
- var addr = end - 1;
- while (addr >= start) {
- var node = tree.findGreatestLessThan(addr);
- if (!node) break;
- var start2 = node.key, end2 = start2 + node.value.size;
- if (start2 < end && start < end2) to_delete.push(start2);
- addr = start2 - 1;
+ /**
+ * Moves a dynamic code entry. Throws an exception if there is no dynamic
+ * code entry with the specified starting address.
+ *
+ * @param {number} from The starting address of the entry being moved.
+ * @param {number} to The destination address.
+ */
+ moveCode(from, to) {
+ const removedNode = this.dynamics_.remove(from);
+ this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
+ this.dynamics_.insert(to, removedNode.value);
}
- for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
-};
-
-
-/**
- * @private
- */
-CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) {
- return addr >= node.key && addr < (node.key + node.value.size);
-};
+ /**
+ * Discards a dynamic code entry. Throws an exception if there is no dynamic
+ * code entry with the specified starting address.
+ *
+ * @param {number} start The starting address of the entry being deleted.
+ */
+ deleteCode(start) {
+ const removedNode = this.dynamics_.remove(start);
+ }
-/**
- * @private
- */
-CodeMap.prototype.findInTree_ = function(tree, addr) {
- var node = tree.findGreatestLessThan(addr);
- return node && this.isAddressBelongsTo_(addr, node) ? node : null;
-};
+ /**
+ * Adds a library entry.
+ *
+ * @param {number} start The starting address.
+ * @param {CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+ addLibrary(start, codeEntry) {
+ this.markPages_(start, start + codeEntry.size);
+ this.libraries_.insert(start, codeEntry);
+ }
+ /**
+ * Adds a static code entry.
+ *
+ * @param {number} start The starting address.
+ * @param {CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+ addStaticCode(start, codeEntry) {
+ this.statics_.insert(start, codeEntry);
+ }
-/**
- * Finds a code entry that contains the specified address. Both static and
- * dynamic code entries are considered. Returns the code entry and the offset
- * within the entry.
- *
- * @param {number} addr Address.
- */
-CodeMap.prototype.findAddress = function(addr) {
- var pageAddr = (addr / CodeMap.PAGE_SIZE)|0;
- if (pageAddr in this.pages_) {
- // Static code entries can contain "holes" of unnamed code.
- // In this case, the whole library is assigned to this address.
- var result = this.findInTree_(this.statics_, addr);
- if (!result) {
- result = this.findInTree_(this.libraries_, addr);
- if (!result) return null;
+ /**
+ * @private
+ */
+ markPages_(start, end) {
+ for (let addr = start; addr <= end;
+ addr += CodeMap.PAGE_SIZE) {
+ this.pages_[(addr / CodeMap.PAGE_SIZE)|0] = 1;
}
- return { entry : result.value, offset : addr - result.key };
}
- var min = this.dynamics_.findMin();
- var max = this.dynamics_.findMax();
- if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
- var dynaEntry = this.findInTree_(this.dynamics_, addr);
- if (dynaEntry == null) return null;
- // Dedupe entry name.
- var entry = dynaEntry.value;
- if (!entry.nameUpdated_) {
- entry.name = this.dynamicsNameGen_.getName(entry.name);
- entry.nameUpdated_ = true;
+
+ /**
+ * @private
+ */
+ deleteAllCoveredNodes_(tree, start, end) {
+ const to_delete = [];
+ let addr = end - 1;
+ while (addr >= start) {
+ const node = tree.findGreatestLessThan(addr);
+ if (!node) break;
+ const start2 = node.key, end2 = start2 + node.value.size;
+ if (start2 < end && start < end2) to_delete.push(start2);
+ addr = start2 - 1;
}
- return { entry : entry, offset : addr - dynaEntry.key };
+ for (let i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
}
- return null;
-};
-
-
-/**
- * Finds a code entry that contains the specified address. Both static and
- * dynamic code entries are considered.
- *
- * @param {number} addr Address.
- */
-CodeMap.prototype.findEntry = function(addr) {
- var result = this.findAddress(addr);
- return result ? result.entry : null;
-};
-
-
-/**
- * Returns a dynamic code entry using its starting address.
- *
- * @param {number} addr Address.
- */
-CodeMap.prototype.findDynamicEntryByStartAddress =
- function(addr) {
- var node = this.dynamics_.find(addr);
- return node ? node.value : null;
-};
+ /**
+ * @private
+ */
+ isAddressBelongsTo_(addr, node) {
+ return addr >= node.key && addr < (node.key + node.value.size);
+ }
-/**
- * Returns an array of all dynamic code entries.
- */
-CodeMap.prototype.getAllDynamicEntries = function() {
- return this.dynamics_.exportValues();
-};
+ /**
+ * @private
+ */
+ findInTree_(tree, addr) {
+ const node = tree.findGreatestLessThan(addr);
+ return node && this.isAddressBelongsTo_(addr, node) ? node : null;
+ }
+ /**
+ * Finds a code entry that contains the specified address. Both static and
+ * dynamic code entries are considered. Returns the code entry and the offset
+ * within the entry.
+ *
+ * @param {number} addr Address.
+ */
+ findAddress(addr) {
+ const pageAddr = (addr / CodeMap.PAGE_SIZE)|0;
+ if (pageAddr in this.pages_) {
+ // Static code entries can contain "holes" of unnamed code.
+ // In this case, the whole library is assigned to this address.
+ let result = this.findInTree_(this.statics_, addr);
+ if (!result) {
+ result = this.findInTree_(this.libraries_, addr);
+ if (!result) return null;
+ }
+ return { entry : result.value, offset : addr - result.key };
+ }
+ const min = this.dynamics_.findMin();
+ const max = this.dynamics_.findMax();
+ if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
+ const dynaEntry = this.findInTree_(this.dynamics_, addr);
+ if (dynaEntry == null) return null;
+ // Dedupe entry name.
+ const entry = dynaEntry.value;
+ if (!entry.nameUpdated_) {
+ entry.name = this.dynamicsNameGen_.getName(entry.name);
+ entry.nameUpdated_ = true;
+ }
+ return { entry, offset : addr - dynaEntry.key };
+ }
+ return null;
+ }
-/**
- * Returns an array of pairs of all dynamic code entries and their addresses.
- */
-CodeMap.prototype.getAllDynamicEntriesWithAddresses = function() {
- return this.dynamics_.exportKeysAndValues();
-};
+ /**
+ * Finds a code entry that contains the specified address. Both static and
+ * dynamic code entries are considered.
+ *
+ * @param {number} addr Address.
+ */
+ findEntry(addr) {
+ const result = this.findAddress(addr);
+ return result ? result.entry : null;
+ }
+ /**
+ * Returns a dynamic code entry using its starting address.
+ *
+ * @param {number} addr Address.
+ */
+ findDynamicEntryByStartAddress(addr) {
+ const node = this.dynamics_.find(addr);
+ return node ? node.value : null;
+ }
-/**
- * Returns an array of all static code entries.
- */
-CodeMap.prototype.getAllStaticEntries = function() {
- return this.statics_.exportValues();
-};
+ /**
+ * Returns an array of all dynamic code entries.
+ */
+ getAllDynamicEntries() {
+ return this.dynamics_.exportValues();
+ }
+ /**
+ * Returns an array of pairs of all dynamic code entries and their addresses.
+ */
+ getAllDynamicEntriesWithAddresses() {
+ return this.dynamics_.exportKeysAndValues();
+ }
-/**
- * Returns an array of pairs of all static code entries and their addresses.
- */
-CodeMap.prototype.getAllStaticEntriesWithAddresses = function() {
- return this.statics_.exportKeysAndValues();
-};
+ /**
+ * Returns an array of all static code entries.
+ */
+ getAllStaticEntries() {
+ return this.statics_.exportValues();
+ }
+ /**
+ * Returns an array of pairs of all static code entries and their addresses.
+ */
+ getAllStaticEntriesWithAddresses() {
+ return this.statics_.exportKeysAndValues();
+ }
-/**
- * Returns an array of all libraries entries.
- */
-CodeMap.prototype.getAllLibrariesEntries = function() {
- return this.libraries_.exportValues();
-};
+ /**
+ * Returns an array of all libraries entries.
+ */
+ getAllLibrariesEntries() {
+ return this.libraries_.exportValues();
+ }
+}
/**
@@ -288,34 +268,31 @@ CodeMap.prototype.getAllLibrariesEntries = function() {
* @param {string} opt_type Code entry type, e.g. SHARED_LIB, CPP.
* @constructor
*/
-CodeMap.CodeEntry = function(size, opt_name, opt_type) {
- this.size = size;
- this.name = opt_name || '';
- this.type = opt_type || '';
- this.nameUpdated_ = false;
-};
-
-
-CodeMap.CodeEntry.prototype.getName = function() {
- return this.name;
-};
-
-
-CodeMap.CodeEntry.prototype.toString = function() {
- return this.name + ': ' + this.size.toString(16);
-};
-
-
-CodeMap.NameGenerator = function() {
- this.knownNames_ = {};
-};
+export class CodeEntry {
+ constructor(size, opt_name, opt_type) {
+ this.size = size;
+ this.name = opt_name || '';
+ this.type = opt_type || '';
+ this.nameUpdated_ = false;
+ }
+ getName() {
+ return this.name;
+ }
-CodeMap.NameGenerator.prototype.getName = function(name) {
- if (!(name in this.knownNames_)) {
- this.knownNames_[name] = 0;
- return name;
+ toString() {
+ return this.name + ': ' + this.size.toString(16);
}
- var count = ++this.knownNames_[name];
- return name + ' {' + count + '}';
-};
+}
+
+class NameGenerator {
+ knownNames_ = { __proto__:null }
+ getName(name) {
+ if (!(name in this.knownNames_)) {
+ this.knownNames_[name] = 0;
+ return name;
+ }
+ const count = ++this.knownNames_[name];
+ return name + ' {' + count + '}';
+ };
+}
diff --git a/chromium/v8/tools/consarray.mjs b/chromium/v8/tools/consarray.mjs
index 450e18f6638..1dc2afe886b 100644
--- a/chromium/v8/tools/consarray.mjs
+++ b/chromium/v8/tools/consarray.mjs
@@ -72,7 +72,7 @@ ConsArray.prototype.atEnd = function() {
* Returns the current item, moves to the next one.
*/
ConsArray.prototype.next = function() {
- var result = this.currCell_.data[this.currCellPos_++];
+ const result = this.currCell_.data[this.currCellPos_++];
if (this.currCellPos_ >= this.currCell_.data.length) {
this.currCell_ = this.currCell_.next;
this.currCellPos_ = 0;
diff --git a/chromium/v8/tools/csvparser.mjs b/chromium/v8/tools/csvparser.mjs
index 03356d82097..e027d47384d 100644
--- a/chromium/v8/tools/csvparser.mjs
+++ b/chromium/v8/tools/csvparser.mjs
@@ -84,9 +84,9 @@ export class CsvParser {
* @param {string} line Input line.
*/
parseLine(line) {
- var pos = 0;
- var endPos = line.length;
- var fields = [];
+ let pos = 0;
+ const endPos = line.length;
+ const fields = [];
if (endPos == 0) return fields;
let nextPos = 0;
while(nextPos !== -1) {
diff --git a/chromium/v8/tools/debug_helper/get-object-properties.cc b/chromium/v8/tools/debug_helper/get-object-properties.cc
index c9208579769..181c58dbf08 100644
--- a/chromium/v8/tools/debug_helper/get-object-properties.cc
+++ b/chromium/v8/tools/debug_helper/get-object-properties.cc
@@ -329,9 +329,10 @@ class ReadStringVisitor : public TqObjectVisitor {
ExternalPointer_t resource_data =
GetOrFinish(object->GetResourceDataValue(accessor_));
#ifdef V8_COMPRESS_POINTERS
- uintptr_t data_address = static_cast<uintptr_t>(DecodeExternalPointer(
- Isolate::FromRoot(GetIsolateRoot(heap_addresses_.any_heap_pointer)),
- resource_data));
+ uintptr_t data_address = static_cast<uintptr_t>(
+ DecodeExternalPointer(GetIsolateForPtrComprFromOnHeapAddress(
+ heap_addresses_.any_heap_pointer),
+ resource_data, kExternalStringResourceDataTag));
#else
uintptr_t data_address = static_cast<uintptr_t>(resource_data);
#endif // V8_COMPRESS_POINTERS
diff --git a/chromium/v8/tools/dumpcpp-driver.mjs b/chromium/v8/tools/dumpcpp-driver.mjs
index fafa85e67eb..8f575d07cb2 100644
--- a/chromium/v8/tools/dumpcpp-driver.mjs
+++ b/chromium/v8/tools/dumpcpp-driver.mjs
@@ -11,7 +11,7 @@ import {
// Dump C++ symbols of shared library if possible
function processArguments(args) {
- var processor = new ArgumentsProcessor(args);
+ const processor = new ArgumentsProcessor(args);
if (processor.parse()) {
return processor.result();
} else {
@@ -25,26 +25,26 @@ function initSourceMapSupport() {
// Overwrite the load function to load scripts synchronously.
SourceMap.load = function(sourceMapURL) {
- var content = readFile(sourceMapURL);
- var sourceMapObject = (JSON.parse(content));
+ const content = readFile(sourceMapURL);
+ const sourceMapObject = (JSON.parse(content));
return new SourceMap(sourceMapURL, sourceMapObject);
};
}
-var entriesProviders = {
+const entriesProviders = {
'unix': UnixCppEntriesProvider,
'windows': WindowsCppEntriesProvider,
'mac': MacCppEntriesProvider
};
-var params = processArguments(arguments);
-var sourceMap = null;
+const params = processArguments(arguments);
+let sourceMap = null;
if (params.sourceMap) {
initSourceMapSupport();
sourceMap = SourceMap.load(params.sourceMap);
}
-var cppProcessor = new CppProcessor(
+const cppProcessor = new CppProcessor(
new (entriesProviders[params.platform])(params.nm, params.targetRootFS,
params.apkEmbeddedLibrary),
params.timedRange, params.pairwiseTimedRange);
diff --git a/chromium/v8/tools/dumpcpp.mjs b/chromium/v8/tools/dumpcpp.mjs
index 9142cad114c..be2dd996e41 100644
--- a/chromium/v8/tools/dumpcpp.mjs
+++ b/chromium/v8/tools/dumpcpp.mjs
@@ -3,7 +3,7 @@
// found in the LICENSE file.
import { LogReader, parseString } from "./logreader.mjs";
-import { CodeMap } from "./codemap.mjs";
+import { CodeMap, CodeEntry } from "./codemap.mjs";
export {
ArgumentsProcessor, UnixCppEntriesProvider,
WindowsCppEntriesProvider, MacCppEntriesProvider,
@@ -11,57 +11,58 @@ export {
import { inherits } from "./tickprocessor.mjs";
-export function CppProcessor(cppEntriesProvider, timedRange, pairwiseTimedRange) {
- LogReader.call(this, {
- 'shared-library': { parsers: [parseString, parseInt, parseInt, parseInt],
+export class CppProcessor extends LogReader {
+ constructor(cppEntriesProvider, timedRange, pairwiseTimedRange) {
+ super({}, timedRange, pairwiseTimedRange);
+ this.dispatchTable_ = {
+ 'shared-library': {
+ parsers: [parseString, parseInt, parseInt, parseInt],
processor: this.processSharedLibrary }
- }, timedRange, pairwiseTimedRange);
+ };
+ this.cppEntriesProvider_ = cppEntriesProvider;
+ this.codeMap_ = new CodeMap();
+ this.lastLogFileName_ = null;
+ }
- this.cppEntriesProvider_ = cppEntriesProvider;
- this.codeMap_ = new CodeMap();
- this.lastLogFileName_ = null;
-}
-inherits(CppProcessor, LogReader);
+ /**
+ * @override
+ */
+ printError(str) {
+ print(str);
+ };
-/**
- * @override
- */
-CppProcessor.prototype.printError = function(str) {
- print(str);
-};
+ processLogFile(fileName) {
+ this.lastLogFileName_ = fileName;
+ let line;
+ while (line = readline()) {
+ this.processLogLine(line);
+ }
+ };
-CppProcessor.prototype.processLogFile = function(fileName) {
- this.lastLogFileName_ = fileName;
- var line;
- 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);
+ };
-CppProcessor.prototype.processLogFileInTest = function(fileName) {
- // Hack file name to avoid dealing with platform specifics.
- this.lastLogFileName_ = 'v8.log';
- var contents = readFile(fileName);
- this.processLogChunk(contents);
-};
+ processSharedLibrary(name, startAddr, endAddr, aslrSlide) {
+ const self = this;
+ const libFuncs = this.cppEntriesProvider_.parseVmSymbols(
+ name, startAddr, endAddr, aslrSlide, function(fName, fStart, fEnd) {
+ const entry = new CodeEntry(fEnd - fStart, fName, 'CPP');
+ self.codeMap_.addStaticCode(fStart, entry);
+ });
+ };
-CppProcessor.prototype.processSharedLibrary = function(
- name, startAddr, endAddr, aslrSlide) {
- var self = this;
- var libFuncs = this.cppEntriesProvider_.parseVmSymbols(
- name, startAddr, endAddr, aslrSlide, function(fName, fStart, fEnd) {
- var entry = new CodeMap.CodeEntry(fEnd - fStart, fName, 'CPP');
- self.codeMap_.addStaticCode(fStart, entry);
- });
-};
-
-CppProcessor.prototype.dumpCppSymbols = function() {
- var staticEntries = this.codeMap_.getAllStaticEntriesWithAddresses();
- var total = staticEntries.length;
- for (var i = 0; i < total; ++i) {
- var entry = staticEntries[i];
- var printValues = ['cpp', '0x' + entry[0].toString(16), entry[1].size,
- '"' + entry[1].name + '"'];
- print(printValues.join(','));
+ dumpCppSymbols() {
+ const staticEntries = this.codeMap_.getAllStaticEntriesWithAddresses();
+ const total = staticEntries.length;
+ for (let i = 0; i < total; ++i) {
+ const entry = staticEntries[i];
+ const printValues = ['cpp', `0x${entry[0].toString(16)}`, entry[1].size,
+ `"${entry[1].name}"`];
+ print(printValues.join(','));
+ }
}
-};
+}
diff --git a/chromium/v8/tools/gcmole/gcmole-test.cc b/chromium/v8/tools/gcmole/gcmole-test.cc
index 92f7a9eda88..8512d7ab4cd 100644
--- a/chromium/v8/tools/gcmole/gcmole-test.cc
+++ b/chromium/v8/tools/gcmole/gcmole-test.cc
@@ -216,5 +216,18 @@ void TestNestedDeadVarAnalysis(Isolate* isolate) {
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.
+ DisallowHeapAllocation no_gc;
+ // Should cause warning.
+ raw_obj.Print();
+}
+
} // namespace internal
} // namespace v8
diff --git a/chromium/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 b/chromium/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
index a8ea9424af4..84b3657c6cc 100644
--- a/chromium/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
+++ b/chromium/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
@@ -1 +1 @@
-7736018d2ca616f7c1477102cc169ee579ee6003
+7e31d257a711b1a77823633e4f19152c3e0718f4
diff --git a/chromium/v8/tools/gcmole/gcmole.cc b/chromium/v8/tools/gcmole/gcmole.cc
index 3c5fb5ce96c..7b32f6c7fd1 100644
--- a/chromium/v8/tools/gcmole/gcmole.cc
+++ b/chromium/v8/tools/gcmole/gcmole.cc
@@ -1067,6 +1067,8 @@ class FunctionAnalyzer {
if (callee != NULL) {
if (KnownToCauseGC(ctx_, callee)) {
out.setGC();
+ scopes_.back().SetGCCauseLocation(
+ clang::FullSourceLoc(call->getExprLoc(), sm_));
}
// Support for virtual methods that might be GC suspects.
@@ -1081,6 +1083,8 @@ class FunctionAnalyzer {
if (target != NULL) {
if (KnownToCauseGC(ctx_, target)) {
out.setGC();
+ scopes_.back().SetGCCauseLocation(
+ clang::FullSourceLoc(call->getExprLoc(), sm_));
}
} else {
// According to the documentation, {getDevirtualizedMethod} might
@@ -1089,6 +1093,8 @@ class FunctionAnalyzer {
// to increase coverage.
if (SuspectedToCauseGC(ctx_, method)) {
out.setGC();
+ scopes_.back().SetGCCauseLocation(
+ clang::FullSourceLoc(call->getExprLoc(), sm_));
}
}
}
@@ -1244,7 +1250,7 @@ class FunctionAnalyzer {
}
DECL_VISIT_STMT(CompoundStmt) {
- scopes_.push_back(GCGuard(stmt, false));
+ scopes_.push_back(GCScope());
Environment out = env;
clang::CompoundStmt::body_iterator end = stmt->body_end();
for (clang::CompoundStmt::body_iterator s = stmt->body_begin();
@@ -1422,7 +1428,8 @@ class FunctionAnalyzer {
out = out.Define(var->getNameAsString());
}
if (IsGCGuard(var->getType())) {
- scopes_.back().has_guard = true;
+ scopes_.back().guard_location =
+ clang::FullSourceLoc(decl->getLocation(), sm_);
}
return out;
@@ -1477,7 +1484,7 @@ class FunctionAnalyzer {
bool HasActiveGuard() {
for (auto s : scopes_) {
- if (s.has_guard) return true;
+ if (s.IsBeforeGCCause()) return true;
}
return false;
}
@@ -1503,14 +1510,26 @@ class FunctionAnalyzer {
Block* block_;
- struct GCGuard {
- clang::CompoundStmt* stmt = NULL;
- bool has_guard = false;
+ struct GCScope {
+ clang::FullSourceLoc guard_location;
+ clang::FullSourceLoc gccause_location;
- GCGuard(clang::CompoundStmt* stmt_, bool has_guard_)
- : stmt(stmt_), has_guard(has_guard_) {}
+ // We're only interested in guards that are declared before any further GC
+ // causing calls (see TestGuardedDeadVarAnalysisMidFunction for example).
+ bool IsBeforeGCCause() {
+ if (!guard_location.isValid()) return false;
+ if (!gccause_location.isValid()) return true;
+ return guard_location.isBeforeInTranslationUnitThan(gccause_location);
+ }
+
+ // After we set the first GC cause in the scope, we don't need the later
+ // ones.
+ void SetGCCauseLocation(clang::FullSourceLoc gccause_location_) {
+ if (gccause_location.isValid()) return;
+ gccause_location = gccause_location_;
+ }
};
- std::vector<GCGuard> scopes_;
+ std::vector<GCScope> scopes_;
};
class ProblemsFinder : public clang::ASTConsumer,
diff --git a/chromium/v8/tools/gcmole/test-expectations.txt b/chromium/v8/tools/gcmole/test-expectations.txt
index 780cea91811..f6c04e4a6c6 100644
--- a/chromium/v8/tools/gcmole/test-expectations.txt
+++ b/chromium/v8/tools/gcmole/test-expectations.txt
@@ -32,4 +32,7 @@ tools/gcmole/gcmole-test.cc:193:3: warning: Possibly dead variable.
tools/gcmole/gcmole-test.cc:216:3: warning: Possibly dead variable.
raw_obj.Print();
^
-11 warnings generated.
+tools/gcmole/gcmole-test.cc:229:3: warning: Possibly dead variable.
+ raw_obj.Print();
+ ^
+12 warnings generated.
diff --git a/chromium/v8/tools/gen-postmortem-metadata.py b/chromium/v8/tools/gen-postmortem-metadata.py
index 84b9ad49905..4e9facd7818 100644
--- a/chromium/v8/tools/gen-postmortem-metadata.py
+++ b/chromium/v8/tools/gen-postmortem-metadata.py
@@ -101,6 +101,16 @@ consts_misc = [
{ 'name': 'OddballOther', 'value': 'Oddball::kOther' },
{ 'name': 'OddballException', 'value': 'Oddball::kException' },
+ { 'name': 'ContextRegister', 'value': 'kContextRegister.code()' },
+ { 'name': 'ReturnRegister0', 'value': 'kReturnRegister0.code()' },
+ { 'name': 'JSFunctionRegister', 'value': 'kJSFunctionRegister.code()' },
+ { 'name': 'InterpreterBytecodeOffsetRegister',
+ 'value': 'kInterpreterBytecodeOffsetRegister.code()' },
+ { 'name': 'InterpreterBytecodeArrayRegister',
+ 'value': 'kInterpreterBytecodeArrayRegister.code()' },
+ { 'name': 'RuntimeCallFunctionRegister',
+ 'value': 'kRuntimeCallFunctionRegister.code()' },
+
{ 'name': 'prop_kind_Data',
'value': 'kData' },
{ 'name': 'prop_kind_Accessor',
@@ -307,6 +317,7 @@ header = '''
*/
#include "src/init/v8.h"
+#include "src/codegen/register-arch.h"
#include "src/execution/frames.h"
#include "src/execution/frames-inl.h" /* for architecture-specific frame constants */
#include "src/objects/contexts.h"
@@ -322,7 +333,7 @@ extern "C" {
/* stack frame constants */
#define FRAME_CONST(value, klass) \
- int v8dbg_frametype_##klass = StackFrame::value;
+ V8_EXPORT int v8dbg_frametype_##klass = StackFrame::value;
STACK_FRAME_TYPE_LIST(FRAME_CONST)
@@ -619,7 +630,7 @@ def load_fields_from_file(filename):
#
prefixes = [ 'ACCESSORS', 'ACCESSORS2', 'ACCESSORS_GCSAFE',
'SMI_ACCESSORS', 'ACCESSORS_TO_SMI',
- 'SYNCHRONIZED_ACCESSORS', 'WEAK_ACCESSORS' ];
+ 'RELEASE_ACQUIRE_ACCESSORS', 'WEAK_ACCESSORS' ];
prefixes += ([ prefix + "_CHECKED" for prefix in prefixes ] +
[ prefix + "_CHECKED2" for prefix in prefixes ])
current = '';
@@ -667,13 +678,18 @@ def load_fields_from_file(filename):
# Emit a block of constants.
#
def emit_set(out, consts):
+ lines = set() # To remove duplicates.
+
# Fix up overzealous parses. This could be done inside the
# parsers but as there are several, it's easiest to do it here.
ws = re.compile('\s+')
for const in consts:
name = ws.sub('', const['name'])
value = ws.sub('', str(const['value'])) # Can be a number.
- out.write('int v8dbg_%s = %s;\n' % (name, value))
+ lines.add('V8_EXPORT int v8dbg_%s = %s;\n' % (name, value))
+
+ for line in lines:
+ out.write(line);
out.write('\n');
#
diff --git a/chromium/v8/tools/ic-explorer.html b/chromium/v8/tools/ic-explorer.html
deleted file mode 100644
index 61d94d65d11..00000000000
--- a/chromium/v8/tools/ic-explorer.html
+++ /dev/null
@@ -1,389 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-Copyright 2016 the V8 project authors. All rights reserved. Use of this source
-code is governed by a BSD-style license that can be found in the LICENSE file.
--->
-
-<head>
- <meta charset="utf-8">
- <title>V8 IC explorer</title>
- <style>
- html {
- font-family: monospace;
- }
-
- .entry-details {}
-
- .entry-details TD {}
-
- .details {
- width: 0.1em;
- }
-
- .details span {
- padding: 0 0.4em 0 0.4em;
- background-color: black;
- color: white;
- border-radius: 25px;
- text-align: center;
- cursor: -webkit-zoom-in;
- }
-
- .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;
- }
- </style>
- <script type="module" src="./ic-processor.js"></script>
-
- <script>
- "use strict"
- let entries = [];
-
- let properties = ['type', 'category', 'functionName', 'filePosition',
- 'state', 'key', 'map', 'reason', 'file',
- ];
-
- // For compatibility with console scripts:
- print = console.log;
-
- class CustomIcProcessor extends IcProcessor {
- constructor() {
- super();
- this.entries = [];
- }
-
- functionName(pc) {
- let entry = this.profile_.findEntry(pc);
- return this.formatName(entry);
- }
-
- processPropertyIC(
- type, pc, time, line, column, old_state, new_state, map, key, modifier,
- slow_reason) {
- let fnName = this.functionName(pc);
- this.entries.push(new Entry(
- type, fnName, time, line, column, key, old_state, new_state, map,
- slow_reason));
- }
- };
-
-
- class Entry {
- constructor(
- type, fn_file, time, line, column, key, oldState, newState, map, reason,
- additional) {
- this.time = time;
- this.type = type;
- this.category = 'other';
- if (this.type.indexOf('Store') !== -1) {
- this.category = 'Store';
- } else if (this.type.indexOf('Load') !== -1) {
- this.category = 'Load';
- }
- let 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;
- this.key = key;
- this.map = map.toString(16);
- this.reason = reason;
- this.additional = additional;
- }
-
- parseMapProperties(parts, offset) {
- let next = parts[++offset];
- if (!next.startsWith('dict')) return offset;
- this.propertiesMode = next.substr(5) == '0' ? 'fast' : 'slow';
- this.numberOfOwnProperties = parts[++offset].substr(4);
- next = parts[++offset];
- this.instanceType = next.substr(5, next.length - 6);
- return offset;
- }
-
- parsePositionAndFile(parts, start) {
- // find the position of 'at' in the parts array.
- let offset = start;
- for (let i = start + 1; i < parts.length; i++) {
- offset++;
- if (parts[i] == 'at') break;
- }
- if (parts[offset] !== 'at') return -1;
- this.position = parts.slice(start, offset).join(' ');
- offset += 1;
- this.isNative = parts[offset] == 'native'
- offset += this.isNative ? 1 : 0;
- this.file = parts[offset];
- return offset;
- }
-}
-
- function loadFile() {
- let files = document.getElementById("uploadInput").files;
-
- let file = files[0];
- let reader = new FileReader();
-
- reader.onload = function(evt) {
- let icProcessor = new CustomIcProcessor();
- icProcessor.processString(this.result);
- entries = icProcessor.entries;
-
- document.getElementById("count").innerHTML = entries.length;
- updateTable();
- }
- reader.readAsText(file);
- initGroupKeySelect();
- }
-
-
- 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() {
- this.groups = {};
- for (let i = 0; i < properties.length; i++) {
- let subProperty = properties[i];
- if (this.property == subProperty) continue;
- this.groups[subProperty] = groupBy(this.entries, subProperty);
- }
- }
- }
-
- function 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;
- }
-
-
-
- function escapeHtml(unsafe) {
- if (!unsafe) return "";
- return unsafe.toString()
- .replace(/&/g, "&amp;")
- .replace(/</g, "&lt;")
- .replace(/>/g, "&gt;")
- .replace(/"/g, "&quot;")
- .replace(/'/g, "&#039;");
- }
-
- function processValue(unsafe) {
- if (!unsafe) return "";
- if (!unsafe.startsWith("http")) return escapeHtml(unsafe);
- let a = document.createElement("a");
- a.href = unsafe;
- a.textContent = unsafe;
- return a;
- }
-
- function updateTable() {
- let select = document.getElementById("group-key");
- let key = select.options[select.selectedIndex].text;
- let tableBody = document.getElementById("table-body");
- removeAllChildren(tableBody);
- let groups = groupBy(entries, key, true);
- display(groups, tableBody);
- }
-
- function selecedOption(node) {
- return node.options[node.selectedIndex]
- }
-
- function removeAllChildren(node) {
- while (node.firstChild) {
- node.removeChild(node.firstChild);
- }
- }
-
- function display(entries, parent) {
- let fragment = document.createDocumentFragment();
-
- function td(tr, content, className) {
- let node = document.createElement("td");
- if (typeof content == "object") {
- node.appendChild(content);
- } else {
- node.innerHTML = content;
- }
- node.className = className
- tr.appendChild(node);
- return node
- }
-
- let max = Math.min(1000, entries.length)
- for (let i = 0; i < max; i++) {
- let entry = entries[i];
- let tr = document.createElement("tr");
- tr.entry = entry;
- td(tr, '<span onclick="toggleDetails(this)">&#8505;</a>', 'details');
- td(tr, entry.percentage + "%", 'percentage');
- td(tr, entry.count, 'count');
- td(tr, processValue(entry.key), 'key');
- fragment.appendChild(tr);
- }
- let omitted = entries.length - max;
- if (omitted > 0) {
- let tr = document.createElement("tr");
- let tdNode = td(tr, 'Omitted ' + omitted + " entries.");
- tdNode.colSpan = 4;
- fragment.appendChild(tr);
- }
- parent.appendChild(fragment);
- }
-
- function displayDrilldown(entry, previousSibling) {
- let tr = document.createElement('tr');
- tr.className = "entry-details";
- tr.style.display = "none";
- // indent by one td.
- tr.appendChild(document.createElement("td"));
- let td = document.createElement("td");
- td.colSpan = 3;
- for (let key in entry.groups) {
- td.appendChild(displayDrilldownGroup(entry, key));
- }
- tr.appendChild(td);
- // Append the new TR after previousSibling.
- previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling)
- }
-
- function displayDrilldownGroup(entry, key) {
- let max = 20;
- let group = entry.groups[key];
- let div = document.createElement("div")
- div.className = 'drilldown-group-title'
- div.textContent = key + ' [top ' + max + ' out of ' + group.length + ']';
- let table = document.createElement("table");
- display(group.slice(0, max), table, false)
- div.appendChild(table);
- return div;
- }
-
- function toggleDetails(node) {
- let tr = node.parentNode.parentNode;
- let entry = tr.entry;
-
- // Create subgroup in-place if the don't exist yet.
- if (entry.groups === undefined) {
- entry.createSubGroups();
- displayDrilldown(entry, tr);
- }
- let details = tr.nextSibling;
- let display = details.style.display;
- if (display != "none") {
- display = "none";
- } else {
- display = "table-row"
- };
- details.style.display = display;
- }
-
- function initGroupKeySelect() {
- let select = document.getElementById("group-key");
- select.options.length = 0;
- for (let i in properties) {
- let option = document.createElement("option");
- option.text = properties[i];
- select.add(option);
- }
- }
-
- function handleOnLoad() {
- document.querySelector("#uploadInput").focus();
- }
- </script>
-</head>
-
-<body onload="handleOnLoad()">
- <h1>
- <span style="color: #00FF00">I</span>
- <span style="color: #FF00FF">C</span>
- <span style="color: #00FFFF">E</span>
- </h1> Your IC-Explorer.
-
- <div id="legend" style="padding-right: 200px">
- <div style="float:right; border-style: solid; border-width: 1px; padding:20px">
- 0 uninitialized<br>
- X no feedback<br>
- 1 monomorphic<br>
- ^ recompute handler<br>
- P polymorphic<br>
- N megamorphic<br>
- G generic
- </div>
- </div>
-
- <h2>Usage</h2> Run your script with <code>--trace_ic</code> and upload <code>v8.log</code> on this page:<br/>
- <code>/path/to/d8 --trace_ic your_script.js</code>
- <h2>Data</h2>
- <form name="fileForm">
- <p>
- <input id="uploadInput" type="file" name="files" onchange="loadFile();"> trace entries: <span id="count">0</span>
- </p>
- </form>
- <h2>Result</h2>
- <p>
- Group-Key:
- <select id="group-key" onchange="updateTable()"></select>
- </p>
- <p>
- <table id="table" width="100%">
- <tbody id="table-body">
- </tbody>
- </table>
- </p>
-</body>
-
-</html>
diff --git a/chromium/v8/tools/ic-processor-driver.mjs b/chromium/v8/tools/ic-processor-driver.mjs
index 779837aa3f8..ef6d83e1e44 100644
--- a/chromium/v8/tools/ic-processor-driver.mjs
+++ b/chromium/v8/tools/ic-processor-driver.mjs
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import { IcProcessor, ArgumentsProcessor, readFile } from "./ic-processor.mjs";
+import { Processor } from "./system-analyzer/processor.mjs";
import { WebInspector } from "./sourcemap.mjs";
+import { BaseArgumentsProcessor } from "./arguments.mjs";
function processArguments(args) {
- var processor = new ArgumentsProcessor(args);
+ const processor = new ArgumentsProcessor(args);
if (processor.parse()) {
return processor.result();
} else {
@@ -14,23 +15,80 @@ function processArguments(args) {
}
}
+/**
+ * A thin wrapper around shell's 'read' function showing a file name on error.
+ */
+export function readFile(fileName) {
+ try {
+ return read(fileName);
+ } catch (e) {
+ print(fileName + ': ' + (e.message || e));
+ throw e;
+ }
+}
+
function initSourceMapSupport() {
// Pull dev tools source maps into our name space.
SourceMap = WebInspector.SourceMap;
// Overwrite the load function to load scripts synchronously.
SourceMap.load = function(sourceMapURL) {
- var content = readFile(sourceMapURL);
- var sourceMapObject = (JSON.parse(content));
+ const content = readFile(sourceMapURL);
+ const sourceMapObject = (JSON.parse(content));
return new SourceMap(sourceMapURL, sourceMapObject);
};
}
-var params = processArguments(arguments);
-var sourceMap = null;
+class ArgumentsProcessor extends BaseArgumentsProcessor {
+ getArgsDispatch() {
+ return {
+ '--range': ['range', 'auto,auto',
+ 'Specify the range limit as [start],[end]'],
+ '--source-map': ['sourceMap', null,
+ 'Specify the source map that should be used for output']
+ };
+ }
+ getDefaultResults() {
+ return {
+ logFileName: 'v8.log',
+ range: 'auto,auto',
+ };
+ }
+}
+
+const params = processArguments(arguments);
+let sourceMap = null;
if (params.sourceMap) {
initSourceMapSupport();
sourceMap = SourceMap.load(params.sourceMap);
}
-var icProcessor = new IcProcessor();
-icProcessor.processLogFile(params.logFileName);
+const processor = new Processor();
+processor.processLogFile(params.logFileName);
+
+const typeAccumulator = new Map();
+
+const accumulator = {
+ __proto__: null,
+ LoadGlobalIC: 0,
+ StoreGlobalIC: 0,
+ LoadIC: 0,
+ StoreIC: 0,
+ KeyedLoadIC: 0,
+ KeyedStoreIC: 0,
+ 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);
+ accumulator[ic.type]++;
+}
+
+print("========================================");
+for (const key of Object.keys(accumulator)) {
+ print(key + ": " + accumulator[key]);
+}
+
+
diff --git a/chromium/v8/tools/ic-processor.mjs b/chromium/v8/tools/ic-processor.mjs
deleted file mode 100644
index 7f6fb03a614..00000000000
--- a/chromium/v8/tools/ic-processor.mjs
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2017 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 { LogReader, parseString, parseVarArgs } from "./logreader.mjs";
-import { BaseArgumentsProcessor } from "./arguments.mjs";
-import { Profile } from "./profile.mjs";
-
-function inherits(childCtor, parentCtor) {
- childCtor.prototype.__proto__ = parentCtor.prototype;
-};
-
-/**
- * A thin wrapper around shell's 'read' function showing a file name on error.
- */
-export function readFile(fileName) {
- try {
- return read(fileName);
- } catch (e) {
- print(fileName + ': ' + (e.message || e));
- throw e;
- }
-}
-
-/**
- * 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 IcProcessor() {
- var propertyICParser = [
- parseInt, parseInt, parseInt, parseInt, parseString, parseString,
- parseInt, parseString, parseString, parseString];
- LogReader.call(this, {
- 'code-creation': {
- parsers: [parseString, parseInt, parseInt, parseInt, parseInt,
- parseString, parseVarArgs],
- processor: this.processCodeCreation },
- 'code-move': { parsers: [parseInt, parseInt],
- processor: this.processCodeMove },
- 'code-delete': { parsers: [parseInt],
- processor: this.processCodeDelete },
- 'sfi-move': { parsers: [parseInt, parseInt],
- processor: this.processFunctionMove },
- 'LoadGlobalIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "LoadGlobalIC") },
- 'StoreGlobalIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "StoreGlobalIC") },
- 'LoadIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "LoadIC") },
- 'StoreIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "StoreIC") },
- 'KeyedLoadIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "KeyedLoadIC") },
- 'KeyedStoreIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "KeyedStoreIC") },
- 'StoreInArrayLiteralIC': {
- parsers : propertyICParser,
- processor: this.processPropertyIC.bind(this, "StoreInArrayLiteralIC") },
- });
- this.profile_ = new Profile();
-
- this.LoadGlobalIC = 0;
- this.StoreGlobalIC = 0;
- this.LoadIC = 0;
- this.StoreIC = 0;
- this.KeyedLoadIC = 0;
- this.KeyedStoreIC = 0;
- this.StoreInArrayLiteralIC = 0;
-}
-inherits(IcProcessor, LogReader);
-
-/**
- * @override
- */
-IcProcessor.prototype.printError = function(str) {
- print(str);
-};
-
-IcProcessor.prototype.processString = function(string) {
- var end = string.length;
- var current = 0;
- var next = 0;
- var line;
- var i = 0;
- var entry;
- while (current < end) {
- next = string.indexOf("\n", current);
- if (next === -1) break;
- i++;
- line = string.substring(current, next);
- current = next + 1;
- this.processLogLine(line);
- }
-}
-
-IcProcessor.prototype.processLogFile = function(fileName) {
- this.collectEntries = true
- this.lastLogFileName_ = fileName;
- var line;
- while (line = readline()) {
- this.processLogLine(line);
- }
- print();
- print("=====================");
- print("LoadGlobal: " + this.LoadGlobalIC);
- print("StoreGlobal: " + this.StoreGlobalIC);
- print("Load: " + this.LoadIC);
- print("Store: " + this.StoreIC);
- print("KeyedLoad: " + this.KeyedLoadIC);
- print("KeyedStore: " + this.KeyedStoreIC);
- print("StoreInArrayLiteral: " + this.StoreInArrayLiteralIC);
-};
-
-IcProcessor.prototype.addEntry = function(entry) {
- this.entries.push(entry);
-}
-
-IcProcessor.prototype.processCodeCreation = function(
- type, kind, timestamp, start, size, name, maybe_func) {
- if (maybe_func.length) {
- var funcAddr = parseInt(maybe_func[0]);
- var state = parseState(maybe_func[1]);
- this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
- } else {
- this.profile_.addCode(type, name, timestamp, start, size);
- }
-};
-
-
-IcProcessor.prototype.processCodeMove = function(from, to) {
- this.profile_.moveCode(from, to);
-};
-
-
-IcProcessor.prototype.processCodeDelete = function(start) {
- this.profile_.deleteCode(start);
-};
-
-
-IcProcessor.prototype.processFunctionMove = function(from, to) {
- this.profile_.moveFunc(from, to);
-};
-
-IcProcessor.prototype.formatName = function(entry) {
- if (!entry) return "<unknown>"
- var name = entry.func.getName();
- var re = /(.*):[0-9]+:[0-9]+$/;
- var array = re.exec(name);
- if (!array) return name;
- return entry.getState() + array[1];
-}
-
-IcProcessor.prototype.processPropertyIC = function (
- type, pc, time, line, column, old_state, new_state, map, name, modifier,
- slow_reason) {
-this[type]++;
-let entry = this.profile_.findEntry(pc);
-print(
- type + ' (' + old_state + '->' + new_state + modifier + ') at ' +
- this.formatName(entry) + ':' + line + ':' + column + ' ' + name +
- ' (map 0x' + map.toString(16) + ')' +
- (slow_reason ? ' ' + slow_reason : '') + 'time: ' + time);
-}
-
-
-
-export class ArgumentsProcessor extends BaseArgumentsProcessor {
- getArgsDispatch() {
- return {
- '--range': ['range', 'auto,auto',
- 'Specify the range limit as [start],[end]'],
- '--source-map': ['sourceMap', null,
- 'Specify the source map that should be used for output']
- };
- }
- getDefaultResults() {
- return {
- logFileName: 'v8.log',
- range: 'auto,auto',
- };
- }
-}
diff --git a/chromium/v8/tools/index.html b/chromium/v8/tools/index.html
index 5ff63c9e332..93155dfbdfd 100644
--- a/chromium/v8/tools/index.html
+++ b/chromium/v8/tools/index.html
@@ -46,7 +46,6 @@ a:hover, a:active {
text-align: center;
padding: 10px 50px 10px 50px ;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
- transition: 0.3s;
background-color: #121212;
width: auto;
}
@@ -65,6 +64,10 @@ dd, dt {
<p>Search through this page to find about the V8 tools to debug, trace and analyze the log files.</p>
<dl class="grid-container">
<div class="card">
+ <dt><a href="./system-analyzer/index.html">System Analyzer</a></dt>
+ <dd>A unified web interface to trace, debug and analyse patterns of how Maps/ICs are created in the real world applications.</dd>
+ </div>
+ <div class="card">
<dt><a href="./callstats.html">Callstats</a></dt>
<dd>Visualize and compare runtime call stats.</dd>
</div>
@@ -73,14 +76,6 @@ dd, dt {
<dd>Visualize heap memory usage.</dd>
</div>
<div class="card">
- <dt><a href="./ic-explorer.html">IC Explorer</a></dt>
- <dd>Analyse inline caches.</dd>
- </div>
- <div class="card">
- <dt><a href="./map-processor.html">Map Processor</a></dt>
- <dd>Analyse Maps and their transition trees.</dd>
- </div>
- <div class="card">
<dt><a href="./parse-processor.html">Parse Processor</a></dt>
<dd>Analyse parse, compile and first-execution.</dd>
</div>
@@ -89,10 +84,6 @@ dd, dt {
<dd>Fancy sampling profile viewer.</dd>
</div>
<div class="card">
- <dt><a href="./system-analyzer/index.html">System Analyzer</a></dt>
- <dd>A unified web interface to trace, debug and analyse patterns of how Maps/ICs are created in the real world applications.</dd>
- </div>
- <div class="card">
<dt><a href="./tick-processor.html">Tick Processor</a></dt>
<dd>Simple sampling profile viewer.</dd>
</div>
diff --git a/chromium/v8/tools/linux-tick-processor b/chromium/v8/tools/linux-tick-processor
index 8e5100b0959..a2ae2b54413 100755
--- a/chromium/v8/tools/linux-tick-processor
+++ b/chromium/v8/tools/linux-tick-processor
@@ -34,4 +34,4 @@ fi
# nm spits out 'no symbols found' messages to stderr.
cat $log_file | $d8_exec --enable-os-system \
- --module $tools_path/tickprocessor-driver.mjs -- $@ 2>/dev/null
+ --module $tools_path/tickprocessor-driver.mjs -- $@
diff --git a/chromium/v8/tools/logreader.mjs b/chromium/v8/tools/logreader.mjs
index 75bc7ddade5..1bd9a4ba02e 100644
--- a/chromium/v8/tools/logreader.mjs
+++ b/chromium/v8/tools/logreader.mjs
@@ -146,11 +146,11 @@ LogReader.prototype.processLogLine = function(line) {
* @return {Array.<number>} Processed stack.
*/
LogReader.prototype.processStack = function(pc, func, stack) {
- var fullStack = func ? [pc, func] : [pc];
- var prevFrame = pc;
- for (var i = 0, n = stack.length; i < n; ++i) {
- var frame = stack[i];
- var firstChar = frame.charAt(0);
+ 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);
@@ -159,7 +159,7 @@ LogReader.prototype.processStack = function(pc, func, stack) {
} else if (firstChar != 'o') {
fullStack.push(parseInt(frame, 16));
} else {
- this.printError("dropping: " + frame);
+ this.printError(`dropping: ${frame}`);
}
}
return fullStack;
@@ -172,9 +172,7 @@ LogReader.prototype.processStack = function(pc, func, stack) {
* @param {!Object} dispatch Dispatch record.
* @return {boolean} True if dispatch must be skipped.
*/
-LogReader.prototype.skipDispatch = function(dispatch) {
- return false;
-};
+LogReader.prototype.skipDispatch = dispatch => false;
// Parses dummy variable for readability;
export const parseString = 'parse-string';
@@ -188,17 +186,17 @@ export const parseVarArgs = 'parse-var-args';
*/
LogReader.prototype.dispatchLogRow_ = function(fields) {
// Obtain the dispatch.
- var command = fields[0];
- var dispatch = this.dispatchTable_[command];
+ const command = fields[0];
+ const dispatch = this.dispatchTable_[command];
if (dispatch === undefined) return;
if (dispatch === null || this.skipDispatch(dispatch)) {
return;
}
// Parse fields.
- var parsedFields = [];
- for (var i = 0; i < dispatch.parsers.length; ++i) {
- var parser = dispatch.parsers[i];
+ 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') {
@@ -208,7 +206,7 @@ LogReader.prototype.dispatchLogRow_ = function(fields) {
parsedFields.push(fields.slice(1 + i));
break;
} else {
- throw new Error("Invalid log field parser: " + parser);
+ throw new Error(`Invalid log field parser: ${parser}`);
}
}
@@ -224,7 +222,7 @@ LogReader.prototype.dispatchLogRow_ = function(fields) {
* @private
*/
LogReader.prototype.processLog_ = function(lines) {
- for (var i = 0, n = lines.length; i < n; ++i) {
+ for (let i = 0, n = lines.length; i < n; ++i) {
this.processLogLine_(lines[i]);
}
}
@@ -238,10 +236,10 @@ LogReader.prototype.processLog_ = function(lines) {
LogReader.prototype.processLogLine_ = function(line) {
if (line.length > 0) {
try {
- var fields = this.csvParser_.parseLine(line);
+ const fields = this.csvParser_.parseLine(line);
this.dispatchLogRow_(fields);
} catch (e) {
- this.printError('line ' + (this.lineNum_ + 1) + ': ' + (e.message || e) + '\n' + e.stack);
+ this.printError(`line ${this.lineNum_ + 1}: ${e.message || e}\n${e.stack}`);
}
}
this.lineNum_++;
diff --git a/chromium/v8/tools/map-processor b/chromium/v8/tools/map-processor
deleted file mode 100755
index ceb69970dff..00000000000
--- a/chromium/v8/tools/map-processor
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-# find the name of the log file to process, it must not start with a dash.
-log_file="v8.log"
-for arg in "$@"
-do
- if ! expr "X${arg}" : "^X-" > /dev/null; then
- log_file=${arg}
- fi
-done
-
-tools_path=`cd $(dirname "$0");pwd`
-if [ ! "$D8_PATH" ]; then
- d8_public=`which d8`
- if [ -x "$d8_public" ]; then D8_PATH=$(dirname "$d8_public"); fi
-fi
-[ -n "$D8_PATH" ] || D8_PATH=$tools_path/..
-d8_exec=$D8_PATH/d8
-
-if [ ! -x "$d8_exec" ]; then
- D8_PATH=`pwd`/out/native
- d8_exec=$D8_PATH/d8
-fi
-
-if [ ! -x "$d8_exec" ]; then
- d8_exec=`grep -m 1 -o '".*/d8"' $log_file | sed 's/"//g'`
-fi
-
-if [ ! -x "$d8_exec" ]; then
- echo "d8 shell not found in $D8_PATH"
- echo "Please provide path to d8 as env var in D8_PATH"
- exit 1
-fi
-
-# nm spits out 'no symbols found' messages to stderr.
-cat $log_file | $d8_exec \
- --module $tools_path/map-processor-driver.mjs -- $@ 2>/dev/null
diff --git a/chromium/v8/tools/map-processor-driver.mjs b/chromium/v8/tools/map-processor-driver.mjs
deleted file mode 100644
index a7a6fefa668..00000000000
--- a/chromium/v8/tools/map-processor-driver.mjs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 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 { WebInspector } from "./sourcemap.mjs";
-import {
- MapProcessor, ArgumentsProcessor, readFile
- } from "./map-processor.mjs";
-
-function processArguments(args) {
- var processor = new ArgumentsProcessor(args);
- if (processor.parse()) {
- return processor.result();
- } else {
- processor.printUsageAndExit();
- }
-}
-
-function initSourceMapSupport() {
- // Pull dev tools source maps into our name space.
- SourceMap = WebInspector.SourceMap;
-
- // Overwrite the load function to load scripts synchronously.
- SourceMap.load = function(sourceMapURL) {
- var content = readFile(sourceMapURL);
- var sourceMapObject = (JSON.parse(content));
- return new SourceMap(sourceMapURL, sourceMapObject);
- };
-}
-
-var params = processArguments(arguments);
-var sourceMap = null;
-if (params.sourceMap) {
- initSourceMapSupport();
- sourceMap = SourceMap.load(params.sourceMap);
-}
-var mapProcessor = new MapProcessor();
-mapProcessor.processLogFile(params.logFileName);
diff --git a/chromium/v8/tools/map-processor.html b/chromium/v8/tools/map-processor.html
deleted file mode 100644
index 16cd2246386..00000000000
--- a/chromium/v8/tools/map-processor.html
+++ /dev/null
@@ -1,1315 +0,0 @@
-<!DOCTYPE html>
-<html>
- <!--
- Copyright 2017 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>
-<meta charset="utf-8">
-<style>
-html, body {
- font-family: sans-serif;
- padding: 0px;
- margin: 0px;
-}
-h1, h2, h3, section {
- padding-left: 15px;
-}
-
-kbd {
- background-color: #eee;
- border-radius: 3px;
- border: 1px solid black;
- display: inline-block;
- font-size: .9em;
- font-weight: bold;
- padding: 0px 4px 2px 4px;
- white-space: nowrap;
-}
-dl {
- display: grid;
- grid-template-columns: min-content auto;
- grid-gap: 10px;
-}
-dt {
- text-align: right;
- white-space: nowrap;
-}
-dd {
- margin: 0;
-}
-
-#content {
- opacity: 0.0;
- height: 0px;
- transition: all 0.5s ease-in-out;
-}
-
-.success #content {
- height: auto;
- opacity: 1.0;
-}
-
-#fileReader {
- width: 100%;
- height: 100px;
- line-height: 100px;
- text-align: center;
- border: solid 1px #000000;
- border-radius: 5px;
- cursor: pointer;
- transition: all 0.5s ease-in-out;
-}
-
-.failure #fileReader {
- background-color: #FFAAAA;
-}
-
-.success #fileReader {
- height: 20px;
- line-height: 20px;
-}
-
-#fileReader:hover {
- background-color: #e0edfe;
-}
-
-.loading #fileReader {
- cursor: wait;
-}
-
-#fileReader > input {
- display: none;
-}
-
-
-#loader {
- display: none;
-}
-
-.loading #loader {
- display: block;
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- height: 100%;
- background-color: rgba(255, 255, 255, 0.5);
-}
-
-#spinner {
- position: absolute;
- width: 100px;
- height: 100px;
- top: 40%;
- left: 50%;
- margin-left: -50px;
- border: 30px solid #000;
- border-top: 30px solid #36E;
- border-radius: 50%;
- animation: spin 1s ease-in-out infinite;
-}
-
-@keyframes spin {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-}
-
-.colorbox {
- width: 10px;
- height: 10px;
- border: 1px black solid;
-}
-
-#stats {
- display: flex;
- height: 250px;
-}
-
-#stats table {
- flex: 1;
- padding-right: 50px;
- max-height: 250px;
- display: inline-block;
-}
-#stats table td {
- cursor: pointer;
-}
-#stats .transitionTable {
- overflow-y: scroll;
-}
-#stats .transitionTable tr {
- max-width: 200px;
-
-}
-#stats .transitionType {
- text-align: right;
- max-width: 380px;
-}
-#stats .transitionType tr td:nth-child(2) {
- text-align: left;
-}
-#stats table thead td {
- border-bottom: 1px black dotted;
-}
-
-#timeline {
- position: relative;
- height: 300px;
- overflow-y: hidden;
- overflow-x: scroll;
- user-select: none;
-}
-#timelineLabel {
- transform: rotate(90deg);
- transform-origin: left bottom 0;
- position: absolute;
- left: 0;
- width: 250px;
- text-align: center;
- font-size: 10px;
- opacity: 0.5;
-}
-#timelineChunks {
- height: 250px;
- position: absolute;
- margin-right: 100px;
-}
-#timelineCanvas {
- height: 250px;
- position: relative;
- overflow: visible;
- pointer-events: none;
-}
-.chunk {
- width: 6px;
- border: 0px white solid;
- border-width: 0 2px 0 2px;
- position: absolute;
- background-size: 100% 100%;
- image-rendering: pixelated;
- bottom: 0px;
-}
-.timestamp {
- height: 250px;
- width: 100px;
- border-left: 1px black dashed;
- padding-left: 4px;
- position: absolute;
- pointer-events: none;
- font-size: 10px;
- opacity: 0.5;
-}
-#timelineOverview {
- width: 100%;
- height: 50px;
- position: relative;
- margin-top: -50px;
- margin-bottom: 10px;
- background-size: 100% 100%;
- border: 1px black solid;
- border-width: 1px 0 1px 0;
- overflow: hidden;
-}
-#timelineOverviewIndicator {
- height: 100%;
- position: absolute;
- box-shadow: 0px 2px 20px -5px black inset;
- top: 0px;
- cursor: ew-resize;
-}
-#timelineOverviewIndicator .leftMask,
-#timelineOverviewIndicator .rightMask {
- background-color: rgba(200, 200, 200, 0.5);
- width: 10000px;
- height: 100%;
- position: absolute;
- top: 0px;
-}
-#timelineOverviewIndicator .leftMask {
- right: 100%;
-}
-#timelineOverviewIndicator .rightMask {
- left: 100%;
-}
-#mapDetails {
- font-family: monospace;
- white-space: pre;
-}
-#transitionView {
- overflow-x: scroll;
- white-space: nowrap;
- min-height: 50px;
- max-height: 200px;
- padding: 50px 0 0 0;
- margin-top: -25px;
- width: 100%;
-}
-.map {
- width: 20px;
- height: 20px;
- display: inline-block;
- border-radius: 50%;
- background-color: black;
- border: 4px solid white;
- font-size: 10px;
- text-align: center;
- line-height: 18px;
- color: white;
- vertical-align: top;
- margin-top: -13px;
- /* raise z-index */
- position: relative;
- z-index: 2;
- cursor: pointer;
-}
-.map.selected {
- border-color: black;
-}
-.transitions {
- display: inline-block;
- margin-left: -15px;
-}
-.transition {
- min-height: 55px;
- margin: 0 0 -2px 2px;
-}
-/* gray out deprecated transitions */
-.deprecated > .transitionEdge,
-.deprecated > .map {
- opacity: 0.5;
-}
-.deprecated > .transition {
- border-color: rgba(0, 0, 0, 0.5);
-}
-/* Show a border for all but the first transition */
-.transition:nth-of-type(2),
-.transition:nth-last-of-type(n+2) {
- border-left: 2px solid;
- margin-left: 0px;
-}
-/* special case for 2 transitions */
-.transition:nth-last-of-type(1) {
- border-left: none;
-}
-/* topmost transitions are not related */
-#transitionView > .transition {
- border-left: none;
-}
-/* topmost transition edge needs initial offset to be aligned */
-#transitionView > .transition > .transitionEdge {
- margin-left: 13px;
-}
-.transitionEdge {
- height: 2px;
- width: 80px;
- display: inline-block;
- margin: 0 0 2px 0;
- background-color: black;
- vertical-align: top;
- padding-left: 15px;
-}
-.transitionLabel {
- color: black;
- transform: rotate(-15deg);
- transform-origin: top left;
- margin-top: -10px;
- font-size: 10px;
- white-space: normal;
- word-break: break-all;
- background-color: rgba(255,255,255,0.5);
-}
-.black{
- background-color: black;
-}
-.red {
- background-color: red;
-}
-.green {
- background-color: green;
-}
-.yellow {
- background-color: yellow;
- color: black;
-}
-.blue {
- background-color: blue;
-}
-.orange {
- background-color: orange;
-}
-.violet {
- background-color: violet;
- color: black;
-}
-.showSubtransitions {
- width: 0;
- height: 0;
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
- border-top: 10px solid black;
- cursor: zoom-in;
- margin: 4px 0 0 4px;
-}
-.showSubtransitions.opened {
- border-top: none;
- border-bottom: 10px solid black;
- cursor: zoom-out;
-}
-#tooltip {
- position: absolute;
- width: 10px;
- height: 10px;
- background-color: red;
- pointer-events: none;
- z-index: 100;
- display: none;
-}
-#searchBarInput {
- width: 200px;
-}
-
-</style>
-<script type="module" src="./map-processor.js"></script>
-<script>
-"use strict"
-// =========================================================================
-const kChunkHeight = 250;
-const kChunkWidth = 10;
-
-class State {
- constructor() {
- this._nofChunks = 400;
- this._map = undefined;
- this._timeline = undefined;
- this._chunks = undefined;
- this._view = new View(this);
- this._navigation = new Navigation(this, this.view);
- }
- get timeline() { return this._timeline }
- set timeline(value) {
- this._timeline = value;
- this.updateChunks();
- this.view.updateTimeline();
- this.view.updateStats();
- }
- get chunks() { return this._chunks }
- get nofChunks() { return this._nofChunks }
- set nofChunks(count) {
- this._nofChunks = count;
- this.updateChunks();
- this.view.updateTimeline();
- }
- get view() { return this._view }
- get navigation() { return this._navigation }
- get map() { return this._map }
- set map(value) {
- this._map = value;
- this._navigation.updateUrl();
- this.view.updateMapDetails();
- this.view.redraw();
- }
- updateChunks() {
- this._chunks = this._timeline.chunks(this._nofChunks);
- }
- get entries() {
- if (!this.map) return {};
- return {
- map: this.map.id,
- time: this.map.time
- }
- }
-}
-
-// =========================================================================
-// DOM Helper
-function $(id) {
- return document.getElementById(id)
-}
-
-function removeAllChildren(node) {
- while (node.lastChild) {
- node.removeChild(node.lastChild);
- }
-}
-
-function selectOption(select, match) {
- let options = select.options;
- for (let i = 0; i < options.length; i++) {
- if (match(i, options[i])) {
- select.selectedIndex = i;
- return;
- }
- }
-}
-
-function div(classes) {
- let 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;
-}
-
-function table(className) {
- let node = document.createElement("table")
- if (className) node.classList.add(className)
- return node;
-}
-
-function td(textOrNode) {
- let node = document.createElement("td");
- if (typeof textOrNode === "object") {
- node.appendChild(textOrNode);
- } else {
- node.innerText = textOrNode;
- }
- return node;
-}
-
-
-function tr() {
- return document.createElement("tr");
-}
-
-define(Array.prototype, "histogram", function(mapFn) {
- let histogram = [];
- for (let i = 0; i < this.length; i++) {
- let value = this[i];
- let index = Math.round(mapFn(value))
- let bucket = histogram[index];
- if (bucket !== undefined) {
- bucket.push(value);
- } else {
- histogram[index] = [value];
- }
- }
- for (let i = 0; i < histogram.length; i++) {
- histogram[i] = histogram[i] || [];
- }
- return histogram;
-});
-
-
-// =========================================================================
-// EventHandlers
-function handleSearchBar(){
- let searchBar = $('searchBarInput');
- let searchBarInput = searchBar.value;
- let selectedMap = V8Map.get(searchBarInput);
- //removeAllChildren($('mapIdList'));
- if(selectedMap){
- let map = selectedMap;
- document.state.map = map;
- searchBar.className = "green";
- } else {
- searchBar.className = "red";
- }
-}
-
-function handleBodyLoad() {
- let upload = $('fileReader');
- upload.onclick = (e) => $("file").click();
- upload.ondragover = (e) => e.preventDefault();
- upload.ondrop = (e) => handleLoadFile(e);
- $('file').onchange = (e) => handleLoadFile(e);
- upload.onkeydown = (e) => {
- if (event.key == "Enter") $("file").click();
- };
- upload.focus();
-
- document.state = new State();
- $("transitionView").addEventListener("mousemove", e => {
- let tooltip = $("tooltip");
- tooltip.style.left = e.pageX + "px";
- tooltip.style.top = e.pageY + "px";
- let map = e.target.map;
- if (map) {
- $("tooltipContents").innerText = map.description;
- }
- });
-
- function handleLoadFile(event) {
- // Used for drop and file change.
- event.preventDefault();
- let host = event.dataTransfer ? event.dataTransfer : event.target;
- let file = host.files[0];
- let reader = new FileReader();
- document.body.className = 'loading';
- reader.onload = function(evt) {
- try {
- handleLoadText(this.result);
- document.body.className = 'success';
- } catch(e) {
- document.body.className = 'failure';
- console.error(e);
- }
- }
- // Defer the reading to allow spinner CSS animation.
- setTimeout(() => reader.readAsText(file), 0);
- }
-}
-
-
-function handleLoadText(text) {
- let mapProcessor = new MapProcessor();
- document.state.timeline = mapProcessor.processString(text);
-}
-
-function handleKeyDown(event) {
- let nav = document.state.navigation;
- switch(event.key) {
- case "ArrowUp":
- event.preventDefault();
- if (event.shiftKey) {
- nav.selectPrevEdge();
- } else {
- nav.moveInChunk(-1);
- }
- return false;
- case "ArrowDown":
- event.preventDefault();
- if (event.shiftKey) {
- nav.selectNextEdge();
- } else {
- nav.moveInChunk(1);
- }
- return false;
- case "ArrowLeft":
- nav.moveInChunks(false);
- break;
- case "ArrowRight":
- nav.moveInChunks(true);
- break;
- case "+":
- nav.increaseTimelineResolution();
- break;
- case "-":
- nav.decreaseTimelineResolution();
- break;
- }
-};
-document.onkeydown = handleKeyDown;
-
-function handleTimelineIndicatorMove(event) {
- if (event.buttons == 0) return;
- let timelineTotalWidth = $("timelineCanvas").offsetWidth;
- let factor = $("timelineOverview").offsetWidth / timelineTotalWidth;
- $("timeline").scrollLeft += event.movementX / factor;
-}
-
-// =========================================================================
-
-Object.defineProperty(Edge.prototype, 'getColor', { value:function() {
- return transitionTypeToColor(this.type);
-}});
-
-class Navigation {
- constructor(state, view) {
- this.state = state;
- this.view = view;
- }
- get map() { return this.state.map }
- set map(value) { this.state.map = value }
- get chunks() { return this.state.chunks }
-
- increaseTimelineResolution() {
- this.state.nofChunks *= 1.5;
- }
-
- decreaseTimelineResolution() {
- this.state.nofChunks /= 1.5;
- }
-
- selectNextEdge() {
- if (!this.map) return;
- if (this.map.children.length != 1) return;
- this.map = this.map.children[0].to;
- }
-
- selectPrevEdge() {
- if (!this.map) return;
- if (!this.map.parent()) return;
- this.map = this.map.parent();
- }
-
- selectDefaultMap() {
- this.map = this.chunks[0].at(0);
- }
- moveInChunks(next) {
- if (!this.map) return this.selectDefaultMap();
- let chunkIndex = this.map.chunkIndex(this.chunks);
- let chunk = this.chunks[chunkIndex];
- let index = chunk.indexOf(this.map);
- if (next) {
- chunk = chunk.next(this.chunks);
- } else {
- chunk = chunk.prev(this.chunks);
- }
- if (!chunk) return;
- index = Math.min(index, chunk.size()-1);
- this.map = chunk.at(index);
- }
-
- moveInChunk(delta) {
- if (!this.map) return this.selectDefaultMap();
- let chunkIndex = this.map.chunkIndex(this.chunks)
- let chunk = this.chunks[chunkIndex];
- let index = chunk.indexOf(this.map) + delta;
- let map;
- if (index < 0) {
- map = chunk.prev(this.chunks).last();
- } else if (index >= chunk.size()) {
- map = chunk.next(this.chunks).first()
- } else {
- map = chunk.at(index);
- }
- this.map = map;
- }
-
- updateUrl() {
- let entries = this.state.entries;
- let params = new URLSearchParams(entries);
- window.history.pushState(entries, "", "?" + params.toString());
- }
-}
-
-class View {
- constructor(state) {
- this.state = state;
- setInterval(this.updateOverviewWindow, 50);
- this.backgroundCanvas = document.createElement("canvas");
- this.transitionView = new TransitionView(state, $("transitionView"));
- this.statsView = new StatsView(state, $("stats"));
- this.isLocked = false;
- }
- get chunks() { return this.state.chunks }
- get timeline() { return this.state.timeline }
- get map() { return this.state.map }
-
- updateStats() {
- this.statsView.update();
- }
-
- updateMapDetails() {
- let details = "";
- if (this.map) {
- details += "ID: " + this.map.id;
- details += "\nSource location: " + this.map.filePosition;
- details += "\n" + this.map.description;
- }
- $("mapDetails").innerText = details;
- this.transitionView.showMap(this.map);
- }
-
- updateTimeline() {
- let chunksNode = $("timelineChunks");
- removeAllChildren(chunksNode);
- 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;
- const timeToPixel = chunks.length * kChunkWidth / duration;
- let addTimestamp = (time, name) => {
- let timeNode = div("timestamp");
- timeNode.innerText = name;
- timeNode.style.left = ((time-start) * 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 = div();
- node.className = "chunk";
- node.style.left = (i * kChunkWidth) + "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);
- chunk.markers.forEach(marker => addTimestamp(marker.time, marker.name));
- }
-
- this.asyncSetTimelineChunkBackground(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.drawOverview();
- this.redraw();
- }
-
- handleChunkMouseMove(event) {
- if (this.isLocked) 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.state.map = map;
- }
-
- handleChunkClick(event) {
- this.isLocked = !this.isLocked;
- }
-
- handleChunkDoubleClick(event) {
- this.isLocked = true;
- let chunk = event.target.chunk;
- if (!chunk) return;
- this.transitionView.showMaps(chunk.getUniqueTransitions());
- }
-
- asyncSetTimelineChunkBackground(backgroundTodo) {
- const kIncrement = 100;
- let start = 0;
- let delay = 1;
- while (start < backgroundTodo.length) {
- let end = Math.min(start+kIncrement, backgroundTodo.length);
- setTimeout((from, to) => {
- for (let i = from; i < to; i++) {
- let [chunk, node] = backgroundTodo[i];
- this.setTimelineChunkBackground(chunk, node);
- }
- }, delay++, start, end);
- start = end;
- }
- }
-
- setTimelineChunkBackground(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.getTransitionBreakdown().forEach(([type, count]) => {
- ctx.fillStyle = transitionTypeToColor(type);
- let height = count / total * kHeight;
- ctx.fillRect(0, y, kWidth, y + height);
- y += height;
- });
- } else {
- chunk.items.forEach(map => {
- ctx.fillStyle = transitionTypeToColor(map.getType());
- 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 + ")";
- }
-
- updateOverviewWindow() {
- let indicator = $("timelineOverviewIndicator");
- let totalIndicatorWidth = $("timelineOverview").offsetWidth;
- let div = $("timeline");
- let timelineTotalWidth = $("timelineCanvas").offsetWidth;
- let factor = $("timelineOverview").offsetWidth / timelineTotalWidth;
- let width = div.offsetWidth * factor;
- let left = div.scrollLeft * factor;
- indicator.style.width = width + "px";
- indicator.style.left = left + "px";
- }
-
- drawOverview() {
- const height = 50;
- const kFactor = 2;
- let canvas = this.backgroundCanvas;
- canvas.height = height;
- canvas.width = window.innerWidth;
- let ctx = canvas.getContext("2d");
-
- let chunks = this.state.timeline.chunkSizes(canvas.width * kFactor);
- let max = chunks.max();
-
- ctx.clearRect(0, 0, canvas.width, height);
- ctx.strokeStyle = "black";
- ctx.fillStyle = "black";
- ctx.beginPath();
- ctx.moveTo(0,height);
- for (let i = 0; i < chunks.length; i++) {
- ctx.lineTo(i/kFactor, height - chunks[i]/max * height);
- }
- ctx.lineTo(chunks.length, height);
- ctx.stroke();
- ctx.closePath();
- ctx.fill();
- let imageData = canvas.toDataURL("image/webp", 0.2);
- $("timelineOverview").style.backgroundImage = "url(" + imageData + ")";
- }
-
- redraw() {
- let canvas= $("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.state.map) return;
- this.drawEdges(ctx);
- }
-
- setMapStyle(map, ctx) {
- ctx.fillStyle = map.edge && map.edge.from ? "black" : "green";
- }
-
- setEdgeStyle(edge, ctx) {
- let color = edge.getColor();
- ctx.strokeStyle = color;
- ctx.fillStyle = color;
- }
-
- markMap(ctx, map) {
- let [x, y] = map.position(this.state.chunks);
- ctx.beginPath();
- this.setMapStyle(map, ctx);
- ctx.arc(x, y, 3, 0, 2 * Math.PI);
- ctx.fill();
- ctx.beginPath();
- ctx.fillStyle = "white";
- ctx.arc(x, y, 2, 0, 2 * Math.PI);
- ctx.fill();
- }
-
- markSelectedMap(ctx, map) {
- let [x, y] = map.position(this.state.chunks);
- ctx.beginPath();
- this.setMapStyle(map, ctx);
- ctx.arc(x, y, 6, 0, 2 * Math.PI);
- 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.state.map;
- while (current && nofEdges < kMaxOutgoingEdges) {
- nofEdges += current.children.length;
- stack.push(current);
- current = current.parent();
- }
- ctx.save();
- this.drawOutgoingEdges(ctx, this.state.map, 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.state.map);
- }
-
- 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.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 = "#666";
-
- 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 TransitionView {
- constructor(state, node) {
- this.state = state;
- this.container = node;
- this.currentNode = node;
- this.currentMap = undefined;
- }
-
- selectMap(map) {
- this.currentMap = map;
- this.state.map = map;
- }
-
- showMap(map) {
- if (this.currentMap === map) return;
- this.currentMap = map;
- this._showMaps([map]);
- }
-
- showMaps(list, name) {
- this.state.view.isLocked = true;
- this._showMaps(list);
- }
-
- _showMaps(list, name) {
- // Hide the container to avoid any layouts.
- this.container.style.display = "none";
- removeAllChildren(this.container);
- list.forEach(map => this.addMapAndParentTransitions(map));
- this.container.style.display = ""
- }
-
- addMapAndParentTransitions(map) {
- if (map === void 0) return;
- this.currentNode = this.container;
- 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);
- }
- }
-
- addMapNode(map) {
- let node = div("map");
- if (map.edge) node.classList.add(map.edge.getColor());
- node.map = map;
- node.addEventListener("click", () => this.selectMap(map));
- if (map.children.length > 1) {
- node.innerText = map.children.length;
- let showSubtree = 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;
- }
-
- 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", map.edge.getColor()];
- let edge = div(classes);
- let labelNode = div("transitionLabel");
- labelNode.innerText = map.edge.toString();
- edge.appendChild(labelNode);
- return edge;
- }
-
- addTransitionTo(map) {
- // transition[ transitions[ transition[...], transition[...], ...]];
-
- let transition = 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 = div("transitions");
- transition.appendChild(subtree);
-
- this.currentNode.appendChild(transition);
- this.currentNode = subtree;
-
- return mapNode;
-
- }
-
- 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]);
- }
- }
- }
-}
-
-class StatsView {
- constructor(state, node) {
- this.state = state;
- this.node = node;
- }
- get timeline() { return this.state.timeline }
- get transitionView() { return this.state.view.transitionView; }
- update() {
- removeAllChildren(this.node);
- this.updateGeneralStats();
- this.updateNamedTransitionsStats();
- }
- updateGeneralStats() {
- let pairs = [
- ["Total", null, e => true],
- ["Transitions", 'black', 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()],
- ];
-
- let text = "";
- let tableNode = table("transitionType");
- tableNode.innerHTML = "<thead><tr><td>Color</td><td>Type</td><td>Count</td><td>Percent</td></tr></thead>";
- let name, filter;
- let total = this.timeline.size();
- pairs.forEach(([name, color, filter]) => {
- let row = tr();
- if (color !== null) {
- row.appendChild(td(div(['colorbox', color])));
- } else {
- row.appendChild(td(""));
- }
- row.onclick = (e) => {
- // lazily compute the stats
- let node = e.target.parentNode;
- if (node.maps == undefined) {
- node.maps = this.timeline.filterUniqueTransitions(filter);
- }
- this.transitionView.showMaps(node.maps);
- }
- row.appendChild(td(name));
- let count = this.timeline.count(filter);
- row.appendChild(td(count));
- let percent = Math.round(count / total * 1000) / 10;
- row.appendChild(td(percent.toFixed(1) + "%"));
- tableNode.appendChild(row);
- });
- this.node.appendChild(tableNode);
- };
- updateNamedTransitionsStats() {
- let tableNode = table("transitionTable");
- let nameMapPairs = Array.from(this.timeline.transitions.entries());
- tableNode.innerHTML = "<thead><tr><td>Propery Name</td><td>#</td></tr></thead>";
- nameMapPairs
- .sort((a,b) => b[1].length - a[1].length)
- .forEach(([name, maps]) => {
- let row = tr();
- row.maps = maps;
- row.addEventListener("click",
- e => this.transitionView.showMaps(
- e.target.parentNode.maps.map(map => map.to)));
- row.appendChild(td(name));
- row.appendChild(td(maps.length));
- tableNode.appendChild(row);
- });
- this.node.appendChild(tableNode);
- }
-}
-
-// =========================================================================
-
-function transitionTypeToColor(type) {
- switch(type) {
- case "new": return "green";
- case "Normalize": return "violet";
- case "SlowToFast": return "orange";
- case "InitialMap": return "yellow";
- case "Transition": return "black";
- case "ReplaceDescriptors": return "red";
- }
- return "black";
-}
-
-// ShadowDom elements =========================================================
-
-</script>
-</head>
-<body onload="handleBodyLoad(event)" onkeypress="handleKeyDown(event)">
- <h1>V8 Map Explorer</h1>
- <section>
- <div id="fileReader" tabindex=1 >
- <span id="label">
- Drag and drop a v8.log file into this area, or click to choose from disk.
- </span>
- <input id="file" type="file" name="files">
- </div>
- <div id="loader">
- <div id="spinner"></div>
- </div>
- </section>
-
- <div id="content">
- <h2>Stats</h2>
- <section id="stats"></section>
-
- <h2>Timeline</h2>
- <div id="timeline">
- <div id="timelineLabel">Frequency</div>
- <div id="timelineChunks"></div>
- <canvas id="timelineCanvas"></canvas>
- </div>
- <div id="timelineOverview"
- onmousemove="handleTimelineIndicatorMove(event)" >
- <div id="timelineOverviewIndicator">
- <div class="leftMask"></div>
- <div class="rightMask"></div>
- </div>
- </div>
-
- <h2>Transitions</h2>
- <section id="transitionView"></section>
- <br/>
-
-
- <h2>Search Map by Address</h2>
- <section id="searchBar"></section>
- <input type="search" id="searchBarInput" placeholder="Search maps by address..">
- <button onclick="handleSearchBar()">Search</button>
- <ul id="mapIdList" title="Map Id List">
- </ul>
-
-
- <h2>Selected Map</h2>
- <section id="mapDetails"></section>
- </div>
-
- <section>
- <h2>Instructions</h2>
- <p>Visualize Map trees that have been gathered using <code>path/to/d8 $FILE --trace-maps</code>.</p>
- <p>You can inspect the transition tree in DevTools by looking at <code>document.state.timeline.values</code>.
- <h3>Keyboard Shortcuts</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>
- </section>
-
- <div id="tooltip">
- <div id="tooltipContents"></div>
- </div>
-</body>
-</html>
diff --git a/chromium/v8/tools/map-processor.mjs b/chromium/v8/tools/map-processor.mjs
deleted file mode 100644
index 7c290abb8d0..00000000000
--- a/chromium/v8/tools/map-processor.mjs
+++ /dev/null
@@ -1,783 +0,0 @@
-// Copyright 2017 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 { LogReader, parseString, parseVarArgs } from "./logreader.mjs";
-import { BaseArgumentsProcessor } from "./arguments.mjs";
-import { Profile } from "./profile.mjs";
-
-// ===========================================================================
-function define(prototype, name, fn) {
- Object.defineProperty(prototype, name, {value:fn, enumerable:false});
-}
-
-define(Array.prototype, "max", function(fn) {
- if (this.length === 0) return undefined;
- if (fn === undefined) fn = (each) => each;
- let max = fn(this[0]);
- for (let i = 1; i < this.length; i++) {
- max = Math.max(max, fn(this[i]));
- }
- return max;
-})
-define(Array.prototype, "first", function() { return this[0] });
-define(Array.prototype, "last", function() { return this[this.length - 1] });
-
-
-/**
- * A thin wrapper around shell's 'read' function showing a file name on error.
- */
-export function readFile(fileName) {
- try {
- return read(fileName);
- } catch (e) {
- console.log(fileName + ': ' + (e.message || e));
- throw e;
- }
-}
-// ===========================================================================
-
-export class MapProcessor extends LogReader {
- constructor() {
- super();
- this.dispatchTable_ = {
- __proto__:null,
- 'code-creation': {
- parsers: [parseString, parseInt, parseInt, parseInt, parseInt,
- parseString, parseVarArgs],
- processor: this.processCodeCreation
- },
- 'code-move': {
- parsers: [parseInt, parseInt],
- 'sfi-move': {
- parsers: [parseInt, parseInt],
- processor: this.processCodeMove
- },
- 'code-delete': {
- parsers: [parseInt],
- processor: this.processCodeDelete
- },
- processor: this.processFunctionMove
- },
- 'map-create': {
- parsers: [parseInt, parseString],
- processor: this.processMapCreate
- },
- 'map': {
- parsers: [parseString, parseInt, parseString, parseString, parseInt, parseInt,
- parseString, parseString, parseString
- ],
- processor: this.processMap
- },
- 'map-details': {
- parsers: [parseInt, parseString, parseString],
- processor: this.processMapDetails
- }
- };
- this.profile_ = new Profile();
- this.timeline_ = new Timeline();
- this.formatPCRegexp_ = /(.*):[0-9]+:[0-9]+$/;
- }
-
- printError(str) {
- console.error(str);
- throw str
- }
-
- processString(string) {
- let end = string.length;
- let current = 0;
- let next = 0;
- let line;
- let i = 0;
- let entry;
- try {
- while (current < end) {
- next = string.indexOf("\n", current);
- if (next === -1) break;
- i++;
- line = string.substring(current, next);
- current = next + 1;
- this.processLogLine(line);
- }
- } catch(e) {
- console.error("Error occurred during parsing, trying to continue: " + e);
- }
- return this.finalize();
- }
-
- processLogFile(fileName) {
- this.collectEntries = true
- this.lastLogFileName_ = fileName;
- let i = 1;
- let line;
- try {
- while (line = readline()) {
- this.processLogLine(line);
- i++;
- }
- } catch(e) {
- console.error("Error occurred during parsing line " + i + ", trying to continue: " + e);
- }
- return this.finalize();
- }
-
- finalize() {
- // TODO(cbruni): print stats;
- this.timeline_.finalize();
- return this.timeline_;
- }
-
- addEntry(entry) {
- this.entries.push(entry);
- }
-
- /**
- * 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;
- }
- throw new Error("unknown code state: " + s);
- }
-
- processCodeCreation(
- type, kind, timestamp, start, size, name, maybe_func) {
- if (maybe_func.length) {
- let funcAddr = parseInt(maybe_func[0]);
- let state = this.parseState(maybe_func[1]);
- this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
- } else {
- this.profile_.addCode(type, name, timestamp, start, size);
- }
- }
-
- processCodeMove(from, to) {
- this.profile_.moveCode(from, to);
- }
-
- processCodeDelete(start) {
- this.profile_.deleteCode(start);
- }
-
- processFunctionMove(from, to) {
- this.profile_.moveFunc(from, to);
- }
-
- 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;
- }
-
- processMap(type, time, from, to, pc, line, column, reason, name) {
- let time_ = parseInt(time);
- if (type === "Deprecate") return this.deprecateMap(type, time_, from);
- let from_ = this.getExistingMap(from, time_);
- let to_ = this.getExistingMap(to, time_);
- let edge = new Edge(type, name, reason, time, from_, to_);
- to_.filePosition = this.formatPC(pc, line, column);
- edge.finishSetup();
- }
-
- deprecateMap(type, time, id) {
- this.getExistingMap(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.createMap(id, time);
- }
-
- processMapDetails(time, id, string) {
- //TODO(cbruni): fix initial map logging.
- let map = this.getExistingMap(id, time);
- map.description = string;
- }
-
- createMap(id, time) {
- let map = new V8Map(id, time);
- this.timeline_.push(map);
- return map;
- }
-
- getExistingMap(id, time) {
- if (id === "0x000000000000") return undefined;
- let map = V8Map.get(id, time);
- if (map === undefined) {
- console.error("No map details provided: id=" + id);
- // Manually patch in a map to continue running.
- return this.createMap(id, time);
- };
- return map;
- }
-}
-
-// ===========================================================================
-
-class V8Map {
- constructor(id, time = -1) {
- if (!id) throw "Invalid ID";
- this.id = id;
- this.time = time;
- if (!(time > 0)) throw "Invalid time";
- this.description = "";
- this.edge = void 0;
- this.children = [];
- this.depth = 0;
- this._isDeprecated = false;
- this.deprecationTargets = null;
- V8Map.set(id, this);
- this.leftId = 0;
- this.rightId = 0;
- this.filePosition = "";
- }
-
- finalizeRootMap(id) {
- let stack = [this];
- while (stack.length > 0) {
- let current = stack.pop();
- if (current.leftId !== 0) {
- console.error("Skipping potential parent loop between maps:", current)
- continue;
- }
- current.finalize(id)
- id += 1;
- current.children.forEach(edge => stack.push(edge.to))
- // TODO implement rightId
- }
- return id;
- }
-
- finalize(id) {
- // Initialize preorder tree traversal Ids for fast subtree inclusion checks
- if (id <= 0) throw "invalid id";
- let currentId = id;
- this.leftId = currentId
- }
-
-
- parent() {
- if (this.edge === void 0) return void 0;
- return this.edge.from;
- }
-
- isDeprecated() {
- return this._isDeprecated;
- }
-
- deprecate() {
- this._isDeprecated = true;
- }
-
- isRoot() {
- return this.edge === void 0 || this.edge.from === void 0;
- }
-
- contains(map) {
- return this.leftId < map.leftId && map.rightId < this.rightId;
- }
-
- addEdge(edge) {
- this.children.push(edge);
- }
-
- chunkIndex(chunks) {
- // Did anybody say O(n)?
- for (let i = 0; i < chunks.length; i++) {
- let chunk = chunks[i];
- if (chunk.isEmpty()) continue;
- if (chunk.last().time < this.time) continue;
- return i;
- }
- return -1;
- }
-
- position(chunks) {
- let index = this.chunkIndex(chunks);
- let xFrom = (index + 0.5) * kChunkWidth;
- let yFrom = kChunkHeight - chunks[index].yOffset(this);
- return [xFrom, yFrom];
- }
-
- transitions() {
- let transitions = Object.create(null);
- let current = this;
- while (current) {
- let edge = current.edge;
- if (edge && edge.isTransition()) {
- transitions[edge.name] = edge;
- }
- current = current.parent()
- }
- return transitions;
- }
-
- getType() {
- return this.edge === void 0 ? "new" : this.edge.type;
- }
-
- isBootstrapped() {
- return this.edge === void 0;
- }
-
- getParents() {
- let parents = [];
- let current = this.parent();
- while (current) {
- parents.push(current);
- current = current.parent();
- }
- return parents;
- }
-
-
- static get(id, time = undefined) {
- let maps = this.cache.get(id);
- if(maps){
- for (let i = 0; i < maps.length; i++) {
- //TODO: Implement time based map search
- if(maps[i].time === time){
- return maps[i];
- }
- }
- // default return the latest
- return maps[maps.length-1];
- }
- }
-
- static set(id, map) {
- if(this.cache.has(id)){
- this.cache.get(id).push(map);
- } else {
- this.cache.set(id, [map]);
- }
- }
-}
-
-V8Map.cache = new Map();
-
-
-
-// ===========================================================================
-class Edge {
- constructor(type, name, reason, time, from, to) {
- this.type = type;
- this.name = name;
- this.reason = reason;
- this.time = time;
- this.from = from;
- this.to = to;
- }
-
- finishSetup() {
- let from = this.from
- if (from) from.addEdge(this);
- let to = this.to;
- 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.error("invalid time order");
- }
- let newDepth = from.depth + 1;
- if (to.depth > 0 && to.depth != newDepth) {
- console.error("Depth has already been initialized");
- }
- to.depth = newDepth;
- }
-
- chunkIndex(chunks) {
- // Did anybody say O(n)?
- for (let i = 0; i < chunks.length; i++) {
- let chunk = chunks[i];
- if (chunk.isEmpty()) continue;
- if (chunk.last().time < this.time) continue;
- return i;
- }
- return -1;
- }
-
- parentEdge() {
- if (!this.from) return undefined;
- return this.from.edge;
- }
-
- chainLength() {
- let length = 0;
- let prev = this;
- while (prev) {
- prev = this.parent;
- length++;
- }
- return length;
- }
-
- isTransition() {
- return this.type === "Transition"
- }
-
- isFastToSlow() {
- return this.type === "Normalize"
- }
-
- isSlowToFast() {
- return this.type === "SlowToFast"
- }
-
- isInitial() {
- return this.type === "InitialMap"
- }
-
- isBootstrapped() {
- return this.type === "new"
- }
-
- isReplaceDescriptors() {
- return this.type === "ReplaceDescriptors"
- }
-
- isCopyAsPrototype() {
- return this.reason === "CopyAsPrototype"
- }
-
- isOptimizeAsPrototype() {
- return this.reason === "OptimizeAsPrototype"
- }
-
- symbol() {
- if (this.isTransition()) return "+";
- if (this.isFastToSlow()) return "⊡";
- if (this.isSlowToFast()) return "⊛";
- if (this.isReplaceDescriptors()) {
- if (this.name) return "+";
- return "∥";
- }
- return "";
- }
-
- toString() {
- let s = this.symbol();
- if (this.isTransition()) return s + this.name;
- if (this.isFastToSlow()) return s + this.reason;
- if (this.isCopyAsPrototype()) return s + "Copy as Prototype";
- if (this.isOptimizeAsPrototype()) {
- return s + "Optimize as Prototype";
- }
- if (this.isReplaceDescriptors() && this.name) {
- return this.type + " " + this.symbol() + this.name;
- }
- return this.type + " " + (this.reason ? this.reason : "") + " " +
- (this.name ? this.name : "")
- }
-}
-
-
-// ===========================================================================
-class Marker {
- constructor(time, name) {
- this.time = parseInt(time);
- this.name = name;
- }
-}
-
-// ===========================================================================
-class Timeline {
- constructor() {
- this.values = [];
- this.transitions = new Map();
- this.markers = [];
- this.startTime = 0;
- this.endTime = 0;
- }
-
- push(map) {
- let time = map.time;
- if (!this.isEmpty() && this.last().time > time) {
- // Invalid insertion order, might happen without --single-process,
- // finding insertion point.
- let insertionPoint = this.find(time);
- this.values.splice(insertionPoint, map);
- } else {
- this.values.push(map);
- }
- if (time > 0) {
- this.endTime = Math.max(this.endTime, time);
- if (this.startTime === 0) {
- this.startTime = time;
- } else {
- this.startTime = Math.min(this.startTime, time);
- }
- }
- }
-
- addMarker(time, message) {
- this.markers.push(new Marker(time, message));
- }
-
- finalize() {
- let id = 0;
- this.forEach(map => {
- if (map.isRoot()) id = map.finalizeRootMap(id + 1);
- if (map.edge && map.edge.name) {
- let edge = map.edge;
- let list = this.transitions.get(edge.name);
- if (list === undefined) {
- this.transitions.set(edge.name, [edge]);
- } else {
- list.push(edge);
- }
- }
- });
- this.markers.sort((a, b) => b.time - a.time);
- }
-
- at(index) {
- return this.values[index]
- }
-
- isEmpty() {
- return this.size() === 0
- }
-
- size() {
- return this.values.length
- }
-
- first() {
- return this.values.first()
- }
-
- last() {
- return this.values.last()
- }
-
- duration() {
- return this.last().time - this.first().time
- }
-
- forEachChunkSize(count, fn) {
- 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;
- fn(index, nextIndex, currentTime, nextTime);
- index = nextIndex
- currentTime = nextTime;
- }
- }
-
- chunkSizes(count) {
- let chunks = [];
- this.forEachChunkSize(count, (start, end) => chunks.push(end - start));
- return chunks;
- }
-
- chunks(count) {
- let chunks = [];
- let emptyMarkers = [];
- this.forEachChunkSize(count, (start, end, startTime, endTime) => {
- let items = this.values.slice(start, end);
- let markers = this.markersAt(startTime, endTime);
- chunks.push(new Chunk(chunks.length, startTime, endTime, items, markers));
- });
- 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);
- }
-
- find(time, offset = 0) {
- return this.basicFind(this.values, each => each.time - time, offset);
- }
-
- markersAt(startTime, endTime) {
- let start = this.basicFind(this.markers, each => each.time - startTime);
- let end = this.basicFind(this.markers, each => each.time - endTime, start);
- return this.markers.slice(start, end);
- }
-
- basicFind(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;
- } else {
- min = mid + 1;
- }
- }
- return min;
- }
-
- count(filter) {
- return this.values.reduce((sum, each) => {
- return sum + (filter(each) === true ? 1 : 0);
- }, 0);
- }
-
- filter(predicate) {
- return this.values.filter(predicate);
- }
-
- filterUniqueTransitions(filter) {
- // Returns a list of Maps whose parent is not in the list.
- return this.values.filter(map => {
- if (filter(map) === false) return false;
- let parent = map.parent();
- if (parent === undefined) return true;
- return filter(parent) === false;
- });
- }
-
- depthHistogram() {
- return this.values.histogram(each => each.depth);
- }
-
- fanOutHistogram() {
- return this.values.histogram(each => each.children.length);
- }
-
- forEach(fn) {
- return this.values.forEach(fn)
- }
-}
-
-
-// ===========================================================================
-class Chunk {
- constructor(index, start, end, items, markers) {
- this.index = index;
- this.start = start;
- this.end = end;
- this.items = items;
- this.markers = markers
- this.height = 0;
- }
-
- isEmpty() {
- return this.items.length === 0;
- }
-
- last() {
- return this.at(this.size() - 1);
- }
-
- first() {
- return this.at(0);
- }
-
- at(index) {
- return this.items[index];
- }
-
- size() {
- return this.items.length;
- }
-
- yOffset(map) {
- // items[0] == oldest map, displayed at the top of the chunk
- // items[n-1] == youngest map, displayed at the bottom of the chunk
- return (1 - (this.indexOf(map) + 0.5) / this.size()) * this.height;
- }
-
- indexOf(map) {
- return this.items.indexOf(map);
- }
-
- has(map) {
- if (this.isEmpty()) return false;
- return this.first().time <= map.time && map.time <= this.last().time;
- }
-
- next(chunks) {
- return this.findChunk(chunks, 1);
- }
-
- prev(chunks) {
- return this.findChunk(chunks, -1);
- }
-
- findChunk(chunks, delta) {
- let i = this.index + delta;
- let chunk = chunks[i];
- while (chunk && chunk.size() === 0) {
- i += delta;
- chunk = chunks[i]
- }
- return chunk;
- }
-
- getTransitionBreakdown() {
- return BreakDown(this.items, map => map.getType())
- }
-
- getUniqueTransitions() {
- // Filter out all the maps that have parents within the same chunk.
- return this.items.filter(map => !map.parent() || !this.has(map.parent()));
- }
-}
-
-
-// ===========================================================================
-function BreakDown(list, map_fn) {
- if (map_fn === void 0) {
- map_fn = each => each;
- }
- let breakdown = {__proto__:null};
- list.forEach(each=> {
- let type = map_fn(each);
- let v = breakdown[type];
- breakdown[type] = (v | 0) + 1
- });
- return Object.entries(breakdown)
- .sort((a,b) => a[1] - b[1]);
-}
-
-
-// ===========================================================================
-export class ArgumentsProcessor extends BaseArgumentsProcessor {
- getArgsDispatch() {
- return {
- '--range': ['range', 'auto,auto',
- 'Specify the range limit as [start],[end]'
- ],
- '--source-map': ['sourceMap', null,
- 'Specify the source map that should be used for output'
- ]
- };
- }
-
- getDefaultResults() {
- return {
- logFileName: 'v8.log',
- range: 'auto,auto',
- };
- }
-}
diff --git a/chromium/v8/tools/mb/mb_unittest.py b/chromium/v8/tools/mb/mb_unittest.py
index 3a0b89b29dd..765cacbc580 100755
--- a/chromium/v8/tools/mb/mb_unittest.py
+++ b/chromium/v8/tools/mb/mb_unittest.py
@@ -337,9 +337,11 @@ class UnitTest(unittest.TestCase):
self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_bot',
'//out/Debug'],
mbw=mbw, ret=0)
- self.assertEqual(
- mbw.files['/fake_src/out/Debug/args.gn'],
- 'import("//build/args/bots/fake_master/fake_args_bot.gn")\n')
+ # TODO(almuthanna): disable test temporarily to
+ # solve this issue https://crbug.com/v8/11102
+ # self.assertEqual(
+ # mbw.files['/fake_src/out/Debug/args.gn'],
+ # 'import("//build/args/bots/fake_master/fake_args_bot.gn")\n')
def test_gen_args_file_mixins(self):
mbw = self.fake_mbw()
diff --git a/chromium/v8/tools/parse-processor-driver.mjs b/chromium/v8/tools/parse-processor-driver.mjs
index 9c72d744ad0..bec5b782eac 100644
--- a/chromium/v8/tools/parse-processor-driver.mjs
+++ b/chromium/v8/tools/parse-processor-driver.mjs
@@ -8,7 +8,7 @@ import {
} from "./parse-processor.mjs";
function processArguments(args) {
- var processor = new ArgumentsProcessor(args);
+ const processor = new ArgumentsProcessor(args);
if (processor.parse()) {
return processor.result();
} else {
@@ -22,17 +22,17 @@ function initSourceMapSupport() {
// Overwrite the load function to load scripts synchronously.
SourceMap.load = function(sourceMapURL) {
- var content = readFile(sourceMapURL);
- var sourceMapObject = (JSON.parse(content));
+ const content = readFile(sourceMapURL);
+ const sourceMapObject = (JSON.parse(content));
return new SourceMap(sourceMapURL, sourceMapObject);
};
}
-var params = processArguments(arguments);
-var sourceMap = null;
+const params = processArguments(arguments);
+let sourceMap = null;
if (params.sourceMap) {
initSourceMapSupport();
sourceMap = SourceMap.load(params.sourceMap);
}
-var parseProcessor = new ParseProcessor();
+const parseProcessor = new ParseProcessor();
parseProcessor.processLogFile(params.logFileName);
diff --git a/chromium/v8/tools/parse-processor.mjs b/chromium/v8/tools/parse-processor.mjs
index ed010d55a4e..f78c4c0261c 100644
--- a/chromium/v8/tools/parse-processor.mjs
+++ b/chromium/v8/tools/parse-processor.mjs
@@ -1,8 +1,6 @@
// Copyright 2017 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.
-"use strict";
-
import { LogReader, parseString } from "./logreader.mjs";
import { BaseArgumentsProcessor } from "./arguments.mjs";
@@ -339,7 +337,7 @@ class Script extends CompilationUnit {
calculateMetrics(printSummary) {
let log = (str) => this.summary += str + '\n';
- log("SCRIPT: " + this.id);
+ log(`SCRIPT: ${this.id}`);
let all = this.funktions;
if (all.length === 0) return;
@@ -354,7 +352,7 @@ class Script extends CompilationUnit {
let value = (funktions.length + "").padStart(6) +
(nofPercent + "%").padStart(5) +
BYTES(ownBytes, this.bytesTotal).padStart(10);
- log((" - " + name).padEnd(20) + value);
+ log((` - ${name}`).padEnd(20) + value);
this.metrics.set(name + "-bytes", ownBytes);
this.metrics.set(name + "-count", funktions.length);
this.metrics.set(name + "-count-percent", nofPercent);
@@ -362,7 +360,7 @@ class Script extends CompilationUnit {
Math.round(ownBytes / this.bytesTotal * 100));
};
- log(" - file: " + this.file);
+ log(` - file: ${this.file}`);
log(' - details: ' +
'isEval=' + this.isEval + ' deserialized=' + this.isDeserialized +
' streamed=' + this.isStreamingCompiled);
@@ -409,7 +407,7 @@ class Script extends CompilationUnit {
// [start+delta*2, acc(metric0, start, start+delta*2), ...],
// ...
// ]
- if (end <= start) throw 'Invalid ranges [' + start + ',' + end + ']';
+ if (end <= start) throw `Invalid ranges [${start},${end}]`;
const timespan = end - start;
const kSteps = Math.ceil(timespan / delta);
// To reduce the time spent iterating over the funktions of this script
@@ -607,8 +605,8 @@ class ExecutionCost {
}
toString() {
- return (' - ' + this.prefix + '-time:').padEnd(24) +
- (" executed=" + formatNumber(this.executedCost) + 'ms').padEnd(20) +
+ return (` - ${this.prefix}-time:`).padEnd(24) +
+ (` executed=${formatNumber(this.executedCost)}ms`).padEnd(20) +
" non-executed=" + formatNumber(this.nonExecutedCost) + 'ms';
}
@@ -623,11 +621,11 @@ class ExecutionCost {
class Funktion extends CompilationUnit {
constructor(name, start, end, script) {
super();
- if (start < 0) throw "invalid start position: " + start;
+ if (start < 0) throw `invalid start position: ${start}`;
if (script.isEval) {
if (end < start) throw 'invalid start end positions';
} else {
- if (end <= 0) throw 'invalid end position: ' + end;
+ if (end <= 0) throw `invalid end position: ${end}`;
if (end <= start) throw 'invalid start end positions';
}
@@ -722,7 +720,7 @@ class Funktion extends CompilationUnit {
}
toString(details = true) {
- let result = 'function' + (this.name ? ' ' + this.name : '') +
+ let result = `function${this.name ? ` ${this.name}` : ''}` +
`() range=${this.start}-${this.end}`;
if (details) result += ` script=${this.script ? this.script.id : 'X'}`;
return result;
@@ -841,7 +839,7 @@ export class ParseProcessor extends LogReader {
processLogFile(fileName) {
this.collectEntries = true
this.lastLogFileName_ = fileName;
- var line;
+ let line;
while (line = readline()) {
this.processLogLine(line);
}
@@ -886,7 +884,7 @@ export class ParseProcessor extends LogReader {
functionName) {
let handlerFn = this.functionEventDispatchTable_[eventName];
if (handlerFn === undefined) {
- console.error('Couldn\'t find handler for function event:' + eventName);
+ console.error(`Couldn't find handler for function event:${eventName}`);
}
handlerFn(
scriptId, startPosition, endPosition, duration, timestamp,
@@ -965,7 +963,7 @@ export class ParseProcessor extends LogReader {
script.preparseTimestamp = toTimestamp(timestamp);
return;
default:
- console.error('Unhandled script event: ' + eventName);
+ console.error(`Unhandled script event: ${eventName}`);
}
}
diff --git a/chromium/v8/tools/profile.mjs b/chromium/v8/tools/profile.mjs
index 50864dce0f9..b2e953f2472 100644
--- a/chromium/v8/tools/profile.mjs
+++ b/chromium/v8/tools/profile.mjs
@@ -25,7 +25,7 @@
// (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 { CodeMap } from "./codemap.mjs";
+import { CodeMap, CodeEntry } from "./codemap.mjs";
import { ConsArray } from "./consarray.mjs";
// TODO: move to separate modules
@@ -42,7 +42,6 @@ export class SourcePosition {
}
export class Script {
-
constructor(id, name, source) {
this.id = id;
this.name = name;
@@ -56,13 +55,13 @@ export class Script {
let sourcePosition = this.lineToColumn.get(line)?.get(column);
if (sourcePosition === undefined) {
sourcePosition = new SourcePosition(this, line, column, )
- this.#addSourcePosition(line, column, sourcePosition);
+ this._addSourcePosition(line, column, sourcePosition);
}
sourcePosition.addEntry(entry);
return sourcePosition;
}
- #addSourcePosition(line, column, sourcePosition) {
+ _addSourcePosition(line, column, sourcePosition) {
let columnToSourcePosition;
if (this.lineToColumn.has(line)) {
columnToSourcePosition = this.lineToColumn.get(line);
@@ -81,455 +80,424 @@ export class Script {
*
* @constructor
*/
-export function Profile() {
- this.codeMap_ = new CodeMap();
- this.topDownTree_ = new CallTree();
- this.bottomUpTree_ = new CallTree();
- this.c_entries_ = {};
- this.ticks_ = [];
- this.scripts_ = [];
- this.urlToScript_ = new Map();
-};
-
-
-/**
- * Returns whether a function with the specified name must be skipped.
- * Should be overriden by subclasses.
- *
- * @param {string} name Function name.
- */
-Profile.prototype.skipThisFunction = function (name) {
- return false;
-};
-
-
-/**
- * Enum for profiler operations that involve looking up existing
- * code entries.
- *
- * @enum {number}
- */
-Profile.Operation = {
- MOVE: 0,
- DELETE: 1,
- TICK: 2
-};
-
-
-/**
- * Enum for code state regarding its dynamic optimization.
- *
- * @enum {number}
- */
-Profile.CodeState = {
- COMPILED: 0,
- OPTIMIZABLE: 1,
- OPTIMIZED: 2
-};
-
-
-/**
- * Called whenever the specified operation has failed finding a function
- * containing the specified address. Should be overriden by subclasses.
- * See the Profile.Operation enum for the list of
- * possible operations.
- *
- * @param {number} operation Operation.
- * @param {number} addr Address of the unknown code.
- * @param {number} opt_stackPos If an unknown address is encountered
- * during stack strace processing, specifies a position of the frame
- * containing the address.
- */
-Profile.prototype.handleUnknownCode = function (
- operation, addr, opt_stackPos) {
-};
+export class Profile {
+ codeMap_ = new CodeMap();
+ topDownTree_ = new CallTree();
+ bottomUpTree_ = new CallTree();
+ c_entries_ = {};
+ ticks_ = [];
+ scripts_ = [];
+ urlToScript_ = new Map();
+
+ /**
+ * Returns whether a function with the specified name must be skipped.
+ * Should be overriden by subclasses.
+ *
+ * @param {string} name Function name.
+ */
+ skipThisFunction(name) {
+ return false;
+ }
+ /**
+ * Enum for profiler operations that involve looking up existing
+ * code entries.
+ *
+ * @enum {number}
+ */
+ static Operation = {
+ MOVE: 0,
+ DELETE: 1,
+ TICK: 2
+ }
-/**
- * Registers a library.
- *
- * @param {string} name Code entry name.
- * @param {number} startAddr Starting address.
- * @param {number} endAddr Ending address.
- */
-Profile.prototype.addLibrary = function (
- name, startAddr, endAddr) {
- var entry = new CodeMap.CodeEntry(
- endAddr - startAddr, name, 'SHARED_LIB');
- this.codeMap_.addLibrary(startAddr, entry);
- return entry;
-};
+ /**
+ * Enum for code state regarding its dynamic optimization.
+ *
+ * @enum {number}
+ */
+ static CodeState = {
+ COMPILED: 0,
+ OPTIMIZABLE: 1,
+ OPTIMIZED: 2
+ }
+ /**
+ * Called whenever the specified operation has failed finding a function
+ * containing the specified address. Should be overriden by subclasses.
+ * See the Profile.Operation enum for the list of
+ * possible operations.
+ *
+ * @param {number} operation Operation.
+ * @param {number} addr Address of the unknown code.
+ * @param {number} opt_stackPos If an unknown address is encountered
+ * during stack strace processing, specifies a position of the frame
+ * containing the address.
+ */
+ handleUnknownCode(operation, addr, opt_stackPos) {}
+
+ /**
+ * Registers a library.
+ *
+ * @param {string} name Code entry name.
+ * @param {number} startAddr Starting address.
+ * @param {number} endAddr Ending address.
+ */
+ addLibrary(name, startAddr, endAddr) {
+ const entry = new CodeEntry(endAddr - startAddr, name, 'SHARED_LIB');
+ this.codeMap_.addLibrary(startAddr, entry);
+ return entry;
+ }
-/**
- * Registers statically compiled code entry.
- *
- * @param {string} name Code entry name.
- * @param {number} startAddr Starting address.
- * @param {number} endAddr Ending address.
- */
-Profile.prototype.addStaticCode = function (
- name, startAddr, endAddr) {
- var entry = new CodeMap.CodeEntry(
- endAddr - startAddr, name, 'CPP');
- this.codeMap_.addStaticCode(startAddr, entry);
- return entry;
-};
+ /**
+ * Registers statically compiled code entry.
+ *
+ * @param {string} name Code entry name.
+ * @param {number} startAddr Starting address.
+ * @param {number} endAddr Ending address.
+ */
+ addStaticCode(name, startAddr, endAddr) {
+ const entry = new CodeEntry(endAddr - startAddr, name, 'CPP');
+ this.codeMap_.addStaticCode(startAddr, entry);
+ return entry;
+ }
+ /**
+ * Registers dynamic (JIT-compiled) code entry.
+ *
+ * @param {string} type Code entry type.
+ * @param {string} name Code entry name.
+ * @param {number} start Starting address.
+ * @param {number} size Code entry size.
+ */
+ addCode(type, name, timestamp, start, size) {
+ const entry = new DynamicCodeEntry(size, type, name);
+ this.codeMap_.addCode(start, entry);
+ return entry;
+ }
-/**
- * Registers dynamic (JIT-compiled) code entry.
- *
- * @param {string} type Code entry type.
- * @param {string} name Code entry name.
- * @param {number} start Starting address.
- * @param {number} size Code entry size.
- */
-Profile.prototype.addCode = function (
- type, name, timestamp, start, size) {
- var entry = new Profile.DynamicCodeEntry(size, type, name);
- this.codeMap_.addCode(start, entry);
- return entry;
-};
+ /**
+ * Registers dynamic (JIT-compiled) code entry.
+ *
+ * @param {string} type Code entry type.
+ * @param {string} name Code entry name.
+ * @param {number} start Starting address.
+ * @param {number} size Code entry size.
+ * @param {number} funcAddr Shared function object address.
+ * @param {Profile.CodeState} state Optimization state.
+ */
+ addFuncCode(type, name, timestamp, start, size, funcAddr, state) {
+ // As code and functions are in the same address space,
+ // it is safe to put them in a single code map.
+ let func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
+ if (!func) {
+ func = new FunctionEntry(name);
+ this.codeMap_.addCode(funcAddr, func);
+ } else if (func.name !== name) {
+ // Function object has been overwritten with a new one.
+ func.name = name;
+ }
+ let entry = this.codeMap_.findDynamicEntryByStartAddress(start);
+ if (entry) {
+ if (entry.size === size && entry.func === func) {
+ // Entry state has changed.
+ entry.state = state;
+ } else {
+ this.codeMap_.deleteCode(start);
+ entry = null;
+ }
+ }
+ if (!entry) {
+ entry = new DynamicFuncCodeEntry(size, type, func, state);
+ this.codeMap_.addCode(start, entry);
+ }
+ return entry;
+ }
+ /**
+ * Reports about moving of a dynamic code entry.
+ *
+ * @param {number} from Current code entry address.
+ * @param {number} to New code entry address.
+ */
+ moveCode(from, to) {
+ try {
+ this.codeMap_.moveCode(from, to);
+ } catch (e) {
+ this.handleUnknownCode(Profile.Operation.MOVE, from);
+ }
+ }
-/**
- * Registers dynamic (JIT-compiled) code entry.
- *
- * @param {string} type Code entry type.
- * @param {string} name Code entry name.
- * @param {number} start Starting address.
- * @param {number} size Code entry size.
- * @param {number} funcAddr Shared function object address.
- * @param {Profile.CodeState} state Optimization state.
- */
-Profile.prototype.addFuncCode = function (
- type, name, timestamp, start, size, funcAddr, state) {
- // As code and functions are in the same address space,
- // it is safe to put them in a single code map.
- var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
- if (!func) {
- func = new Profile.FunctionEntry(name);
- this.codeMap_.addCode(funcAddr, func);
- } else if (func.name !== name) {
- // Function object has been overwritten with a new one.
- func.name = name;
+ deoptCode( timestamp, code, inliningId, scriptOffset, bailoutType,
+ sourcePositionText, deoptReasonText) {
}
- var entry = this.codeMap_.findDynamicEntryByStartAddress(start);
- if (entry) {
- if (entry.size === size && entry.func === func) {
- // Entry state has changed.
- entry.state = state;
- } else {
+
+ /**
+ * Reports about deletion of a dynamic code entry.
+ *
+ * @param {number} start Starting address.
+ */
+ deleteCode(start) {
+ try {
this.codeMap_.deleteCode(start);
- entry = null;
+ } catch (e) {
+ this.handleUnknownCode(Profile.Operation.DELETE, start);
}
}
- if (!entry) {
- entry = new Profile.DynamicFuncCodeEntry(size, type, func, state);
- this.codeMap_.addCode(start, entry);
- }
- return entry;
-};
-
-/**
- * Reports about moving of a dynamic code entry.
- *
- * @param {number} from Current code entry address.
- * @param {number} to New code entry address.
- */
-Profile.prototype.moveCode = function (from, to) {
- try {
- this.codeMap_.moveCode(from, to);
- } catch (e) {
- this.handleUnknownCode(Profile.Operation.MOVE, from);
+ /**
+ * Adds source positions for given code.
+ */
+ addSourcePositions(start, script, startPos, endPos, sourcePositions,
+ inliningPositions, inlinedFunctions) {
+ // CLI does not need source code => ignore.
}
-};
-
-Profile.prototype.deoptCode = function (
- timestamp, code, inliningId, scriptOffset, bailoutType,
- sourcePositionText, deoptReasonText) {
-};
-/**
- * Reports about deletion of a dynamic code entry.
- *
- * @param {number} start Starting address.
- */
-Profile.prototype.deleteCode = function (start) {
- try {
- this.codeMap_.deleteCode(start);
- } catch (e) {
- this.handleUnknownCode(Profile.Operation.DELETE, start);
+ /**
+ * Adds script source code.
+ */
+ addScriptSource(id, url, source) {
+ const script = new Script(id, url, source);
+ this.scripts_[id] = script;
+ this.urlToScript_.set(url, script);
}
-};
-
-/**
- * Adds source positions for given code.
- */
-Profile.prototype.addSourcePositions = function (
- start, script, startPos, endPos, sourcePositions, inliningPositions,
- inlinedFunctions) {
- // CLI does not need source code => ignore.
-};
-
-/**
- * Adds script source code.
- */
-Profile.prototype.addScriptSource = function (id, url, source) {
- const script = new Script(id, url, source);
- this.scripts_[id] = script;
- this.urlToScript_.set(url, script);
-};
-
-
-/**
- * Adds script source code.
- */
-Profile.prototype.getScript = function (url) {
- return this.urlToScript_.get(url);
-};
-/**
- * Reports about moving of a dynamic code entry.
- *
- * @param {number} from Current code entry address.
- * @param {number} to New code entry address.
- */
-Profile.prototype.moveFunc = function (from, to) {
- if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
- this.codeMap_.moveCode(from, to);
+ /**
+ * Adds script source code.
+ */
+ getScript(url) {
+ return this.urlToScript_.get(url);
}
-};
-
-
-/**
- * Retrieves a code entry by an address.
- *
- * @param {number} addr Entry address.
- */
-Profile.prototype.findEntry = function (addr) {
- return this.codeMap_.findEntry(addr);
-};
+ /**
+ * Reports about moving of a dynamic code entry.
+ *
+ * @param {number} from Current code entry address.
+ * @param {number} to New code entry address.
+ */
+ moveFunc(from, to) {
+ if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
+ this.codeMap_.moveCode(from, to);
+ }
+ }
-/**
- * Records a tick event. Stack must contain a sequence of
- * addresses starting with the program counter value.
- *
- * @param {Array<number>} stack Stack sample.
- */
-Profile.prototype.recordTick = function (time_ns, vmState, stack) {
- var processedStack = this.resolveAndFilterFuncs_(stack);
- this.bottomUpTree_.addPath(processedStack);
- processedStack.reverse();
- this.topDownTree_.addPath(processedStack);
-};
+ /**
+ * Retrieves a code entry by an address.
+ *
+ * @param {number} addr Entry address.
+ */
+ findEntry(addr) {
+ return this.codeMap_.findEntry(addr);
+ }
+ /**
+ * Records a tick event. Stack must contain a sequence of
+ * addresses starting with the program counter value.
+ *
+ * @param {Array<number>} stack Stack sample.
+ */
+ recordTick(time_ns, vmState, stack) {
+ const processedStack = this.resolveAndFilterFuncs_(stack);
+ this.bottomUpTree_.addPath(processedStack);
+ processedStack.reverse();
+ this.topDownTree_.addPath(processedStack);
+ }
-/**
- * Translates addresses into function names and filters unneeded
- * functions.
- *
- * @param {Array<number>} stack Stack sample.
- */
-Profile.prototype.resolveAndFilterFuncs_ = function (stack) {
- var result = [];
- var last_seen_c_function = '';
- var look_for_first_c_function = false;
- for (var i = 0; i < stack.length; ++i) {
- var entry = this.codeMap_.findEntry(stack[i]);
- if (entry) {
- var name = entry.getName();
- if (i === 0 && (entry.type === 'CPP' || entry.type === 'SHARED_LIB')) {
- look_for_first_c_function = true;
- }
- if (look_for_first_c_function && entry.type === 'CPP') {
- last_seen_c_function = name;
- }
- if (!this.skipThisFunction(name)) {
- result.push(name);
+ /**
+ * Translates addresses into function names and filters unneeded
+ * functions.
+ *
+ * @param {Array<number>} stack Stack sample.
+ */
+ resolveAndFilterFuncs_(stack) {
+ const result = [];
+ let last_seen_c_function = '';
+ let look_for_first_c_function = false;
+ for (let i = 0; i < stack.length; ++i) {
+ const entry = this.codeMap_.findEntry(stack[i]);
+ if (entry) {
+ const name = entry.getName();
+ if (i === 0 && (entry.type === 'CPP' || entry.type === 'SHARED_LIB')) {
+ look_for_first_c_function = true;
+ }
+ if (look_for_first_c_function && entry.type === 'CPP') {
+ last_seen_c_function = name;
+ }
+ if (!this.skipThisFunction(name)) {
+ result.push(name);
+ }
+ } else {
+ this.handleUnknownCode(Profile.Operation.TICK, stack[i], i);
+ if (i === 0) result.push("UNKNOWN");
}
- } else {
- this.handleUnknownCode(Profile.Operation.TICK, stack[i], i);
- if (i === 0) result.push("UNKNOWN");
- }
- if (look_for_first_c_function &&
- i > 0 &&
- (!entry || entry.type !== 'CPP') &&
- last_seen_c_function !== '') {
- if (this.c_entries_[last_seen_c_function] === undefined) {
- this.c_entries_[last_seen_c_function] = 0;
+ if (look_for_first_c_function &&
+ i > 0 &&
+ (!entry || entry.type !== 'CPP') &&
+ last_seen_c_function !== '') {
+ if (this.c_entries_[last_seen_c_function] === undefined) {
+ this.c_entries_[last_seen_c_function] = 0;
+ }
+ this.c_entries_[last_seen_c_function]++;
+ look_for_first_c_function = false; // Found it, we're done.
}
- this.c_entries_[last_seen_c_function]++;
- look_for_first_c_function = false; // Found it, we're done.
}
+ return result;
}
- return result;
-};
-
-
-/**
- * Performs a BF traversal of the top down call graph.
- *
- * @param {function(CallTree.Node)} f Visitor function.
- */
-Profile.prototype.traverseTopDownTree = function (f) {
- this.topDownTree_.traverse(f);
-};
-
-
-/**
- * Performs a BF traversal of the bottom up call graph.
- *
- * @param {function(CallTree.Node)} f Visitor function.
- */
-Profile.prototype.traverseBottomUpTree = function (f) {
- this.bottomUpTree_.traverse(f);
-};
-
-
-/**
- * Calculates a top down profile for a node with the specified label.
- * If no name specified, returns the whole top down calls tree.
- *
- * @param {string} opt_label Node label.
- */
-Profile.prototype.getTopDownProfile = function (opt_label) {
- return this.getTreeProfile_(this.topDownTree_, opt_label);
-};
+ /**
+ * Performs a BF traversal of the top down call graph.
+ *
+ * @param {function(CallTreeNode)} f Visitor function.
+ */
+ traverseTopDownTree(f) {
+ this.topDownTree_.traverse(f);
+ }
-/**
- * Calculates a bottom up profile for a node with the specified label.
- * If no name specified, returns the whole bottom up calls tree.
- *
- * @param {string} opt_label Node label.
- */
-Profile.prototype.getBottomUpProfile = function (opt_label) {
- return this.getTreeProfile_(this.bottomUpTree_, opt_label);
-};
+ /**
+ * Performs a BF traversal of the bottom up call graph.
+ *
+ * @param {function(CallTreeNode)} f Visitor function.
+ */
+ traverseBottomUpTree(f) {
+ this.bottomUpTree_.traverse(f);
+ }
+ /**
+ * Calculates a top down profile for a node with the specified label.
+ * If no name specified, returns the whole top down calls tree.
+ *
+ * @param {string} opt_label Node label.
+ */
+ getTopDownProfile(opt_label) {
+ return this.getTreeProfile_(this.topDownTree_, opt_label);
+ }
-/**
- * Helper function for calculating a tree profile.
- *
- * @param {Profile.CallTree} tree Call tree.
- * @param {string} opt_label Node label.
- */
-Profile.prototype.getTreeProfile_ = function (tree, opt_label) {
- if (!opt_label) {
- tree.computeTotalWeights();
- return tree;
- } else {
- var subTree = tree.cloneSubtree(opt_label);
- subTree.computeTotalWeights();
- return subTree;
+ /**
+ * Calculates a bottom up profile for a node with the specified label.
+ * If no name specified, returns the whole bottom up calls tree.
+ *
+ * @param {string} opt_label Node label.
+ */
+ getBottomUpProfile(opt_label) {
+ return this.getTreeProfile_(this.bottomUpTree_, opt_label);
}
-};
+ /**
+ * Helper function for calculating a tree profile.
+ *
+ * @param {Profile.CallTree} tree Call tree.
+ * @param {string} opt_label Node label.
+ */
+ getTreeProfile_(tree, opt_label) {
+ if (!opt_label) {
+ tree.computeTotalWeights();
+ return tree;
+ } else {
+ const subTree = tree.cloneSubtree(opt_label);
+ subTree.computeTotalWeights();
+ return subTree;
+ }
+ }
-/**
- * Calculates a flat profile of callees starting from a node with
- * the specified label. If no name specified, starts from the root.
- *
- * @param {string} opt_label Starting node label.
- */
-Profile.prototype.getFlatProfile = function (opt_label) {
- var counters = new CallTree();
- var rootLabel = opt_label || CallTree.ROOT_NODE_LABEL;
- var precs = {};
- precs[rootLabel] = 0;
- var root = counters.findOrAddChild(rootLabel);
-
- this.topDownTree_.computeTotalWeights();
- this.topDownTree_.traverseInDepth(
- function onEnter(node) {
- if (!(node.label in precs)) {
- precs[node.label] = 0;
- }
- var nodeLabelIsRootLabel = node.label == rootLabel;
- if (nodeLabelIsRootLabel || precs[rootLabel] > 0) {
- if (precs[rootLabel] == 0) {
- root.selfWeight += node.selfWeight;
- root.totalWeight += node.totalWeight;
- } else {
- var rec = root.findOrAddChild(node.label);
- rec.selfWeight += node.selfWeight;
- if (nodeLabelIsRootLabel || precs[node.label] == 0) {
- rec.totalWeight += node.totalWeight;
+ /**
+ * Calculates a flat profile of callees starting from a node with
+ * the specified label. If no name specified, starts from the root.
+ *
+ * @param {string} opt_label Starting node label.
+ */
+ getFlatProfile(opt_label) {
+ const counters = new CallTree();
+ const rootLabel = opt_label || CallTree.ROOT_NODE_LABEL;
+ const precs = {};
+ precs[rootLabel] = 0;
+ const root = counters.findOrAddChild(rootLabel);
+
+ this.topDownTree_.computeTotalWeights();
+ this.topDownTree_.traverseInDepth(
+ function onEnter(node) {
+ if (!(node.label in precs)) {
+ precs[node.label] = 0;
+ }
+ const nodeLabelIsRootLabel = node.label == rootLabel;
+ if (nodeLabelIsRootLabel || precs[rootLabel] > 0) {
+ if (precs[rootLabel] == 0) {
+ root.selfWeight += node.selfWeight;
+ root.totalWeight += node.totalWeight;
+ } else {
+ const rec = root.findOrAddChild(node.label);
+ rec.selfWeight += node.selfWeight;
+ if (nodeLabelIsRootLabel || precs[node.label] == 0) {
+ rec.totalWeight += node.totalWeight;
+ }
}
+ precs[node.label]++;
}
- precs[node.label]++;
- }
- },
- function onExit(node) {
- if (node.label == rootLabel || precs[rootLabel] > 0) {
- precs[node.label]--;
- }
- },
- null);
-
- if (!opt_label) {
- // If we have created a flat profile for the whole program, we don't
- // need an explicit root in it. Thus, replace the counters tree
- // root with the node corresponding to the whole program.
- counters.root_ = root;
- } else {
- // Propagate weights so percents can be calculated correctly.
- counters.getRoot().selfWeight = root.selfWeight;
- counters.getRoot().totalWeight = root.totalWeight;
+ },
+ function onExit(node) {
+ if (node.label == rootLabel || precs[rootLabel] > 0) {
+ precs[node.label]--;
+ }
+ },
+ null);
+
+ if (!opt_label) {
+ // If we have created a flat profile for the whole program, we don't
+ // need an explicit root in it. Thus, replace the counters tree
+ // root with the node corresponding to the whole program.
+ counters.root_ = root;
+ } else {
+ // Propagate weights so percents can be calculated correctly.
+ counters.getRoot().selfWeight = root.selfWeight;
+ counters.getRoot().totalWeight = root.totalWeight;
+ }
+ return counters;
}
- return counters;
-};
-
-Profile.CEntryNode = function (name, ticks) {
- this.name = name;
- this.ticks = ticks;
-}
-
-
-Profile.prototype.getCEntryProfile = function () {
- var result = [new Profile.CEntryNode("TOTAL", 0)];
- var total_ticks = 0;
- for (var f in this.c_entries_) {
- var ticks = this.c_entries_[f];
- total_ticks += ticks;
- result.push(new Profile.CEntryNode(f, ticks));
+ getCEntryProfile() {
+ const result = [new CEntryNode("TOTAL", 0)];
+ let total_ticks = 0;
+ for (let f in this.c_entries_) {
+ const ticks = this.c_entries_[f];
+ total_ticks += ticks;
+ result.push(new CEntryNode(f, ticks));
+ }
+ result[0].ticks = total_ticks; // Sorting will keep this at index 0.
+ result.sort((n1, n2) => n2.ticks - n1.ticks || (n2.name < n1.name ? -1 : 1));
+ return result;
}
- result[0].ticks = total_ticks; // Sorting will keep this at index 0.
- result.sort(function (n1, n2) {
- return n2.ticks - n1.ticks || (n2.name < n1.name ? -1 : 1)
- });
- return result;
-}
-/**
- * Cleans up function entries that are not referenced by code entries.
- */
-Profile.prototype.cleanUpFuncEntries = function () {
- var referencedFuncEntries = [];
- var entries = this.codeMap_.getAllDynamicEntriesWithAddresses();
- for (var i = 0, l = entries.length; i < l; ++i) {
- if (entries[i][1].constructor === Profile.FunctionEntry) {
- entries[i][1].used = false;
+ /**
+ * Cleans up function entries that are not referenced by code entries.
+ */
+ cleanUpFuncEntries() {
+ const referencedFuncEntries = [];
+ const entries = this.codeMap_.getAllDynamicEntriesWithAddresses();
+ for (let i = 0, l = entries.length; i < l; ++i) {
+ if (entries[i][1].constructor === FunctionEntry) {
+ entries[i][1].used = false;
+ }
}
- }
- for (var i = 0, l = entries.length; i < l; ++i) {
- if ("func" in entries[i][1]) {
- entries[i][1].func.used = true;
+ for (let i = 0, l = entries.length; i < l; ++i) {
+ if ("func" in entries[i][1]) {
+ entries[i][1].func.used = true;
+ }
}
- }
- for (var i = 0, l = entries.length; i < l; ++i) {
- if (entries[i][1].constructor === Profile.FunctionEntry &&
- !entries[i][1].used) {
- this.codeMap_.deleteCode(entries[i][0]);
+ for (let i = 0, l = entries.length; i < l; ++i) {
+ if (entries[i][1].constructor === FunctionEntry &&
+ !entries[i][1].used) {
+ this.codeMap_.deleteCode(entries[i][0]);
+ }
}
}
-};
+}
+
+class CEntryNode {
+ constructor(name, ticks) {
+ this.name = name;
+ this.ticks = ticks;
+ }
+}
/**
@@ -540,35 +508,30 @@ Profile.prototype.cleanUpFuncEntries = function () {
* @param {string} name Function name.
* @constructor
*/
-Profile.DynamicCodeEntry = function (size, type, name) {
- CodeMap.CodeEntry.call(this, size, name, type);
-};
-
-
-/**
- * Returns node name.
- */
-Profile.DynamicCodeEntry.prototype.getName = function () {
- return this.type + ': ' + this.name;
-};
-
-
-/**
- * Returns raw node name (without type decoration).
- */
-Profile.DynamicCodeEntry.prototype.getRawName = function () {
- return this.name;
-};
-
+class DynamicCodeEntry extends CodeEntry {
+ constructor(size, type, name) {
+ super(size, name, type);
+ }
+
+ getName() {
+ return this.type + ': ' + this.name;
+ }
-Profile.DynamicCodeEntry.prototype.isJSFunction = function () {
- return false;
-};
+ /**
+ * Returns raw node name (without type decoration).
+ */
+ getRawName() {
+ return this.name;
+ }
+ isJSFunction() {
+ return false;
+ }
-Profile.DynamicCodeEntry.prototype.toString = function () {
- return this.getName() + ': ' + this.size.toString(16);
-};
+ toString() {
+ return this.getName() + ': ' + this.size.toString(16);
+ }
+}
/**
@@ -576,51 +539,42 @@ Profile.DynamicCodeEntry.prototype.toString = function () {
*
* @param {number} size Code size.
* @param {string} type Code type.
- * @param {Profile.FunctionEntry} func Shared function entry.
+ * @param {FunctionEntry} func Shared function entry.
* @param {Profile.CodeState} state Code optimization state.
* @constructor
*/
-Profile.DynamicFuncCodeEntry = function (size, type, func, state) {
- CodeMap.CodeEntry.call(this, size, '', type);
- this.func = func;
- this.state = state;
-};
-
-Profile.DynamicFuncCodeEntry.STATE_PREFIX = ["", "~", "*"];
-
-/**
- * Returns state.
- */
-Profile.DynamicFuncCodeEntry.prototype.getState = function () {
- return Profile.DynamicFuncCodeEntry.STATE_PREFIX[this.state];
-};
-
-/**
- * Returns node name.
- */
-Profile.DynamicFuncCodeEntry.prototype.getName = function () {
- var name = this.func.getName();
- return this.type + ': ' + this.getState() + name;
-};
-
-
-/**
- * Returns raw node name (without type decoration).
- */
-Profile.DynamicFuncCodeEntry.prototype.getRawName = function () {
- return this.func.getName();
-};
+class DynamicFuncCodeEntry extends CodeEntry {
+ constructor(size, type, func, state) {
+ super(size, '', type);
+ this.func = func;
+ this.state = state;
+ }
+ static STATE_PREFIX = ["", "~", "*"];
+ getState() {
+ return DynamicFuncCodeEntry.STATE_PREFIX[this.state];
+ }
-Profile.DynamicFuncCodeEntry.prototype.isJSFunction = function () {
- return true;
-};
+ getName() {
+ const name = this.func.getName();
+ return this.type + ': ' + this.getState() + name;
+ }
+ /**
+ * Returns raw node name (without type decoration).
+ */
+ getRawName() {
+ return this.func.getName();
+ }
-Profile.DynamicFuncCodeEntry.prototype.toString = function () {
- return this.getName() + ': ' + this.size.toString(16);
-};
+ isJSFunction() {
+ return true;
+ }
+ toString() {
+ return this.getName() + ': ' + this.size.toString(16);
+ }
+}
/**
* Creates a shared function object entry.
@@ -628,304 +582,279 @@ Profile.DynamicFuncCodeEntry.prototype.toString = function () {
* @param {string} name Function name.
* @constructor
*/
-Profile.FunctionEntry = function (name) {
- CodeMap.CodeEntry.call(this, 0, name);
-};
-
-
-/**
- * Returns node name.
- */
-Profile.FunctionEntry.prototype.getName = function () {
- var name = this.name;
- if (name.length == 0) {
- name = '<anonymous>';
- } else if (name.charAt(0) == ' ') {
- // An anonymous function with location: " aaa.js:10".
- name = '<anonymous>' + name;
- }
- return name;
-};
+class FunctionEntry extends CodeEntry {
+ constructor(name) {
+ super(0, name);
+ }
-Profile.FunctionEntry.prototype.toString = CodeMap.CodeEntry.prototype.toString;
+ /**
+ * Returns node name.
+ */
+ getName() {
+ let name = this.name;
+ if (name.length == 0) {
+ name = '<anonymous>';
+ } else if (name.charAt(0) == ' ') {
+ // An anonymous function with location: " aaa.js:10".
+ name = `<anonymous>${name}`;
+ }
+ return name;
+ }
+}
/**
* Constructs a call graph.
*
* @constructor
*/
-function CallTree() {
- this.root_ = new CallTree.Node(
- CallTree.ROOT_NODE_LABEL);
-};
-
-
-/**
- * The label of the root node.
- */
-CallTree.ROOT_NODE_LABEL = '';
-
-
-/**
- * @private
- */
-CallTree.prototype.totalsComputed_ = false;
-
-
-/**
- * Returns the tree root.
- */
-CallTree.prototype.getRoot = function () {
- return this.root_;
-};
-
-
-/**
- * Adds the specified call path, constructing nodes as necessary.
- *
- * @param {Array<string>} path Call path.
- */
-CallTree.prototype.addPath = function (path) {
- if (path.length == 0) {
- return;
+class CallTree {
+ root_ = new CallTreeNode(CallTree.ROOT_NODE_LABEL);
+ totalsComputed_ = false;
+
+ /**
+ * The label of the root node.
+ */
+ static ROOT_NODE_LABEL = '';
+
+ /**
+ * Returns the tree root.
+ */
+ getRoot() {
+ return this.root_;
}
- var curr = this.root_;
- for (var i = 0; i < path.length; ++i) {
- curr = curr.findOrAddChild(path[i]);
- }
- curr.selfWeight++;
- this.totalsComputed_ = false;
-};
-
-/**
- * Finds an immediate child of the specified parent with the specified
- * label, creates a child node if necessary. If a parent node isn't
- * specified, uses tree root.
- *
- * @param {string} label Child node label.
- */
-CallTree.prototype.findOrAddChild = function (label) {
- return this.root_.findOrAddChild(label);
-};
-
-
-/**
- * Creates a subtree by cloning and merging all subtrees rooted at nodes
- * with a given label. E.g. cloning the following call tree on label 'A'
- * will give the following result:
- *
- * <A>--<B> <B>
- * / /
- * <root> == clone on 'A' ==> <root>--<A>
- * \ \
- * <C>--<A>--<D> <D>
- *
- * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the
- * source call tree.
- *
- * @param {string} label The label of the new root node.
- */
-CallTree.prototype.cloneSubtree = function (label) {
- var subTree = new CallTree();
- this.traverse(function (node, parent) {
- if (!parent && node.label != label) {
- return null;
+ /**
+ * Adds the specified call path, constructing nodes as necessary.
+ *
+ * @param {Array<string>} path Call path.
+ */
+ addPath(path) {
+ if (path.length == 0) {
+ return;
}
- var child = (parent ? parent : subTree).findOrAddChild(node.label);
- child.selfWeight += node.selfWeight;
- return child;
- });
- return subTree;
-};
-
-
-/**
- * Computes total weights in the call graph.
- */
-CallTree.prototype.computeTotalWeights = function () {
- if (this.totalsComputed_) {
- return;
+ let curr = this.root_;
+ for (let i = 0; i < path.length; ++i) {
+ curr = curr.findOrAddChild(path[i]);
+ }
+ curr.selfWeight++;
+ this.totalsComputed_ = false;
}
- this.root_.computeTotalWeight();
- this.totalsComputed_ = true;
-};
+ /**
+ * Finds an immediate child of the specified parent with the specified
+ * label, creates a child node if necessary. If a parent node isn't
+ * specified, uses tree root.
+ *
+ * @param {string} label Child node label.
+ */
+ findOrAddChild(label) {
+ return this.root_.findOrAddChild(label);
+ }
-/**
- * Traverses the call graph in preorder. This function can be used for
- * building optionally modified tree clones. This is the boilerplate code
- * for this scenario:
- *
- * callTree.traverse(function(node, parentClone) {
- * var nodeClone = cloneNode(node);
- * if (parentClone)
- * parentClone.addChild(nodeClone);
- * return nodeClone;
- * });
- *
- * @param {function(CallTree.Node, *)} f Visitor function.
- * The second parameter is the result of calling 'f' on the parent node.
- */
-CallTree.prototype.traverse = function (f) {
- var pairsToProcess = new ConsArray();
- pairsToProcess.concat([{ node: this.root_, param: null }]);
- while (!pairsToProcess.atEnd()) {
- var pair = pairsToProcess.next();
- var node = pair.node;
- var newParam = f(node, pair.param);
- var morePairsToProcess = [];
- node.forEachChild(function (child) {
- morePairsToProcess.push({ node: child, param: newParam });
+ /**
+ * Creates a subtree by cloning and merging all subtrees rooted at nodes
+ * with a given label. E.g. cloning the following call tree on label 'A'
+ * will give the following result:
+ *
+ * <A>--<B> <B>
+ * / /
+ * <root> == clone on 'A' ==> <root>--<A>
+ * \ \
+ * <C>--<A>--<D> <D>
+ *
+ * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the
+ * source call tree.
+ *
+ * @param {string} label The label of the new root node.
+ */
+ cloneSubtree(label) {
+ const subTree = new CallTree();
+ this.traverse((node, parent) => {
+ if (!parent && node.label != label) {
+ return null;
+ }
+ const child = (parent ? parent : subTree).findOrAddChild(node.label);
+ child.selfWeight += node.selfWeight;
+ return child;
});
- pairsToProcess.concat(morePairsToProcess);
+ return subTree;
}
-};
+ /**
+ * Computes total weights in the call graph.
+ */
+ computeTotalWeights() {
+ if (this.totalsComputed_) return;
+ this.root_.computeTotalWeight();
+ this.totalsComputed_ = true;
+ }
-/**
- * Performs an indepth call graph traversal.
- *
- * @param {function(CallTree.Node)} enter A function called
- * prior to visiting node's children.
- * @param {function(CallTree.Node)} exit A function called
- * after visiting node's children.
- */
-CallTree.prototype.traverseInDepth = function (enter, exit) {
- function traverse(node) {
- enter(node);
- node.forEachChild(traverse);
- exit(node);
+ /**
+ * Traverses the call graph in preorder. This function can be used for
+ * building optionally modified tree clones. This is the boilerplate code
+ * for this scenario:
+ *
+ * callTree.traverse(function(node, parentClone) {
+ * var nodeClone = cloneNode(node);
+ * if (parentClone)
+ * parentClone.addChild(nodeClone);
+ * return nodeClone;
+ * });
+ *
+ * @param {function(CallTreeNode, *)} f Visitor function.
+ * The second parameter is the result of calling 'f' on the parent node.
+ */
+ traverse(f) {
+ const pairsToProcess = new ConsArray();
+ pairsToProcess.concat([{ node: this.root_, param: null }]);
+ while (!pairsToProcess.atEnd()) {
+ const pair = pairsToProcess.next();
+ const node = pair.node;
+ const newParam = f(node, pair.param);
+ const morePairsToProcess = [];
+ node.forEachChild((child) => {
+ morePairsToProcess.push({ node: child, param: newParam });
+ });
+ pairsToProcess.concat(morePairsToProcess);
+ }
}
- traverse(this.root_);
-};
+
+ /**
+ * Performs an indepth call graph traversal.
+ *
+ * @param {function(CallTreeNode)} enter A function called
+ * prior to visiting node's children.
+ * @param {function(CallTreeNode)} exit A function called
+ * after visiting node's children.
+ */
+ traverseInDepth(enter, exit) {
+ function traverse(node) {
+ enter(node);
+ node.forEachChild(traverse);
+ exit(node);
+ }
+ traverse(this.root_);
+ }
+}
/**
* Constructs a call graph node.
*
* @param {string} label Node label.
- * @param {CallTree.Node} opt_parent Node parent.
- */
-CallTree.Node = function (label, opt_parent) {
- this.label = label;
- this.parent = opt_parent;
- this.children = {};
-};
-
-
-/**
- * Node self weight (how many times this node was the last node in
- * a call path).
- * @type {number}
- */
-CallTree.Node.prototype.selfWeight = 0;
-
-
-/**
- * Node total weight (includes weights of all children).
- * @type {number}
+ * @param {CallTreeNode} opt_parent Node parent.
*/
-CallTree.Node.prototype.totalWeight = 0;
+ class CallTreeNode {
+ /**
+ * Node self weight (how many times this node was the last node in
+ * a call path).
+ * @type {number}
+ */
+ selfWeight = 0;
+
+ /**
+ * Node total weight (includes weights of all children).
+ * @type {number}
+ */
+ totalWeight = 0;
+ children = {};
+
+ constructor(label, opt_parent) {
+ this.label = label;
+ this.parent = opt_parent;
+ }
-/**
- * Adds a child node.
- *
- * @param {string} label Child node label.
- */
-CallTree.Node.prototype.addChild = function (label) {
- var child = new CallTree.Node(label, this);
- this.children[label] = child;
- return child;
-};
-
+ /**
+ * Adds a child node.
+ *
+ * @param {string} label Child node label.
+ */
+ addChild(label) {
+ const child = new CallTreeNode(label, this);
+ this.children[label] = child;
+ return child;
+ }
-/**
- * Computes node's total weight.
- */
-CallTree.Node.prototype.computeTotalWeight =
- function () {
- var totalWeight = this.selfWeight;
+ /**
+ * Computes node's total weight.
+ */
+ computeTotalWeight() {
+ let totalWeight = this.selfWeight;
this.forEachChild(function (child) {
totalWeight += child.computeTotalWeight();
});
return this.totalWeight = totalWeight;
- };
-
-
-/**
- * Returns all node's children as an array.
- */
-CallTree.Node.prototype.exportChildren = function () {
- var result = [];
- this.forEachChild(function (node) { result.push(node); });
- return result;
-};
-
-
-/**
- * Finds an immediate child with the specified label.
- *
- * @param {string} label Child node label.
- */
-CallTree.Node.prototype.findChild = function (label) {
- return this.children[label] || null;
-};
-
-
-/**
- * Finds an immediate child with the specified label, creates a child
- * node if necessary.
- *
- * @param {string} label Child node label.
- */
-CallTree.Node.prototype.findOrAddChild = function (label) {
- return this.findChild(label) || this.addChild(label);
-};
+ }
+ /**
+ * Returns all node's children as an array.
+ */
+ exportChildren() {
+ const result = [];
+ this.forEachChild(function (node) { result.push(node); });
+ return result;
+ }
-/**
- * Calls the specified function for every child.
- *
- * @param {function(CallTree.Node)} f Visitor function.
- */
-CallTree.Node.prototype.forEachChild = function (f) {
- for (var c in this.children) {
- f(this.children[c]);
+ /**
+ * Finds an immediate child with the specified label.
+ *
+ * @param {string} label Child node label.
+ */
+ findChild(label) {
+ return this.children[label] || null;
}
-};
+ /**
+ * Finds an immediate child with the specified label, creates a child
+ * node if necessary.
+ *
+ * @param {string} label Child node label.
+ */
+ findOrAddChild(label) {
+ return this.findChild(label) || this.addChild(label);
+ }
-/**
- * Walks up from the current node up to the call tree root.
- *
- * @param {function(CallTree.Node)} f Visitor function.
- */
-CallTree.Node.prototype.walkUpToRoot = function (f) {
- for (var curr = this; curr != null; curr = curr.parent) {
- f(curr);
+ /**
+ * Calls the specified function for every child.
+ *
+ * @param {function(CallTreeNode)} f Visitor function.
+ */
+ forEachChild(f) {
+ for (let c in this.children) {
+ f(this.children[c]);
+ }
}
-};
+ /**
+ * Walks up from the current node up to the call tree root.
+ *
+ * @param {function(CallTreeNode)} f Visitor function.
+ */
+ walkUpToRoot(f) {
+ for (let curr = this; curr != null; curr = curr.parent) {
+ f(curr);
+ }
+ }
-/**
- * Tries to find a node with the specified path.
- *
- * @param {Array<string>} labels The path.
- * @param {function(CallTree.Node)} opt_f Visitor function.
- */
-CallTree.Node.prototype.descendToChild = function (
- labels, opt_f) {
- for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) {
- var child = curr.findChild(labels[pos]);
- if (opt_f) {
- opt_f(child, pos);
+ /**
+ * Tries to find a node with the specified path.
+ *
+ * @param {Array<string>} labels The path.
+ * @param {function(CallTreeNode)} opt_f Visitor function.
+ */
+ descendToChild(labels, opt_f) {
+ let curr = this;
+ for (let pos = 0; pos < labels.length && curr != null; pos++) {
+ const child = curr.findChild(labels[pos]);
+ if (opt_f) {
+ opt_f(child, pos);
+ }
+ curr = child;
}
- curr = child;
+ return curr;
}
- return curr;
-};
+}
export function JsonProfile() {
this.codeMap_ = new CodeMap();
@@ -937,7 +866,7 @@ export function JsonProfile() {
JsonProfile.prototype.addLibrary = function (
name, startAddr, endAddr) {
- var entry = new CodeMap.CodeEntry(
+ const entry = new CodeEntry(
endAddr - startAddr, name, 'SHARED_LIB');
this.codeMap_.addLibrary(startAddr, entry);
@@ -948,7 +877,7 @@ JsonProfile.prototype.addLibrary = function (
JsonProfile.prototype.addStaticCode = function (
name, startAddr, endAddr) {
- var entry = new CodeMap.CodeEntry(
+ const entry = new CodeEntry(
endAddr - startAddr, name, 'CPP');
this.codeMap_.addStaticCode(startAddr, entry);
@@ -967,7 +896,7 @@ JsonProfile.prototype.addCode = function (
codeId = staticEntry.entry.codeId;
}
- var entry = new CodeMap.CodeEntry(size, name, 'CODE');
+ const entry = new CodeEntry(size, name, 'CODE');
this.codeMap_.addCode(start, entry);
entry.codeId = codeId;
@@ -975,7 +904,7 @@ JsonProfile.prototype.addCode = function (
name: entry.name,
timestamp: timestamp,
type: entry.type,
- kind: kind
+ kind: kind,
};
return entry;
@@ -985,22 +914,22 @@ JsonProfile.prototype.addFuncCode = function (
kind, name, timestamp, start, size, funcAddr, state) {
// As code and functions are in the same address space,
// it is safe to put them in a single code map.
- var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
+ let func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
if (!func) {
- var func = new CodeMap.CodeEntry(0, name, 'SFI');
+ func = new CodeEntry(0, name, 'SFI');
this.codeMap_.addCode(funcAddr, func);
func.funcId = this.functionEntries_.length;
- this.functionEntries_.push({ name: name, codes: [] });
+ this.functionEntries_.push({ name, codes: [] });
} else if (func.name !== name) {
// Function object has been overwritten with a new one.
func.name = name;
func.funcId = this.functionEntries_.length;
- this.functionEntries_.push({ name: name, codes: [] });
+ this.functionEntries_.push({ name, codes: [] });
}
// TODO(jarin): Insert the code object into the SFI's code list.
- var entry = this.codeMap_.findDynamicEntryByStartAddress(start);
+ let entry = this.codeMap_.findDynamicEntryByStartAddress(start);
if (entry) {
if (entry.size === size && entry.func === func) {
// Entry state has changed.
@@ -1011,7 +940,7 @@ JsonProfile.prototype.addFuncCode = function (
}
}
if (!entry) {
- entry = new CodeMap.CodeEntry(size, name, 'JS');
+ entry = new CodeEntry(size, name, 'JS');
this.codeMap_.addCode(start, entry);
entry.codeId = this.codeEntries_.length;
@@ -1031,7 +960,7 @@ JsonProfile.prototype.addFuncCode = function (
type: entry.type,
kind: kind,
func: func.funcId,
- tm: timestamp
+ tm: timestamp,
});
}
return entry;
@@ -1041,25 +970,25 @@ JsonProfile.prototype.moveCode = function (from, to) {
try {
this.codeMap_.moveCode(from, to);
} catch (e) {
- printErr("Move: unknown source " + from);
+ printErr(`Move: unknown source ${from}`);
}
};
JsonProfile.prototype.addSourcePositions = function (
start, script, startPos, endPos, sourcePositions, inliningPositions,
inlinedFunctions) {
- var entry = this.codeMap_.findDynamicEntryByStartAddress(start);
+ const entry = this.codeMap_.findDynamicEntryByStartAddress(start);
if (!entry) return;
- var codeId = entry.codeId;
+ const codeId = entry.codeId;
// Resolve the inlined functions list.
if (inlinedFunctions.length > 0) {
inlinedFunctions = inlinedFunctions.substring(1).split("S");
- for (var i = 0; i < inlinedFunctions.length; i++) {
- var funcAddr = parseInt(inlinedFunctions[i]);
- var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
+ for (let i = 0; i < inlinedFunctions.length; i++) {
+ const funcAddr = parseInt(inlinedFunctions[i]);
+ const func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
if (!func || func.funcId === undefined) {
- printErr("Could not find function " + inlinedFunctions[i]);
+ printErr(`Could not find function ${inlinedFunctions[i]}`);
inlinedFunctions[i] = null;
} else {
inlinedFunctions[i] = func.funcId;
@@ -1083,7 +1012,6 @@ JsonProfile.prototype.addScriptSource = function (id, url, source) {
this.scripts_[id] = new Script(id, url, source);
};
-
JsonProfile.prototype.deoptCode = function (
timestamp, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) {
@@ -1100,7 +1028,7 @@ JsonProfile.prototype.deoptCode = function (
scriptOffset: scriptOffset,
posText: sourcePositionText,
reason: deoptReasonText,
- bailoutType: bailoutType
+ bailoutType: bailoutType,
};
}
}
@@ -1110,7 +1038,7 @@ JsonProfile.prototype.deleteCode = function (start) {
try {
this.codeMap_.deleteCode(start);
} catch (e) {
- printErr("Delete: unknown address " + start);
+ printErr(`Delete: unknown address ${start}`);
}
};
@@ -1127,9 +1055,9 @@ JsonProfile.prototype.findEntry = function (addr) {
JsonProfile.prototype.recordTick = function (time_ns, vmState, stack) {
// TODO(jarin) Resolve the frame-less case (when top of stack is
// known code).
- var processedStack = [];
- for (var i = 0; i < stack.length; i++) {
- var resolved = this.codeMap_.findAddress(stack[i]);
+ const processedStack = [];
+ for (let i = 0; i < stack.length; i++) {
+ const resolved = this.codeMap_.findAddress(stack[i]);
if (resolved) {
processedStack.push(resolved.entry.codeId, resolved.offset);
} else {
@@ -1157,7 +1085,7 @@ JsonProfile.prototype.writeJson = function () {
write(',\n');
write(' "ticks": [\n');
- for (var i = 0; i < this.ticks_.length; i++) {
+ for (let i = 0; i < this.ticks_.length; i++) {
write(' ');
writeJson(this.ticks_[i]);
if (i < this.ticks_.length - 1) {
diff --git a/chromium/v8/tools/profile_view.mjs b/chromium/v8/tools/profile_view.mjs
index 9349cc6a7a9..9ee687dafd4 100644
--- a/chromium/v8/tools/profile_view.mjs
+++ b/chromium/v8/tools/profile_view.mjs
@@ -47,12 +47,12 @@ export function ViewBuilder(samplingRate) {
*/
ViewBuilder.prototype.buildView = function(
callTree, opt_bottomUpViewWeights) {
- var head;
- var samplingRate = this.samplingRate;
- var createViewNode = this.createViewNode;
+ let head;
+ const samplingRate = this.samplingRate;
+ const createViewNode = this.createViewNode;
callTree.traverse(function(node, viewParent) {
- var totalWeight = node.totalWeight * samplingRate;
- var selfWeight = node.selfWeight * samplingRate;
+ const totalWeight = node.totalWeight * samplingRate;
+ let selfWeight = node.selfWeight * samplingRate;
if (opt_bottomUpViewWeights === true) {
if (viewParent === head) {
selfWeight = totalWeight;
@@ -60,7 +60,7 @@ ViewBuilder.prototype.buildView = function(
selfWeight = 0;
}
}
- var viewNode = createViewNode(node.label, totalWeight, selfWeight, head);
+ const viewNode = createViewNode(node.label, totalWeight, selfWeight, head);
if (viewParent) {
viewParent.addChild(viewNode);
} else {
@@ -68,7 +68,7 @@ ViewBuilder.prototype.buildView = function(
}
return viewNode;
});
- var view = this.createView(head);
+ const view = this.createView(head);
return view;
};
@@ -79,9 +79,7 @@ ViewBuilder.prototype.buildView = function(
* @param {ProfileView.Node} head View head node.
* @return {ProfileView} Profile view.
*/
-ViewBuilder.prototype.createView = function(head) {
- return new ProfileView(head);
-};
+ViewBuilder.prototype.createView = head => new ProfileView(head);
/**
@@ -96,11 +94,11 @@ ViewBuilder.prototype.createView = function(head) {
* @param {ProfileView.Node} head Profile view head.
* @return {ProfileView.Node} Profile view node.
*/
-ViewBuilder.prototype.createViewNode = function(
- funcName, totalTime, selfTime, head) {
- return new ProfileView.Node(
- funcName, totalTime, selfTime, head);
-};
+ViewBuilder.prototype.createViewNode = (
+ funcName, totalTime, selfTime, head) =>
+ new ProfileView.Node(
+ funcName, totalTime, selfTime, head)
+;
/**
@@ -135,10 +133,10 @@ ProfileView.prototype.sort = function(sortFunc) {
* @param {function(ProfileView.Node)} f Visitor function.
*/
ProfileView.prototype.traverse = function(f) {
- var nodesToTraverse = new ConsArray();
+ const nodesToTraverse = new ConsArray();
nodesToTraverse.concat([this.head]);
while (!nodesToTraverse.atEnd()) {
- var node = nodesToTraverse.next();
+ const node = nodesToTraverse.next();
f(node);
nodesToTraverse.concat(node.children);
}
diff --git a/chromium/v8/tools/sourcemap.mjs b/chromium/v8/tools/sourcemap.mjs
index 77af4133cfe..8ddab13cb73 100644
--- a/chromium/v8/tools/sourcemap.mjs
+++ b/chromium/v8/tools/sourcemap.mjs
@@ -77,7 +77,7 @@ WebInspector.SourceMap = function(sourceMappingURL, payload)
if (!WebInspector.SourceMap.prototype._base64Map) {
const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
WebInspector.SourceMap.prototype._base64Map = {};
- for (var i = 0; i < base64Digits.length; ++i)
+ for (let i = 0; i < base64Digits.length; ++i)
WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i;
}
@@ -107,7 +107,7 @@ WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback)
function contentLoaded(error, statusCode, headers, content)
{
if (error || !content || statusCode >= 400) {
- console.error("Could not load content for " + sourceMapURL + " : " + (error || ("HTTP status code: " + statusCode)));
+ console.error(`Could not load content for ${sourceMapURL} : ${error || (`HTTP status code: ${statusCode}`)}`);
callback(null);
return;
}
@@ -115,8 +115,8 @@ WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback)
if (content.slice(0, 3) === ")]}")
content = content.substring(content.indexOf('\n'));
try {
- var payload = /** @type {SourceMapV3} */ (JSON.parse(content));
- var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL;
+ const payload = /** @type {SourceMapV3} */ (JSON.parse(content));
+ const baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL;
callback(new WebInspector.SourceMap(baseURL, payload));
} catch(e) {
console.error(e.message);
@@ -129,7 +129,7 @@ WebInspector.SourceMap.prototype = {
/**
* @return {Array.<string>}
*/
- sources: function()
+ sources()
{
return Object.keys(this._sources);
},
@@ -138,7 +138,7 @@ WebInspector.SourceMap.prototype = {
* @param {string} sourceURL
* @return {string|undefined}
*/
- sourceContent: function(sourceURL)
+ sourceContent(sourceURL)
{
return this._sourceContentByURL[sourceURL];
},
@@ -148,12 +148,12 @@ WebInspector.SourceMap.prototype = {
* @param {WebInspector.ResourceType} contentType
* @return {WebInspector.ContentProvider}
*/
- sourceContentProvider: function(sourceURL, contentType)
+ sourceContentProvider(sourceURL, contentType)
{
- var lastIndexOfDot = sourceURL.lastIndexOf(".");
- var extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot + 1) : "";
- var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()];
- var sourceContent = this.sourceContent(sourceURL);
+ const lastIndexOfDot = sourceURL.lastIndexOf(".");
+ const extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot + 1) : "";
+ const mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()];
+ const sourceContent = this.sourceContent(sourceURL);
if (sourceContent)
return new WebInspector.StaticContentProvider(contentType, sourceContent, mimeType);
return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType, mimeType);
@@ -162,7 +162,7 @@ WebInspector.SourceMap.prototype = {
/**
* @param {SourceMapV3} mappingPayload
*/
- _parseMappingPayload: function(mappingPayload)
+ _parseMappingPayload(mappingPayload)
{
if (mappingPayload.sections)
this._parseSections(mappingPayload.sections);
@@ -173,10 +173,10 @@ WebInspector.SourceMap.prototype = {
/**
* @param {Array.<SourceMapV3.Section>} sections
*/
- _parseSections: function(sections)
+ _parseSections(sections)
{
- for (var i = 0; i < sections.length; ++i) {
- var section = sections[i];
+ for (let i = 0; i < sections.length; ++i) {
+ const section = sections[i];
this._parseMap(section.map, section.offset.line, section.offset.column);
}
},
@@ -186,14 +186,14 @@ WebInspector.SourceMap.prototype = {
* @param {number} columnNumber in compiled resource
* @return {?Array}
*/
- findEntry: function(lineNumber, columnNumber)
+ findEntry(lineNumber, columnNumber)
{
- var first = 0;
- var count = this._mappings.length;
+ let first = 0;
+ let count = this._mappings.length;
while (count > 1) {
- var step = count >> 1;
- var middle = first + step;
- var mapping = this._mappings[middle];
+ const step = count >> 1;
+ const middle = first + step;
+ const mapping = this._mappings[middle];
if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1]))
count = step;
else {
@@ -201,7 +201,7 @@ WebInspector.SourceMap.prototype = {
count -= step;
}
}
- var entry = this._mappings[first];
+ const entry = this._mappings[first];
if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1])))
return null;
return entry;
@@ -212,11 +212,11 @@ WebInspector.SourceMap.prototype = {
* @param {number} lineNumber in the originating resource
* @return {Array}
*/
- findEntryReversed: function(sourceURL, lineNumber)
+ findEntryReversed(sourceURL, lineNumber)
{
- var mappings = this._reverseMappingsBySourceURL[sourceURL];
+ const mappings = this._reverseMappingsBySourceURL[sourceURL];
for ( ; lineNumber < mappings.length; ++lineNumber) {
- var mapping = mappings[lineNumber];
+ const mapping = mappings[lineNumber];
if (mapping)
return mapping;
}
@@ -226,32 +226,32 @@ WebInspector.SourceMap.prototype = {
/**
* @override
*/
- _parseMap: function(map, lineNumber, columnNumber)
+ _parseMap(map, lineNumber, columnNumber)
{
- var sourceIndex = 0;
- var sourceLineNumber = 0;
- var sourceColumnNumber = 0;
- var nameIndex = 0;
-
- var sources = [];
- var originalToCanonicalURLMap = {};
- for (var i = 0; i < map.sources.length; ++i) {
- var originalSourceURL = map.sources[i];
- var sourceRoot = map.sourceRoot || "";
- if (sourceRoot && !sourceRoot.endsWith("/"))
- sourceRoot += "/";
- var href = sourceRoot + originalSourceURL;
- var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
+ let sourceIndex = 0;
+ let sourceLineNumber = 0;
+ let sourceColumnNumber = 0;
+ let nameIndex = 0;
+
+ const sources = [];
+ const originalToCanonicalURLMap = {};
+ for (let i = 0; i < map.sources.length; ++i) {
+ const originalSourceURL = map.sources[i];
+ let sourceRoot = map.sourceRoot || "";
+ if (sourceRoot && !sourceRoot.endsWith("/")) sourceRoot += "/";
+ const href = sourceRoot + originalSourceURL;
+ const url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
originalToCanonicalURLMap[originalSourceURL] = url;
sources.push(url);
this._sources[url] = true;
- if (map.sourcesContent && map.sourcesContent[i])
+ if (map.sourcesContent && map.sourcesContent[i]) {
this._sourceContentByURL[url] = map.sourcesContent[i];
+ }
}
- var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings);
- var sourceURL = sources[sourceIndex];
+ const stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings);
+ let sourceURL = sources[sourceIndex];
while (true) {
if (stringCharIterator.peek() === ",")
@@ -272,7 +272,7 @@ WebInspector.SourceMap.prototype = {
continue;
}
- var sourceIndexDelta = this._decodeVLQ(stringCharIterator);
+ const sourceIndexDelta = this._decodeVLQ(stringCharIterator);
if (sourceIndexDelta) {
sourceIndex += sourceIndexDelta;
sourceURL = sources[sourceIndex];
@@ -285,17 +285,18 @@ WebInspector.SourceMap.prototype = {
this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber]);
}
- for (var i = 0; i < this._mappings.length; ++i) {
- var mapping = this._mappings[i];
- var url = mapping[2];
- if (!url)
- continue;
- if (!this._reverseMappingsBySourceURL[url])
+ for (let i = 0; i < this._mappings.length; ++i) {
+ const mapping = this._mappings[i];
+ const url = mapping[2];
+ if (!url) continue;
+ if (!this._reverseMappingsBySourceURL[url]) {
this._reverseMappingsBySourceURL[url] = [];
- var reverseMappings = this._reverseMappingsBySourceURL[url];
- var sourceLine = mapping[3];
- if (!reverseMappings[sourceLine])
+ }
+ const reverseMappings = this._reverseMappingsBySourceURL[url];
+ const sourceLine = mapping[3];
+ if (!reverseMappings[sourceLine]) {
reverseMappings[sourceLine] = [mapping[0], mapping[1]];
+ }
}
},
@@ -303,7 +304,7 @@ WebInspector.SourceMap.prototype = {
* @param {string} char
* @return {boolean}
*/
- _isSeparator: function(char)
+ _isSeparator(char)
{
return char === "," || char === ";";
},
@@ -312,19 +313,20 @@ WebInspector.SourceMap.prototype = {
* @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator
* @return {number}
*/
- _decodeVLQ: function(stringCharIterator)
+ _decodeVLQ(stringCharIterator)
{
// Read unsigned value.
- var result = 0;
- var shift = 0;
+ let result = 0;
+ let shift = 0;
+ let digit;
do {
- var digit = this._base64Map[stringCharIterator.next()];
+ digit = this._base64Map[stringCharIterator.next()];
result += (digit & this._VLQ_BASE_MASK) << shift;
shift += this._VLQ_BASE_SHIFT;
} while (digit & this._VLQ_CONTINUATION_MASK);
// Fix the sign.
- var negative = result & 1;
+ const negative = result & 1;
// Use unsigned right shift, so that the 32nd bit is properly shifted
// to the 31st, and the 32nd becomes unset.
result >>>= 1;
@@ -359,7 +361,7 @@ WebInspector.SourceMap.StringCharIterator.prototype = {
/**
* @return {string}
*/
- next: function()
+ next()
{
return this._string.charAt(this._position++);
},
@@ -367,7 +369,7 @@ WebInspector.SourceMap.StringCharIterator.prototype = {
/**
* @return {string}
*/
- peek: function()
+ peek()
{
return this._string.charAt(this._position);
},
@@ -375,7 +377,7 @@ WebInspector.SourceMap.StringCharIterator.prototype = {
/**
* @return {boolean}
*/
- hasNext: function()
+ hasNext()
{
return this._position < this._string.length;
}
diff --git a/chromium/v8/tools/splaytree.mjs b/chromium/v8/tools/splaytree.mjs
index 867274a787e..eaba4e4b57d 100644
--- a/chromium/v8/tools/splaytree.mjs
+++ b/chromium/v8/tools/splaytree.mjs
@@ -75,7 +75,7 @@ SplayTree.prototype.insert = function(key, value) {
if (this.root_.key == key) {
return;
}
- var node = new SplayTree.Node(key, value);
+ const node = new SplayTree.Node(key, value);
if (key > this.root_.key) {
node.left = this.root_;
node.right = this.root_.right;
@@ -99,17 +99,17 @@ SplayTree.prototype.insert = function(key, value) {
*/
SplayTree.prototype.remove = function(key) {
if (this.isEmpty()) {
- throw Error('Key not found: ' + key);
+ throw Error(`Key not found: ${key}`);
}
this.splay_(key);
if (this.root_.key != key) {
- throw Error('Key not found: ' + key);
+ throw Error(`Key not found: ${key}`);
}
- var removed = this.root_;
+ const removed = this.root_;
if (!this.root_.left) {
this.root_ = this.root_.right;
} else {
- var right = this.root_.right;
+ 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);
@@ -144,7 +144,7 @@ SplayTree.prototype.findMin = function() {
if (this.isEmpty()) {
return null;
}
- var current = this.root_;
+ let current = this.root_;
while (current.left) {
current = current.left;
}
@@ -159,7 +159,7 @@ SplayTree.prototype.findMax = function(opt_startNode) {
if (this.isEmpty()) {
return null;
}
- var current = opt_startNode || this.root_;
+ let current = opt_startNode || this.root_;
while (current.right) {
current = current.right;
}
@@ -195,7 +195,7 @@ SplayTree.prototype.findGreatestLessThan = function(key) {
* with keys.
*/
SplayTree.prototype.exportKeysAndValues = function() {
- var result = [];
+ const result = [];
this.traverse_(function(node) { result.push([node.key, node.value]); });
return result;
};
@@ -205,7 +205,7 @@ SplayTree.prototype.exportKeysAndValues = function() {
* @return {Array<*>} An array containing all the values of tree's nodes.
*/
SplayTree.prototype.exportValues = function() {
- var result = [];
+ const result = [];
this.traverse_(function(node) { result.push(node.value); });
return result;
};
@@ -230,9 +230,9 @@ SplayTree.prototype.splay_ = function(key) {
// 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.
- var dummy, left, right;
+ let dummy, left, right;
dummy = left = right = new SplayTree.Node(null, null);
- var current = this.root_;
+ let current = this.root_;
while (true) {
if (key < current.key) {
if (!current.left) {
@@ -240,7 +240,7 @@ SplayTree.prototype.splay_ = function(key) {
}
if (key < current.left.key) {
// Rotate right.
- var tmp = current.left;
+ const tmp = current.left;
current.left = tmp.right;
tmp.right = current;
current = tmp;
@@ -258,7 +258,7 @@ SplayTree.prototype.splay_ = function(key) {
}
if (key > current.right.key) {
// Rotate left.
- var tmp = current.right;
+ const tmp = current.right;
current.right = tmp.left;
tmp.left = current;
current = tmp;
@@ -290,9 +290,9 @@ SplayTree.prototype.splay_ = function(key) {
* @private
*/
SplayTree.prototype.traverse_ = function(f) {
- var nodesToVisit = [this.root_];
+ const nodesToVisit = [this.root_];
while (nodesToVisit.length > 0) {
- var node = nodesToVisit.shift();
+ const node = nodesToVisit.shift();
if (node == null) {
continue;
}
diff --git a/chromium/v8/tools/system-analyzer/app-model.mjs b/chromium/v8/tools/system-analyzer/app-model.mjs
index 37fa5ae2f33..a0b176c1708 100644
--- a/chromium/v8/tools/system-analyzer/app-model.mjs
+++ b/chromium/v8/tools/system-analyzer/app-model.mjs
@@ -3,100 +3,116 @@
// found in the LICENSE file.
class State {
- #timeSelection = { start: 0, end: Infinity };
- #map;
- #ic;
- #selectedMapLogEvents;
- #selectedIcLogEvents;
- #selectedSourcePositionLogEvents;
- #nofChunks;
- #chunks;
- #icTimeline;
- #mapTimeline;
- #minStartTime = Number.POSITIVE_INFINITY;
- #maxEndTime = Number.NEGATIVE_INFINITY;
+ _timeSelection = {start: 0, end: Infinity};
+ _map;
+ _ic;
+ _selectedMapLogEntries;
+ _selectedIcLogEntries;
+ _selectedDeoptLogEntries;
+ _selectedSourcePositions;
+ _nofChunks;
+ _chunks;
+ _icTimeline;
+ _mapTimeline;
+ _deoptTimeline;
+ _minStartTime = Number.POSITIVE_INFINITY;
+ _maxEndTime = Number.NEGATIVE_INFINITY;
get minStartTime() {
- return this.#minStartTime;
+ return this._minStartTime;
}
get maxEndTime() {
- return this.#maxEndTime;
+ return this._maxEndTime;
}
- #updateTimeRange(timeline) {
- this.#minStartTime = Math.min(this.#minStartTime, timeline.startTime);
- this.#maxEndTime = Math.max(this.#maxEndTime, timeline.endTime);
+
+ 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);
+ }
+
+ _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;
}
get mapTimeline() {
- return this.#mapTimeline;
+ return this._mapTimeline;
}
set mapTimeline(timeline) {
- this.#updateTimeRange(timeline);
- timeline.startTime = this.#minStartTime;
- timeline.endTime = this.#maxEndTime;
- this.#mapTimeline = timeline;
+ this._updateTimeRange(timeline);
+ this._mapTimeline = timeline;
+ }
+ get icTimeline() {
+ return this._icTimeline;
}
set icTimeline(timeline) {
- this.#updateTimeRange(timeline);
- timeline.startTime = this.#minStartTime;
- timeline.endTime = this.#maxEndTime;
- this.#icTimeline = timeline;
+ this._updateTimeRange(timeline);
+ this._icTimeline = timeline;
}
- get icTimeline() {
- return this.#icTimeline;
+ get deoptTimeline() {
+ return this._deoptTimeline;
+ }
+ set deoptTimeline(timeline) {
+ this._updateTimeRange(timeline);
+ this._deoptTimeline = timeline;
}
set chunks(value) {
- //TODO(zcankara) split up between maps and ics, and every timeline track
- this.#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;
+ // TODO(zcankara) split up between maps and ics, and every timeline track
+ return this._chunks;
}
get nofChunks() {
- return this.#nofChunks;
+ return this._nofChunks;
}
set nofChunks(count) {
- this.#nofChunks = count;
+ this._nofChunks = count;
}
get map() {
- //TODO(zcankara) rename as selectedMapEvents, array of selected events
- return this.#map;
+ // TODO(zcankara) rename as selectedMapEvents, array of selected events
+ return this._map;
}
set map(value) {
- //TODO(zcankara) rename as selectedMapEvents, array of selected events
+ // TODO(zcankara) rename as selectedMapEvents, array of selected events
if (!value) return;
- this.#map = value;
+ this._map = value;
}
get ic() {
- //TODO(zcankara) rename selectedICEvents, array of selected events
- return this.#ic;
+ // TODO(zcankara) rename selectedICEvents, array of selected events
+ return this._ic;
}
set ic(value) {
- //TODO(zcankara) rename selectedIcEvents, array of selected events
+ // TODO(zcankara) rename selectedIcEvents, array of selected events
if (!value) return;
- this.#ic = value;
+ this._ic = value;
}
- get selectedMapLogEvents() {
- return this.#selectedMapLogEvents;
+ get selectedMapLogEntries() {
+ return this._selectedMapLogEntries;
}
- set selectedMapLogEvents(value) {
+ set selectedMapLogEntries(value) {
if (!value) return;
- this.#selectedMapLogEvents = value;
+ this._selectedMapLogEntries = value;
}
- get selectedSourcePositionLogEvents() {
- return this.#selectedSourcePositionLogEvents;
+ get selectedSourcePositions() {
+ return this._selectedSourcePositions;
}
- set selectedSourcePositionLogEvents(value) {
- this.#selectedSourcePositionLogEvents = value;
+ set selectedSourcePositions(value) {
+ this._selectedSourcePositions = value;
}
- get selectedIcLogEvents() {
- return this.#selectedIcLogEvents;
+ get selectedIcLogEntries() {
+ return this._selectedIcLogEntries;
}
- set selectedIcLogEvents(value) {
+ set selectedIcLogEntries(value) {
if (!value) return;
- this.#selectedIcLogEvents = value;
+ this._selectedIcLogEntries = value;
}
get timeSelection() {
- return this.#timeSelection;
+ return this._timeSelection;
}
get entries() {
if (!this.map) return {};
@@ -106,4 +122,4 @@ class State {
}
}
-export { State };
+export {State};
diff --git a/chromium/v8/tools/system-analyzer/events.mjs b/chromium/v8/tools/system-analyzer/events.mjs
index 8e9a5a0b446..69529233b46 100644
--- a/chromium/v8/tools/system-analyzer/events.mjs
+++ b/chromium/v8/tools/system-analyzer/events.mjs
@@ -3,44 +3,49 @@
// found in the LICENSE file.
class SelectionEvent extends CustomEvent {
- static name = "showentries";
+ // TODO: turn into static class fields once Safari supports it.
+ static get name() {
+ return 'showentries';
+ }
constructor(entries) {
- super(SelectionEvent.name, { bubbles: true, composed: true });
+ super(SelectionEvent.name, {bubbles: true, composed: true});
if (!Array.isArray(entries) || entries.length == 0) {
- throw new Error("No valid entries selected!");
+ throw new Error('No valid entries selected!');
}
this.entries = entries;
}
}
class FocusEvent extends CustomEvent {
- static name = "showentrydetail";
+ static get name() {
+ return 'showentrydetail';
+ }
constructor(entry) {
- super(FocusEvent.name, { bubbles: true, composed: true });
+ super(FocusEvent.name, {bubbles: true, composed: true});
this.entry = entry;
}
}
class SelectTimeEvent extends CustomEvent {
- static name = 'timerangeselect';
+ static get name() {
+ return 'timerangeselect';
+ }
constructor(start, end) {
- super(SelectTimeEvent.name, { bubbles: true, composed: true });
+ super(SelectTimeEvent.name, {bubbles: true, composed: true});
this.start = start;
this.end = end;
}
}
class SynchronizeSelectionEvent extends CustomEvent {
- static name = 'syncselection';
+ static get name() {
+ return 'syncselection';
+ }
constructor(start, end) {
- super(SynchronizeSelectionEvent.name, { bubbles: true, composed: true });
+ super(SynchronizeSelectionEvent.name, {bubbles: true, composed: true});
this.start = start;
this.end = end;
}
}
-
-export {
- SelectionEvent, FocusEvent, SelectTimeEvent,
- SynchronizeSelectionEvent
-};
+export {SelectionEvent, FocusEvent, SelectTimeEvent, SynchronizeSelectionEvent};
diff --git a/chromium/v8/tools/system-analyzer/helper.mjs b/chromium/v8/tools/system-analyzer/helper.mjs
index 782b3f34569..854a51fcf38 100644
--- a/chromium/v8/tools/system-analyzer/helper.mjs
+++ b/chromium/v8/tools/system-analyzer/helper.mjs
@@ -22,26 +22,6 @@ function formatSeconds(millis) {
return (millis * kMillis2Seconds).toFixed(2) + 's';
}
-function 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)));
-}
-
-// DOM Helpers
-function removeAllChildren(node) {
- let range = document.createRange();
- range.selectNodeContents(node);
- range.deleteContents();
-}
-
-function $(id) {
- return document.querySelector(id)
-}
-
class CSSColor {
static getColor(name) {
const style = getComputedStyle(document.body);
@@ -101,7 +81,6 @@ class CSSColor {
static get violet() {
return CSSColor.getColor('violet');
}
-
}
function typeToColor(type) {
@@ -136,26 +115,77 @@ function typeToColor(type) {
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;
+ }
-function div(classes) {
- let node = document.createElement('div');
- if (classes !== void 0) {
- if (typeof classes === 'string') {
- node.classList.add(classes);
- } else {
- classes.forEach(cls => node.classList.add(cls));
+ 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)));
}
- return node;
+}
+
+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' });
+ const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
}
+
$(id) {
return this.shadowRoot.querySelector(id);
}
@@ -164,32 +194,54 @@ class V8CustomElement extends HTMLElement {
return this.shadowRoot.querySelectorAll(query);
}
- div(classes) { return div(classes) }
+ update() {
+ // 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');
+ }
+}
- table(className) {
- let node = document.createElement('table')
- if (className) node.classList.add(className)
- return node;
+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();
}
- td(textOrNode) {
- let node = document.createElement('td');
- if (typeof textOrNode === 'object') {
- node.appendChild(textOrNode);
- } else {
- node.innerText = textOrNode;
- }
- return node;
+ _nextRowDataSlice() {
+ return this._rowData.splice(0, 100);
}
- tr() {
- return document.createElement('tr');
+ _addMoreRows() {
+ const fragment = new DocumentFragment();
+ for (let row of this._nextRowDataSlice()) {
+ const tr = this._rowElementCreator(row);
+ fragment.appendChild(tr);
+ }
+ this._table.querySelector('tbody').appendChild(fragment);
}
+}
- removeAllChildren(node) { return removeAllChildren(node); }
+function delay(time) {
+ return new Promise(resolver => setTimeout(resolver, time));
}
export {
- defineCustomElement, V8CustomElement, removeAllChildren,
- $, div, typeToColor, CSSColor
+ DOM,
+ $,
+ V8CustomElement,
+ formatBytes,
+ typeToColor,
+ CSSColor,
+ delay,
+ LazyTable,
};
diff --git a/chromium/v8/tools/system-analyzer/ic-model.mjs b/chromium/v8/tools/system-analyzer/ic-model.mjs
index 8340e9b7566..2bb40b6853a 100644
--- a/chromium/v8/tools/system-analyzer/ic-model.mjs
+++ b/chromium/v8/tools/system-analyzer/ic-model.mjs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import Processor from "./processor.mjs";
+import {IcLogEntry} from './log/ic.mjs';
// For compatibility with console scripts:
print = console.log;
@@ -23,11 +23,11 @@ export class Group {
}
createSubGroups() {
+ // TODO: use Map
this.groups = {};
- for (let i = 0; i < Processor.kProperties.length; i++) {
- let subProperty = Processor.kProperties[i];
- if (this.property == subProperty) continue;
- this.groups[subProperty] = Group.groupBy(this.entries, subProperty);
+ for (const propertyName of IcLogEntry.propertyNames) {
+ if (this.property == propertyName) continue;
+ this.groups[propertyName] = Group.groupBy(this.entries, propertyName);
}
}
@@ -51,8 +51,7 @@ export class Group {
group.percentage = Math.round(group.count / length * 100 * 100) / 100;
result.push(group);
}
- result.sort((a, b) => { return b.count - a.count });
+ result.sort((a, b) => {return b.count - a.count});
return result;
}
-
}
diff --git a/chromium/v8/tools/system-analyzer/ic-panel-template.html b/chromium/v8/tools/system-analyzer/ic-panel-template.html
index 53c5eb77fca..ee08901fb02 100644
--- a/chromium/v8/tools/system-analyzer/ic-panel-template.html
+++ b/chromium/v8/tools/system-analyzer/ic-panel-template.html
@@ -25,37 +25,49 @@ found in the LICENSE file. -->
padding: 0.5em 0 0.2em 0;
}
- .entry-details {}
-
- .entry-details TD {}
-
- .details {
- width: 0.1em;
- }
-
- .details span {
- padding: 0 0.4em 0 0.4em;
- background-color: var(--on-surface-color);
- color: var(--surface-color);
- border-radius: 25px;
+ .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 {
- padding-right: 20px;
+ 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;
}
- dl {
- float: right;
- border-style: solid;
- border-width: 1px;
- padding: 20px;
+ #legend dt {
+ font-family: monospace;
+ }
+ #legend h3 {
+ margin-top: 10px;
+ }
+ .scroller {
+ max-height: 800px;
+ overflow-y: scroll;
}
</style>
<div class="panel">
- <h2>IC Panel</h2>
+ <h2>IC Panel <span id="count"></span></h2>
<div id="legend">
+ <h3>Legend</h3>
<dl>
<dt>0</dt>
<dd>uninitialized</dd>
@@ -73,22 +85,14 @@ found in the LICENSE file. -->
<dd>generic</dd>
</dl>
</div>
- <h3>Data</h3>
- <p>Trace Count: <span id="count">0</span></p>
- <h3>Result</h3>
<p>
- Group-Key:
+ Group by IC-property:
<select id="group-key"></select>
</p>
- <p>
- Filter by Time
- <input type="search" id="filter-time-start" placeholder="start"></input> :
- <input type="search" id="filter-time-end" placeholder="end"></input>
- <button id="filterICTimeBtn">Filter</button>
- <p>
- <table id="table" width="100%">
- <tbody id="table-body">
- </tbody>
- </table>
- </p>
+ <div class="panelBody">
+ <table id="table" width="100%">
+ <tbody id="table-body">
+ </tbody>
+ </table>
+ </div>
</div>
diff --git a/chromium/v8/tools/system-analyzer/ic-panel.mjs b/chromium/v8/tools/system-analyzer/ic-panel.mjs
index a8f68c31f5d..d81d06d0d6d 100644
--- a/chromium/v8/tools/system-analyzer/ic-panel.mjs
+++ b/chromium/v8/tools/system-analyzer/ic-panel.mjs
@@ -2,223 +2,190 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import { Group } from './ic-model.mjs';
-import Processor from "./processor.mjs";
-import { MapLogEvent } from "./log/map.mjs";
-import { FocusEvent, SelectTimeEvent, SelectionEvent } from './events.mjs';
-import { defineCustomElement, V8CustomElement } from './helper.mjs';
-
-defineCustomElement('ic-panel', (templateText) =>
- class ICPanel extends V8CustomElement {
- #selectedLogEvents;
- #timeline;
- constructor() {
- super(templateText);
- this.initGroupKeySelect();
- this.groupKey.addEventListener(
- 'change', e => this.updateTable(e));
- this.$('#filterICTimeBtn').addEventListener(
- 'click', e => this.handleICTimeFilter(e));
- }
- set timeline(value) {
- console.assert(value !== undefined, "timeline undefined!");
- this.#timeline = value;
- this.selectedLogEvents = this.#timeline.all;
- this.updateCount();
- }
- 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 selectedLogEvents(value) {
- this.#selectedLogEvents = value;
- this.updateCount();
- this.updateTable();
- }
-
- updateCount() {
- this.count.innerHTML = this.selectedLogEvents.length;
- }
-
- get selectedLogEvents() {
- return this.#selectedLogEvents;
- }
-
- updateTable(event) {
- let select = this.groupKey;
- let key = select.options[select.selectedIndex].text;
- let tableBody = this.tableBody;
- this.removeAllChildren(tableBody);
- let groups = Group.groupBy(this.selectedLogEvents, key, true);
- this.render(groups, tableBody);
- }
-
- escapeHtml(unsafe) {
- if (!unsafe) return "";
- return unsafe.toString()
- .replace(/&/g, "&amp;")
- .replace(/</g, "&lt;")
- .replace(/>/g, "&gt;")
- .replace(/"/g, "&quot;")
- .replace(/'/g, "&#039;");
- }
- processValue(unsafe) {
- if (!unsafe) return "";
- if (!unsafe.startsWith("http")) return this.escapeHtml(unsafe);
- let a = document.createElement("a");
- a.href = unsafe;
- a.textContent = unsafe;
- return a;
- }
-
- td(tr, content, className) {
- let node = document.createElement("td");
- if (typeof content == "object") {
- node.appendChild(content);
- } else {
- node.innerHTML = content;
- }
- node.className = className;
- tr.appendChild(node);
- return node
- }
-
- handleMapClick(e) {
- const entry = e.target.parentNode.entry;
- const id = entry.key;
- const selectedMapLogEvents =
- this.searchIcLogEventToMapLogEvent(id, entry.entries);
- this.dispatchEvent(new SelectionEvent(selectedMapLogEvents));
- }
-
- searchIcLogEventToMapLogEvent(id, icLogEvents) {
- // searches for mapLogEvents using the id, time
- const selectedMapLogEventsSet = new Set();
- for (const icLogEvent of icLogEvents) {
- const time = icLogEvent.time;
- const selectedMap = MapLogEvent.get(id, time);
- selectedMapLogEventsSet.add(selectedMap);
- }
- return Array.from(selectedMapLogEventsSet);
- }
-
- //TODO(zcankara) Handle in the processor for events with source positions.
- handleFilePositionClick(e) {
- const entry = e.target.parentNode.entry;
- this.dispatchEvent(new FocusEvent(entry.filePosition));
- }
-
- render(entries, parent) {
- let fragment = document.createDocumentFragment();
- let max = Math.min(1000, entries.length)
- for (let i = 0; i < max; i++) {
- let entry = entries[i];
- let tr = document.createElement("tr");
- tr.entry = entry;
- //TODO(zcankara) Create one bound method and use it everywhere
- if (entry.property === "map") {
- tr.addEventListener('click', e => this.handleMapClick(e));
- tr.classList.add('clickable');
- } else if (entry.property == "filePosition") {
- tr.classList.add('clickable');
- tr.addEventListener('click',
- e => this.handleFilePositionClick(e));
+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 details = this.td(tr, '<span>&#8505;</a>', 'details');
- //TODO(zcankara) don't keep the whole function context alive
- details.onclick = _ => this.toggleDetails(details);
- this.td(tr, entry.percentage + "%", 'percentage');
- this.td(tr, entry.count, 'count');
- this.td(tr, this.processValue(entry.key), 'key');
- fragment.appendChild(tr);
- }
- let omitted = entries.length - max;
- if (omitted > 0) {
- let tr = document.createElement("tr");
- let tdNode = this.td(tr, 'Omitted ' + omitted + " entries.");
- tdNode.colSpan = 4;
- fragment.appendChild(tr);
- }
- parent.appendChild(fragment);
- }
-
-
- renderDrilldown(entry, previousSibling) {
- let tr = document.createElement('tr');
- tr.className = "entry-details";
- tr.style.display = "none";
- // indent by one td.
- tr.appendChild(document.createElement("td"));
- let td = document.createElement("td");
- td.colSpan = 3;
- for (let key in entry.groups) {
- td.appendChild(this.renderDrilldownGroup(entry, key));
- }
- tr.appendChild(td);
- // Append the new TR after previousSibling.
- previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling)
- }
-
- renderDrilldownGroup(entry, key) {
- let max = 20;
- let group = entry.groups[key];
- let div = document.createElement("div")
- div.className = 'drilldown-group-title'
- div.textContent = key + ' [top ' + max + ' out of ' + group.length + ']';
- let table = document.createElement("table");
- this.render(group.slice(0, max), table, false)
- div.appendChild(table);
- return div;
- }
-
- toggleDetails(node) {
- let tr = node.parentNode;
- let entry = tr.entry;
- // Create subgroup in-place if the don't exist yet.
- if (entry.groups === undefined) {
- entry.createSubGroups();
- this.renderDrilldown(entry, tr);
- }
- let details = tr.nextSibling;
- let display = details.style.display;
- if (display != "none") {
- display = "none";
- } else {
- display = "table-row"
- };
- details.style.display = display;
- }
-
- initGroupKeySelect() {
- let select = this.groupKey;
- select.options.length = 0;
- for (let i in Processor.kProperties) {
- let option = document.createElement("option");
- option.text = Processor.kProperties[i];
- select.add(option);
- }
- }
-
- handleICTimeFilter(e) {
- this.dispatchEvent(new SelectTimeEvent(
- parseInt(this.$('#filter-time-start').value),
- parseInt(this.$('#filter-time-end').value)));
- }
-
- });
+ 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/chromium/v8/tools/system-analyzer/index.css b/chromium/v8/tools/system-analyzer/index.css
index c3defb5b8cd..5b55182f681 100644
--- a/chromium/v8/tools/system-analyzer/index.css
+++ b/chromium/v8/tools/system-analyzer/index.css
@@ -18,6 +18,7 @@
--blue: #6e77dc;
--orange: #dc9b6e;
--violet: #d26edc;
+ --border-color: 128, 128, 128;
}
[data-theme="light"] {
@@ -43,28 +44,60 @@
}
body {
- font-family: "Roboto", sans-serif;
+ font-family: sans-serif;
font-size: 14px;
color: var(--on-background-color);
- margin-left: 2.5%;
- margin-right: 2.5%;
+ margin: 10px 10px 0 10px;
background-color: var(--background-color);
- letter-spacing: 0.5px;
}
-h2,
-h4 {
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- transition: 0.3s;
- color: var(--on-surface-color);
- padding: 10px 20px;
- text-align: center;
- text-decoration: none;
+
+section {
+ margin-bottom: 10px;
+}
+
+::-webkit-scrollbar, ::-webkit-scrollbar-track, ::-webkit-scrollbar-corner {
+ background-color: rgba(0, 0, 0, 0.0);
+}
+::-webkit-scrollbar, ::-webkit-scrollbar-track {
+ width: 10px;
+ height: 10px;
+}
+::-webkit-scrollbar-thumb {
+ background-color: rgba(128, 128, 128, 0.5);
+ border-radius: 8px;
+ cursor: pointer;
+}
+::-webkit-scrollbar-thumb:hover {
+ background-color: rgba(128, 128, 128, 0.8);
+}
+
+kbd {
+ color: var(--on-primary-color);
+ background-color: var(--primary-color);
+ border-radius: 3px;
+ border: 1px solid var(--on-primary-color);
display: inline-block;
+ font-size: .9em;
+ font-weight: bold;
+ padding: 0px 4px 2px 4px;
+ white-space: nowrap;
}
+
+a {
+ color: var(--primary-color);
+ text-decoration: none;
+}
+a:hover {
+ color: var(--secondary-color);
+}
+a:link {
+ color: var(--secondary-color);
+}
+
dl {
display: grid;
grid-template-columns: min-content auto;
- grid-gap: 10px;
+ grid-gap: 5px;
}
dt {
text-align: right;
@@ -73,15 +106,25 @@ dt {
dd {
margin: 0;
}
+
.panel {
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- transition: 0.3s;
background-color: var(--surface-color);
color: var(--on-surface-color);
padding: 10px 10px 10px 10px;
- margin: auto;
- overflow-x: scroll;
+ border-radius: 10px;
+ border: 3px solid rgba(var(--border-color), 0.2);
+}
+
+.panelBody {
+ max-height: 800px;
+ overflow-y: scroll;
+ margin: 0 -10px -10px 0;
+}
+
+.panel > h2 {
+ margin-top: 5px;
}
+
button {
cursor: pointer;
}
@@ -90,11 +133,21 @@ select,
button {
background-color: var(--surface-color);
color: var(--on-surface-color);
+ border: 2px solid rgba(var(--border-color), 0.4);
+ border-radius: 5px;
+ padding: 2px;
+}
+input:hover,
+select:hover,
+button:hover {
+ border: 2px solid rgba(var(--border-color), 0.6);
}
+
.colorbox {
width: 10px;
height: 10px;
border: 1px var(--background-color) solid;
+ border-radius: 50%;
}
.primary {
@@ -146,10 +199,4 @@ button {
background-color: var(--primary-color);
color: var(--on-primary-color);
cursor: pointer;
-}
-
-a:link {
- color: var(--secondary-color);
- background-color: transparent;
- text-decoration: none;
-}
+} \ No newline at end of file
diff --git a/chromium/v8/tools/system-analyzer/index.html b/chromium/v8/tools/system-analyzer/index.html
index c9104461147..a861300f910 100644
--- a/chromium/v8/tools/system-analyzer/index.html
+++ b/chromium/v8/tools/system-analyzer/index.html
@@ -2,34 +2,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. -->
-
<html lang="en">
-
<head>
<meta charset="UTF-8">
<title>Indicium</title>
- <link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
<!-- <link rel="icon" type="image/png" href="/images/favicon.png"/> -->
- <script type="module" src="index.mjs"></script>
- <link rel="stylesheet" type="text/css" href="./index.css">
- <style>
- #instructions {
- padding: 10px 10px 60px 10px;
- margin: auto;
- }
- kbd {
- background-color: var(--primary-color);
- color: var(--on-primary-color);
- border-radius: 3px;
- border: 1px solid var(--on-primary-color);
- display: inline-block;
- font-size: .9em;
- font-weight: bold;
- padding: 0px 4px 2px 4px;
- white-space: nowrap;
- }
+ <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">
+ <script type="module">
+ // Force instatiating the log-reader before anything else.
+ import "./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");
+ })();
+ </script>
+ <link rel="stylesheet" type="text/css" href="./index.css">
+ <style>
.theme-switch-wrapper {
display: inline-block;
align-items: center;
@@ -37,9 +32,9 @@ found in the LICENSE file. -->
.theme-switch {
display: inline-block;
- height: 34px;
+ height: 16px;
position: relative;
- width: 60px;
+ width: 38px;
}
.theme-switch input {
@@ -54,150 +49,138 @@ found in the LICENSE file. -->
position: absolute;
right: 0;
top: 0;
- transition: .4s;
+ border-radius: 34px;
}
.slider:before {
background-color: var(--surface-color);
- bottom: 4px;
+ position: absolute;
+ height: 10px;
+ width: 10px;
+ bottom: 3px;
content: "";
- height: 26px;
left: 4px;
- position: absolute;
- transition: .4s;
- width: 26px;
- }
-
- input:checked+.slider {
- background-color: var(--primary-color);
+ border-radius: 50%;
}
input:checked+.slider:before {
- transform: translateX(26px);
- }
-
- .slider.round {
- border-radius: 34px;
- }
-
- .slider.round:before {
- border-radius: 50%;
+ transform: translateX(20px);
}
#container.initial {
display: none;
}
- #container.loaded {
- display: grid;
- align-content: center;
- grid-template-columns: repeat(auto-fit, minmax(400px, 800px));
- grid-template-rows: repeat(auto-fit, minmax(400px, 800px));
- grid-auto-flow: dense;
- }
-
- #container.loaded>#timeline-panel {
- grid-column: span 2;
- overflow: scroll;
+ #timeline-panel {
+ width: 100%;
}
- a {
- color: var(--primary-color);
+ .panels{
+ display: grid;
+ align-content: center;
+ grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
+ grid-auto-flow: row dense;
+ grid-gap: 10px;
+ margin-top: 10px;
}
- a:hover {
- color: var(--secondary-color);
+ dt::after {
+ content: ":";
}
</style>
- <script type="module">
- import { App } from './index.mjs';
-
- globalThis.app = new App("#log-file-reader", "#map-panel",
- "#timeline-panel", "#ic-panel", "#map-track", "#ic-track",
- "#source-panel");
- </script>
</head>
<body>
- <div id="content">
- <section id="file-reader">
- <log-file-reader id="log-file-reader"></log-file-reader>
- </section>
- <div class="theme-switch-wrapper">
- <label class="theme-switch" for="checkbox">
- <input type="checkbox" id="checkbox" />
- <div class="slider round"></div>
- </label>
- </div>
- <div id="container" class="initial">
- <timeline-panel id="timeline-panel">
- <timeline-track id="map-track"></timeline-track>
- <timeline-track id="ic-track"></timeline-track>
- </timeline-panel>
+ <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-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>
</div>
- </div>
- <div id="instructions">
- <h2>Instructions</h2>
- <p>
- Unified web interface to analyse runtime information stored in the v8 log.
- </p>
- For generating log file from
- <a href="https://v8.dev/docs/build" target="_blank">d8</a>:
- <p>
- Log Options:
- </p>
- <dl>
- <dt>--trace-maps:</dt>
- <dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank">
- Maps</a></dd>
- <dt>--trace_ic:</dt>
- <dd>Log
- <a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank">
- ICs</a></dd>
- <dt>--log-source-code:</dt>
- <dd>Log source code</dd>
- </dl>
- Usage:
- <ul>
- <li><code>/path/do/d8 --trace-maps --trace_ic --log-source-code $FILE
- </code></li>
- </ul>
- For generating a log file from Chrome:
- <ul>
- <li><code>/path/to/chrome --user-data-dir=/var/tmp/chr1 --no-sandbox
- --js-flags='--trace-ic --trace-maps --log-source-code’
- $WEBSITE_URL</code></li>
- </ul>
- <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>
+ </section>
+
+ <div class="panels">
+ <section id="settings" class="panel">
+ <h2>Settings</h2>
+ <span>Theme:</span>
+ <div class="theme-switch-wrapper">
+ <label class="theme-switch" for="theme-switch-input">
+ <input type="checkbox" id="theme-switch-input" />
+ <div class="slider"></div>
+ </label>
+ </div>
+ </section>
+
+ <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>
+ </section>
</div>
</body>
-
</html>
diff --git a/chromium/v8/tools/system-analyzer/index.mjs b/chromium/v8/tools/system-analyzer/index.mjs
index 80e5b799486..dfc858e5d66 100644
--- a/chromium/v8/tools/system-analyzer/index.mjs
+++ b/chromium/v8/tools/system-analyzer/index.mjs
@@ -2,167 +2,178 @@
// 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 { SelectionEvent, FocusEvent, SelectTimeEvent } from "./events.mjs";
-import { State } from "./app-model.mjs";
-import { MapLogEvent } from "./log/map.mjs";
-import { IcLogEvent } from "./log/ic.mjs";
-import Processor from "./processor.mjs";
-import { SourcePosition } from "../profile.mjs";
-import { $ } from "./helper.mjs";
-import "./ic-panel.mjs";
-import "./timeline-panel.mjs";
-import "./map-panel.mjs";
-import "./log-file-reader.mjs";
-import "./source-panel.mjs";
-
+import {State} from './app-model.mjs';
+import {FocusEvent, SelectionEvent, SelectTimeEvent} from './events.mjs';
+import {$} from './helper.mjs';
+import {IcLogEntry} from './log/ic.mjs';
+import {MapLogEntry} from './log/map.mjs';
+import {Processor} from './processor.mjs';
class App {
- #state;
- #view;
- #navigation;
- constructor(fileReaderId, mapPanelId, timelinePanelId,
- icPanelId, mapTrackId, icTrackId, sourcePanelId) {
- this.#view = {
+ _state;
+ _view;
+ _navigation;
+ _startupPromise;
+ constructor(
+ fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId, icPanelId,
+ mapTrackId, icTrackId, deoptTrackId, sourcePanelId) {
+ this._view = {
+ __proto__: null,
logFileReader: $(fileReaderId),
icPanel: $(icPanelId),
mapPanel: $(mapPanelId),
+ mapStatsPanel: $(mapStatsPanelId),
timelinePanel: $(timelinePanelId),
mapTrack: $(mapTrackId),
icTrack: $(icTrackId),
+ deoptTrack: $(deoptTrackId),
sourcePanel: $(sourcePanelId)
};
- this.#state = new State();
- this.#navigation = new Navigation(this.#state, this.#view);
- document.addEventListener('keydown',
- e => this.#navigation.handleKeyDown(e));
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
- this.toggleSwitch.addEventListener("change", (e) => this.switchTheme(e));
- this.#view.logFileReader.addEventListener("fileuploadstart", (e) =>
- this.handleFileUpload(e)
- );
- this.#view.logFileReader.addEventListener("fileuploadend", (e) =>
- this.handleDataUpload(e)
- );
- Object.entries(this.#view).forEach(([_, panel]) => {
- panel.addEventListener(SelectionEvent.name,
- e => this.handleShowEntries(e));
- panel.addEventListener(FocusEvent.name,
- e => this.handleShowEntryDetail(e));
- panel.addEventListener(SelectTimeEvent.name,
- e => this.handleTimeRangeSelect(e));
- });
+ this.toggleSwitch.addEventListener('change', (e) => this.switchTheme(e));
+ this._view.logFileReader.addEventListener(
+ 'fileuploadstart', (e) => this.handleFileUploadStart(e));
+ this._view.logFileReader.addEventListener(
+ 'fileuploadend', (e) => this.handleFileUploadEnd(e));
+ this._startupPromise = this.runAsyncInitialize();
+ }
+
+ 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'),
+ ]);
+ document.addEventListener(
+ 'keydown', e => this._navigation?.handleKeyDown(e));
+ document.addEventListener(
+ SelectionEvent.name, e => this.handleShowEntries(e));
+ document.addEventListener(
+ FocusEvent.name, e => this.handleShowEntryDetail(e));
+ document.addEventListener(
+ SelectTimeEvent.name, e => this.handleTimeRangeSelect(e));
}
+
handleShowEntries(e) {
- if (e.entries[0] instanceof MapLogEvent) {
+ if (e.entries[0] instanceof MapLogEntry) {
this.showMapEntries(e.entries);
- } else if (e.entries[0] instanceof IcLogEvent) {
+ } 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!");
+ throw new Error('Unknown selection type!');
}
+ e.stopPropagation();
}
showMapEntries(entries) {
- this.#state.selectedMapLogEvents = entries;
- this.#view.mapPanel.selectedMapLogEvents = this.#state.selectedMapLogEvents;
+ this._state.selectedMapLogEntries = entries;
+ this._view.mapPanel.selectedMapLogEntries = entries;
+ this._view.mapStatsPanel.selectedLogEntries = entries;
}
showIcEntries(entries) {
- this.#state.selectedIcLogEvents = entries;
- this.#view.icPanel.selectedLogEvents = this.#state.selectedIcLogEvents;
+ this._state.selectedIcLogEntries = entries;
+ this._view.icPanel.selectedLogEntries = entries;
+ }
+ showDeoptEntries(entries) {
+ this._state.selectedDeoptLogEntries = entries;
}
showSourcePositionEntries(entries) {
- //TODO(zcankara) Handle multiple source position selection events
- this.#view.sourcePanel.selectedSourcePositions = entries;
+ // TODO: Handle multiple source position selection events
+ this._view.sourcePanel.selectedSourcePositions = entries
}
handleTimeRangeSelect(e) {
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._view.timelinePanel.timeSelection = {start, end};
}
+
handleShowEntryDetail(e) {
- if (e.entry instanceof MapLogEvent) {
- this.selectMapLogEvent(e.entry);
- } else if (e.entry instanceof IcLogEvent) {
- this.selectICLogEvent(e.entry);
+ 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.selectSourcePositionEvent(e.entry);
+ this.selectSourcePosition(e.entry);
} else {
- throw new Error("Unknown selection type!");
+ throw new Error('Unknown selection type!');
}
+ e.stopPropagation();
}
- selectTimeRange(start, end) {
- this.#state.timeSelection.start = start;
- this.#state.timeSelection.end = end;
- this.#state.icTimeline.selectTimeRange(start, end);
- this.#state.mapTimeline.selectTimeRange(start, end);
- this.#view.mapPanel.selectedMapLogEvents =
- this.#state.mapTimeline.selection;
- this.#view.icPanel.selectedLogEvents = this.#state.icTimeline.selection;
- }
- selectMapLogEvent(entry) {
- this.#state.map = entry;
- this.#view.mapTrack.selectedEntry = entry;
- this.#view.mapPanel.map = entry;
+ selectMapLogEntry(entry) {
+ this._state.map = entry;
+ this._view.mapTrack.selectedEntry = entry;
+ this._view.mapPanel.map = entry;
}
- selectICLogEvent(entry) {
- this.#state.ic = entry;
- this.#view.icPanel.selectedLogEvents = [entry];
+ selectICLogEntry(entry) {
+ this._state.ic = entry;
+ this._view.icPanel.selectedLogEntries = [entry];
}
- selectSourcePositionEvent(sourcePositions) {
+ selectSourcePosition(sourcePositions) {
if (!sourcePositions.script) return;
- this.#view.sourcePanel.selectedSourcePositions = [sourcePositions];
+ this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
}
- handleFileUpload(e) {
+ handleFileUploadStart(e) {
this.restartApp();
- $("#container").className = "initial";
+ $('#container').className = 'initial';
}
+
restartApp() {
- this.#state = new State();
- this.#navigation = new Navigation(this.#state, this.#view);
- }
- // Event log processing
- handleLoadTextProcessor(text) {
- let logProcessor = new Processor();
- logProcessor.processString(text);
- return logProcessor;
+ this._state = new State();
+ this._navigation = new Navigation(this._state, this._view);
}
- // call when a new file uploaded
- handleDataUpload(e) {
- if (!e.detail) return;
- $("#container").className = "loaded";
- // instantiate the app logic
- let fileData = e.detail;
- const processor = this.handleLoadTextProcessor(fileData.chunk);
- const mapTimeline = processor.mapTimeline;
- const icTimeline = processor.icTimeline;
- //TODO(zcankara) Make sure only one instance of src event map ic id match
- // Load map log events timeline.
- this.#state.mapTimeline = mapTimeline;
- // Transitions must be set before timeline for stats panel.
- this.#view.mapPanel.transitions = this.#state.mapTimeline.transitions;
- this.#view.mapTrack.data = mapTimeline;
- this.#state.chunks = this.#view.mapTrack.chunks;
- this.#view.mapPanel.timeline = mapTimeline;
- // Load ic log events timeline.
- this.#state.icTimeline = icTimeline;
- this.#view.icPanel.timeline = icTimeline;
- this.#view.icTrack.data = icTimeline;
- this.#view.sourcePanel.data = processor.scripts
- this.fileLoaded = true;
+ async handleFileUploadEnd(e) {
+ await this._startupPromise;
+ try {
+ const processor = new Processor(e.detail);
+ 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.
+ 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
+ } catch (e) {
+ this._view.logFileReader.error = 'Log file contains errors!'
+ throw (e);
+ } finally {
+ $('#container').className = 'loaded';
+ this.fileLoaded = true;
+ }
}
refreshTimelineTrackView() {
- this.#view.mapTrack.data = this.#state.mapTimeline;
- this.#view.icTrack.data = this.#state.icTimeline;
+ this._view.mapTrack.data = this._state.mapTimeline;
+ this._view.icTrack.data = this._state.icTimeline;
+ this._view.deoptTrack.data = this._state.deoptTimeline;
}
switchTheme(event) {
- document.documentElement.dataset.theme = event.target.checked
- ? "light"
- : "dark";
+ document.documentElement.dataset.theme =
+ event.target.checked ? 'light' : 'dark';
if (this.fileLoaded) {
this.refreshTimelineTrackView();
}
@@ -170,10 +181,10 @@ class App {
}
class Navigation {
- #view;
+ _view;
constructor(state, view) {
this.state = state;
- this.#view = view;
+ this._view = view;
}
get map() {
return this.state.map
@@ -182,37 +193,37 @@ class Navigation {
this.state.map = value
}
get chunks() {
- return this.state.chunks
+ return this.state.mapTimeline.chunks;
}
increaseTimelineResolution() {
- this.#view.timelinePanel.nofChunks *= 1.5;
+ this._view.timelinePanel.nofChunks *= 1.5;
this.state.nofChunks *= 1.5;
}
decreaseTimelineResolution() {
- this.#view.timelinePanel.nofChunks /= 1.5;
+ this._view.timelinePanel.nofChunks /= 1.5;
this.state.nofChunks /= 1.5;
}
selectNextEdge() {
if (!this.map) return;
if (this.map.children.length != 1) return;
this.map = this.map.children[0].to;
- this.#view.mapTrack.selectedEntry = this.map;
+ this._view.mapTrack.selectedEntry = this.map;
this.updateUrl();
- this.#view.mapPanel.map = this.map;
+ this._view.mapPanel.map = this.map;
}
selectPrevEdge() {
if (!this.map) return;
if (!this.map.parent()) return;
this.map = this.map.parent();
- this.#view.mapTrack.selectedEntry = this.map;
+ this._view.mapTrack.selectedEntry = this.map;
this.updateUrl();
- this.#view.mapPanel.map = this.map;
+ this._view.mapPanel.map = this.map;
}
selectDefaultMap() {
this.map = this.chunks[0].at(0);
- this.#view.mapTrack.selectedEntry = this.map;
+ this._view.mapTrack.selectedEntry = this.map;
this.updateUrl();
- this.#view.mapPanel.map = this.map;
+ this._view.mapPanel.map = this.map;
}
moveInChunks(next) {
if (!this.map) return this.selectDefaultMap();
@@ -227,9 +238,9 @@ class Navigation {
if (!chunk) return;
index = Math.min(index, chunk.size() - 1);
this.map = chunk.at(index);
- this.#view.mapTrack.selectedEntry = this.map;
+ this._view.mapTrack.selectedEntry = this.map;
this.updateUrl();
- this.#view.mapPanel.map = this.map;
+ this._view.mapPanel.map = this.map;
}
moveInChunk(delta) {
if (!this.map) return this.selectDefaultMap();
@@ -245,9 +256,9 @@ class Navigation {
map = chunk.at(index);
}
this.map = map;
- this.#view.mapTrack.selectedEntry = this.map;
+ this._view.mapTrack.selectedEntry = this.map;
this.updateUrl();
- this.#view.mapPanel.map = this.map;
+ this._view.mapPanel.map = this.map;
}
updateUrl() {
let entries = this.state.entries;
@@ -256,7 +267,7 @@ class Navigation {
}
handleKeyDown(event) {
switch (event.key) {
- case "ArrowUp":
+ case 'ArrowUp':
event.preventDefault();
if (event.shiftKey) {
this.selectPrevEdge();
@@ -264,7 +275,7 @@ class Navigation {
this.moveInChunk(-1);
}
return false;
- case "ArrowDown":
+ case 'ArrowDown':
event.preventDefault();
if (event.shiftKey) {
this.selectNextEdge();
@@ -272,20 +283,20 @@ class Navigation {
this.moveInChunk(1);
}
return false;
- case "ArrowLeft":
+ case 'ArrowLeft':
this.moveInChunks(false);
break;
- case "ArrowRight":
+ case 'ArrowRight':
this.moveInChunks(true);
break;
- case "+":
+ case '+':
this.increaseTimelineResolution();
break;
- case "-":
+ case '-':
this.decreaseTimelineResolution();
break;
}
}
}
-export { App };
+export {App};
diff --git a/chromium/v8/tools/system-analyzer/log-file-reader-template.html b/chromium/v8/tools/system-analyzer/log-file-reader-template.html
index e20ce1ea207..e54d45990af 100644
--- a/chromium/v8/tools/system-analyzer/log-file-reader-template.html
+++ b/chromium/v8/tools/system-analyzer/log-file-reader-template.html
@@ -7,26 +7,26 @@ found in the LICENSE file. -->
</head>
<style>
#fileReader {
- width: 100%;
height: 100px;
line-height: 100px;
text-align: center;
- border-radius: 5px;
cursor: pointer;
transition: all 0.5s ease-in-out;
- border: 2px solid var(--primary-color);
background-color: var(--surface-color);
}
+
+ #fileReader:hover {
+ background-color: var(--primary-color);
+ color: var(--on-primary-color);
+ }
- #fileReader.done {
+ .done #fileReader{
height: 20px;
line-height: 20px;
- box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
}
- #fileReader:hover {
- background-color: var(--primary-color);
- color: var(--on-primary-color);
+ .fail #fileReader {
+ background-color: var(--error-color);
}
.loading #fileReader {
@@ -50,7 +50,6 @@ found in the LICENSE file. -->
height: 100%;
background-color: var(--file-reader-background-color);
}
-
#spinner {
position: absolute;
width: 100px;
@@ -74,9 +73,8 @@ found in the LICENSE file. -->
}
}
</style>
-
-<section id="fileReaderSection">
- <div id="fileReader" tabindex=1>
+<div id="root">
+ <div id="fileReader" class="panel" tabindex=1>
<span id="label">
Drag and drop a v8.log file into this area, or click to choose from disk.
</span>
@@ -85,4 +83,4 @@ found in the LICENSE file. -->
<div id="loader">
<div id="spinner"></div>
</div>
-</section>
+</div>
diff --git a/chromium/v8/tools/system-analyzer/log-file-reader.mjs b/chromium/v8/tools/system-analyzer/log-file-reader.mjs
index 4b5238d89d2..c46d792d006 100644
--- a/chromium/v8/tools/system-analyzer/log-file-reader.mjs
+++ b/chromium/v8/tools/system-analyzer/log-file-reader.mjs
@@ -1,80 +1,84 @@
// 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 { defineCustomElement, V8CustomElement } from './helper.mjs';
+import {DOM, V8CustomElement} from './helper.mjs';
-defineCustomElement('log-file-reader', (templateText) =>
- class LogFileReader extends V8CustomElement {
- constructor() {
- super(templateText);
- this.addEventListener('click', e => this.handleClick(e));
- this.addEventListener('dragover', e => this.handleDragOver(e));
- this.addEventListener('drop', e => this.handleChange(e));
- this.$('#file').addEventListener('change', e => this.handleChange(e));
- this.$('#fileReader').addEventListener('keydown',
- e => this.handleKeyEvent(e));
- }
+DOM.defineCustomElement('log-file-reader',
+ (templateText) =>
+ class LogFileReader extends V8CustomElement {
+ constructor() {
+ super(templateText);
+ this.addEventListener('click', e => this.handleClick(e));
+ this.addEventListener('dragover', e => this.handleDragOver(e));
+ this.addEventListener('drop', e => this.handleChange(e));
+ this.$('#file').addEventListener('change', e => this.handleChange(e));
+ this.$('#fileReader')
+ .addEventListener('keydown', e => this.handleKeyEvent(e));
+ }
- get section() {
- return this.$('#fileReaderSection');
- }
+ set error(message) {
+ this._updateLabel(message);
+ this.root.className = 'fail';
+ }
- updateLabel(text) {
- this.$('#label').innerText = text;
- }
+ _updateLabel(text) {
+ this.$('#label').innerText = text;
+ }
- handleKeyEvent(event) {
- if (event.key == "Enter") this.handleClick(event);
- }
+ handleKeyEvent(event) {
+ if (event.key == 'Enter') this.handleClick(event);
+ }
- handleClick(event) {
- this.$('#file').click();
- }
+ handleClick(event) {
+ this.$('#file').click();
+ }
- handleChange(event) {
- // Used for drop and file change.
- event.preventDefault();
- this.dispatchEvent(new CustomEvent(
- 'fileuploadstart', { bubbles: true, composed: true }));
- var host = event.dataTransfer ? event.dataTransfer : event.target;
- this.readFile(host.files[0]);
- }
+ handleChange(event) {
+ // Used for drop and file change.
+ event.preventDefault();
+ this.dispatchEvent(
+ new CustomEvent('fileuploadstart', {bubbles: true, composed: true}));
+ const host = event.dataTransfer ? event.dataTransfer : event.target;
+ this.readFile(host.files[0]);
+ }
- handleDragOver(event) {
- event.preventDefault();
- }
+ handleDragOver(event) {
+ event.preventDefault();
+ }
- connectedCallback() {
- this.$('#fileReader').focus();
- }
+ connectedCallback() {
+ this.fileReader.focus();
+ }
+
+ get fileReader() {
+ return this.$('#fileReader');
+ }
- readFile(file) {
- if (!file) {
- this.updateLabel('Failed to load file.');
- return;
- }
- this.$('#fileReader').blur();
- this.section.className = 'loading';
- const reader = new FileReader();
- reader.onload = (e) => {
- try {
- let dataModel = Object.create(null);
- dataModel.file = file;
- dataModel.chunk = e.target.result;
- this.updateLabel('Finished loading \'' + file.name + '\'.');
- this.dispatchEvent(new CustomEvent(
- 'fileuploadend', {
- bubbles: true, composed: true,
- detail: dataModel
- }));
- this.section.className = 'success';
- this.$('#fileReader').classList.add('done');
- } catch (err) {
- console.error(err);
- this.section.className = 'failure';
- }
- };
- // Delay the loading a bit to allow for CSS animations to happen.
- setTimeout(() => reader.readAsText(file), 0);
+ get root() {
+ return this.$('#root');
+ }
+
+ readFile(file) {
+ if (!file) {
+ this.error = 'Failed to load file.';
+ return;
}
- });
+ this.fileReader.blur();
+ this.root.className = 'loading';
+ const reader = new FileReader();
+ reader.onload = (e) => this.handleFileLoad(e, file);
+ // Delay the loading a bit to allow for CSS animations to happen.
+ setTimeout(() => reader.readAsText(file), 0);
+ }
+
+ handleFileLoad(e, file) {
+ const chunk = e.target.result;
+ this._updateLabel(`Finished loading '${file.name}'.`);
+ this.dispatchEvent(new CustomEvent('fileuploadend', {
+ bubbles: true,
+ composed: true,
+ detail: chunk,
+ }));
+ this.root.className = 'done';
+ }
+});
diff --git a/chromium/v8/tools/system-analyzer/log/deopt.mjs b/chromium/v8/tools/system-analyzer/log/deopt.mjs
new file mode 100644
index 00000000000..f3ff1a71a26
--- /dev/null
+++ b/chromium/v8/tools/system-analyzer/log/deopt.mjs
@@ -0,0 +1,10 @@
+// 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/chromium/v8/tools/system-analyzer/log/ic.mjs b/chromium/v8/tools/system-analyzer/log/ic.mjs
index 5001e60c364..b6c7ec55537 100644
--- a/chromium/v8/tools/system-analyzer/log/ic.mjs
+++ b/chromium/v8/tools/system-analyzer/log/ic.mjs
@@ -1,12 +1,12 @@
// 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 { Event } from './log.mjs';
+import {LogEntry} from './log.mjs';
-class IcLogEvent extends Event {
+export class IcLogEntry extends LogEntry {
constructor(
- type, fn_file, time, line, column, key, oldState, newState, map, reason,
- script, additional) {
+ type, fn_file, time, line, column, key, oldState, newState, map, reason,
+ script, modifier, additional) {
super(type, time);
this.category = 'other';
if (this.type.indexOf('Store') !== -1) {
@@ -27,9 +27,9 @@ class IcLogEvent extends Event {
this.reason = reason;
this.additional = additional;
this.script = script;
+ this.modifier = modifier;
}
-
parseMapProperties(parts, offset) {
let next = parts[++offset];
if (!next.startsWith('dict')) return offset;
@@ -55,6 +55,11 @@ class IcLogEvent extends Event {
this.file = parts[offset];
return offset;
}
-}
-export { IcLogEvent };
+ static get propertyNames() {
+ return [
+ 'type', 'category', 'functionName', 'filePosition', 'state', 'key', 'map',
+ 'reason', 'file'
+ ];
+ }
+}
diff --git a/chromium/v8/tools/system-analyzer/log/log.mjs b/chromium/v8/tools/system-analyzer/log/log.mjs
index 2945f0e76b8..69195d78538 100644
--- a/chromium/v8/tools/system-analyzer/log/log.mjs
+++ b/chromium/v8/tools/system-analyzer/log/log.mjs
@@ -2,21 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
-class Event {
- #time;
- #type;
+export class LogEntry {
+ _time;
+ _type;
constructor(type, time) {
- //TODO(zcankara) remove type and add empty getters to override
- this.#time = time;
- this.#type = type;
+ // TODO(zcankara) remove type and add empty getters to override
+ this._time = time;
+ this._type = type;
}
get time() {
- return this.#time;
+ return this._time;
}
get type() {
- return this.#type;
+ return this._type;
}
-}
-
-export { Event };
+ // Returns an Array of all possible #type values.
+ static get allTypes() {
+ throw new Error('Not implemented.');
+ }
+} \ No newline at end of file
diff --git a/chromium/v8/tools/system-analyzer/log/map.mjs b/chromium/v8/tools/system-analyzer/log/map.mjs
index 38c8a9a63a7..4df6fb847c2 100644
--- a/chromium/v8/tools/system-analyzer/log/map.mjs
+++ b/chromium/v8/tools/system-analyzer/log/map.mjs
@@ -2,20 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import { typeToColor } from '../helper.mjs';
-import { Event } from './log.mjs';
+import {LogEntry} from './log.mjs';
// ===========================================================================
// Map Log Events
-const kChunkHeight = 250;
+const kChunkHeight = 200;
const kChunkWidth = 10;
function define(prototype, name, fn) {
- Object.defineProperty(prototype, name, { value: fn, enumerable: false });
+ Object.defineProperty(prototype, name, {value: fn, enumerable: false});
}
-define(Array.prototype, 'max', function (fn) {
+define(Array.prototype, 'max', function(fn) {
if (this.length === 0) return undefined;
if (fn === undefined) fn = (each) => each;
let max = fn(this[0]);
@@ -24,22 +23,21 @@ define(Array.prototype, 'max', function (fn) {
}
return max;
})
-define(Array.prototype, 'first', function () {
+define(Array.prototype, 'first', function() {
return this[0]
});
-define(Array.prototype, 'last', function () {
+define(Array.prototype, 'last', function() {
return this[this.length - 1]
});
// ===========================================================================
// Map Log Events
-class MapLogEvent extends Event {
+class MapLogEntry extends LogEntry {
edge = void 0;
children = [];
depth = 0;
- // TODO(zcankara): Change this to private class field.
- #isDeprecated = false;
+ _isDeprecated = false;
deprecatedTargets = null;
leftId = 0;
rightId = 0;
@@ -49,7 +47,7 @@ class MapLogEvent extends Event {
constructor(id, time) {
if (!time) throw new Error('Invalid time');
super(id, time);
- MapLogEvent.set(id, this);
+ MapLogEntry.set(id, this);
this.id = id;
}
@@ -58,7 +56,7 @@ class MapLogEvent extends Event {
while (stack.length > 0) {
let current = stack.pop();
if (current.leftId !== 0) {
- console.error('Skipping potential parent loop between maps:', current)
+ console.warn('Skipping potential parent loop between maps:', current)
continue;
}
current.finalize(id)
@@ -82,11 +80,11 @@ class MapLogEvent extends Event {
}
isDeprecated() {
- return this.#isDeprecated;
+ return this._isDeprecated;
}
deprecate() {
- this.#isDeprecated = true;
+ this._isDeprecated = true;
}
isRoot() {
@@ -172,7 +170,7 @@ class MapLogEvent extends Event {
}
}
-MapLogEvent.cache = new Map();
+MapLogEntry.cache = new Map();
// ===========================================================================
class Edge {
@@ -185,24 +183,20 @@ class Edge {
this.to = to;
}
- getColor() {
- return typeToColor(this.type);
- }
-
finishSetup() {
- let from = this.from;
+ const from = this.from;
if (from) from.addEdge(this);
- let to = this.to;
+ const to = this.to;
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.error('invalid time order');
+ console.warn('invalid time order');
}
let newDepth = from.depth + 1;
if (to.depth > 0 && to.depth != newDepth) {
- console.error('Depth has already been initialized');
+ console.warn('Depth has already been initialized');
}
to.depth = newDepth;
}
@@ -288,9 +282,8 @@ class Edge {
return this.type + ' ' + this.symbol() + this.name;
}
return this.type + ' ' + (this.reason ? this.reason : '') + ' ' +
- (this.name ? this.name : '')
+ (this.name ? this.name : '')
}
}
-
-export { MapLogEvent, Edge, kChunkWidth, kChunkHeight };
+export {MapLogEntry, Edge, kChunkWidth, kChunkHeight};
diff --git a/chromium/v8/tools/system-analyzer/map-panel-template.html b/chromium/v8/tools/system-analyzer/map-panel-template.html
index 6363a6d7c3d..12d6ec5a14c 100644
--- a/chromium/v8/tools/system-analyzer/map-panel-template.html
+++ b/chromium/v8/tools/system-analyzer/map-panel-template.html
@@ -10,7 +10,6 @@ found in the LICENSE file. -->
width: 200px;
}
</style>
-<stats-panel id="stats-panel"></stats-panel>
<div class="panel">
<h2>Map Panel</h2>
<map-transitions id="map-transitions"></map-transitions>
diff --git a/chromium/v8/tools/system-analyzer/map-panel.mjs b/chromium/v8/tools/system-analyzer/map-panel.mjs
index c78bce91a28..1516038a2df 100644
--- a/chromium/v8/tools/system-analyzer/map-panel.mjs
+++ b/chromium/v8/tools/system-analyzer/map-panel.mjs
@@ -1,90 +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.
-import "./stats-panel.mjs";
-import "./map-panel/map-details.mjs";
-import "./map-panel/map-transitions.mjs";
-import { FocusEvent } from './events.mjs';
-import { MapLogEvent } from "./log/map.mjs";
-import { defineCustomElement, V8CustomElement } from './helper.mjs';
+import './stats-panel.mjs';
+import './map-panel/map-details.mjs';
+import './map-panel/map-transitions.mjs';
-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));
- }
+import {FocusEvent} from './events.mjs';
+import {DOM, V8CustomElement} from './helper.mjs';
+import {MapLogEntry} from './log/map.mjs';
- handleUpdateMapDetails(e) {
- if (e.entry instanceof MapLogEvent) {
- this.mapDetailsPanel.mapDetails = e.entry;
- }
- }
+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));
+ }
- get statsPanel() {
- return this.$('#stats-panel');
+ handleUpdateMapDetails(e) {
+ if (e.entry instanceof MapLogEntry) {
+ this.mapDetailsPanel.map = e.entry;
}
+ }
- get mapTransitionsPanel() {
- return this.$('#map-transitions');
- }
+ get mapTransitionsPanel() {
+ return this.$('#map-transitions');
+ }
- get mapDetailsPanel() {
- return this.$('#map-details');
- }
+ get mapDetailsPanel() {
+ return this.$('#map-details');
+ }
- get searchBarBtn() {
- return this.$('#searchBarBtn');
- }
+ get searchBarBtn() {
+ return this.$('#searchBarBtn');
+ }
- get searchBar() {
- return this.$('#searchBar');
- }
+ get searchBar() {
+ return this.$('#searchBar');
+ }
- get mapDetails() {
- return this.mapDetailsPanel.mapDetails;
- }
+ set timeline(timeline) {
+ this._timeline = timeline;
+ }
- // send a timeline to the stats-panel
- set timeline(value) {
- console.assert(value !== undefined, "timeline undefined!");
- this.statsPanel.timeline = value;
- this.statsPanel.update();
- }
- get transitions() {
- return this.statsPanel.transitions;
- }
- set transitions(value) {
- this.statsPanel.transitions = value;
- }
-
- set map(value) {
- this.#map = value;
- this.mapTransitionsPanel.map = this.#map;
- }
+ 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 = MapLogEvent.get(parseInt(searchBarInput));
- if (selectedMap) {
- searchBar.className = "success";
- } else {
- searchBar.className = "failure";
- }
- this.dispatchEvent(new FocusEvent(selectedMap));
- }
-
- set selectedMapLogEvents(list) {
- this.mapTransitionsPanel.selectedMapLogEvents = list;
- }
- get selectedMapLogEvents() {
- return this.mapTransitionsPanel.selectedMapLogEvents;
+ 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/chromium/v8/tools/system-analyzer/map-panel/map-details.mjs b/chromium/v8/tools/system-analyzer/map-panel/map-details.mjs
index d471609dba8..bcf8f9c9aa1 100644
--- a/chromium/v8/tools/system-analyzer/map-panel/map-details.mjs
+++ b/chromium/v8/tools/system-analyzer/map-panel/map-details.mjs
@@ -1,48 +1,47 @@
// 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 { V8CustomElement, defineCustomElement } from "../helper.mjs";
-import { FocusEvent } from "../events.mjs";
+import {FocusEvent} from '../events.mjs';
+import {DOM, V8CustomElement} from '../helper.mjs';
+
+DOM.defineCustomElement(
+ './map-panel/map-details',
+ (templateText) => class MapDetails extends V8CustomElement {
+ _map;
-defineCustomElement(
- "./map-panel/map-details",
- (templateText) =>
- class MapDetails extends V8CustomElement {
constructor() {
super(templateText);
- this.#filePositionNode.addEventListener("click", e =>
- this.handleFilePositionClick(e)
- );
- this.selectedMap = undefined;
+ this._filePositionNode.onclick = e => this._handleFilePositionClick(e);
}
- get mapDetails() {
- return this.$("#mapDetails");
+
+ get _mapDetails() {
+ return this.$('#mapDetails');
}
- get #filePositionNode() {
- return this.$("#filePositionNode");
+ get _filePositionNode() {
+ return this.$('#filePositionNode');
}
- setSelectedMap(value) {
- this.selectedMap = value;
+ set map(map) {
+ if (this._map === map) return;
+ this._map = map;
+ this.update();
}
- set mapDetails(map) {
- let details = "";
- let clickableDetails = "";
- if (map) {
- clickableDetails += "ID: " + map.id;
- clickableDetails += "\nSource location: " + map.filePosition;
- details += "\n" + map.description;
- this.setSelectedMap(map);
+ _update() {
+ let details = '';
+ let clickableDetails = '';
+ if (this._map) {
+ clickableDetails = `ID: ${this._map.id}`;
+ clickableDetails += `\nSource location: ${this._map.filePosition}`;
+ details = this._map.description;
}
- this.#filePositionNode.innerText = clickableDetails;
- this.#filePositionNode.classList.add("clickable");
- this.mapDetails.innerText = details;
+ this._filePositionNode.innerText = clickableDetails;
+ this._filePositionNode.classList.add('clickable');
+ this._mapDetails.innerText = details;
}
- handleFilePositionClick() {
- this.dispatchEvent(new FocusEvent(this.selectedMap.sourcePosition));
+ _handleFilePositionClick(event) {
+ this.dispatchEvent(new FocusEvent(this._map.sourcePosition));
}
- }
-);
+ });
diff --git a/chromium/v8/tools/system-analyzer/map-panel/map-transitions-template.html b/chromium/v8/tools/system-analyzer/map-panel/map-transitions-template.html
index 99fb251b195..c4cab2bf46a 100644
--- a/chromium/v8/tools/system-analyzer/map-panel/map-transitions-template.html
+++ b/chromium/v8/tools/system-analyzer/map-panel/map-transitions-template.html
@@ -41,7 +41,7 @@ found in the LICENSE file. -->
}
.map.selected {
- border-color: var(--map-background-color);
+ border-color: var(--on-surface-color);
}
.transitions {
diff --git a/chromium/v8/tools/system-analyzer/map-panel/map-transitions.mjs b/chromium/v8/tools/system-analyzer/map-panel/map-transitions.mjs
index d508b886949..60462a1db22 100644
--- a/chromium/v8/tools/system-analyzer/map-panel/map-transitions.mjs
+++ b/chromium/v8/tools/system-analyzer/map-panel/map-transitions.mjs
@@ -1,194 +1,184 @@
// 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 { V8CustomElement, defineCustomElement } from "../helper.mjs";
-import { FocusEvent } from "../events.mjs";
-
-defineCustomElement(
- "./map-panel/map-transitions",
- (templateText) =>
- class MapTransitions extends V8CustomElement {
- #map;
- #selectedMapLogEvents;
- 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";
- let map = e.target.map;
- if (map) {
- this.tooltipContents.innerText = map.description;
- }
- }
-
- selectMap(map) {
- this.currentMap = map;
- this.showMap();
- this.dispatchEvent(new FocusEvent(map));
- }
-
- dblClickSelectMap(map) {
- this.dispatchEvent(new FocusEvent(map));
- }
-
- showMap() {
- // Called when a map selected
- if (this.currentMap === this.#map) return;
- this.currentMap = this.#map;
- this.selectedMapLogEvents = [this.#map];
- this.dispatchEvent(new FocusEvent(this.#map));
- }
-
- showMaps() {
- // Timeline dbl click to show map transitions of selected maps
- this.transitionView.style.display = "none";
- this.removeAllChildren(this.transitionView);
- this.selectedMapLogEvents.forEach((map) =>
- this.addMapAndParentTransitions(map));
- this.transitionView.style.display = "";
- }
-
- set selectedMapLogEvents(list) {
- this.#selectedMapLogEvents = list;
- this.showMaps();
- }
-
- get selectedMapLogEvents() {
- return this.#selectedMapLogEvents;
- }
-
- addMapAndParentTransitions(map) {
- if (map === void 0) return;
- 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
- );
- }
- }
-
- addMapNode(map) {
- let node = this.div("map");
- if (map.edge) node.style.backgroundColor = map.edge.getColor();
- node.map = map;
- node.addEventListener("click", () => this.selectMap(map));
- node.addEventListener("dblclick", () => this.dblClickSelectMap(map));
- if (map.children.length > 1) {
- node.innerText = map.children.length;
- let showSubtree = this.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;
- }
-
- 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 = this.div(classes);
- edge.style.backgroundColor = map.edge.getColor();
- let labelNode = this.div("transitionLabel");
- labelNode.innerText = map.edge.toString();
- edge.appendChild(labelNode);
- return edge;
- }
-
- addTransitionTo(map) {
- // transition[ transitions[ transition[...], transition[...], ...]];
-
- let transition = this.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 = this.div("transitions");
- transition.appendChild(subtree);
-
- this.currentNode.appendChild(transition);
- this.currentNode = subtree;
-
- return mapNode;
- }
-
- 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]);
- }
+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/chromium/v8/tools/system-analyzer/processor.mjs b/chromium/v8/tools/system-analyzer/processor.mjs
index 0634174aefb..49448bb9da0 100644
--- a/chromium/v8/tools/system-analyzer/processor.mjs
+++ b/chromium/v8/tools/system-analyzer/processor.mjs
@@ -2,23 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import { MapLogEvent, Edge } from "./log/map.mjs";
-import { IcLogEvent } from "./log/ic.mjs";
-import { Timeline } from "./timeline.mjs";
-import { LogReader, parseString, parseVarArgs } from "../logreader.mjs";
-import { Profile } from "../profile.mjs";
+import {LogReader, parseString, parseVarArgs} from '../logreader.mjs';
+import {Profile} from '../profile.mjs';
-// ===========================================================================
+import {DeoptLogEntry} from './log/deopt.mjs';
+import {IcLogEntry} from './log/ic.mjs';
+import {Edge, MapLogEntry} from './log/map.mjs';
+import {Timeline} from './timeline.mjs';
+// ===========================================================================
-class Processor extends LogReader {
- #profile = new Profile();
- #mapTimeline = new Timeline();
- #icTimeline = new Timeline();
- #formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
+export class Processor extends LogReader {
+ _profile = new Profile();
+ _mapTimeline = new Timeline();
+ _icTimeline = new Timeline();
+ _deoptTimeline = new Timeline();
+ _formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
MAJOR_VERSION = 7;
MINOR_VERSION = 6;
- constructor() {
+ constructor(logString) {
super();
this.propertyICParser = [
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
@@ -33,9 +35,17 @@ class Processor extends LogReader {
],
processor: this.processCodeCreation
},
+ 'code-deopt': {
+ parsers: [
+ parseInt, parseInt, parseInt, parseInt, parseInt, parseString,
+ parseString, parseString
+ ],
+ processor: this.processCodeDeopt
+ },
'v8-version': {
parsers: [
- parseInt, parseInt,
+ parseInt,
+ parseInt,
],
processor: this.processV8Version
},
@@ -44,12 +54,12 @@ class Processor extends LogReader {
processor: this.processScriptSource
},
'code-move':
- { parsers: [parseInt, parseInt], processor: this.processCodeMove },
- 'code-delete': { parsers: [parseInt], processor: this.processCodeDelete },
+ {parsers: [parseInt, parseInt], processor: this.processCodeMove},
+ 'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
'sfi-move':
- { parsers: [parseInt, parseInt], processor: this.processFunctionMove },
+ {parsers: [parseInt, parseInt], processor: this.processFunctionMove},
'map-create':
- { parsers: [parseInt, parseString], processor: this.processMapCreate },
+ {parsers: [parseInt, parseString], processor: this.processMapCreate},
'map': {
parsers: [
parseString, parseInt, parseString, parseString, parseInt, parseInt,
@@ -90,6 +100,7 @@ class Processor extends LogReader {
processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
},
};
+ if (logString) this.processString(logString);
}
printError(str) {
@@ -114,7 +125,7 @@ class Processor extends LogReader {
this.processLogLine(line);
}
} catch (e) {
- console.error('Error occurred during parsing, trying to continue: ' + e);
+ console.error(`Error occurred during parsing, trying to continue: ${e}`);
}
this.finalize();
}
@@ -131,23 +142,23 @@ class Processor extends LogReader {
}
} catch (e) {
console.error(
- 'Error occurred during parsing line ' + i +
- ', trying to continue: ' + e);
+ `Error occurred during parsing line ${i}` +
+ ', trying to continue: ' + e);
}
this.finalize();
}
finalize() {
// TODO(cbruni): print stats;
- this.#mapTimeline.transitions = new Map();
+ this._mapTimeline.transitions = new Map();
let id = 0;
- this.#mapTimeline.forEach(map => {
+ this._mapTimeline.forEach(map => {
if (map.isRoot()) id = map.finalizeRootMap(id + 1);
if (map.edge && map.edge.name) {
- let edge = map.edge;
- let list = this.#mapTimeline.transitions.get(edge.name);
+ const edge = map.edge;
+ const list = this._mapTimeline.transitions.get(edge.name);
if (list === undefined) {
- this.#mapTimeline.transitions.set(edge.name, [edge]);
+ this._mapTimeline.transitions.set(edge.name, [edge]);
} else {
list.push(edge);
}
@@ -167,45 +178,50 @@ class Processor extends LogReader {
case '*':
return Profile.CodeState.OPTIMIZED;
}
- throw new Error('unknown code state: ' + s);
+ throw new Error(`unknown code state: ${s}`);
}
processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
if (maybe_func.length) {
- let funcAddr = parseInt(maybe_func[0]);
- let state = this.parseState(maybe_func[1]);
- this.#profile.addFuncCode(
- type, name, timestamp, start, size, funcAddr, state);
+ const funcAddr = parseInt(maybe_func[0]);
+ const state = this.parseState(maybe_func[1]);
+ this._profile.addFuncCode(
+ type, name, timestamp, start, size, funcAddr, state);
} else {
- this.#profile.addCode(type, name, timestamp, start, size);
+ this._profile.addCode(type, name, timestamp, start, size);
}
}
+ 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)) {
+ 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.`);
+ `Unsupported version ${majorVersion}.${minorVersion}. \n` +
+ `Please use the matching tool for given the V8 version.`);
}
}
processScriptSource(scriptId, url, source) {
- this.#profile.addScriptSource(scriptId, url, source);
+ this._profile.addScriptSource(scriptId, url, source);
}
processCodeMove(from, to) {
- this.#profile.moveCode(from, to);
+ this._profile.moveCode(from, to);
}
processCodeDelete(start) {
- this.#profile.deleteCode(start);
+ this._profile.deleteCode(start);
}
processFunctionMove(from, to) {
- this.#profile.moveFunc(from, to);
+ this._profile.moveFunc(from, to);
}
formatName(entry) {
@@ -218,34 +234,34 @@ class Processor extends LogReader {
}
processPropertyIC(
- type, pc, time, line, column, old_state, new_state, map, key, modifier,
- slow_reason) {
+ type, pc, time, line, column, old_state, new_state, map, key, modifier,
+ slow_reason) {
let fnName = this.functionName(pc);
let parts = fnName.split(' ');
- let fileName = parts[1];
+ let fileName = parts[parts.length - 1];
let script = this.getScript(fileName);
// TODO: Use SourcePosition here directly
- let entry = new IcLogEvent(
- type, fnName, time, line, column, key, old_state, new_state, map,
- slow_reason, script);
+ let entry = new IcLogEntry(
+ type, fnName, time, line, column, key, old_state, new_state, map,
+ slow_reason, script, modifier);
if (script) {
entry.sourcePosition = script.addSourcePosition(line, column, entry);
}
- this.#icTimeline.push(entry);
+ this._icTimeline.push(entry);
}
functionName(pc) {
- let entry = this.#profile.findEntry(pc);
+ let entry = this._profile.findEntry(pc);
return this.formatName(entry);
}
formatPC(pc, line, column) {
- let entry = this.#profile.findEntry(pc);
+ let entry = this._profile.findEntry(pc);
if (!entry) return '<unknown>'
- if (entry.type === 'Builtin') {
- return entry.name;
- }
+ if (entry.type === 'Builtin') {
+ return entry.name;
+ }
let name = entry.func.getName();
- let array = this.#formatPCRegexp.exec(name);
+ let array = this._formatPCRegexp.exec(name);
if (array === null) {
entry = name;
} else {
@@ -255,22 +271,27 @@ class Processor extends LogReader {
}
processFileName(filePositionLine) {
- if (!(/\s/.test(filePositionLine))) return;
+ if (!filePositionLine.includes(' ')) return;
+ // Try to handle urls with file positions: https://foo.bar.com/:17:330"
filePositionLine = filePositionLine.split(' ');
- let file = filePositionLine[1].split(':')[0];
- return file;
+ let parts = filePositionLine[1].split(':');
+ if (parts[0].length <= 5) return parts[0] + ':' + parts[1];
+ return parts[1];
}
processMap(type, time, from, to, pc, line, column, reason, name) {
let time_ = parseInt(time);
if (type === 'Deprecate') return this.deprecateMap(type, time_, from);
- let from_ = this.getExistingMap(from, time_);
- let to_ = this.getExistingMap(to, time_);
+ let from_ = this.getExistingMapEntry(from, time_);
+ let to_ = this.getExistingMapEntry(to, time_);
// 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);
- to_.script = this.getScript(fileName);
+ // TODO: avoid undefined source positions.
+ if (fileName !== undefined) {
+ to_.script = this.getScript(fileName);
+ }
if (to_.script) {
to_.sourcePosition = to_.script.addSourcePosition(line, column, to_)
}
@@ -278,40 +299,40 @@ class Processor extends LogReader {
}
deprecateMap(type, time, id) {
- this.getExistingMap(id, time).deprecate();
+ this.getExistingMapEntry(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.createMap(id, time);
+ let map = this.createMapEntry(id, time);
}
processMapDetails(time, id, string) {
// TODO(cbruni): fix initial map logging.
- let map = this.getExistingMap(id, time);
+ let map = this.getExistingMapEntry(id, time);
map.description = string;
}
- createMap(id, time) {
- let map = new MapLogEvent(id, time);
- this.#mapTimeline.push(map);
+ createMapEntry(id, time) {
+ let map = new MapLogEntry(id, time);
+ this._mapTimeline.push(map);
return map;
}
- getExistingMap(id, time) {
+ getExistingMapEntry(id, time) {
if (id === '0x000000000000') return undefined;
- let map = MapLogEvent.get(id, time);
+ let map = MapLogEntry.get(id, time);
if (map === undefined) {
- console.error('No map details provided: id=' + id);
+ console.error(`No map details provided: id=${id}`);
// Manually patch in a map to continue running.
- return this.createMap(id, time);
+ return this.createMapEntry(id, time);
};
return map;
}
getScript(url) {
- const script = this.#profile.getScript(url);
+ const script = this._profile.getScript(url);
// TODO create placeholder script for empty urls.
if (script === undefined) {
console.error(`Could not find script for url: '${url}'`)
@@ -320,28 +341,18 @@ class Processor extends LogReader {
}
get icTimeline() {
- return this.#icTimeline;
+ return this._icTimeline;
}
get mapTimeline() {
- return this.#mapTimeline;
+ return this._mapTimeline;
+ }
+
+ get deoptTimeline() {
+ return this._deoptTimeline;
}
get scripts() {
- return this.#profile.scripts_.filter(script => script !== undefined);
+ return this._profile.scripts_.filter(script => script !== undefined);
}
}
-
-Processor.kProperties = [
- 'type',
- 'category',
- 'functionName',
- 'filePosition',
- 'state',
- 'key',
- 'map',
- 'reason',
- 'file'
-];
-
-export { Processor as default };
diff --git a/chromium/v8/tools/system-analyzer/source-panel-template.html b/chromium/v8/tools/system-analyzer/source-panel-template.html
index 102d30ea282..01b777042f3 100644
--- a/chromium/v8/tools/system-analyzer/source-panel-template.html
+++ b/chromium/v8/tools/system-analyzer/source-panel-template.html
@@ -19,7 +19,7 @@ found in the LICENSE file. -->
}
pre.scriptNode span::before {
- content: counter(sourceLineCounter) " ";
+ content: counter(sourceLineCounter) ": ";
display: inline-block;
width: 4em;
padding-left: auto;
@@ -27,26 +27,28 @@ found in the LICENSE file. -->
text-align: right;
}
-mark {
- width: 1ch;
- height: 1lh;
- border-radius: 0.1lh;
- border: 0.5px var(--background-color) solid;
- cursor: pointer;
-}
+ 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);
+ }
-.marked {
- background-color: var(--primary-color);
- color: var(--on-primary-color);
-}
+ #script-dropdown {
+ width: 100%;
+ margin-bottom: 10px;
+ }
</style>
<div class="panel">
<h2>Source Panel</h2>
- <div class="script-dropdown">
- <label for="scripts-label">Scripts:</label>
- <select id="script-dropdown"></select>
- </div>
- <div id="script">
+ <select id="script-dropdown"></select>
+ <div id="script" class="panelBody">
<pre class="scripNode"></pre>
</div>
</div>
diff --git a/chromium/v8/tools/system-analyzer/source-panel.mjs b/chromium/v8/tools/system-analyzer/source-panel.mjs
index a10f2bccd27..a4dc07fb451 100644
--- a/chromium/v8/tools/system-analyzer/source-panel.mjs
+++ b/chromium/v8/tools/system-analyzer/source-panel.mjs
@@ -1,127 +1,173 @@
// 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 { V8CustomElement, defineCustomElement } from "./helper.mjs";
-import { SelectionEvent, FocusEvent } from "./events.mjs";
-import { MapLogEvent } from "./log/map.mjs";
-import { IcLogEvent } from "./log/ic.mjs";
-
-defineCustomElement(
- "source-panel",
- (templateText) =>
- class SourcePanel extends V8CustomElement {
- #selectedSourcePositions;
- #scripts = [];
- #script;
- constructor() {
- super(templateText);
- this.scriptDropdown.addEventListener(
- 'change', e => this.handleSelectScript(e));
- }
- get script() {
- return this.$('#script');
- }
- get scriptNode() {
- return this.$('.scriptNode');
- }
- set script(script) {
- this.#script = script;
- this.renderSourcePanel();
- }
- set selectedSourcePositions(sourcePositions) {
- this.#selectedSourcePositions = sourcePositions;
- }
- get selectedSourcePositions() {
- return this.#selectedSourcePositions;
- }
- set data(value) {
- this.#scripts = value;
- this.initializeScriptDropdown();
- this.script = this.#scripts[0];
- }
- get scriptDropdown() {
- return this.$("#script-dropdown");
- }
- initializeScriptDropdown() {
- this.#scripts.sort((a, b) => a.name.localeCompare(b.name));
- let select = this.scriptDropdown;
- select.options.length = 0;
- for (const script of this.#scripts) {
- const option = document.createElement("option");
- option.text = `${script.name} (id=${script.id})`;
- option.script = script;
- select.add(option);
- }
- }
+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';
+
+DOM.defineCustomElement('source-panel',
+ (templateText) =>
+ class SourcePanel extends V8CustomElement {
+ _selectedSourcePositions = [];
+ _sourcePositionsToMarkNodes;
+ _scripts = [];
+ _script;
+ constructor() {
+ super(templateText);
+ this.scriptDropdown.addEventListener(
+ 'change', e => this._handleSelectScript(e));
+ }
- renderSourcePanel() {
- const builder = new LineBuilder(this, this.#script);
- const scriptNode = builder.createScriptNode();
- const oldScriptNode = this.script.childNodes[1];
- this.script.replaceChild(scriptNode, oldScriptNode);
- }
+ get script() {
+ return this.$('#script');
+ }
- handleSelectScript(e) {
- const option = this.scriptDropdown.options[this.scriptDropdown.selectedIndex];
- this.script = option.script;
- }
+ get scriptNode() {
+ return this.$('.scriptNode');
+ }
- handleSourcePositionClick(e) {
- let icLogEvents = [];
- let mapLogEvents = [];
- for (const entry of e.target.sourcePosition.entries) {
- if (entry instanceof MapLogEvent) {
- mapLogEvents.push(entry);
- } else if (entry instanceof IcLogEvent) {
- icLogEvents.push(entry);
- }
- }
- if (icLogEvents.length > 0 ) {
- this.dispatchEvent(new SelectionEvent(icLogEvents));
- this.dispatchEvent(new FocusEvent(icLogEvents[0]));
- }
- if (mapLogEvents.length > 0) {
- this.dispatchEvent(new SelectionEvent(mapLogEvents));
- this.dispatchEvent(new FocusEvent(mapLogEvents[0]));
- }
- }
+ set script(script) {
+ if (this._script === script) return;
+ this._script = script;
+ this._renderSourcePanel();
+ this._updateScriptDropdownSelection();
+ }
+
+ set selectedSourcePositions(sourcePositions) {
+ this._selectedSourcePositions = sourcePositions;
+ // TODO: highlight multiple scripts
+ this.script = sourcePositions[0]?.script;
+ this._focusSelectedMarkers();
+ }
+
+ set data(scripts) {
+ this._scripts = scripts;
+ this._initializeScriptDropdown();
+ }
+
+ get scriptDropdown() {
+ return this.$('#script-dropdown');
+ }
+
+ _initializeScriptDropdown() {
+ this._scripts.sort((a, b) => a.name.localeCompare(b.name));
+ let select = this.scriptDropdown;
+ select.options.length = 0;
+ for (const script of this._scripts) {
+ const option = document.createElement('option');
+ const size = formatBytes(script.source.length);
+ option.text = `${script.name} (id=${script.id} size=${size})`;
+ option.script = script;
+ select.add(option);
+ }
+ }
+ _updateScriptDropdownSelection() {
+ this.scriptDropdown.selectedIndex =
+ this._script ? this._scripts.indexOf(this._script) : -1;
+ }
+
+ async _renderSourcePanel() {
+ let scriptNode;
+ if (this._script) {
+ await delay(1);
+ const builder =
+ new LineBuilder(this, this._script, this._selectedSourcePositions);
+ scriptNode = builder.createScriptNode();
+ this._sourcePositionsToMarkNodes = builder.sourcePositionToMarkers;
+ } else {
+ scriptNode = document.createElement('pre');
+ this._selectedMarkNodes = undefined;
+ }
+ const oldScriptNode = this.script.childNodes[1];
+ this.script.replaceChild(scriptNode, oldScriptNode);
+ }
+ async _focusSelectedMarkers() {
+ await delay(100);
+ // Remove all marked nodes.
+ for (let markNode of this._sourcePositionsToMarkNodes.values()) {
+ markNode.className = '';
+ }
+ for (let sourcePosition of this._selectedSourcePositions) {
+ this._sourcePositionsToMarkNodes.get(sourcePosition).className = 'marked';
}
-);
+ const sourcePosition = this._selectedSourcePositions[0];
+ if (!sourcePosition) return;
+ const markNode = this._sourcePositionsToMarkNodes.get(sourcePosition);
+ markNode.scrollIntoView(
+ {behavior: 'smooth', block: 'nearest', inline: 'center'});
+ }
+
+ _handleSelectScript(e) {
+ const option =
+ this.scriptDropdown.options[this.scriptDropdown.selectedIndex];
+ this.script = option.script;
+ this.selectLogEntries(this._script.entries());
+ }
+ 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));
+ }
+ }
+});
class SourcePositionIterator {
- #entries;
- #index = 0;
+ _entries;
+ _index = 0;
constructor(sourcePositions) {
- this.#entries = sourcePositions;
+ this._entries = sourcePositions;
+ }
+
+ * forLine(lineIndex) {
+ this._findStart(lineIndex);
+ while (!this._done() && this._current().line === lineIndex) {
+ yield this._current();
+ this._next();
+ }
}
- *forLine(lineIndex) {
- while(!this.#done() && this.#current().line === lineIndex) {
- yield this.#current();
- this.#next();
+ _findStart(lineIndex) {
+ while (!this._done() && this._current().line < lineIndex) {
+ this._next();
}
}
- #current() {
- return this.#entries[this.#index];
+ _current() {
+ return this._entries[this._index];
}
- #done() {
- return this.#index + 1 >= this.#entries.length;
+ _done() {
+ return this._index + 1 >= this._entries.length;
}
- #next() {
- this.#index++;
+ _next() {
+ this._index++;
}
}
-function * lineIterator(source) {
+function* lineIterator(source) {
let current = 0;
let line = 1;
- while(current < source.length) {
- const next = source.indexOf("\n", current);
+ while (current < source.length) {
+ const next = source.indexOf('\n', current);
if (next === -1) break;
yield [line, source.substring(current, next)];
line++;
@@ -131,59 +177,61 @@ function * lineIterator(source) {
}
class LineBuilder {
- #script
- #clickHandler
- #sourcePositions
-
- constructor(panel, script) {
- this.#script = script;
- this.#clickHandler = panel.handleSourcePositionClick.bind(panel);
+ _script;
+ _clickHandler;
+ _sourcePositions;
+ _selection;
+ _sourcePositionToMarkers = new Map();
+
+ constructor(panel, script, highlightPositions) {
+ this._script = script;
+ this._selection = new Set(highlightPositions);
+ this._clickHandler = panel.handleSourcePositionClick.bind(panel);
// TODO: sort on script finalization.
script.sourcePositions.sort((a, b) => {
if (a.line === b.line) return a.column - b.column;
return a.line - b.line;
- })
- this.#sourcePositions
- = new SourcePositionIterator(script.sourcePositions);
+ });
+ this._sourcePositions = new SourcePositionIterator(script.sourcePositions);
+ }
+ get sourcePositionToMarkers() {
+ return this._sourcePositionToMarkers;
}
createScriptNode() {
- const scriptNode = document.createElement("pre");
+ const scriptNode = document.createElement('pre');
scriptNode.classList.add('scriptNode');
- for (let [lineIndex, line] of lineIterator(this.#script.source)) {
- scriptNode.appendChild(this.#createLineNode(lineIndex, line));
+ for (let [lineIndex, line] of lineIterator(this._script.source)) {
+ scriptNode.appendChild(this._createLineNode(lineIndex, line));
}
return scriptNode;
}
- #createLineNode(lineIndex, line) {
- const lineNode = document.createElement("span");
- let columnIndex = 0;
- for (const sourcePosition of this.#sourcePositions.forLine(lineIndex)) {
+ _createLineNode(lineIndex, line) {
+ const lineNode = document.createElement('span');
+ let columnIndex = 0;
+ for (const sourcePosition of this._sourcePositions.forLine(lineIndex)) {
const nextColumnIndex = sourcePosition.column - 1;
- lineNode.appendChild(
- document.createTextNode(
- line.substring(columnIndex, nextColumnIndex)));
+ lineNode.appendChild(document.createTextNode(
+ line.substring(columnIndex, nextColumnIndex)));
columnIndex = nextColumnIndex;
lineNode.appendChild(
- this.#createMarkerNode(line[columnIndex], sourcePosition));
+ this._createMarkerNode(line[columnIndex], sourcePosition));
columnIndex++;
}
lineNode.appendChild(
- document.createTextNode(line.substring(columnIndex) + "\n"));
+ document.createTextNode(line.substring(columnIndex) + '\n'));
return lineNode;
}
- #createMarkerNode(text, sourcePosition) {
- const marker = document.createElement("mark");
- marker.classList.add('marked');
+ _createMarkerNode(text, sourcePosition) {
+ const marker = document.createElement('mark');
+ this._sourcePositionToMarkers.set(sourcePosition, marker);
marker.textContent = text;
marker.sourcePosition = sourcePosition;
- marker.onclick = this.#clickHandler;
+ marker.onclick = this._clickHandler;
return marker;
}
-
-
} \ No newline at end of file
diff --git a/chromium/v8/tools/system-analyzer/stats-panel-template.html b/chromium/v8/tools/system-analyzer/stats-panel-template.html
index 7aa149a5881..fb91fad1cf0 100644
--- a/chromium/v8/tools/system-analyzer/stats-panel-template.html
+++ b/chromium/v8/tools/system-analyzer/stats-panel-template.html
@@ -14,43 +14,60 @@ found in the LICENSE file. -->
margin: auto;
}
- #stats table {
+ table {
flex: 1;
- padding-right: 50px;
max-height: 250px;
display: inline-block;
overflow-y: scroll;
+ border-collapse: collapse;
+ }
+ table td {
+ padding: 2px;
}
- #stats table td {
- cursor: pointer;
+ table thead td {
+ border-bottom: 1px var(--on-surface-color) dotted;
}
- #stats .transitionTable {
- overflow-y: scroll;
+ table tbody td {
+ cursor: pointer;
}
- #stats .transitionTable tr {
+ #nameTable tr {
max-width: 200px;
}
- #stats .transitionType {
+ #nameTable tr td:nth-child(1) {
text-align: right;
- max-width: 380px;
}
- #stats .transitionType tr td:nth-child(2) {
- text-align: left;
+ #typeTable {
+ text-align: right;
+ max-width: 380px;
}
- #stats table thead td {
- border-bottom: 1px var(--on-surface-color) dotted;
+ #typeTable tr td:nth-child(2) {
+ text-align: left;
}
</style>
<div class="panel">
- <h2>Stats Panel</h2>
- <h3>Stats</h3>
+ <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/chromium/v8/tools/system-analyzer/stats-panel.mjs b/chromium/v8/tools/system-analyzer/stats-panel.mjs
index 9e637015bc0..dd0ac78489a 100644
--- a/chromium/v8/tools/system-analyzer/stats-panel.mjs
+++ b/chromium/v8/tools/system-analyzer/stats-panel.mjs
@@ -1,43 +1,40 @@
// 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 { V8CustomElement, defineCustomElement } from "./helper.mjs";
-import { SelectionEvent } from "./events.mjs";
+import {SelectionEvent} from './events.mjs';
+import {DOM, V8CustomElement} from './helper.mjs';
+import {delay, LazyTable} from './helper.mjs';
-defineCustomElement(
- "stats-panel",
- (templateText) =>
- class StatsPanel extends V8CustomElement {
- #timeline;
- #transitions;
+DOM.defineCustomElement(
+ 'stats-panel', (templateText) => class StatsPanel extends V8CustomElement {
+ _timeline;
+ _transitions;
+ _selectedLogEntries;
constructor() {
super(templateText);
}
get stats() {
- return this.$("#stats");
+ return this.$('#stats');
}
- set timeline(value) {
- //TODO(zcankara) Trigger update
- this.#timeline = value;
+ set timeline(timeline) {
+ this._timeline = timeline;
+ this.selectedLogEntries = timeline.all
}
- get timeline() {
- return this.#timeline;
+ set selectedLogEntries(entries) {
+ this._selectedLogEntries = entries;
+ this.update();
}
set transitions(value) {
- this.#transitions = value;
+ this._transitions = value;
}
- get transitions() {
- return this.#transitions;
- }
-
- filterUniqueTransitions(filter) {
+ _filterUniqueTransitions(filter) {
// Returns a list of Maps whose parent is not in the list.
- return this.timeline.filter((map) => {
+ return this._selectedLogEntries.filter((map) => {
if (filter(map) === false) return false;
let parent = map.parent();
if (parent === undefined) return true;
@@ -45,95 +42,88 @@ defineCustomElement(
});
}
- update() {
- this.removeAllChildren(this.stats);
- this.updateGeneralStats();
- this.updateNamedTransitionsStats();
+ _update() {
+ this._updateGeneralStats();
+ this._updateNamedTransitionsStats();
}
- updateGeneralStats() {
- console.assert(this.#timeline !== undefined, "Timeline not set yet!");
+ _updateGeneralStats() {
+ console.assert(this._timeline !== undefined, 'Timeline not set yet!');
let pairs = [
- ["Total", null, (e) => true],
- ["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()],
+ ['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",
+ 'Replace Descriptors',
+ 'red',
(e) => e.edge && e.edge.isReplaceDescriptors(),
],
[
- "Copy as Prototype",
- "red",
+ 'Copy as Prototype',
+ 'red',
(e) => e.edge && e.edge.isCopyAsPrototype(),
],
[
- "Optimize as Prototype",
+ 'Optimize as Prototype',
null,
(e) => e.edge && e.edge.isOptimizeAsPrototype(),
],
- ["Deprecated", null, (e) => e.isDeprecated()],
- ["Bootstrapped", "green", (e) => e.isBootstrapped()],
+ ['Deprecated', null, (e) => e.isDeprecated()],
+ ['Bootstrapped', 'green', (e) => e.isBootstrapped()],
+ ['Total', null, (e) => true],
];
- let text = "";
- let tableNode = this.table("transitionType");
- tableNode.innerHTML =
- "<thead><tr><td>Color</td><td>Type</td><td>Count</td>" +
- "<td>Percent</td></tr></thead>";
- let name, filter;
- let total = this.timeline.size();
+ let tbody = document.createElement('tbody');
+ let total = this._selectedLogEntries.length;
pairs.forEach(([name, color, filter]) => {
- let row = this.tr();
+ let row = DOM.tr();
if (color !== null) {
- row.appendChild(this.td(this.div(["colorbox", color])));
+ row.appendChild(DOM.td(DOM.div(['colorbox', color])));
} else {
- row.appendChild(this.td(""));
+ 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);
+ node.maps = this._filterUniqueTransitions(filter);
}
this.dispatchEvent(new SelectionEvent(node.maps));
};
- row.appendChild(this.td(name));
- let count = this.timeline.count(filter);
- row.appendChild(this.td(count));
+ 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(this.td(percent.toFixed(1) + "%"));
- tableNode.appendChild(row);
+ row.appendChild(DOM.td(percent.toFixed(1) + '%'));
+ tbody.appendChild(row);
});
- this.stats.appendChild(tableNode);
+ 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 tableNode = this.table("transitionTable");
- let nameMapPairs = Array.from(this.transitions.entries());
- tableNode.innerHTML =
- "<thead><tr><td>Propery Name</td><td>#</td></tr></thead>";
- nameMapPairs
- .sort((a, b) => b[1].length - a[1].length)
- .forEach(([name, maps]) => {
- let row = this.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(this.td(name));
- row.appendChild(this.td(maps.length));
- tableNode.appendChild(row);
- });
- this.stats.appendChild(tableNode);
+ _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/chromium/v8/tools/system-analyzer/timeline-panel-template.html b/chromium/v8/tools/system-analyzer/timeline-panel-template.html
index dd869947166..2641c714414 100644
--- a/chromium/v8/tools/system-analyzer/timeline-panel-template.html
+++ b/chromium/v8/tools/system-analyzer/timeline-panel-template.html
@@ -5,54 +5,9 @@ found in the LICENSE file. -->
<head>
<link href="./index.css" rel="stylesheet">
</head>
-<style>
- #timelineOverview {
- width: 100%;
- height: 50px;
- position: relative;
- margin-top: -50px;
- margin-bottom: 10px;
- background-size: 100% 100%;
- border: 1px var(--primary-color) solid;
- border-width: 1px 0 1px 0;
- overflow: hidden;
- }
-
- #timelineOverviewIndicator {
- height: 100%;
- position: absolute;
- box-shadow: 0px 2px 20px -5px var(--primary-color) inset;
- top: 0px;
- cursor: ew-resize;
- }
-
- #timelineOverviewIndicator .leftMask,
- #timelineOverviewIndicator .rightMask {
- background-color: rgba(240, 230, 230, 0.3);
- width: 10000px;
- height: 100%;
- position: absolute;
- top: 0px;
- }
-
- #timelineOverviewIndicator .leftMask {
- right: 100%;
- }
-
- #timelineOverviewIndicator .rightMask {
- left: 100%;
- }
-</style>
<div class="panel">
<h2>Timeline Panel</h2>
- <h3>Timeline</h3>
<div>
<slot></slot>
</div>
- <div id="timelineOverview">
- <div id="timelineOverviewIndicator">
- <div class="leftMask"></div>
- <div class="rightMask"></div>
- </div>
- </div>
</div>
diff --git a/chromium/v8/tools/system-analyzer/timeline-panel.mjs b/chromium/v8/tools/system-analyzer/timeline-panel.mjs
index afe05c24bdd..a61d2efc905 100644
--- a/chromium/v8/tools/system-analyzer/timeline-panel.mjs
+++ b/chromium/v8/tools/system-analyzer/timeline-panel.mjs
@@ -2,92 +2,54 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import { defineCustomElement, V8CustomElement } from './helper.mjs';
-import { SynchronizeSelectionEvent } from './events.mjs';
import './timeline/timeline-track.mjs';
-defineCustomElement('timeline-panel', (templateText) =>
- class TimelinePanel extends V8CustomElement {
- #timeSelection = { start: 0, end: Infinity };
- constructor() {
- super(templateText);
- this.timelineOverview.addEventListener(
- 'mousemove', e => this.handleTimelineIndicatorMove(e));
- this.addEventListener(
- 'scrolltrack', e => this.handleTrackScroll(e));
- this.addEventListener(
- SynchronizeSelectionEvent.name, e => this.handleMouseMoveSelection(e));
- this.backgroundCanvas = document.createElement('canvas');
- this.isLocked = false;
- }
-
- get timelineOverview() {
- return this.$('#timelineOverview');
- }
-
- get timelineOverviewIndicator() {
- return this.$('#timelineOverviewIndicator');
- }
-
- //TODO(zcankara) Remove dependency to timelineCanvas here
- get timelineCanvas() {
- return this.timelineTracks[0].timelineCanvas;
- }
- //TODO(zcankara) Remove dependency to timeline here
- get timeline() {
- return this.timelineTracks[0].timeline;
- }
- set nofChunks(count) {
- for (const track of this.timelineTracks) {
- track.nofChunks = count;
+import {SynchronizeSelectionEvent} from './events.mjs';
+import {DOM, V8CustomElement} from './helper.mjs';
+
+DOM.defineCustomElement(
+ 'timeline-panel',
+ (templateText) => class TimelinePanel extends V8CustomElement {
+ constructor() {
+ super(templateText);
+ this.addEventListener('scrolltrack', e => this.handleTrackScroll(e));
+ this.addEventListener(
+ SynchronizeSelectionEvent.name,
+ e => this.handleSelectionSyncronization(e));
}
- }
- get nofChunks() {
- return this.timelineTracks[0].nofChunks;
- }
- get timelineTracks() {
- return this.$("slot").assignedNodes().filter(
- track => track.nodeType === Node.ELEMENT_NODE);
- }
- handleTrackScroll(event) {
- //TODO(zcankara) add forEachTrack helper method
- for (const track of this.timelineTracks) {
- track.scrollLeft = event.detail;
+
+ set nofChunks(count) {
+ for (const track of this.timelineTracks) {
+ track.nofChunks = count;
+ }
}
- }
- handleMouseMoveSelection(event) {
- this.selectionMouseMove(event.start, event.end);
- }
+ get nofChunks() {
+ return this.timelineTracks[0].nofChunks;
+ }
- selectionMouseMove(start, end) {
- for (const track of this.timelineTracks) {
- track.startTime = start;
- track.endTime = end;
+ get timelineTracks() {
+ return this.$('slot').assignedNodes().filter(
+ node => node.nodeType === Node.ELEMENT_NODE);
}
- }
- handleTimelineIndicatorMove(event) {
- if (event.buttons == 0) return;
- let timelineTotalWidth = this.timelineCanvas.offsetWidth;
- let factor = this.timelineOverview.offsetWidth / timelineTotalWidth;
- for (const track of this.timelineTracks) {
- track.timelineIndicatorMove(event.movementX / factor);
+ handleTrackScroll(event) {
+ // TODO(zcankara) add forEachTrack helper method
+ for (const track of this.timelineTracks) {
+ track.scrollLeft = event.detail;
+ }
}
- this.updateOverviewWindow();
- }
- updateOverviewWindow() {
- let indicator = this.timelineOverviewIndicator;
- let totalIndicatorWidth =
- this.timelineOverview.offsetWidth;
- let div = this.timeline;
- let timelineTotalWidth = this.timelineCanvas.offsetWidth;
- let factor = totalIndicatorWidth / timelineTotalWidth;
- let width = div.offsetWidth * factor;
- let left = div.scrollLeft * factor;
- indicator.style.width = width + 'px';
- indicator.style.left = left + 'px';
- }
+ handleSelectionSyncronization(event) {
+ this.timeSelection = {start: event.start, end: event.end};
+ }
- });
+ set timeSelection(timeSelection) {
+ if (timeSelection.start > timeSelection.end) {
+ throw new Error('Invalid time range');
+ }
+ for (const track of this.timelineTracks) {
+ track.timeSelection = timeSelection;
+ }
+ }
+ });
diff --git a/chromium/v8/tools/system-analyzer/timeline.mjs b/chromium/v8/tools/system-analyzer/timeline.mjs
index 16e12cc4aa4..996f108b6a4 100644
--- a/chromium/v8/tools/system-analyzer/timeline.mjs
+++ b/chromium/v8/tools/system-analyzer/timeline.mjs
@@ -3,34 +3,49 @@
// found in the LICENSE file.
class Timeline {
- #values;
- #selection;
- #uniqueTypes;
- constructor() {
- this.#values = [];
+ // Class:
+ _model;
+ // Array of #model instances:
+ _values;
+ // Current selection, subset of #values:
+ _selection;
+ _uniqueTypes;
+
+ constructor(model) {
+ this._model = model;
+ this._values = [];
this.startTime = 0;
this.endTime = 0;
}
+
+ get model() {
+ return this._model;
+ }
+
get all() {
- return this.#values;
+ return this._values;
}
+
get selection() {
- return this.#selection;
+ return this._selection;
}
+
set selection(value) {
- this.#selection = value;
+ this._selection = value;
}
+
selectTimeRange(start, end) {
- this.#selection = this.filter(
- e => e.time >= start && e.time <= end);
+ this._selection = this.filter(e => e.time >= start && e.time <= end);
}
+
getChunks(windowSizeMs) {
- //TODO(zcankara) Fill this one
+ // TODO(zcankara) Fill this one
return this.chunkSizes(windowSizeMs);
}
+
get values() {
- //TODO(zcankara) Not to break something delete later
- return this.#values;
+ // TODO(zcankara) Not to break something delete later
+ return this._values;
}
count(filter) {
@@ -49,9 +64,9 @@ class Timeline {
// Invalid insertion order, might happen without --single-process,
// finding insertion point.
let insertionPoint = this.find(time);
- this.#values.splice(insertionPoint, event);
+ this._values.splice(insertionPoint, event);
} else {
- this.#values.push(event);
+ this._values.push(event);
}
if (time > 0) {
this.endTime = Math.max(this.endTime, time);
@@ -64,7 +79,7 @@ class Timeline {
}
at(index) {
- return this.#values[index];
+ return this._values[index];
}
isEmpty() {
@@ -72,39 +87,25 @@ class Timeline {
}
size() {
- return this.#values.length;
+ return this._values.length;
+ }
+
+ get length() {
+ return this._values.length;
}
first() {
- return this.#values[0];
+ return this._values[0];
}
last() {
- return this.#values[this.#values.length - 1];
+ return this._values[this._values.length - 1];
}
duration() {
return this.last().time - this.first().time;
}
- groupByTypes() {
- this.#uniqueTypes = new Map();
- for (const entry of this.all) {
- if (!this.#uniqueTypes.has(entry.type)) {
- this.#uniqueTypes.set(entry.type, [entry]);
- } else {
- this.#uniqueTypes.get(entry.type).push(entry);
- }
- }
- }
-
- get uniqueTypes() {
- if (this.#uniqueTypes === undefined) {
- this.groupByTypes();
- }
- return this.#uniqueTypes;
- }
-
forEachChunkSize(count, fn) {
const increment = this.duration() / count;
let currentTime = this.first().time + increment;
@@ -127,7 +128,7 @@ class Timeline {
chunks(count) {
let chunks = [];
this.forEachChunkSize(count, (start, end, startTime, endTime) => {
- let items = this.#values.slice(start, end);
+ let items = this._values.slice(start, end);
chunks.push(new Chunk(chunks.length, startTime, endTime, items));
});
return chunks;
@@ -137,14 +138,14 @@ class Timeline {
const first = this.find(start);
if (first < 0) return [];
const last = this.find(end, first);
- return this.#values.slice(first, last);
+ return this._values.slice(first, last);
}
find(time, offset = 0) {
- return this.#find(this.#values, each => each.time - time, offset);
+ return this._find(this._values, each => each.time - time, offset);
}
- #find(array, cmp, offset = 0) {
+ _find(array, cmp, offset = 0) {
let min = offset;
let max = array.length;
while (min < max) {
@@ -159,16 +160,28 @@ class Timeline {
return min;
}
+ initializeTypes() {
+ const types = new Map();
+ for (const entry of this.all) {
+ types.get(entry.type)?.push(entry) ?? types.set(entry.type, [entry])
+ }
+ return this._uniqueTypes = types;
+ }
+
+ get uniqueTypes() {
+ return this._uniqueTypes ?? this.initializeTypes();
+ }
+
depthHistogram() {
- return this.#values.histogram(each => each.depth);
+ return this._values.histogram(each => each.depth);
}
fanOutHistogram() {
- return this.#values.histogram(each => each.children.length);
+ return this._values.histogram(each => each.children.length);
}
forEach(fn) {
- return this.#values.forEach(fn);
+ return this._values.forEach(fn);
}
}
@@ -239,7 +252,7 @@ class Chunk {
if (event_fn === void 0) {
event_fn = each => each;
}
- let breakdown = { __proto__: null };
+ let breakdown = {__proto__: null};
this.items.forEach(each => {
const type = event_fn(each);
const v = breakdown[type];
@@ -251,7 +264,6 @@ class Chunk {
filter() {
return this.items.filter(map => !map.parent() || !this.has(map.parent()));
}
-
}
-export { Timeline, Chunk };
+export {Timeline, Chunk};
diff --git a/chromium/v8/tools/system-analyzer/timeline/timeline-track-template.html b/chromium/v8/tools/system-analyzer/timeline/timeline-track-template.html
index 93f30747be7..e14b927e4b3 100644
--- a/chromium/v8/tools/system-analyzer/timeline/timeline-track-template.html
+++ b/chromium/v8/tools/system-analyzer/timeline/timeline-track-template.html
@@ -8,11 +8,10 @@ found in the LICENSE file. -->
<style>
#timeline {
position: relative;
- height: 300px;
+ height: calc(200px + 12px);
overflow-y: hidden;
overflow-x: scroll;
user-select: none;
- background-color: var(--timeline-background-color);
}
#timelineLabel {
@@ -20,20 +19,20 @@ found in the LICENSE file. -->
transform-origin: left bottom 0;
position: absolute;
left: 0;
- width: 250px;
+ width: 200px;
text-align: center;
font-size: 10px;
opacity: 0.5;
}
#timelineChunks {
- height: 250px;
+ height: 200px;
position: absolute;
margin-right: 100px;
}
#timelineCanvas {
- height: 250px;
+ height: 200px;
position: relative;
overflow: visible;
pointer-events: none;
@@ -41,40 +40,54 @@ found in the LICENSE file. -->
.chunk {
width: 6px;
- border: 0px var(--timeline-background-color) solid;
- border-width: 0 2px 0 2px;
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: 250px;
+ height: 200px;
width: 100px;
- border-left: 1px var(--surface-color) dashed;
+ border-left: 1px var(--on-surface-color) dashed;
padding-left: 4px;
position: absolute;
pointer-events: none;
font-size: 10px;
- opacity: 0.5;
}
#legend {
position: relative;
float: right;
- text-align: center;
width: 100%;
max-width: 280px;
padding-left: 20px;
padding-top: 10px;
+ border-collapse: collapse;
}
th,
td {
width: 200px;
- text-align: center;
- padding: 5px;
+ 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 {
@@ -90,35 +103,36 @@ found in the LICENSE file. -->
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;
- z-index: 2;
}
</style>
-<div class="timeline">
- <div id="legend">
- <table>
- <thead>
- <tr>
- <td>Color</td>
- <td>Type</td>
- <td>Count</td>
- <td>Percent</td>
- </tr>
- </thead>
- <tbody id="legendContent">
- </tbody>
- </table>
- </div>
- <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>
-</div>
+<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/chromium/v8/tools/system-analyzer/timeline/timeline-track.mjs b/chromium/v8/tools/system-analyzer/timeline/timeline-track.mjs
index 4905b782f22..a37bcce2c56 100644
--- a/chromium/v8/tools/system-analyzer/timeline/timeline-track.mjs
+++ b/chromium/v8/tools/system-analyzer/timeline/timeline-track.mjs
@@ -2,503 +2,517 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import {
- defineCustomElement, V8CustomElement,
- typeToColor, CSSColor
-} from '../helper.mjs';
-import { kChunkWidth, kChunkHeight } from "../log/map.mjs";
-import {
- SelectionEvent, FocusEvent, SelectTimeEvent,
- SynchronizeSelectionEvent
-} from '../events.mjs';
-
-defineCustomElement('./timeline/timeline-track', (templateText) =>
- class TimelineTrack extends V8CustomElement {
- static SELECTION_OFFSET = 20;
- #timeline;
- #nofChunks = 400;
- #chunks;
- #selectedEntry;
- #timeToPixel;
- #timeSelection = { start: 0, end: Infinity };
- #isSelected = false;
- #timeStartOffset;
- #mouseDownTime;
- 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;
- }
+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) {
- if (e.target.className === "chunk") return;
- this.#isSelected = true;
- this.#mouseDownTime = this.positionToTime(e.clientX);
- }
- handleTimeSelectionMouseMove(e) {
- if (!this.#isSelected) return;
- let mouseMoveTime = this.positionToTime(e.clientX);
- let startTime = this.#mouseDownTime;
- let endTime = mouseMoveTime;
- if (this.isOnLeftHandle(e.clientX)) {
- startTime = mouseMoveTime;
- endTime = this.positionToTime(this.rightHandlePosX);
- } else if (this.isOnRightHandle(e.clientX)) {
- startTime = this.positionToTime(this.leftHandlePosX);
- endTime = mouseMoveTime;
- }
- this.dispatchEvent(new SynchronizeSelectionEvent(
- Math.min(startTime, endTime),
- Math.max(startTime, endTime)));
- }
- handleTimeSelectionMouseUp(e) {
- this.#isSelected = false;
- this.dispatchEvent(new SelectTimeEvent(this.#timeSelection.start,
- this.#timeSelection.end));
+ handleTimeSelectionMouseDown(e) {
+ let xPosition = e.clientX
+ // Update origin time in case we click on a handle.
+ if (this.isOnLeftHandle(xPosition)) {
+ xPosition = this.rightHandlePosX;
}
- isOnLeftHandle(posX) {
- return (Math.abs(this.leftHandlePosX - posX)
- <= TimelineTrack.SELECTION_OFFSET);
- }
- isOnRightHandle(posX) {
- return (Math.abs(this.rightHandlePosX - posX)
- <= TimelineTrack.SELECTION_OFFSET);
+ else if (this.isOnRightHandle(xPosition)) {
+ xPosition = this.leftHandlePosX;
}
+ this._selectionOriginTime = this.positionToTime(xPosition);
+ }
+ isOnLeftHandle(posX) {
+ return (
+ Math.abs(this.leftHandlePosX - posX) <= TimelineTrack.SELECTION_OFFSET);
+ }
- set startTime(value) {
- console.assert(
- value <= this.#timeSelection.end,
- "Selection start time greater than end time!");
- this.#timeSelection.start = value;
- this.updateSelection();
- }
- set endTime(value) {
- console.assert(
- value > this.#timeSelection.start,
- "Selection end time smaller than start time!");
- this.#timeSelection.end = value;
- this.updateSelection();
- }
+ isOnRightHandle(posX) {
+ return (
+ Math.abs(this.rightHandlePosX - posX) <=
+ TimelineTrack.SELECTION_OFFSET);
+ }
- updateSelection() {
- let startTimePos = this.timeToPosition(this.#timeSelection.start);
- let endTimePos = this.timeToPosition(this.#timeSelection.end);
- this.leftHandle.style.left = startTimePos + "px";
- this.selection.style.left = startTimePos + "px";
- this.rightHandle.style.left = endTimePos + "px";
- this.selection.style.width =
- Math.abs(this.rightHandlePosX - this.leftHandlePosX) + "px";
- }
+ 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)));
+ }
- get leftHandlePosX() {
- let leftHandlePosX = this.leftHandle.getBoundingClientRect().x;
- return leftHandlePosX;
- }
- get rightHandlePosX() {
- let rightHandlePosX = this.rightHandle.getBoundingClientRect().x;
- return rightHandlePosX;
- }
+ 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));
+ }
- // 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;
- }
+ set timeSelection(selection) {
+ this._timeSelection.start = selection.start;
+ this._timeSelection.end = selection.end;
+ this.updateSelection();
+ }
- positionToTime(posX) {
- let posTimelineX = this.positionOnTimeline(posX) + this.#timeStartOffset;
- return posTimelineX / this.#timeToPixel;
- }
+ get _isSelecting() {
+ return this._selectionOriginTime >= 0;
+ }
- timeToPosition(time) {
- let posX = time * this.#timeToPixel;
- posX -= this.#timeStartOffset
- return posX;
- }
+ 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 leftHandle() {
- return this.$('.leftHandle');
- }
- get rightHandle() {
- return this.$('.rightHandle');
- }
- get selection() {
- return this.$('.selection');
- }
+ get leftHandlePosX() {
+ return this.leftHandle.getBoundingClientRect().x;
+ }
- get timelineCanvas() {
- return this.$('#timelineCanvas');
- }
+ get rightHandlePosX() {
+ return this.rightHandle.getBoundingClientRect().x;
+ }
- get timelineChunks() {
- return this.$('#timelineChunks');
- }
+ // 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;
+ }
- get timeline() {
- return this.$('#timeline');
- }
+ positionToTime(posX) {
+ let posTimelineX = this.positionOnTimeline(posX) + this._timeStartOffset;
+ return posTimelineX / this._timeToPixel;
+ }
- get timelineLegend() {
- return this.$('#legend');
- }
+ timeToPosition(time) {
+ let posX = time * this._timeToPixel;
+ posX -= this._timeStartOffset
+ return posX;
+ }
- get timelineLegendContent() {
- return this.$('#legendContent');
- }
- set data(value) {
- this.#timeline = value;
- this.updateChunks();
- this.updateTimeline();
- this.renderLegend();
- }
+ get leftHandle() {
+ return this.$('.leftHandle');
+ }
- get data() {
- return this.#timeline;
- }
+ get rightHandle() {
+ return this.$('.rightHandle');
+ }
- set nofChunks(count) {
- this.#nofChunks = count;
- this.updateChunks();
- this.updateTimeline();
- }
- 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;
- }
+ 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();
+ }
- set scrollLeft(offset) {
- this.timeline.scrollLeft = offset;
+ _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;
+ }
- renderLegend() {
- let timelineLegend = this.timelineLegend;
- let timelineLegendContent = this.timelineLegendContent;
- this.removeAllChildren(timelineLegendContent);
- let row = this.tr();
- row.entries = this.data.all;
- row.classList.add('clickable');
+ _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));
- row.appendChild(this.td(""));
- let td = this.td("All");
+ 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(this.td(this.data.all.length));
- row.appendChild(this.td("100%"));
+ 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);
- let colorIterator = 0;
- this.#timeline.uniqueTypes.forEach((entries, type) => {
- let row = this.tr();
- row.entries = entries;
- row.classList.add('clickable');
- row.addEventListener('dblclick', e => this.handleEntryTypeDblClick(e));
- let color = typeToColor(type);
- if (color !== null) {
- let div = this.div(["colorbox"]);
- div.style.backgroundColor = color;
- row.appendChild(this.td(div));
- } else {
- row.appendChild(this.td(""));
- }
- let td = this.td(type);
- row.appendChild(td);
- row.appendChild(this.td(entries.length));
- let percent = (entries.length / this.data.all.length) * 100;
- row.appendChild(this.td(percent.toFixed(1) + "%"));
- timelineLegendContent.appendChild(row);
- colorIterator += 1;
- });
- timelineLegend.appendChild(timelineLegendContent);
- }
+ });
+ // 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));
- }
+ handleEntryTypeDblClick(e) {
+ this.dispatchEvent(new SelectionEvent(e.target.parentNode.entries));
+ }
- timelineIndicatorMove(offset) {
- this.timeline.scrollLeft += offset;
- }
+ timelineIndicatorMove(offset) {
+ this.timeline.scrollLeft += offset;
+ }
- handleTimelineScroll(e) {
- let horizontal = e.currentTarget.scrollLeft;
- this.dispatchEvent(new CustomEvent(
- 'scrolltrack', {
- bubbles: true, composed: true,
- detail: horizontal
- }));
- }
+ handleTimelineScroll(e) {
+ let horizontal = e.currentTarget.scrollLeft;
+ this.dispatchEvent(new CustomEvent(
+ 'scrolltrack', {bubbles: true, composed: true, detail: horizontal}));
+ }
- asyncSetTimelineChunkBackground(backgroundTodo) {
- const kIncrement = 100;
- let start = 0;
- let delay = 1;
- while (start < backgroundTodo.length) {
- let end = Math.min(start + kIncrement, backgroundTodo.length);
- setTimeout((from, to) => {
- for (let i = from; i < to; i++) {
- let [chunk, node] = backgroundTodo[i];
- this.setTimelineChunkBackground(chunk, node);
- }
- }, delay++, start, end);
- start = end;
+ 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);
}
+ }
- setTimelineChunkBackground(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 = typeToColor(type);
- let height = count / total * kHeight;
- ctx.fillRect(0, y, kWidth, y + height);
- y += height;
- });
- } else {
- chunk.items.forEach(map => {
- ctx.fillStyle = 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 + ')';
+ 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);
+ });
}
- updateTimeline() {
- let chunksNode = this.timelineChunks;
- this.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 = this.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 = this.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.asyncSetTimelineChunkBackground(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();
- }
+ let imageData = this.backgroundCanvas.toDataURL('image/webp', 0.2);
+ node.style.backgroundImage = `url(${imageData})`;
+ }
- handleChunkMouseMove(event) {
- if (this.isLocked) return false;
- let chunk = event.target.chunk;
- if (!chunk) return;
- // topmost map (at chunk.height) == map #0.
- let relativeIndex =
+ _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));
- }
+ let map = chunk.at(relativeIndex);
+ this.dispatchEvent(new FocusEvent(map));
+ }
- handleChunkClick(event) {
- this.isLocked = !this.isLocked;
- }
+ handleChunkClick(event) {
+ this.isLocked = !this.isLocked;
+ }
- handleChunkDoubleClick(event) {
- this.isLocked = true;
- let chunk = event.target.chunk;
- if (!chunk) return;
- let maps = chunk.items;
- this.dispatchEvent(new SelectionEvent(maps));
- }
+ 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;
- }
+ 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 = typeToColor(edge.type);
- ctx.strokeStyle = color;
- ctx.fillStyle = color;
- }
+ 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();
- }
+ 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();
- }
+ 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();
+ 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, this.selectedEntry, 3);
+ // this.drawOutgoingEdges(ctx, current, 1);
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);
}
+ // 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;
+ 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) {
- ctx.quadraticCurveTo(midX, midY, xTo, yTo);
+ centerX = (xFrom / 2 + midX + xTo / 2) / 2;
+ centerY = (yFrom / 2 + midY + yTo / 2) / 2;
} else {
- ctx.lineTo(xTo, yTo);
+ centerX = xTo;
+ centerY = 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 = typeToColor(edge.type);
- ctx.fillText(
+ 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];
}
+ 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);
- }
+ 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/chromium/v8/tools/testrunner/local/variants.py b/chromium/v8/tools/testrunner/local/variants.py
index 0f8e20536c2..4236c1678a0 100644
--- a/chromium/v8/tools/testrunner/local/variants.py
+++ b/chromium/v8/tools/testrunner/local/variants.py
@@ -12,7 +12,7 @@ ALL_VARIANT_FLAGS = {
# Alias of exhaustive variants, but triggering new test framework features.
"infra_staging": [[]],
"interpreted_regexp": [["--regexp-interpret-all"]],
- "experimental_regexp": [["--enable-experimental-regexp-engine"]],
+ "experimental_regexp": [["--default-to-experimental-regexp-engine"]],
"jitless": [["--jitless"]],
"minor_mc": [["--minor-mc"]],
"nci": [["--turbo-nci"]],
@@ -28,11 +28,13 @@ ALL_VARIANT_FLAGS = {
# For WebAssembly, we test "Liftoff-only" in the nooptimization variant and
# "TurboFan-only" in the stress variant. The WebAssembly configuration is
# independent of JS optimizations, so we can combine those configs.
- "nooptimization": [["--no-opt", "--liftoff", "--no-wasm-tier-up"]],
+ "nooptimization": [["--no-opt", "--liftoff", "--no-wasm-tier-up",
+ "--wasm-generic-wrapper"]],
"slow_path": [["--force-slow-path"]],
"stress": [["--stress-opt", "--no-liftoff", "--stress-lazy-source-positions"]],
"stress_concurrent_allocation": [["--stress-concurrent-allocation"]],
"stress_js_bg_compile_wasm_code_gc": [["--stress-background-compile",
+ "--finalize-streaming-on-background",
"--stress-wasm-code-gc"]],
"stress_incremental_marking": [["--stress-incremental-marking"]],
"stress_snapshot": [["--stress-snapshot"]],
@@ -59,10 +61,10 @@ INCOMPATIBLE_FLAGS_PER_VARIANT = {
"stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile"],
"stress": ["--no-stress-opt", "--always-opt", "--no-always-opt", "--liftoff", "--max-inlined-bytecode-size=*",
"--max-inlined-bytecode-size-cumulative=*", "--stress-inline"],
- "turboprop": ["--turbo-inlining", "--interrupt-budget=*", "--no-turboprop"],
+ "turboprop": ["--interrupt-budget=*", "--no-turboprop"],
"code_serializer": ["--cache=after-execute", "--cache=full-code-cache", "--cache=none"],
"no_local_heaps": ["--concurrent-inlining", "--turboprop"],
- "experimental_regexp": ["--no-enable-experimental-regexp-engine"],
+ "experimental_regexp": ["--no-enable-experimental-regexp-engine", "--no-default-to-experimental-regexp-engine"],
}
# Flags that lead to a contradiction under certain build variables.
diff --git a/chromium/v8/tools/testrunner/objects/testcase.py b/chromium/v8/tools/testrunner/objects/testcase.py
index 72ca01a4214..e037f996797 100644
--- a/chromium/v8/tools/testrunner/objects/testcase.py
+++ b/chromium/v8/tools/testrunner/objects/testcase.py
@@ -49,13 +49,21 @@ RESOURCES_PATTERN = re.compile(r"//\s+Resources:(.*)")
LOAD_PATTERN = re.compile(
r"(?:load|readbuffer|read)\((?:'|\")([^'\"]+)(?:'|\")\)")
# Pattern to auto-detect files to push on Android for statements like:
-# import "path/to/file.js"
-MODULE_RESOURCES_PATTERN_1 = re.compile(
- r"(?:import|export)(?:\(| )(?:'|\")([^'\"]+)(?:'|\")")
-# Pattern to auto-detect files to push on Android for statements like:
# import foobar from "path/to/file.js"
-MODULE_RESOURCES_PATTERN_2 = re.compile(
- r"(?:import|export).*from (?:'|\")([^'\"]+)(?:'|\")")
+# import {foo, bar} from "path/to/file.js"
+# export {"foo" as "bar"} from "path/to/file.js"
+MODULE_FROM_RESOURCES_PATTERN = re.compile(
+ r"(?:import|export).*?from\s*\(?['\"]([^'\"]+)['\"]",
+ re.MULTILINE | re.DOTALL)
+# Pattern to detect files to push on Android for statements like:
+# import "path/to/file.js"
+# import("module.mjs").catch()...
+MODULE_IMPORT_RESOURCES_PATTERN = re.compile(
+ r"import\s*\(?['\"]([^'\"]+)['\"]",
+ re.MULTILINE | re.DOTALL)
+# Pattern to detect and strip test262 frontmatter from tests to prevent false
+# positives for MODULE_RESOURCES_PATTERN above.
+TEST262_FRONTMATTER_PATTERN = re.compile(r"/\*---.*?---\*/", re.DOTALL)
TIMEOUT_LONG = "long"
@@ -402,19 +410,26 @@ class D8TestCase(TestCase):
result = []
def add_path(path):
result.append(os.path.abspath(path.replace('/', os.path.sep)))
+ def add_import_path(import_path):
+ add_path(os.path.normpath(
+ os.path.join(os.path.dirname(file), import_path)))
+ def strip_test262_frontmatter(input):
+ return TEST262_FRONTMATTER_PATTERN.sub('', input)
for match in RESOURCES_PATTERN.finditer(source):
# There are several resources per line. Relative to base dir.
for path in match.group(1).strip().split():
add_path(path)
+ # Strip test262 frontmatter before looking for load() and import/export
+ # statements.
+ source = strip_test262_frontmatter(source)
for match in LOAD_PATTERN.finditer(source):
# Files in load statements are relative to base dir.
add_path(match.group(1))
- for match in MODULE_RESOURCES_PATTERN_1.finditer(source):
- # Imported files are relative to the file importing them.
- add_path(os.path.join(os.path.dirname(file), match.group(1)))
- for match in MODULE_RESOURCES_PATTERN_2.finditer(source):
- # Imported files are relative to the file importing them.
- add_path(os.path.join(os.path.dirname(file), match.group(1)))
+ # Imported files are relative to the file importing them.
+ for match in MODULE_FROM_RESOURCES_PATTERN.finditer(source):
+ add_import_path(match.group(1))
+ for match in MODULE_IMPORT_RESOURCES_PATTERN.finditer(source):
+ add_import_path(match.group(1))
return result
def _get_resources(self):
diff --git a/chromium/v8/tools/testrunner/outproc/base.py b/chromium/v8/tools/testrunner/outproc/base.py
index 847b2242ffa..9646b96c068 100644
--- a/chromium/v8/tools/testrunner/outproc/base.py
+++ b/chromium/v8/tools/testrunner/outproc/base.py
@@ -137,6 +137,9 @@ class ExpectedOutProc(OutProc):
self._regenerate_expected_files = regenerate_expected_files
def _is_failure_output(self, output):
+ if output.exit_code != 0:
+ return True
+
with open(self._expected_filename, 'r') as f:
expected_lines = f.readlines()
diff --git a/chromium/v8/tools/tickprocessor-driver.mjs b/chromium/v8/tools/tickprocessor-driver.mjs
index a8cce2f708f..e7020e388d2 100644
--- a/chromium/v8/tools/tickprocessor-driver.mjs
+++ b/chromium/v8/tools/tickprocessor-driver.mjs
@@ -34,7 +34,7 @@ import {
// Tick Processor's code flow.
function processArguments(args) {
- var processor = new ArgumentsProcessor(args);
+ const processor = new ArgumentsProcessor(args);
if (processor.parse()) {
return processor.result();
} else {
@@ -48,25 +48,25 @@ function initSourceMapSupport() {
// Overwrite the load function to load scripts synchronously.
SourceMap.load = function(sourceMapURL) {
- var content = readFile(sourceMapURL);
- var sourceMapObject = (JSON.parse(content));
+ const content = readFile(sourceMapURL);
+ const sourceMapObject = (JSON.parse(content));
return new SourceMap(sourceMapURL, sourceMapObject);
};
}
-var entriesProviders = {
+const entriesProviders = {
'unix': UnixCppEntriesProvider,
'windows': WindowsCppEntriesProvider,
'mac': MacCppEntriesProvider
};
-var params = processArguments(arguments);
-var sourceMap = null;
+const params = processArguments(arguments);
+let sourceMap = null;
if (params.sourceMap) {
initSourceMapSupport();
sourceMap = SourceMap.load(params.sourceMap);
}
-var tickProcessor = new TickProcessor(
+const tickProcessor = new TickProcessor(
new (entriesProviders[params.platform])(params.nm, params.objdump, params.targetRootFS,
params.apkEmbeddedLibrary),
params.separateIc,
diff --git a/chromium/v8/tools/tickprocessor.mjs b/chromium/v8/tools/tickprocessor.mjs
index b5aff3b23f5..5b746d943a5 100644
--- a/chromium/v8/tools/tickprocessor.mjs
+++ b/chromium/v8/tools/tickprocessor.mjs
@@ -36,31 +36,30 @@ export function inherits(childCtor, parentCtor) {
};
-function V8Profile(separateIc, separateBytecodes, separateBuiltins,
- separateStubs) {
- Profile.call(this);
- var regexps = [];
- if (!separateIc) regexps.push(V8Profile.IC_RE);
- if (!separateBytecodes) regexps.push(V8Profile.BYTECODES_RE);
- if (!separateBuiltins) regexps.push(V8Profile.BUILTINS_RE);
- if (!separateStubs) regexps.push(V8Profile.STUBS_RE);
- if (regexps.length > 0) {
- this.skipThisFunction = function(name) {
- for (var i=0; i<regexps.length; i++) {
- if (regexps[i].test(name)) return true;
- }
- return false;
- };
+class V8Profile extends Profile {
+ static IC_RE =
+ /^(LoadGlobalIC: )|(Handler: )|(?:CallIC|LoadIC|StoreIC)|(?:Builtin: (?:Keyed)?(?:Load|Store)IC_)/;
+ static BYTECODES_RE = /^(BytecodeHandler: )/;
+ static BUILTINS_RE = /^(Builtin: )/;
+ static STUBS_RE = /^(Stub: )/;
+
+ constructor(separateIc, separateBytecodes, separateBuiltins, separateStubs) {
+ super();
+ const regexps = [];
+ if (!separateIc) regexps.push(V8Profile.IC_RE);
+ if (!separateBytecodes) regexps.push(V8Profile.BYTECODES_RE);
+ if (!separateBuiltins) regexps.push(V8Profile.BUILTINS_RE);
+ if (!separateStubs) regexps.push(V8Profile.STUBS_RE);
+ if (regexps.length > 0) {
+ this.skipThisFunction = function(name) {
+ for (let i=0; i<regexps.length; i++) {
+ if (regexps[i].test(name)) return true;
+ }
+ return false;
+ };
+ }
}
-};
-inherits(V8Profile, Profile);
-
-
-V8Profile.IC_RE =
- /^(LoadGlobalIC: )|(Handler: )|(?:CallIC|LoadIC|StoreIC)|(?:Builtin: (?:Keyed)?(?:Load|Store)IC_)/;
-V8Profile.BYTECODES_RE = /^(BytecodeHandler: )/
-V8Profile.BUILTINS_RE = /^(Builtin: )/
-V8Profile.STUBS_RE = /^(Stub: )/
+}
/**
@@ -85,7 +84,7 @@ function parseState(s) {
case "~": return Profile.CodeState.OPTIMIZABLE;
case "*": return Profile.CodeState.OPTIMIZED;
}
- throw new Error("unknown code state: " + s);
+ throw new Error(`unknown code state: ${s}`);
}
@@ -166,29 +165,29 @@ export function TickProcessor(
this.stateFilter_ = stateFilter;
this.runtimeTimerFilter_ = runtimeTimerFilter;
this.sourceMap = sourceMap;
- var ticks = this.ticks_ =
+ const ticks = this.ticks_ =
{ total: 0, unaccounted: 0, excluded: 0, gc: 0 };
distortion = parseInt(distortion);
// Convert picoseconds to nanoseconds.
this.distortion_per_entry = isNaN(distortion) ? 0 : (distortion / 1000);
this.distortion = 0;
- var rangelimits = range ? range.split(",") : [];
- var range_start = parseInt(rangelimits[0]);
- var range_end = parseInt(rangelimits[1]);
+ const rangelimits = range ? range.split(",") : [];
+ const range_start = parseInt(rangelimits[0]);
+ const range_end = parseInt(rangelimits[1]);
// Convert milliseconds to nanoseconds.
this.range_start = isNaN(range_start) ? -Infinity : (range_start * 1000);
this.range_end = isNaN(range_end) ? Infinity : (range_end * 1000)
V8Profile.prototype.handleUnknownCode = function(
operation, addr, opt_stackPos) {
- var op = Profile.Operation;
+ const op = Profile.Operation;
switch (operation) {
case op.MOVE:
- printErr('Code move event for unknown code: 0x' + addr.toString(16));
+ printErr(`Code move event for unknown code: 0x${addr.toString(16)}`);
break;
case op.DELETE:
- printErr('Code delete event for unknown code: 0x' + addr.toString(16));
+ printErr(`Code delete event for unknown code: 0x${addr.toString(16)}`);
break;
case op.TICK:
// Only unknown PCs (the first frame) are reported as unaccounted,
@@ -273,7 +272,7 @@ TickProcessor.prototype.isJsCode = function(name) {
TickProcessor.prototype.processLogFile = function(fileName) {
this.lastLogFileName_ = fileName;
- var line;
+ let line;
while (line = readline()) {
this.processLogLine(line);
}
@@ -283,18 +282,18 @@ TickProcessor.prototype.processLogFile = function(fileName) {
TickProcessor.prototype.processLogFileInTest = function(fileName) {
// Hack file name to avoid dealing with platform specifics.
this.lastLogFileName_ = 'v8.log';
- var contents = readFile(fileName);
+ const contents = readFile(fileName);
this.processLogChunk(contents);
};
TickProcessor.prototype.processSharedLibrary = function(
name, startAddr, endAddr, aslrSlide) {
- var entry = this.profile_.addLibrary(name, startAddr, endAddr, aslrSlide);
+ const entry = this.profile_.addLibrary(name, startAddr, endAddr, aslrSlide);
this.setCodeType(entry.getName(), 'SHARED_LIB');
- var self = this;
- var libFuncs = this.cppEntriesProvider_.parseVmSymbols(
+ const self = this;
+ const libFuncs = this.cppEntriesProvider_.parseVmSymbols(
name, startAddr, endAddr, aslrSlide, function(fName, fStart, fEnd) {
self.profile_.addStaticCode(fName, fStart, fEnd);
self.setCodeType(fName, 'CPP');
@@ -305,8 +304,8 @@ TickProcessor.prototype.processSharedLibrary = function(
TickProcessor.prototype.processCodeCreation = function(
type, kind, timestamp, start, size, name, maybe_func) {
if (maybe_func.length) {
- var funcAddr = parseInt(maybe_func[0]);
- var state = parseState(maybe_func[1]);
+ const funcAddr = parseInt(maybe_func[0]);
+ const state = parseState(maybe_func[1]);
this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
} else {
this.profile_.addCode(type, name, timestamp, start, size);
@@ -386,7 +385,7 @@ TickProcessor.prototype.processTick = function(pc,
} else if (tos_or_external_callback) {
// Find out, if top of stack was pointing inside a JS function
// meaning that we have encountered a frameless invocation.
- var funcEntry = this.profile_.findEntry(tos_or_external_callback);
+ const funcEntry = this.profile_.findEntry(tos_or_external_callback);
if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
tos_or_external_callback = 0;
}
@@ -412,14 +411,14 @@ TickProcessor.prototype.processHeapSampleBegin = function(space, state, ticks) {
TickProcessor.prototype.processHeapSampleEnd = function(space, state) {
if (space != 'Heap' || !this.currentProducerProfile_) return;
- print('Generation ' + this.generation_ + ':');
- var tree = this.currentProducerProfile_;
+ print(`Generation ${this.generation_}:`);
+ const tree = this.currentProducerProfile_;
tree.computeTotalWeights();
- var producersView = this.viewBuilder_.buildView(tree);
+ const producersView = this.viewBuilder_.buildView(tree);
// Sort by total time, desc, then by name, desc.
- producersView.sort(function(rec1, rec2) {
- return rec2.totalTime - rec1.totalTime ||
- (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); });
+ producersView.sort((rec1, rec2) =>
+ rec2.totalTime - rec1.totalTime ||
+ (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1) );
this.printHeavyProfile(producersView.head.children);
this.currentProducerProfile_ = null;
@@ -433,46 +432,46 @@ TickProcessor.prototype.printStatistics = function() {
return;
}
- print('Statistical profiling result from ' + this.lastLogFileName_ +
+ print(`Statistical profiling result from ${this.lastLogFileName_}` +
', (' + this.ticks_.total +
' ticks, ' + this.ticks_.unaccounted + ' unaccounted, ' +
this.ticks_.excluded + ' excluded).');
if (this.ticks_.total == 0) return;
- var flatProfile = this.profile_.getFlatProfile();
- var flatView = this.viewBuilder_.buildView(flatProfile);
+ const flatProfile = this.profile_.getFlatProfile();
+ const flatView = this.viewBuilder_.buildView(flatProfile);
// Sort by self time, desc, then by name, desc.
- flatView.sort(function(rec1, rec2) {
- return rec2.selfTime - rec1.selfTime ||
- (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); });
- var totalTicks = this.ticks_.total;
+ flatView.sort((rec1, rec2) =>
+ rec2.selfTime - rec1.selfTime ||
+ (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1) );
+ let totalTicks = this.ticks_.total;
if (this.ignoreUnknown_) {
totalTicks -= this.ticks_.unaccounted;
}
- var printAllTicks = !this.onlySummary_;
+ const printAllTicks = !this.onlySummary_;
// Count library ticks
- var flatViewNodes = flatView.head.children;
- var self = this;
+ const flatViewNodes = flatView.head.children;
+ const self = this;
- var libraryTicks = 0;
+ let libraryTicks = 0;
if(printAllTicks) this.printHeader('Shared libraries');
this.printEntries(flatViewNodes, totalTicks, null,
- function(name) { return self.isSharedLibrary(name); },
+ name => self.isSharedLibrary(name),
function(rec) { libraryTicks += rec.selfTime; }, printAllTicks);
- var nonLibraryTicks = totalTicks - libraryTicks;
+ const nonLibraryTicks = totalTicks - libraryTicks;
- var jsTicks = 0;
+ let jsTicks = 0;
if(printAllTicks) this.printHeader('JavaScript');
this.printEntries(flatViewNodes, totalTicks, nonLibraryTicks,
- function(name) { return self.isJsCode(name); },
+ name => self.isJsCode(name),
function(rec) { jsTicks += rec.selfTime; }, printAllTicks);
- var cppTicks = 0;
+ let cppTicks = 0;
if(printAllTicks) this.printHeader('C++');
this.printEntries(flatViewNodes, totalTicks, nonLibraryTicks,
- function(name) { return self.isCppCode(name); },
+ name => self.isCppCode(name),
function(rec) { cppTicks += rec.selfTime; }, printAllTicks);
this.printHeader('Summary');
@@ -488,22 +487,22 @@ TickProcessor.prototype.printStatistics = function() {
if(printAllTicks) {
print('\n [C++ entry points]:');
print(' ticks cpp total name');
- var c_entry_functions = this.profile_.getCEntryProfile();
- var total_c_entry = c_entry_functions[0].ticks;
- for (var i = 1; i < c_entry_functions.length; i++) {
+ const c_entry_functions = this.profile_.getCEntryProfile();
+ const total_c_entry = c_entry_functions[0].ticks;
+ for (let i = 1; i < c_entry_functions.length; i++) {
const c = c_entry_functions[i];
this.printLine(c.name, c.ticks, total_c_entry, totalTicks);
}
this.printHeavyProfHeader();
- var heavyProfile = this.profile_.getBottomUpProfile();
- var heavyView = this.viewBuilder_.buildView(heavyProfile);
+ const heavyProfile = this.profile_.getBottomUpProfile();
+ const heavyView = this.viewBuilder_.buildView(heavyProfile);
// To show the same percentages as in the flat profile.
heavyView.head.totalTime = totalTicks;
// Sort by total time, desc, then by name, desc.
- heavyView.sort(function(rec1, rec2) {
- return rec2.totalTime - rec1.totalTime ||
- (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); });
+ heavyView.sort((rec1, rec2) =>
+ rec2.totalTime - rec1.totalTime ||
+ (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1) );
this.printHeavyProfile(heavyView.head.children);
}
};
@@ -512,7 +511,7 @@ TickProcessor.prototype.printStatistics = function() {
function padLeft(s, len) {
s = s.toString();
if (s.length < len) {
- var padLength = len - s.length;
+ const padLength = len - s.length;
if (!(padLength in padLeft)) {
padLeft[padLength] = new Array(padLength + 1).join(' ');
}
@@ -523,18 +522,18 @@ function padLeft(s, len) {
TickProcessor.prototype.printHeader = function(headerTitle) {
- print('\n [' + headerTitle + ']:');
+ print(`\n [${headerTitle}]:`);
print(' ticks total nonlib name');
};
TickProcessor.prototype.printLine = function(
entry, ticks, totalTicks, nonLibTicks) {
- var pct = ticks * 100 / totalTicks;
- var nonLibPct = nonLibTicks != null
+ const pct = ticks * 100 / totalTicks;
+ const nonLibPct = nonLibTicks != null
? padLeft((ticks * 100 / nonLibTicks).toFixed(1), 5) + '% '
: ' ';
- print(' ' + padLeft(ticks, 5) + ' ' +
+ print(` ${padLeft(ticks, 5)} ` +
padLeft(pct.toFixed(1), 5) + '% ' +
nonLibPct +
entry);
@@ -554,8 +553,8 @@ TickProcessor.prototype.printHeavyProfHeader = function() {
TickProcessor.prototype.processProfile = function(
profile, filterP, func) {
- for (var i = 0, n = profile.length; i < n; ++i) {
- var rec = profile[i];
+ for (let i = 0, n = profile.length; i < n; ++i) {
+ const rec = profile[i];
if (!filterP(rec.internalFuncName)) {
continue;
}
@@ -564,8 +563,8 @@ TickProcessor.prototype.processProfile = function(
};
TickProcessor.prototype.getLineAndColumn = function(name) {
- var re = /:([0-9]+):([0-9]+)$/;
- var array = re.exec(name);
+ const re = /:([0-9]+):([0-9]+)$/;
+ const array = re.exec(name);
if (!array) {
return null;
}
@@ -581,28 +580,28 @@ TickProcessor.prototype.formatFunctionName = function(funcName) {
if (!this.hasSourceMap()) {
return funcName;
}
- var lc = this.getLineAndColumn(funcName);
+ const lc = this.getLineAndColumn(funcName);
if (lc == null) {
return funcName;
}
// in source maps lines and columns are zero based
- var lineNumber = lc.line - 1;
- var column = lc.column - 1;
- var entry = this.sourceMap.findEntry(lineNumber, column);
- var sourceFile = entry[2];
- var sourceLine = entry[3] + 1;
- var sourceColumn = entry[4] + 1;
+ const lineNumber = lc.line - 1;
+ const column = lc.column - 1;
+ const entry = this.sourceMap.findEntry(lineNumber, column);
+ const sourceFile = entry[2];
+ const sourceLine = entry[3] + 1;
+ const sourceColumn = entry[4] + 1;
return sourceFile + ':' + sourceLine + ':' + sourceColumn + ' -> ' + funcName;
};
TickProcessor.prototype.printEntries = function(
profile, totalTicks, nonLibTicks, filterP, callback, printAllTicks) {
- var that = this;
+ const that = this;
this.processProfile(profile, filterP, function (rec) {
if (rec.selfTime == 0) return;
callback(rec);
- var funcName = that.formatFunctionName(rec.internalFuncName);
+ const funcName = that.formatFunctionName(rec.internalFuncName);
if(printAllTicks) {
that.printLine(funcName, rec.selfTime, totalTicks, nonLibTicks);
}
@@ -611,14 +610,14 @@ TickProcessor.prototype.printEntries = function(
TickProcessor.prototype.printHeavyProfile = function(profile, opt_indent) {
- var self = this;
- var indent = opt_indent || 0;
- var indentStr = padLeft('', indent);
- this.processProfile(profile, function() { return true; }, function (rec) {
+ const self = this;
+ const indent = opt_indent || 0;
+ const indentStr = padLeft('', indent);
+ this.processProfile(profile, () => true, function (rec) {
// Cut off too infrequent callers.
if (rec.parentTotalPercent < TickProcessor.CALL_PROFILE_CUTOFF_PCT) return;
- var funcName = self.formatFunctionName(rec.internalFuncName);
- print(' ' + padLeft(rec.totalTime, 5) + ' ' +
+ const funcName = self.formatFunctionName(rec.internalFuncName);
+ print(` ${padLeft(rec.totalTime, 5)} ` +
padLeft(rec.parentTotalPercent.toFixed(1), 5) + '% ' +
indentStr + funcName);
// Limit backtrace depth.
@@ -641,8 +640,8 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
libName, libStart, libEnd, libASLRSlide, processorFunc) {
this.loadSymbols(libName);
- var lastUnknownSize;
- var lastAdded;
+ let lastUnknownSize;
+ let lastAdded;
function inRange(funcInfo, start, end) {
return funcInfo.start >= start && funcInfo.end <= end;
@@ -682,7 +681,7 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
}
while (true) {
- var funcInfo = this.parseNextLine();
+ const funcInfo = this.parseNextLine();
if (funcInfo === null) {
continue;
} else if (funcInfo === false) {
@@ -707,9 +706,7 @@ CppEntriesProvider.prototype.loadSymbols = function(libName) {
};
-CppEntriesProvider.prototype.parseNextLine = function() {
- return false;
-};
+CppEntriesProvider.prototype.parseNextLine = () => false;
export function UnixCppEntriesProvider(nmExec, objdumpExec, targetRootFS, apkEmbeddedLibrary) {
@@ -760,17 +757,17 @@ UnixCppEntriesProvider.prototype.parseNextLine = function() {
if (this.symbols.length == 0) {
return false;
}
- var lineEndPos = this.symbols[0].indexOf('\n', this.parsePos);
+ const lineEndPos = this.symbols[0].indexOf('\n', this.parsePos);
if (lineEndPos == -1) {
this.symbols.shift();
this.parsePos = 0;
return this.parseNextLine();
}
- var line = this.symbols[0].substring(this.parsePos, lineEndPos);
+ const line = this.symbols[0].substring(this.parsePos, lineEndPos);
this.parsePos = lineEndPos + 1;
- var fields = line.match(this.FUNC_RE);
- var funcInfo = null;
+ const fields = line.match(this.FUNC_RE);
+ let funcInfo = null;
if (fields) {
funcInfo = { name: fields[3], start: parseInt(fields[1], 16) + this.fileOffsetMinusVma };
if (fields[2]) {
@@ -830,9 +827,9 @@ WindowsCppEntriesProvider.EXE_IMAGE_BASE = 0x00400000;
WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
libName = this.targetRootFS + libName;
- var fileNameFields = libName.match(WindowsCppEntriesProvider.FILENAME_RE);
+ const fileNameFields = libName.match(WindowsCppEntriesProvider.FILENAME_RE);
if (!fileNameFields) return;
- var mapFileName = fileNameFields[1] + '.map';
+ const mapFileName = fileNameFields[1] + '.map';
this.moduleType_ = fileNameFields[2].toLowerCase();
try {
this.symbols = read(mapFileName);
@@ -844,26 +841,26 @@ WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
WindowsCppEntriesProvider.prototype.parseNextLine = function() {
- var lineEndPos = this.symbols.indexOf('\r\n', this.parsePos);
+ const lineEndPos = this.symbols.indexOf('\r\n', this.parsePos);
if (lineEndPos == -1) {
return false;
}
- var line = this.symbols.substring(this.parsePos, lineEndPos);
+ const line = this.symbols.substring(this.parsePos, lineEndPos);
this.parsePos = lineEndPos + 2;
// Image base entry is above all other symbols, so we can just
// terminate parsing.
- var imageBaseFields = line.match(WindowsCppEntriesProvider.IMAGE_BASE_RE);
+ const imageBaseFields = line.match(WindowsCppEntriesProvider.IMAGE_BASE_RE);
if (imageBaseFields) {
- var imageBase = parseInt(imageBaseFields[1], 16);
+ const imageBase = parseInt(imageBaseFields[1], 16);
if ((this.moduleType_ == 'exe') !=
(imageBase == WindowsCppEntriesProvider.EXE_IMAGE_BASE)) {
return false;
}
}
- var fields = line.match(WindowsCppEntriesProvider.FUNC_RE);
+ const fields = line.match(WindowsCppEntriesProvider.FUNC_RE);
return fields ?
{ name: this.unmangleName(fields[1]), start: parseInt(fields[2], 16) } :
null;
@@ -881,8 +878,8 @@ WindowsCppEntriesProvider.prototype.parseNextLine = function() {
WindowsCppEntriesProvider.prototype.unmangleName = function(name) {
// Empty or non-mangled name.
if (name.length < 1 || name.charAt(0) != '?') return name;
- var nameEndPos = name.indexOf('@@');
- var components = name.substring(1, nameEndPos).split('@');
+ const nameEndPos = name.indexOf('@@');
+ const components = name.substring(1, nameEndPos).split('@');
components.reverse();
return components.join('::');
};
diff --git a/chromium/v8/tools/v8_presubmit.py b/chromium/v8/tools/v8_presubmit.py
index 6fbc3ad2ede..db008aabf17 100755
--- a/chromium/v8/tools/v8_presubmit.py
+++ b/chromium/v8/tools/v8_presubmit.py
@@ -131,6 +131,39 @@ def TorqueLintWorker(command):
print('Error running format-torque.py')
process.kill()
+def JSLintWorker(command):
+ def format_file(command):
+ try:
+ file_name = command[-1]
+ with open(file_name, "r") as file_handle:
+ contents = file_handle.read()
+
+ process = subprocess.Popen(command, stdout=PIPE, stderr=subprocess.PIPE)
+ output, err = process.communicate()
+ rc = process.returncode
+ if rc != 0:
+ sys.stdout.write("error code " + str(rc) + " running clang-format.\n")
+ return rc
+
+ if output != contents:
+ return 1
+
+ return 0
+ except KeyboardInterrupt:
+ process.kill()
+ except Exception:
+ print('Error running clang-format. Please make sure you have depot_tools' +
+ ' in your $PATH. Lint check skipped.')
+ process.kill()
+
+ rc = format_file(command)
+ if rc == 1:
+ # There are files that need to be formatted, let's format them in place.
+ file_name = command[-1]
+ sys.stdout.write("Formatting %s.\n" % (file_name))
+ rc = format_file(command[:-1] + ["-i", file_name])
+ return rc
+
class FileContentsCache(object):
def __init__(self, sums_file_name):
@@ -392,6 +425,33 @@ class TorqueLintProcessor(CacheableSourceFileProcessor):
return None, arguments
+class JSLintProcessor(CacheableSourceFileProcessor):
+ """
+ Check .{m}js file to verify they follow the JS Style guide.
+ """
+ def __init__(self, use_cache=True):
+ super(JSLintProcessor, self).__init__(
+ use_cache=use_cache, cache_file_path='.jslint-cache',
+ file_type='JavaScript')
+
+ def IsRelevant(self, name):
+ return name.endswith('.js') or name.endswith('.mjs')
+
+ def GetPathsToSearch(self):
+ return ['tools/system-analyzer']
+
+ def GetProcessorWorker(self):
+ return JSLintWorker
+
+ def GetProcessorScript(self):
+ for path in [TOOLS_PATH] + os.environ["PATH"].split(os.pathsep):
+ path = path.strip('"')
+ clang_format = os.path.join(path, 'clang_format.py')
+ if os.path.isfile(clang_format):
+ return clang_format, []
+
+ return None, []
+
COPYRIGHT_HEADER_PATTERN = re.compile(
r'Copyright [\d-]*20[0-2][0-9] the V8 project authors. All rights reserved.')
@@ -708,6 +768,9 @@ def Main():
print("Running Torque formatting check...")
success &= TorqueLintProcessor(use_cache=use_linter_cache).RunOnPath(
workspace)
+ print("Running JavaScript formatting check...")
+ success &= JSLintProcessor(use_cache=use_linter_cache).RunOnPath(
+ workspace)
print("Running copyright header, trailing whitespaces and " \
"two empty lines between declarations check...")
success &= SourceProcessor().RunOnPath(workspace)
diff --git a/chromium/v8/tools/v8heapconst.py b/chromium/v8/tools/v8heapconst.py
index d8e81c49096..0dd31d4ad25 100644
--- a/chromium/v8/tools/v8heapconst.py
+++ b/chromium/v8/tools/v8heapconst.py
@@ -62,17 +62,17 @@ INSTANCE_TYPES = {
98: "FUNCTION_TEMPLATE_RARE_DATA_TYPE",
99: "INTERCEPTOR_INFO_TYPE",
100: "INTERPRETER_DATA_TYPE",
- 101: "PROMISE_CAPABILITY_TYPE",
- 102: "PROMISE_REACTION_TYPE",
- 103: "PROPERTY_DESCRIPTOR_OBJECT_TYPE",
- 104: "PROTOTYPE_INFO_TYPE",
- 105: "SCRIPT_TYPE",
- 106: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE",
- 107: "STACK_FRAME_INFO_TYPE",
- 108: "STACK_TRACE_FRAME_TYPE",
- 109: "TEMPLATE_OBJECT_DESCRIPTION_TYPE",
- 110: "TUPLE2_TYPE",
- 111: "WASM_CAPI_FUNCTION_DATA_TYPE",
+ 101: "MODULE_REQUEST_TYPE",
+ 102: "PROMISE_CAPABILITY_TYPE",
+ 103: "PROMISE_REACTION_TYPE",
+ 104: "PROPERTY_DESCRIPTOR_OBJECT_TYPE",
+ 105: "PROTOTYPE_INFO_TYPE",
+ 106: "SCRIPT_TYPE",
+ 107: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE",
+ 108: "STACK_FRAME_INFO_TYPE",
+ 109: "STACK_TRACE_FRAME_TYPE",
+ 110: "TEMPLATE_OBJECT_DESCRIPTION_TYPE",
+ 111: "TUPLE2_TYPE",
112: "WASM_EXCEPTION_TAG_TYPE",
113: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
114: "WASM_INDIRECT_FUNCTION_TABLE_TYPE",
@@ -113,42 +113,44 @@ INSTANCE_TYPES = {
149: "SMALL_ORDERED_HASH_MAP_TYPE",
150: "SMALL_ORDERED_HASH_SET_TYPE",
151: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
- 152: "SOURCE_TEXT_MODULE_TYPE",
- 153: "SYNTHETIC_MODULE_TYPE",
- 154: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
- 155: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
- 156: "WEAK_FIXED_ARRAY_TYPE",
- 157: "TRANSITION_ARRAY_TYPE",
- 158: "CELL_TYPE",
- 159: "CODE_TYPE",
- 160: "CODE_DATA_CONTAINER_TYPE",
- 161: "COVERAGE_INFO_TYPE",
- 162: "DESCRIPTOR_ARRAY_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_STRUCT_TYPE",
- 181: "WEAK_ARRAY_LIST_TYPE",
- 182: "WEAK_CELL_TYPE",
- 183: "JS_PROXY_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",
1057: "JS_OBJECT_TYPE",
- 184: "JS_GLOBAL_OBJECT_TYPE",
- 185: "JS_GLOBAL_PROXY_TYPE",
- 186: "JS_MODULE_NAMESPACE_TYPE",
+ 186: "JS_GLOBAL_OBJECT_TYPE",
+ 187: "JS_GLOBAL_PROXY_TYPE",
+ 188: "JS_MODULE_NAMESPACE_TYPE",
1040: "JS_SPECIAL_API_OBJECT_TYPE",
1041: "JS_PRIMITIVE_WRAPPER_TYPE",
1042: "JS_MAP_KEY_ITERATOR_TYPE",
@@ -205,16 +207,16 @@ INSTANCE_TYPES = {
# List of known V8 maps.
KNOWN_MAPS = {
- ("read_only_space", 0x02115): (170, "MetaMap"),
+ ("read_only_space", 0x02115): (171, "MetaMap"),
("read_only_space", 0x0213d): (67, "NullMap"),
- ("read_only_space", 0x02165): (162, "DescriptorArrayMap"),
- ("read_only_space", 0x0218d): (156, "WeakFixedArrayMap"),
+ ("read_only_space", 0x02165): (153, "StrongDescriptorArrayMap"),
+ ("read_only_space", 0x0218d): (158, "WeakFixedArrayMap"),
("read_only_space", 0x021cd): (96, "EnumCacheMap"),
("read_only_space", 0x02201): (117, "FixedArrayMap"),
("read_only_space", 0x0224d): (8, "OneByteInternalizedStringMap"),
- ("read_only_space", 0x02299): (167, "FreeSpaceMap"),
- ("read_only_space", 0x022c1): (166, "OnePointerFillerMap"),
- ("read_only_space", 0x022e9): (166, "TwoPointerFillerMap"),
+ ("read_only_space", 0x02299): (168, "FreeSpaceMap"),
+ ("read_only_space", 0x022c1): (167, "OnePointerFillerMap"),
+ ("read_only_space", 0x022e9): (167, "TwoPointerFillerMap"),
("read_only_space", 0x02311): (67, "UninitializedMap"),
("read_only_space", 0x02389): (67, "UndefinedMap"),
("read_only_space", 0x023cd): (66, "HeapNumberMap"),
@@ -226,14 +228,14 @@ KNOWN_MAPS = {
("read_only_space", 0x0257d): (64, "SymbolMap"),
("read_only_space", 0x025a5): (40, "OneByteStringMap"),
("read_only_space", 0x025cd): (129, "ScopeInfoMap"),
- ("read_only_space", 0x025f5): (175, "SharedFunctionInfoMap"),
- ("read_only_space", 0x0261d): (159, "CodeMap"),
- ("read_only_space", 0x02645): (158, "CellMap"),
- ("read_only_space", 0x0266d): (174, "GlobalPropertyCellMap"),
+ ("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", 0x02695): (70, "ForeignMap"),
- ("read_only_space", 0x026bd): (157, "TransitionArrayMap"),
+ ("read_only_space", 0x026bd): (159, "TransitionArrayMap"),
("read_only_space", 0x026e5): (45, "ThinOneByteStringMap"),
- ("read_only_space", 0x0270d): (165, "FeedbackVectorMap"),
+ ("read_only_space", 0x0270d): (166, "FeedbackVectorMap"),
("read_only_space", 0x0273d): (67, "ArgumentsMarkerMap"),
("read_only_space", 0x0279d): (67, "ExceptionMap"),
("read_only_space", 0x027f9): (67, "TerminationExceptionMap"),
@@ -241,13 +243,13 @@ KNOWN_MAPS = {
("read_only_space", 0x028c1): (67, "StaleRegisterMap"),
("read_only_space", 0x02921): (130, "ScriptContextTableMap"),
("read_only_space", 0x02949): (127, "ClosureFeedbackCellArrayMap"),
- ("read_only_space", 0x02971): (164, "FeedbackMetadataArrayMap"),
+ ("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): (160, "CodeDataContainerMap"),
- ("read_only_space", 0x02a61): (161, "CoverageInfoMap"),
+ ("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"),
@@ -259,8 +261,8 @@ KNOWN_MAPS = {
("read_only_space", 0x02bc9): (123, "OrderedHashMapMap"),
("read_only_space", 0x02bf1): (124, "OrderedHashSetMap"),
("read_only_space", 0x02c19): (125, "OrderedNameDictionaryMap"),
- ("read_only_space", 0x02c41): (172, "PreparseDataMap"),
- ("read_only_space", 0x02c69): (173, "PropertyArrayMap"),
+ ("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"),
@@ -268,15 +270,15 @@ KNOWN_MAPS = {
("read_only_space", 0x02d31): (149, "SmallOrderedHashMapMap"),
("read_only_space", 0x02d59): (150, "SmallOrderedHashSetMap"),
("read_only_space", 0x02d81): (151, "SmallOrderedNameDictionaryMap"),
- ("read_only_space", 0x02da9): (152, "SourceTextModuleMap"),
- ("read_only_space", 0x02dd1): (153, "SyntheticModuleMap"),
- ("read_only_space", 0x02df9): (155, "UncompiledDataWithoutPreparseDataMap"),
- ("read_only_space", 0x02e21): (154, "UncompiledDataWithPreparseDataMap"),
+ ("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): (181, "WeakArrayListMap"),
+ ("read_only_space", 0x02e71): (183, "WeakArrayListMap"),
("read_only_space", 0x02e99): (119, "EphemeronHashTableMap"),
- ("read_only_space", 0x02ec1): (163, "EmbedderDataArrayMap"),
- ("read_only_space", 0x02ee9): (182, "WeakCellMap"),
+ ("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"),
@@ -295,72 +297,74 @@ KNOWN_MAPS = {
("read_only_space", 0x03169): (67, "SelfReferenceMarkerMap"),
("read_only_space", 0x03191): (67, "BasicBlockCountersMarkerMap"),
("read_only_space", 0x031d5): (87, "ArrayBoilerplateDescriptionMap"),
- ("read_only_space", 0x032a5): (99, "InterceptorInfoMap"),
- ("read_only_space", 0x05399): (72, "PromiseFulfillReactionJobTaskMap"),
- ("read_only_space", 0x053c1): (73, "PromiseRejectReactionJobTaskMap"),
- ("read_only_space", 0x053e9): (74, "CallableTaskMap"),
- ("read_only_space", 0x05411): (75, "CallbackTaskMap"),
- ("read_only_space", 0x05439): (76, "PromiseResolveThenableJobTaskMap"),
- ("read_only_space", 0x05461): (79, "FunctionTemplateInfoMap"),
- ("read_only_space", 0x05489): (80, "ObjectTemplateInfoMap"),
- ("read_only_space", 0x054b1): (81, "AccessCheckInfoMap"),
- ("read_only_space", 0x054d9): (82, "AccessorInfoMap"),
- ("read_only_space", 0x05501): (83, "AccessorPairMap"),
- ("read_only_space", 0x05529): (84, "AliasedArgumentsEntryMap"),
- ("read_only_space", 0x05551): (85, "AllocationMementoMap"),
- ("read_only_space", 0x05579): (88, "AsmWasmDataMap"),
- ("read_only_space", 0x055a1): (89, "AsyncGeneratorRequestMap"),
- ("read_only_space", 0x055c9): (90, "BreakPointMap"),
- ("read_only_space", 0x055f1): (91, "BreakPointInfoMap"),
- ("read_only_space", 0x05619): (92, "CachedTemplateObjectMap"),
- ("read_only_space", 0x05641): (94, "ClassPositionsMap"),
- ("read_only_space", 0x05669): (95, "DebugInfoMap"),
- ("read_only_space", 0x05691): (98, "FunctionTemplateRareDataMap"),
- ("read_only_space", 0x056b9): (100, "InterpreterDataMap"),
- ("read_only_space", 0x056e1): (101, "PromiseCapabilityMap"),
- ("read_only_space", 0x05709): (102, "PromiseReactionMap"),
- ("read_only_space", 0x05731): (103, "PropertyDescriptorObjectMap"),
- ("read_only_space", 0x05759): (104, "PrototypeInfoMap"),
- ("read_only_space", 0x05781): (105, "ScriptMap"),
- ("read_only_space", 0x057a9): (106, "SourceTextModuleInfoEntryMap"),
- ("read_only_space", 0x057d1): (107, "StackFrameInfoMap"),
- ("read_only_space", 0x057f9): (108, "StackTraceFrameMap"),
- ("read_only_space", 0x05821): (109, "TemplateObjectDescriptionMap"),
- ("read_only_space", 0x05849): (110, "Tuple2Map"),
- ("read_only_space", 0x05871): (111, "WasmCapiFunctionDataMap"),
- ("read_only_space", 0x05899): (112, "WasmExceptionTagMap"),
- ("read_only_space", 0x058c1): (113, "WasmExportedFunctionDataMap"),
- ("read_only_space", 0x058e9): (114, "WasmIndirectFunctionTableMap"),
- ("read_only_space", 0x05911): (115, "WasmJSFunctionDataMap"),
- ("read_only_space", 0x05939): (116, "WasmValueMap"),
- ("read_only_space", 0x05961): (135, "SloppyArgumentsElementsMap"),
- ("read_only_space", 0x05989): (171, "OnHeapBasicBlockProfilerDataMap"),
- ("read_only_space", 0x059b1): (168, "InternalClassMap"),
- ("read_only_space", 0x059d9): (177, "SmiPairMap"),
- ("read_only_space", 0x05a01): (176, "SmiBoxMap"),
- ("read_only_space", 0x05a29): (146, "ExportedSubClassBaseMap"),
- ("read_only_space", 0x05a51): (147, "ExportedSubClassMap"),
- ("read_only_space", 0x05a79): (68, "AbstractInternalClassSubclass1Map"),
- ("read_only_space", 0x05aa1): (69, "AbstractInternalClassSubclass2Map"),
- ("read_only_space", 0x05ac9): (134, "InternalClassWithSmiElementsMap"),
- ("read_only_space", 0x05af1): (169, "InternalClassWithStructElementsMap"),
- ("read_only_space", 0x05b19): (148, "ExportedSubClass2Map"),
- ("read_only_space", 0x05b41): (178, "SortStateMap"),
- ("read_only_space", 0x05b69): (86, "AllocationSiteWithWeakNextMap"),
- ("read_only_space", 0x05b91): (86, "AllocationSiteWithoutWeakNextMap"),
- ("read_only_space", 0x05bb9): (77, "LoadHandler1Map"),
- ("read_only_space", 0x05be1): (77, "LoadHandler2Map"),
- ("read_only_space", 0x05c09): (77, "LoadHandler3Map"),
- ("read_only_space", 0x05c31): (78, "StoreHandler0Map"),
- ("read_only_space", 0x05c59): (78, "StoreHandler1Map"),
- ("read_only_space", 0x05c81): (78, "StoreHandler2Map"),
- ("read_only_space", 0x05ca9): (78, "StoreHandler3Map"),
+ ("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"),
("map_space", 0x02115): (1057, "ExternalMap"),
("map_space", 0x0213d): (1072, "JSMessageObjectMap"),
- ("map_space", 0x02165): (180, "WasmRttEqrefMap"),
- ("map_space", 0x0218d): (180, "WasmRttExternrefMap"),
- ("map_space", 0x021b5): (180, "WasmRttFuncrefMap"),
- ("map_space", 0x021dd): (180, "WasmRttI31refMap"),
+ ("map_space", 0x02165): (182, "WasmRttEqrefMap"),
+ ("map_space", 0x0218d): (182, "WasmRttExternrefMap"),
+ ("map_space", 0x021b5): (182, "WasmRttFuncrefMap"),
+ ("map_space", 0x021dd): (182, "WasmRttI31refMap"),
}
# List of known V8 objects.
@@ -395,20 +399,21 @@ KNOWN_OBJECTS = {
("read_only_space", 0x0325d): "EmptyFeedbackMetadata",
("read_only_space", 0x03269): "EmptyPropertyCell",
("read_only_space", 0x0327d): "EmptyPropertyDictionary",
- ("read_only_space", 0x032cd): "NoOpInterceptorInfo",
- ("read_only_space", 0x032f5): "EmptyWeakArrayList",
- ("read_only_space", 0x03301): "InfinityValue",
- ("read_only_space", 0x0330d): "MinusZeroValue",
- ("read_only_space", 0x03319): "MinusInfinityValue",
- ("read_only_space", 0x03325): "SelfReferenceMarker",
- ("read_only_space", 0x03365): "BasicBlockCountersMarker",
- ("read_only_space", 0x033a9): "OffHeapTrampolineRelocationInfo",
- ("read_only_space", 0x033b5): "TrampolineTrivialCodeDataContainer",
- ("read_only_space", 0x033c1): "TrampolinePromiseRejectionCodeDataContainer",
- ("read_only_space", 0x033cd): "GlobalThisBindingScopeInfo",
- ("read_only_space", 0x03405): "EmptyFunctionScopeInfo",
- ("read_only_space", 0x0342d): "NativeScopeInfo",
- ("read_only_space", 0x03449): "HashSeed",
+ ("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",
("old_space", 0x02115): "ArgumentsIteratorAccessor",
("old_space", 0x02159): "ArrayLengthAccessor",
("old_space", 0x0219d): "BoundFunctionLengthAccessor",
@@ -444,27 +449,27 @@ KNOWN_OBJECTS = {
("old_space", 0x02a61): "StringSplitCache",
("old_space", 0x02e69): "RegExpMultipleCache",
("old_space", 0x03271): "BuiltinsConstantsTable",
- ("old_space", 0x0364d): "AsyncFunctionAwaitRejectSharedFun",
- ("old_space", 0x03675): "AsyncFunctionAwaitResolveSharedFun",
- ("old_space", 0x0369d): "AsyncGeneratorAwaitRejectSharedFun",
- ("old_space", 0x036c5): "AsyncGeneratorAwaitResolveSharedFun",
- ("old_space", 0x036ed): "AsyncGeneratorYieldResolveSharedFun",
- ("old_space", 0x03715): "AsyncGeneratorReturnResolveSharedFun",
- ("old_space", 0x0373d): "AsyncGeneratorReturnClosedRejectSharedFun",
- ("old_space", 0x03765): "AsyncGeneratorReturnClosedResolveSharedFun",
- ("old_space", 0x0378d): "AsyncIteratorValueUnwrapSharedFun",
- ("old_space", 0x037b5): "PromiseAllResolveElementSharedFun",
- ("old_space", 0x037dd): "PromiseAllSettledResolveElementSharedFun",
- ("old_space", 0x03805): "PromiseAllSettledRejectElementSharedFun",
- ("old_space", 0x0382d): "PromiseAnyRejectElementSharedFun",
- ("old_space", 0x03855): "PromiseCapabilityDefaultRejectSharedFun",
- ("old_space", 0x0387d): "PromiseCapabilityDefaultResolveSharedFun",
- ("old_space", 0x038a5): "PromiseCatchFinallySharedFun",
- ("old_space", 0x038cd): "PromiseGetCapabilitiesExecutorSharedFun",
- ("old_space", 0x038f5): "PromiseThenFinallySharedFun",
- ("old_space", 0x0391d): "PromiseThrowerFinallySharedFun",
- ("old_space", 0x03945): "PromiseValueThunkFinallySharedFun",
- ("old_space", 0x0396d): "ProxyRevokeSharedFun",
+ ("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",
}
# Lower 32 bits of first page addresses for various heap spaces.
diff --git a/chromium/v8/tools/whitespace.txt b/chromium/v8/tools/whitespace.txt
index 6e2bc1cf764..d6024b5b7d9 100644
--- a/chromium/v8/tools/whitespace.txt
+++ b/chromium/v8/tools/whitespace.txt
@@ -7,10 +7,11 @@ A Smi balks into a war and says:
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......
+The bartender starts to shake the bottles........................
+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.....
Today's answer to life the universe and everything is 12950!
Today's answer to life the universe and everything is 6728!
+Today's answer to life the universe and everything is 6728!!