diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-26 22:15:17 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-26 22:15:17 +0000 |
commit | 756cefa0028e898e6a401ae3154db87d53f59914 (patch) | |
tree | 9c13d3039e82f2887e11462f3c71d96dc8cbd9bf | |
parent | fe60195a19a160fa09f76aab21f355e63caa4faa (diff) | |
download | chromium_src-756cefa0028e898e6a401ae3154db87d53f59914.zip chromium_src-756cefa0028e898e6a401ae3154db87d53f59914.tar.gz chromium_src-756cefa0028e898e6a401ae3154db87d53f59914.tar.bz2 |
Check in a new linux reference build and enable the page cycler tests.
We were crashing while trying to load fonts. Your patch for font
fallback fixes the crash.
Review URL: http://codereview.chromium.org/112061
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16932 0039d316-1c4b-4281-b951-d872f2087c98
28 files changed, 2926 insertions, 310 deletions
diff --git a/chrome/test/page_cycler/page_cycler_test.cc b/chrome/test/page_cycler/page_cycler_test.cc index 1978c3c..1158248 100644 --- a/chrome/test/page_cycler/page_cycler_test.cc +++ b/chrome/test/page_cycler/page_cycler_test.cc @@ -259,8 +259,6 @@ class PageCyclerReferenceTest : public PageCyclerTest { } }; -#if !defined(OS_LINUX) - // file-URL tests TEST_F(PageCyclerTest, MozFile) { RunTest("moz", false); @@ -359,6 +357,4 @@ TEST_F(PageCyclerReferenceTest, BloatHttp) { } #endif -#endif // !defined(OS_LINUX) - } // namespace diff --git a/chrome/tools/test/reference_build/chrome_linux/chrome b/chrome/tools/test/reference_build/chrome_linux/chrome Binary files differindex d9c91bf..deebaa3 100755 --- a/chrome/tools/test/reference_build/chrome_linux/chrome +++ b/chrome/tools/test/reference_build/chrome_linux/chrome diff --git a/chrome/tools/test/reference_build/chrome_linux/chrome.pak b/chrome/tools/test/reference_build/chrome_linux/chrome.pak Binary files differindex a1b28e3..9cc4b57 100644 --- a/chrome/tools/test/reference_build/chrome_linux/chrome.pak +++ b/chrome/tools/test/reference_build/chrome_linux/chrome.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/da.pak b/chrome/tools/test/reference_build/chrome_linux/locales/da.pak Binary files differindex 0a47477..454f647 100644 --- a/chrome/tools/test/reference_build/chrome_linux/locales/da.pak +++ b/chrome/tools/test/reference_build/chrome_linux/locales/da.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak b/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak Binary files differindex 22ba218..820f520 100644 --- a/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak +++ b/chrome/tools/test/reference_build/chrome_linux/locales/en-US.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/he.pak b/chrome/tools/test/reference_build/chrome_linux/locales/he.pak Binary files differindex a3ac813..dd94230 100644 --- a/chrome/tools/test/reference_build/chrome_linux/locales/he.pak +++ b/chrome/tools/test/reference_build/chrome_linux/locales/he.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak b/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak Binary files differindex 9d564c5..a2c8627 100644 --- a/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak +++ b/chrome/tools/test/reference_build/chrome_linux/locales/zh-TW.pak diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js index ba879a0..65cc7d0 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/Console.js @@ -577,31 +577,36 @@ WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, rep this.url = url; this.groupLevel = groupLevel; this.repeatCount = repeatCount; - - switch (this.level) { - case WebInspector.ConsoleMessage.MessageLevel.Trace: - var span = document.createElement("span"); - span.addStyleClass("console-formatted-trace"); - var stack = Array.prototype.slice.call(arguments, 6); - var funcNames = stack.map(function(f) { - return f || WebInspector.UIString("(anonymous function)"); - }); - span.appendChild(document.createTextNode(funcNames.join("\n"))); - this.formattedMessage = span; - break; - case WebInspector.ConsoleMessage.MessageLevel.Object: - this.formattedMessage = this._format(["%O", arguments[6]]); - break; - default: - this.formattedMessage = this._format(Array.prototype.slice.call(arguments, 6)); - break; - } - - // This is used for inline message bubbles in SourceFrames, or other plain-text representations. - this.message = this.formattedMessage.textContent; + if (arguments.length > 6) + this.setMessageBody(Array.prototype.slice.call(arguments, 6)); } WebInspector.ConsoleMessage.prototype = { + setMessageBody: function(args) + { + switch (this.level) { + case WebInspector.ConsoleMessage.MessageLevel.Trace: + var span = document.createElement("span"); + span.addStyleClass("console-formatted-trace"); + var stack = Array.prototype.slice.call(args); + var funcNames = stack.map(function(f) { + return f || WebInspector.UIString("(anonymous function)"); + }); + span.appendChild(document.createTextNode(funcNames.join("\n"))); + this.formattedMessage = span; + break; + case WebInspector.ConsoleMessage.MessageLevel.Object: + this.formattedMessage = this._format(["%O", args[0]]); + break; + default: + this.formattedMessage = this._format(args); + break; + } + + // This is used for inline message bubbles in SourceFrames, or other plain-text representations. + this.message = this.formattedMessage.textContent; + }, + isErrorOrWarning: function() { return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error); diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js index 16e31b8..822bf35 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ElementsTreeOutline.js @@ -571,7 +571,7 @@ WebInspector.ElementsTreeElement.prototype = { parseContainerElement.innerHTML = "<span " + newText + "></span>"; var parseElement = parseContainerElement.firstChild; if (!parseElement || !parseElement.hasAttributes()) { - editingCancelled(element, context); + this._editingCancelled(element, context); return; } diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfileDataGridTree.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfileDataGridTree.js new file mode 100644 index 0000000..84d9923 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/ProfileDataGridTree.js @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2009 280 North Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.ProfileDataGridNode = function(profileView, profileNode, owningTree, hasChildren) +{ + this.profileView = profileView; + this.profileNode = profileNode; + + WebInspector.DataGridNode.call(this, null, hasChildren); + + this.addEventListener("populate", this._populate, this); + + this.tree = owningTree; + + this.childrenByCallUID = {}; + this.lastComparator = null; + + this.callUID = profileNode.callUID; + this.selfTime = profileNode.selfTime; + this.totalTime = profileNode.totalTime; + this.functionName = profileNode.functionName; + this.numberOfCalls = profileNode.numberOfCalls; + this.url = profileNode.url; +} + +WebInspector.ProfileDataGridNode.prototype = { + get data() + { + function formatMilliseconds(time) + { + return Number.secondsToString(time / 1000, WebInspector.UIString.bind(WebInspector), true); + } + + var data = {}; + + data["function"] = this.functionName; + data["calls"] = this.numberOfCalls; + + if (this.profileView.showSelfTimeAsPercent) + data["self"] = WebInspector.UIString("%.2f%%", this.selfPercent); + else + data["self"] = formatMilliseconds(this.selfTime); + + if (this.profileView.showTotalTimeAsPercent) + data["total"] = WebInspector.UIString("%.2f%%", this.totalPercent); + else + data["total"] = formatMilliseconds(this.totalTime); + + if (this.profileView.showAverageTimeAsPercent) + data["average"] = WebInspector.UIString("%.2f%%", this.averagePercent); + else + data["average"] = formatMilliseconds(this.averageTime); + + return data; + }, + + createCell: function(columnIdentifier) + { + var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier); + + if (columnIdentifier === "self" && this._searchMatchedSelfColumn) + cell.addStyleClass("highlight"); + else if (columnIdentifier === "total" && this._searchMatchedTotalColumn) + cell.addStyleClass("highlight"); + else if (columnIdentifier === "average" && this._searchMatchedAverageColumn) + cell.addStyleClass("highlight"); + else if (columnIdentifier === "calls" && this._searchMatchedCallsColumn) + cell.addStyleClass("highlight"); + + if (columnIdentifier !== "function") + return cell; + + if (this.profileNode._searchMatchedFunctionColumn) + cell.addStyleClass("highlight"); + + if (this.profileNode.url) { + var fileName = WebInspector.displayNameForURL(this.profileNode.url); + + var urlElement = document.createElement("a"); + urlElement.className = "profile-node-file webkit-html-resource-link"; + urlElement.href = this.profileNode.url; + urlElement.lineNumber = this.profileNode.lineNumber; + + if (this.profileNode.lineNumber > 0) + urlElement.textContent = fileName + ":" + this.profileNode.lineNumber; + else + urlElement.textContent = fileName; + + cell.insertBefore(urlElement, cell.firstChild); + } + + return cell; + }, + + select: function(supressSelectedEvent) + { + WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent); + this.profileView._dataGridNodeSelected(this); + }, + + deselect: function(supressDeselectedEvent) + { + WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent); + this.profileView._dataGridNodeDeselected(this); + }, + + expand: function() + { + if (!this.parent) { + var currentComparator = this.parent.lastComparator; + + if (!currentComparator || (currentComparator === this.lastComparator)) + return; + + this.sort(currentComparator); + } + + WebInspector.DataGridNode.prototype.expand.call(this); + }, + + sort: function(/*Function*/ comparator, /*Boolean*/ force) + { + var gridNodeGroups = [[this]]; + + for (var gridNodeGroupIndex = 0; gridNodeGroupIndex < gridNodeGroups.length; ++gridNodeGroupIndex) { + var gridNodes = gridNodeGroups[gridNodeGroupIndex]; + var count = gridNodes.length; + + for (var index = 0; index < count; ++index) { + var gridNode = gridNodes[index]; + + // If the grid node is collapsed, then don't sort children (save operation for later). + // If the grid node has the same sorting as previously, then there is no point in sorting it again. + if (!force && !gridNode.expanded || gridNode.lastComparator === comparator) + continue; + + gridNode.lastComparator = comparator; + + var children = gridNode.children; + var childCount = children.length; + + if (childCount) { + children.sort(comparator); + + for (var childIndex = 0; childIndex < childCount; ++childIndex) + children[childIndex]._recalculateSiblings(childIndex); + + gridNodeGroups.push(children); + } + } + } + }, + + insertChild: function(/*ProfileDataGridNode*/ profileDataGridNode, index) + { + WebInspector.DataGridNode.prototype.insertChild.call(this, profileDataGridNode, index); + + this.childrenByCallUID[profileDataGridNode.callUID] = profileDataGridNode; + }, + + removeChild: function(/*ProfileDataGridNode*/ profileDataGridNode) + { + WebInspector.DataGridNode.prototype.removeChild.call(this, profileDataGridNode); + + delete this.childrenByCallUID[profileDataGridNode.callUID]; + }, + + removeChildren: function(/*ProfileDataGridNode*/ profileDataGridNode) + { + WebInspector.DataGridNode.prototype.removeChildren.call(this); + + this.childrenByCallUID = {}; + }, + + findChild: function(/*Node*/ node) + { + if (!node) + return null; + return this.childrenByCallUID[node.callUID]; + }, + + get averageTime() + { + return this.selfTime / Math.max(1, this.numberOfCalls); + }, + + get averagePercent() + { + return this.averageTime / this.tree.totalTime * 100.0; + }, + + get selfPercent() + { + return this.selfTime / this.tree.totalTime * 100.0; + }, + + get totalPercent() + { + return this.totalTime / this.tree.totalTime * 100.0; + }, + + // When focusing and collapsing we modify lots of nodes in the tree. + // This allows us to restore them all to their original state when we revert. + _save: function() + { + if (this._savedChildren) + return; + + this._savedSelfTime = this.selfTime; + this._savedTotalTime = this.totalTime; + this._savedNumberOfCalls = this.numberOfCalls; + + this._savedChildren = this.children.slice(); + }, + + // When focusing and collapsing we modify lots of nodes in the tree. + // This allows us to restore them all to their original state when we revert. + _restore: function() + { + if (!this._savedChildren) + return; + + this.selfTime = this._savedSelfTime; + this.totalTime = this._savedTotalTime; + this.numberOfCalls = this._savedNumberOfCalls; + + this.removeChildren(); + + var children = this._savedChildren; + var count = children.length; + + for (var index = 0; index < count; ++index) { + children[index]._restore(); + this.appendChild(children[index]); + } + }, + + _merge: function(child, shouldAbsorb) + { + this.selfTime += child.selfTime; + + if (!shouldAbsorb) { + this.totalTime += child.totalTime; + this.numberOfCalls += child.numberOfCalls; + } + + var children = this.children.slice(); + + this.removeChildren(); + + var count = children.length; + + for (var index = 0; index < count; ++index) { + if (!shouldAbsorb || children[index] !== child) + this.appendChild(children[index]); + } + + children = child.children.slice(); + count = children.length; + + for (var index = 0; index < count; ++index) { + var orphanedChild = children[index], + existingChild = this.childrenByCallUID[orphanedChild.callUID]; + + if (existingChild) + existingChild._merge(orphanedChild, false); + else + this.appendChild(orphanedChild); + } + } +} + +WebInspector.ProfileDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; + +WebInspector.ProfileDataGridTree = function(profileView, profileNode) +{ + this.tree = this; + this.children = []; + + this.profileView = profileView; + + this.totalTime = profileNode.totalTime; + this.lastComparator = null; + + this.childrenByCallUID = {}; +} + +WebInspector.ProfileDataGridTree.prototype = { + get expanded() + { + return true; + }, + + appendChild: function(child) + { + this.insertChild(child, this.children.length); + }, + + insertChild: function(child, index) + { + this.children.splice(index, 0, child); + this.childrenByCallUID[child.callUID] = child; + }, + + removeChildren: function() + { + this.children = []; + this.childrenByCallUID = {}; + }, + + findChild: WebInspector.ProfileDataGridNode.prototype.findChild, + sort: WebInspector.ProfileDataGridNode.prototype.sort, + + _save: function() + { + if (this._savedChildren) + return; + + this._savedTotalTime = this.totalTime; + this._savedChildren = this.children.slice(); + }, + + restore: function() + { + if (!this._savedChildren) + return; + + this.children = this._savedChildren; + this.totalTime = this._savedTotalTime; + + var children = this.children; + var count = children.length; + + for (var index = 0; index < count; ++index) + children[index]._restore(); + + this._savedChildren = null; + } +} + +WebInspector.ProfileDataGridTree.propertyComparators = [{}, {}]; + +WebInspector.ProfileDataGridTree.propertyComparator = function(/*String*/ property, /*Boolean*/ isAscending) +{ + var comparator = this.propertyComparators[(isAscending ? 1 : 0)][property]; + + if (!comparator) { + if (isAscending) { + comparator = function(lhs, rhs) + { + if (lhs[property] < rhs[property]) + return -1; + + if (lhs[property] > rhs[property]) + return 1; + + return 0; + } + } else { + comparator = function(lhs, rhs) + { + if (lhs[property] > rhs[property]) + return -1; + + if (lhs[property] < rhs[property]) + return 1; + + return 0; + } + } + + this.propertyComparators[(isAscending ? 1 : 0)][property] = comparator; + } + + return comparator; +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/codemap.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/codemap.js new file mode 100644 index 0000000..3766db0 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/codemap.js @@ -0,0 +1,230 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Constructs a mapper that maps addresses into code entries. + * + * @constructor + */ +devtools.profiler.CodeMap = function() { + /** + * Dynamic code entries. Used for JIT compiled code. + */ + this.dynamics_ = new goog.structs.SplayTree(); + + /** + * Name generator for entries having duplicate names. + */ + this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator(); + + /** + * Static code entries. Used for libraries code. + */ + this.statics_ = new goog.structs.SplayTree(); + + /** + * Map of memory pages occupied with static code. + */ + this.pages_ = []; +}; + + +/** + * The number of alignment bits in a page address. + */ +devtools.profiler.CodeMap.PAGE_ALIGNMENT = 12; + + +/** + * Page size in bytes. + */ +devtools.profiler.CodeMap.PAGE_SIZE = + 1 << devtools.profiler.CodeMap.PAGE_ALIGNMENT; + + +/** + * Adds a dynamic (i.e. moveable and discardable) code entry. + * + * @param {number} start The starting address. + * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. + */ +devtools.profiler.CodeMap.prototype.addCode = function(start, codeEntry) { + 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. + */ +devtools.profiler.CodeMap.prototype.moveCode = function(from, to) { + var removedNode = this.dynamics_.remove(from); + 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. + */ +devtools.profiler.CodeMap.prototype.deleteCode = function(start) { + var removedNode = this.dynamics_.remove(start); +}; + + +/** + * Adds a static code entry. + * + * @param {number} start The starting address. + * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. + */ +devtools.profiler.CodeMap.prototype.addStaticCode = function( + start, codeEntry) { + this.markPages_(start, start + codeEntry.size); + this.statics_.insert(start, codeEntry); +}; + + +/** + * @private + */ +devtools.profiler.CodeMap.prototype.markPages_ = function(start, end) { + for (var addr = start; addr <= end; + addr += devtools.profiler.CodeMap.PAGE_SIZE) { + this.pages_[addr >> devtools.profiler.CodeMap.PAGE_ALIGNMENT] = 1; + } +}; + + +/** + * @private + */ +devtools.profiler.CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) { + return addr >= node.key && addr < (node.key + node.value.size); +}; + + +/** + * @private + */ +devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) { + var node = tree.findGreatestLessThan(addr); + return node && this.isAddressBelongsTo_(addr, node) ? node.value : null; +}; + + +/** + * Finds a code entry that contains the specified address. Both static and + * dynamic code entries are considered. + * + * @param {number} addr Address. + */ +devtools.profiler.CodeMap.prototype.findEntry = function(addr) { + var pageAddr = addr >> devtools.profiler.CodeMap.PAGE_ALIGNMENT; + if (pageAddr in this.pages_) { + return this.findInTree_(this.statics_, addr); + } + 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. + if (!dynaEntry.nameUpdated_) { + dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name); + dynaEntry.nameUpdated_ = true; + } + return dynaEntry; + } + return null; +}; + + +/** + * Returns an array of all dynamic code entries, including deleted ones. + */ +devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() { + return this.dynamics_.exportValues(); +}; + + +/** + * Returns an array of all static code entries. + */ +devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() { + return this.statics_.exportValues(); +}; + + +/** + * Creates a code entry object. + * + * @param {number} size Code entry size in bytes. + * @param {string} opt_name Code entry name. + * @constructor + */ +devtools.profiler.CodeMap.CodeEntry = function(size, opt_name) { + this.size = size; + this.name = opt_name || ''; + this.nameUpdated_ = false; +}; + + +devtools.profiler.CodeMap.CodeEntry.prototype.getName = function() { + return this.name; +}; + + +devtools.profiler.CodeMap.CodeEntry.prototype.toString = function() { + return this.name + ': ' + this.size.toString(16); +}; + + +devtools.profiler.CodeMap.NameGenerator = function() { + this.knownNames_ = []; +}; + + +devtools.profiler.CodeMap.NameGenerator.prototype.getName = function(name) { + if (!(name in this.knownNames_)) { + this.knownNames_[name] = 0; + return name; + } + var count = ++this.knownNames_[name]; + return name + ' {' + count + '}'; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/consarray.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/consarray.js new file mode 100644 index 0000000..c67abb7 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/consarray.js @@ -0,0 +1,93 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +/** + * Constructs a ConsArray object. It is used mainly for tree traversal. + * In this use case we have lots of arrays that we need to iterate + * sequentally. The internal Array implementation is horribly slow + * when concatenating on large (10K items) arrays due to memory copying. + * That's why we avoid copying memory and insead build a linked list + * of arrays to iterate through. + * + * @constructor + */ +function ConsArray() { + this.tail_ = new ConsArray.Cell(null, null); + this.currCell_ = this.tail_; + this.currCellPos_ = 0; +}; + + +/** + * Concatenates another array for iterating. Empty arrays are ignored. + * This operation can be safely performed during ongoing ConsArray + * iteration. + * + * @param {Array} arr Array to concatenate. + */ +ConsArray.prototype.concat = function(arr) { + if (arr.length > 0) { + this.tail_.data = arr; + this.tail_ = this.tail_.next = new ConsArray.Cell(null, null); + } +}; + + +/** + * Whether the end of iteration is reached. + */ +ConsArray.prototype.atEnd = function() { + return this.currCell_ === null || + this.currCell_.data === null || + this.currCellPos_ >= this.currCell_.data.length; +}; + + +/** + * Returns the current item, moves to the next one. + */ +ConsArray.prototype.next = function() { + var result = this.currCell_.data[this.currCellPos_++]; + if (this.currCellPos_ >= this.currCell_.data.length) { + this.currCell_ = this.currCell_.next; + this.currCellPos_ = 0; + } + return result; +}; + + +/** + * A cell object used for constructing a list in ConsArray. + * + * @constructor + */ +ConsArray.Cell = function(data, next) { + this.data = data; + this.next = next; +}; + diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/csvparser.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/csvparser.js new file mode 100644 index 0000000..9e58dea --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/csvparser.js @@ -0,0 +1,98 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Initlialize namespaces. +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Creates a CSV lines parser. + */ +devtools.profiler.CsvParser = function() { +}; + + +/** + * A regex for matching a trailing quote. + * @private + */ +devtools.profiler.CsvParser.TRAILING_QUOTE_RE_ = /\"$/; + + +/** + * A regex for matching a double quote. + * @private + */ +devtools.profiler.CsvParser.DOUBLE_QUOTE_RE_ = /\"\"/g; + + +/** + * Parses a line of CSV-encoded values. Returns an array of fields. + * + * @param {string} line Input line. + */ +devtools.profiler.CsvParser.prototype.parseLine = function(line) { + var insideQuotes = false; + var fields = []; + var prevPos = 0; + for (var i = 0, n = line.length; i < n; ++i) { + switch (line.charAt(i)) { + case ',': + if (!insideQuotes) { + fields.push(line.substring(prevPos, i)); + prevPos = i + 1; + } + break; + case '"': + if (!insideQuotes) { + insideQuotes = true; + // Skip the leading quote. + prevPos++; + } else { + if (i + 1 < n && line.charAt(i + 1) != '"') { + insideQuotes = false; + } else { + i++; + } + } + break; + } + } + if (n > 0) { + fields.push(line.substring(prevPos)); + } + + for (i = 0; i < fields.length; ++i) { + // Eliminate trailing quotes. + fields[i] = fields[i].replace(devtools.profiler.CsvParser.TRAILING_QUOTE_RE_, ''); + // Convert quoted quotes into single ones. + fields[i] = fields[i].replace(devtools.profiler.CsvParser.DOUBLE_QUOTE_RE_, '"'); + } + return fields; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js index 4454b83..890f704 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/debugger_agent.js @@ -15,13 +15,25 @@ goog.provide('devtools.DebuggerAgent'); devtools.DebuggerAgent = function() { RemoteDebuggerAgent.DebuggerOutput = goog.bind(this.handleDebuggerOutput_, this); - + RemoteDebuggerAgent.DidGetContextId = + goog.bind(this.didGetContextId_, this); + RemoteDebuggerAgent.DidIsProfilingStarted = + goog.bind(this.didIsProfilingStarted_, this); + RemoteDebuggerAgent.DidGetLogLines = + goog.bind(this.didGetLogLines_, this); + + /** + * Id of the inspected page global context. It is used for filtering scripts. + * @type {number} + */ + this.contextId_ = null; + /** * Mapping from script id to script info. * @type {Object} */ this.parsedScripts_ = null; - + /** * Mapping from the request id to the devtools.BreakpointInfo for the * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for @@ -30,36 +42,74 @@ devtools.DebuggerAgent = function() { * @type {Object} */ this.requestNumberToBreakpointInfo_ = null; - + /** * Information on current stack top frame. * See JavaScriptCallFrame.idl. * @type {?devtools.CallFrame} */ this.currentCallFrame_ = null; - + /** * Whether to stop in the debugger on the exceptions. * @type {boolean} */ this.pauseOnExceptions_ = true; - + /** * Mapping: request sequence number->callback. * @type {Object} */ - this.requestSeqToCallback_ = null; + this.requestSeqToCallback_ = null; + + /** + * Whether the scripts list has been requested. + * @type {boolean} + */ + this.scriptsCacheInitialized_ = false; + + /** + * Whether user has stopped profiling and we are retrieving the rest of + * profiler's log. + * @type {boolean} + */ + this.isProcessingProfile_ = false; + + /** + * The position in log file to read from. + * @type {number} + */ + this.lastProfileLogPosition_ = 0; + + /** + * Profiler processor instance. + * @type {devtools.profiler.Processor} + */ + this.profilerProcessor_ = new devtools.profiler.Processor(); }; /** * Resets debugger agent to its initial state. */ - devtools.DebuggerAgent.prototype.reset = function() { - this.parsedScripts_ = {}; - this.requestNumberToBreakpointInfo_ = {}; - this.currentCallFrame_ = null; - this.requestSeqToCallback_ = {}; +devtools.DebuggerAgent.prototype.reset = function() { + this.scriptsCacheInitialized_ = false; + this.contextId_ = null; + this.parsedScripts_ = {}; + this.requestNumberToBreakpointInfo_ = {}; + this.currentCallFrame_ = null; + this.requestSeqToCallback_ = {}; +}; + + +/** + * Requests scripts list if it has not been requested yet. + */ +devtools.DebuggerAgent.prototype.initializeScriptsCache = function() { + if (!this.scriptsCacheInitialized_) { + this.scriptsCacheInitialized_ = true; + this.requestScripts(); + } }; @@ -68,12 +118,51 @@ devtools.DebuggerAgent = function() { * processed in handleScriptsResponse_. */ devtools.DebuggerAgent.prototype.requestScripts = function() { + if (this.contextId_ === null) { + // Update context id first to filter the scripts. + RemoteDebuggerAgent.GetContextId(); + return; + } + var cmd = new devtools.DebugCommand('scripts', { + 'includeSource': false + }); + devtools.DebuggerAgent.sendCommand_(cmd); + // Force v8 execution so that it gets to processing the requested command. + devtools.tools.evaluateJavaScript('javascript:void(0)'); +}; + + +/** + * Asynchronously requests the debugger for the script source. + * @param {number} scriptId Id of the script whose source should be resolved. + * @param {function(source:?string):void} callback Function that will be called + * when the source resolution is completed. 'source' parameter will be null + * if the resolution fails. + */ +devtools.DebuggerAgent.prototype.resolveScriptSource = function( + scriptId, callback) { + var script = this.parsedScripts_[scriptId]; + if (!script) { + callback(null); + return; + } + var cmd = new devtools.DebugCommand('scripts', { + 'ids': [scriptId], 'includeSource': true }); devtools.DebuggerAgent.sendCommand_(cmd); // Force v8 execution so that it gets to processing the requested command. devtools.tools.evaluateJavaScript('javascript:void(0)'); + + this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { + if (msg.isSuccess()) { + var scriptJson = msg.getBody()[0]; + callback(scriptJson.source); + } else { + callback(null); + } + }; }; @@ -94,14 +183,14 @@ devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line) { if (!script) { return; } - + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); - + var breakpointInfo = script.getBreakpointInfo(line); if (breakpointInfo) { return; } - + breakpointInfo = new devtools.BreakpointInfo(sourceId, line); script.addBreakpointInfo(breakpointInfo); @@ -110,9 +199,9 @@ devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line) { 'target': sourceId, 'line': line }); - + this.requestNumberToBreakpointInfo_[cmd.getSequenceNumber()] = breakpointInfo; - + devtools.DebuggerAgent.sendCommand_(cmd); }; @@ -126,7 +215,7 @@ devtools.DebuggerAgent.prototype.removeBreakpoint = function(sourceId, line) { if (!script) { return; } - + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); var breakpointInfo = script.getBreakpointInfo(line); @@ -182,7 +271,7 @@ devtools.DebuggerAgent.prototype.resumeExecution = function() { * @return {boolean} True iff the debugger will pause execution on the * exceptions. */ -devtools.DebuggerAgent.prototype.pauseOnExceptions = function() { +devtools.DebuggerAgent.prototype.pauseOnExceptions = function() { return this.pauseOnExceptions_; }; @@ -192,7 +281,7 @@ devtools.DebuggerAgent.prototype.pauseOnExceptions = function() { * @param {boolean} value True iff execution should be stopped in the debugger * on the exceptions. */ -devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value) {
+devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value) { this.pauseOnExceptions_ = value; }; @@ -229,28 +318,51 @@ devtools.DebuggerAgent.prototype.requestEvaluate = function( * children are resolved. */ devtools.DebuggerAgent.prototype.resolveChildren = function(object, callback) { - var handles = []; - var names = []; - for (var name in object) { - var value = object[name]; - if (goog.isObject(value) && 'ref' in value) { - handles.push(value.ref); - names.push(name); + if ('ref' in object) { + this.requestLookup_([object.ref], function(msg) { + var result = {}; + if (msg.isSuccess()) { + var handleToObject = msg.getBody(); + var resolved = handleToObject[object.ref]; + devtools.DebuggerAgent.formatObjectProperties_(resolved, result); + } else { + result.error = 'Failed to resolve children: ' + msg.getMessage(); + } + object.resolvedValue = result; + callback(object); + }); + + return; + } else { + if (!object.resolvedValue) { + var message = 'Corrupted object: ' + JSON.stringify(object); + object.resolvedValue = {}; + object.resolvedValue.error = message; } - } - if (handles.length == 0) { callback(object); + } +}; + + +/** + * Starts (resumes) profiling. + */ +devtools.DebuggerAgent.prototype.startProfiling = function() { + if (this.isProcessingProfile_) { return; } - this.requestLookup_(handles, function(msg) { - var handleToObject = msg.getBody(); - for (var i = 0; i < names.length; i++) { - var name = names[i]; - var jsonObj = handleToObject[object[name].ref] - object[name] = devtools.DebuggerAgent.formatValue_(jsonObj, msg); - } - callback(object); - }); + RemoteDebuggerAgent.StartProfiling(); + // Query if profiling has been really started. + RemoteDebuggerAgent.IsProfilingStarted(); +}; + + +/** + * Stops (pauses) profiling. + */ +devtools.DebuggerAgent.prototype.stopProfiling = function() { + this.isProcessingProfile_ = true; + RemoteDebuggerAgent.StopProfiling(); }; @@ -271,7 +383,9 @@ devtools.DebuggerAgent.prototype.requestClearBreakpoint_ = function( * Sends 'backtrace' request to v8. */ devtools.DebuggerAgent.prototype.requestBacktrace_ = function() { - var cmd = new devtools.DebugCommand('backtrace'); + var cmd = new devtools.DebugCommand('backtrace', { + 'compactFormat':true + }); devtools.DebuggerAgent.sendCommand_(cmd); }; @@ -304,6 +418,7 @@ devtools.DebuggerAgent.prototype.stepCommand_ = function(action) { */ devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback) { var cmd = new devtools.DebugCommand('lookup', { + 'compactFormat':true, 'handles': handles }); devtools.DebuggerAgent.sendCommand_(cmd); @@ -312,6 +427,17 @@ devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback) { /** + * Handles GetContextId response. + * @param {number} contextId Id of the inspected page global context. + */ +devtools.DebuggerAgent.prototype.didGetContextId_ = function(contextId) { + this.contextId_ = contextId; + // Update scripts. + this.requestScripts(); +}; + + +/** * Handles output sent by v8 debugger. The output is either asynchronous event * or response to a previously sent request. See protocol definitioun for more * details on the output format. @@ -325,8 +451,8 @@ devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output) { debugPrint('Failed to handle debugger reponse:\n' + e); throw e; } - - + + if (msg.getType() == 'event') { if (msg.getEvent() == 'break') { this.handleBreakEvent_(msg); @@ -383,15 +509,15 @@ devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) { if (body.script) { sourceId = body.script.id; } - + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); - + this.currentCallFrame_ = new devtools.CallFrame(); this.currentCallFrame_.sourceID = sourceId; this.currentCallFrame_.line = line; this.currentCallFrame_.script = body.script; this.requestBacktrace_(); - } else { + } else { this.resumeExecution(); } }; @@ -401,10 +527,19 @@ devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) { * @param {devtools.DebuggerMessage} msg */ devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg) { + if (this.invokeCallbackForResponse_(msg)) { + return; + } + var scripts = msg.getBody(); for (var i = 0; i < scripts.length; i++) { var script = scripts[i]; - + + // Skip scripts from other tabs. + if (!this.isScriptFromInspectedContext_(script, msg)) { + continue; + } + // We may already have received the info in an afterCompile event. if (script.id in this.parsedScripts_) { continue; @@ -415,11 +550,33 @@ devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg) { /** + * @param {Object} script Json object representing script. + * @param {devtools.DebuggerMessage} msg Debugger response. + */ +devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_ = function( + script, msg) { + if (!script.context) { + // Always ignore scripts from the utility context. + return false; + } + var context = msg.lookup(script.context.ref); + var scriptContextId = context.data; + if (!goog.isDef(scriptContextId)) { + return false; // Always ignore scripts from the utility context. + } + if (this.contextId_ === null) { + return true; + } + return (scriptContextId == this.contextId_); +}; + + +/** * @param {devtools.DebuggerMessage} msg */ devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg) { var requestSeq = msg.getRequestSeq(); - var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq]; + var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq]; if (!breakpointInfo) { // TODO(yurys): handle this case return; @@ -431,7 +588,7 @@ devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg) { } var idInV8 = msg.getBody().breakpoint; breakpointInfo.setV8Id(idInV8); - + if (breakpointInfo.isRemoved()) { this.requestClearBreakpoint_(idInV8); } @@ -443,11 +600,50 @@ devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg) { */ devtools.DebuggerAgent.prototype.handleAfterCompileEvent_ = function(msg) { var script = msg.getBody().script; + // Ignore scripts from other tabs. + if (!this.isScriptFromInspectedContext_(script, msg)) { + return; + } this.addScriptInfo_(script); }; /** + * Handles current profiler status. + */ +devtools.DebuggerAgent.prototype.didIsProfilingStarted_ = function( + is_started) { + if (is_started) { + // Start to query log data. + RemoteDebuggerAgent.GetLogLines(this.lastProfileLogPosition_); + } + WebInspector.setRecordingProfile(is_started); +}; + + +/** + * Handles a portion of a profiler log retrieved by GetLogLines call. + * @param {string} log A portion of profiler log. + * @param {number} newPosition The position in log file to read from + * next time. + */ +devtools.DebuggerAgent.prototype.didGetLogLines_ = function( + log, newPosition) { + if (log.length > 0) { + this.profilerProcessor_.processLogChunk(log); + this.lastProfileLogPosition_ = newPosition; + } else if (this.isProcessingProfile_) { + this.isProcessingProfile_ = false; + WebInspector.setRecordingProfile(false); + WebInspector.addProfile(this.profilerProcessor_.createProfileForView()); + return; + } + setTimeout(function() { RemoteDebuggerAgent.GetLogLines(newPosition); }, + this.isProcessingProfile_ ? 100 : 1000); +}; + + +/** * Adds the script info to the local cache. This method assumes that the script * is not in the cache yet. * @param {Object} script Script json object from the debugger message. @@ -477,9 +673,9 @@ devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) { if (!this.currentCallFrame_) { return; } - + var script = this.currentCallFrame_.script; - + var callerFrame = null; var f = null; var frames = msg.getBody().frames; @@ -490,9 +686,9 @@ devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) { f.caller = callerFrame; callerFrame = f; } - + this.currentCallFrame_ = f; - + WebInspector.pausedScript(); DevToolsHost.activateWindow(); }; @@ -501,15 +697,18 @@ devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) { /** * Handles response to a command by invoking its callback (if any). * @param {devtools.DebuggerMessage} msg + * @return {boolean} Whether a callback for the given message was found and + * excuted. */ devtools.DebuggerAgent.prototype.invokeCallbackForResponse_ = function(msg) { var callback = this.requestSeqToCallback_[msg.getRequestSeq()]; if (!callback) { // It may happend if reset was called. - return; + return false; } delete this.requestSeqToCallback_[msg.getRequestSeq()]; callback(msg); + return true; }; @@ -526,26 +725,24 @@ devtools.DebuggerAgent.prototype.evaluateInCallFrame_ = function(expression) { */ devtools.DebuggerAgent.formatCallFrame_ = function(stackFrame, script, msg) { var sourceId = script.id; - var func = msg.lookup(stackFrame.func.ref); - var funcScript = msg.lookup(func.script.ref); - if (funcScript && 'id' in funcScript) { - sourceId = funcScript.id; - } - var funcName = devtools.DebuggerAgent.formatFunctionCall_(stackFrame, msg); - + var func = stackFrame.func; + var sourceId = func.scriptId; + var funcName = func.name || func.inferredName || '(anonymous function)'; + var scope = {}; - + // Add arguments. - devtools.DebuggerAgent.valuesArrayToMap_(stackFrame.arguments, scope, msg); - + devtools.DebuggerAgent.argumentsArrayToMap_(stackFrame.arguments, scope); + // Add local variables. - devtools.DebuggerAgent.valuesArrayToMap_(stackFrame.locals, scope, msg); + devtools.DebuggerAgent.propertiesToMap_(stackFrame.locals, scope); - var thisObject = msg.lookup(stackFrame.receiver.ref); + var thisObject = devtools.DebuggerAgent.formatObjectReference_( + stackFrame.receiver); // Add variable with name 'this' to the scope. - scope['this'] = devtools.DebuggerAgent.formatObject_(thisObject, msg); - + scope['this'] = thisObject; + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(stackFrame.line); var result = new devtools.CallFrame(); result.sourceID = sourceId; @@ -560,187 +757,86 @@ devtools.DebuggerAgent.formatCallFrame_ = function(stackFrame, script, msg) { /** - * Returns user-friendly representation of the function call from the stack - * frame. - * @param {Object} stackFrame Frame json object from 'backtrace' response. - * @return {!string} Function name with argument values. - */ -devtools.DebuggerAgent.formatFunctionCall_ = function(stackFrame, msg) { - var func = msg.lookup(stackFrame.func.ref); - return func.name || func.inferredName || '(anonymous function)'; -}; - - -/** - * Converts an object from the debugger response to the format understandable - * by ScriptsPanel. - * @param {Object} object An object from the debugger protocol response. - * @param {devtools.DebuggerMessage} msg Parsed debugger response. - * @return {!Object} Object describing 'object' in the format expected by - * ScriptsPanel and its panes. - */ -devtools.DebuggerAgent.formatObject_ = function(object, msg) { - var result = {}; - devtools.DebuggerAgent.formatObjectProperties_(object, msg, result); - return { 'value': result }; -}; - - -/** - * Converts a function from the debugger response to the format understandable - * by ScriptsPanel. - * @param {Object} func Function object from the debugger protocol response. - * @param {devtools.DebuggerMessage} msg Parsed debugger response. - * @return {!Object} Object describing 'func' in the format expected by - * ScriptsPanel and its panes. - */ -devtools.DebuggerAgent.formatFunction_ = function(func, msg) { - var result = {}; - devtools.DebuggerAgent.formatObjectProperties_(func, msg, result); - result.name = func.name; - - var holder = function() {}; - holder.value = result; - return holder; -}; - - -/** * Collects properties for an object from the debugger response. * @param {Object} object An object from the debugger protocol response. - * @param {devtools.DebuggerMessage} msg Parsed debugger response. * @param {Object} result A map to put the properties in. */ -devtools.DebuggerAgent.formatObjectProperties_ = function(object, - msg, result) { - devtools.DebuggerAgent.propertiesToMap_(object.properties, result, msg); +devtools.DebuggerAgent.formatObjectProperties_ = function(object, result) { + devtools.DebuggerAgent.propertiesToMap_(object.properties, result); result.protoObject = devtools.DebuggerAgent.formatObjectReference_( - object.protoObject, msg); + object.protoObject); result.prototypeObject = devtools.DebuggerAgent.formatObjectReference_( - object.prototypeObject, msg); + object.prototypeObject); result.constructorFunction = devtools.DebuggerAgent.formatObjectReference_( - object.constructorFunction, msg); + object.constructorFunction); }; /** * For each property in 'properties' puts its name and user-friendly value into * 'map'. - * @param {Array.<Object>} properties Receiver properties array from 'backtrace' - * response. + * @param {Array.<Object>} properties Receiver properties or locals array from + * 'backtrace' response. * @param {Object} map Result holder. - * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. */ -devtools.DebuggerAgent.propertiesToMap_ = function(properties, map, msg) { +devtools.DebuggerAgent.propertiesToMap_ = function(properties, map) { for (var j = 0; j < properties.length; j++) { var nextValue = properties[j]; - map[nextValue.name] = devtools.DebuggerAgent.formatObjectReference_( - nextValue, msg); + // Skip unnamed properties. They may appear e.g. when number of actual + // parameters is greater the that of formal. In that case the superfluous + // parameters will be present in the arguments list as elements without + // names. + if (nextValue.name) { + map[nextValue.name] = + devtools.DebuggerAgent.formatObjectReference_(nextValue.value); + } } }; /** - * For each property in 'array' puts its name and user-friendly value into - * 'map'. Each object referenced from the array is expected to be included in - * the message. - * @param {Array.<Object>} array Arguments or locals array from 'backtrace' - * response. + * Puts arguments from the protocol arguments array to the map assigning names + * to the anonymous arguments. + * @param {Array.<Object>} array Arguments array from 'backtrace' response. * @param {Object} map Result holder. - * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. */ -devtools.DebuggerAgent.valuesArrayToMap_ = function(array, map, msg) { +devtools.DebuggerAgent.argumentsArrayToMap_ = function(array, map) { for (var j = 0; j < array.length; j++) { var nextValue = array[j]; - - var object = msg.lookup(nextValue.value.ref); - var val = object ? - devtools.DebuggerAgent.formatValue_(object, msg) : - '<unresolved ref: ' + nextValue.value.ref + '>'; - map[nextValue.name] = val; - } -}; - - -/** - * TODO(yurys): we should merge all this formatting code with the one for - * elements tree. - * @param {Object} object An object reference from the debugger response. - * @param {devtools.DebuggerMessage} msg Parsed debugger response. - * @return {*} The reference representation expected by ScriptsPanel. - */ -devtools.DebuggerAgent.formatObjectReference_ = function(objectRef, msg) { - if (!('ref' in objectRef)) { - return objectRef; + // Skip unnamed properties. They may appear e.g. when number of actual + // parameters is greater the that of formal. In that case the superfluous + // parameters will be present in the arguments list as elements without + // names. + var name = nextValue.name ? nextValue.name : '<arg #' + j + '>'; + map[name] = devtools.DebuggerAgent.formatObjectReference_(nextValue.value); } - var object = msg.lookup(objectRef.ref); - if (!object) { - return objectRef; - } - switch (object.type) { - case 'number': - case 'string': - case 'boolean': - return object.value; - case 'undefined': - return undefined; - case 'null': - return null; - case 'function': { - var result = function() {}; - result.ref = objectRef.ref; - return result; - } - case 'object': - return objectRef; - default: - return objectRef; - }; }; /** - * @param {Object} object An object from the debugger response. - * @param {devtools.DebuggerMessage} msg Parsed debugger response. + * @param {Object} v An object reference from the debugger response. * @return {*} The value representation expected by ScriptsPanel. */ -devtools.DebuggerAgent.formatValue_ = function(object, msg) { - if (!object) { - return object; - } - switch (object.type) { - case 'number': - case 'string': - case 'boolean': - return object.value; - case 'undefined': - return undefined; - case 'null': - return null; - case 'function': - return devtools.DebuggerAgent.formatFunction_(object, msg); - case 'object': - return devtools.DebuggerAgent.formatObject_(object, msg); - default: - return '<invalid value>'; - }; -}; - - -devtools.DebuggerAgent.formatObjectReference_old = function(objectRef, msg) { - if (!objectRef.ref) { - return 'illegal ref'; - } - - var object = msg.lookup(objectRef.ref); - if (!object) { - return '{ref: ' + objectRef.ref + '}'; - } - - if ('value' in object) { - return object.value; +devtools.DebuggerAgent.formatObjectReference_ = function(v) { + if (v.type == 'object') { + return v; + } else if (v.type == 'function') { + var f = function() {}; + f.ref = v.ref; + return f; + } else if (goog.isDef(v.value)) { + return v.value; + } else if (v.type == 'undefined') { + return 'undefined'; + } else if (v.type == 'null') { + return 'null'; + } else if (v.name) { + return v.name; + } else if (v.className) { + return v.className; + } else { + return '<unresolved ref: ' + v.ref + ', type: ' + v.type + '>'; } - return '[' + object.type + ']'; }; @@ -773,7 +869,7 @@ devtools.DebuggerAgent.v8ToWwebkitLineNumber_ = function(line) { devtools.ScriptInfo = function(scriptId, lineOffset) { this.scriptId_ = scriptId; this.lineOffset_ = lineOffset; - + this.lineToBreakpointInfo_ = {}; }; @@ -823,7 +919,7 @@ devtools.ScriptInfo.prototype.removeBreakpointInfo = function(breakpoint) { */ devtools.BreakpointInfo = function(sourceId, line) { this.sourceId_ = sourceId; - this.line_ = line; + this.line_ = line; this.v8id_ = -1; this.removed_ = false; }; @@ -922,7 +1018,7 @@ devtools.CallFrame.prototype.evaluate = function(expression) { */ devtools.CallFrame.handleEvaluateResponse_ = function(response) { var body = response.getBody(); - var value = devtools.DebuggerAgent.formatValue_(body); + var value = devtools.DebuggerAgent.formatObjectReference_(body); WebInspector.addMessageToConsole(new WebInspector.ConsoleCommandResult( value, false /* exception */, null /* commandMessage */)); }; @@ -936,7 +1032,7 @@ devtools.CallFrame.handleEvaluateResponse_ = function(response) { */ devtools.DebugCommand = function(command, opt_arguments) { this.command_ = command; - this.type_ = 'request'; + this.type_ = 'request'; this.seq_ = ++devtools.DebugCommand.nextSeq_; if (opt_arguments) { this.arguments_ = opt_arguments; @@ -971,11 +1067,10 @@ devtools.DebugCommand.prototype.toJSONProtocol = function() { if (this.arguments_) { json.arguments = this.arguments_; } - return goog.json.serialize(json); + return JSON.stringify(json); }; - /** * JSON messages sent from v8 debugger. See protocol definition for more * details: http://code.google.com/p/v8/wiki/DebuggerProtocol diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html index 3176bea..5fd2c60 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.html @@ -54,6 +54,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="inspector_controller.js"></script> <script type="text/javascript" src="inspector_controller_impl.js"></script> <script type="text/javascript" src="inspector.js"></script> + <script type="text/javascript" src="codemap.js"></script> + <script type="text/javascript" src="consarray.js"></script> + <script type="text/javascript" src="csvparser.js"></script> + <script type="text/javascript" src="profile.js"></script> + <script type="text/javascript" src="profile_view.js"></script> + <script type="text/javascript" src="profiler_processor.js"></script> + <script type="text/javascript" src="splaytree.js"></script> <script type="text/javascript" src="Object.js"></script> <script type="text/javascript" src="TextPrompt.js"></script> <script type="text/javascript" src="Placard.js"></script> @@ -95,6 +102,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="DatabaseQueryView.js"></script> <script type="text/javascript" src="ScriptView.js"></script> <script type="text/javascript" src="ProfileView.js"></script> + <script type="text/javascript" src="ProfileDataGridTree.js"></script> <script type="text/javascript" src="devtools.js"></script> <script type="text/javascript" src="devtools_host_stub.js"></script> </head> diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js index 107a8ea..3b2a6e1 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools.js @@ -13,6 +13,29 @@ goog.require('devtools.DebuggerAgent'); goog.require('devtools.DomAgent'); goog.require('devtools.NetAgent'); + +/** + * Dispatches raw message from the host. + * @param {Object} msg Message to dispatch. + */ +devtools.dispatch = function(msg) { + var delegate = msg[0]; + var methodName = msg[1]; + var remoteName = 'Remote' + delegate.substring(0, delegate.length - 8); + var agent = window[remoteName]; + if (!agent) { + debugPrint('No remote agent "' + remoteName + '" found.'); + return; + } + var method = agent[methodName]; + if (!method) { + debugPrint('No method "' + remoteName + '.' + methodName + '" found.'); + return; + } + method.apply(this, msg.slice(2)); +}; + + devtools.ToolsAgent = function() { RemoteToolsAgent.DidEvaluateJavaScript = devtools.Callback.processCallback; RemoteToolsAgent.DidExecuteUtilityFunction = @@ -38,7 +61,6 @@ devtools.ToolsAgent.prototype.reset = function() { this.debuggerAgent_.reset(); this.domAgent_.getDocumentElementAsync(); - this.debuggerAgent_.requestScripts(); }; @@ -266,6 +288,17 @@ WebInspector.Console.prototype._evalInInspectedWindow = function(expr) { /** + * Disable autocompletion in the console. + * TODO(yurys): change WebKit implementation to allow asynchronous completion. + * @override + */ +WebInspector.Console.prototype.completions = function( + wordRange, bestMatchOnly) { + return null; +}; + + +/** * @override */ WebInspector.ElementsPanel.prototype.updateStyles = function(forceUpdate) { @@ -309,7 +342,7 @@ WebInspector.ElementsPanel.prototype.invokeWithStyleSet_ = if (node && node.nodeType == Node.ELEMENT_NODE) { var callback = function(stylesStr) { - var styles = goog.json.parse(stylesStr); + var styles = JSON.parse(stylesStr); if (!styles.computedStyle) { return; } @@ -375,7 +408,7 @@ WebInspector.PropertiesSidebarPane.prototype.update = function(object) { devtools.tools.getDomAgent().getNodePrototypesAsync(object.id_, function(json) { // Get array of prototype user-friendly names. - var prototypes = goog.json.parse(json); + var prototypes = JSON.parse(json); for (var i = 0; i < prototypes.length; ++i) { var prototype = {}; prototype.id_ = object.id_; @@ -469,7 +502,7 @@ WebInspector.SourceView.prototype.setupSourceFrameIfNeeded = function() { var netAgent = devtools.tools.getNetAgent(); netAgent.getResourceContentAsync(identifier, function(source) { - var resource = netAgent.getResource(identifier); + var resource = WebInspector.resources[identifier]; if (InspectorController.addSourceToFrame(resource.mimeType, source, element)) { delete self._frameNeedsSetup; @@ -487,6 +520,48 @@ WebInspector.SourceView.prototype.setupSourceFrameIfNeeded = function() { /** + * This override is necessary for adding script source asynchronously. + * @override + */ +WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded = function() { + if (!this._frameNeedsSetup) { + return; + } + + this.attach(); + + if (this.script.source) { + this.didResolveScriptSource_(); + } else { + var self = this; + devtools.tools.getDebuggerAgent().resolveScriptSource( + this.script.sourceID, + function(source) { + self.script.source = source || '<source is not available>'; + self.didResolveScriptSource_(); + }); + } +}; + + +/** + * Performs source frame setup when script source is aready resolved. + */ +WebInspector.ScriptView.prototype.didResolveScriptSource_ = function() { + if (!InspectorController.addSourceToFrame( + "text/javascript", this.script.source, this.sourceFrame.element)) { + return; + } + + delete this._frameNeedsSetup; + + this.sourceFrame.addEventListener( + "syntax highlighting complete", this._syntaxHighlightingComplete, this); + this.sourceFrame.syntaxHighlightJavascript(); +}; + + +/** * Dummy object used during properties inspection. * @see WebInspector.didGetNodePropertiesAsync_ */ @@ -505,7 +580,7 @@ WebInspector.dummyFunction_ = function() {}; */ WebInspector.didGetNodePropertiesAsync_ = function(treeOutline, constructor, nodeId, path, json) { - var props = goog.json.parse(json); + var props = JSON.parse(json); var properties = []; var obj = {}; obj.devtools$$nodeId_ = nodeId; @@ -596,7 +671,7 @@ WebInspector.ScopeChainSidebarPane.TreeElement.inherits( */ WebInspector.ScopeChainSidebarPane.TreeElement.prototype.onpopulate = function() { - var obj = this.parentObject[this.propertyName].value; + var obj = this.parentObject[this.propertyName]; devtools.tools.getDebuggerAgent().resolveChildren(obj, goog.bind(this.didResolveChildren_, this)); }; @@ -608,15 +683,15 @@ WebInspector.ScopeChainSidebarPane.TreeElement.prototype.onpopulate = WebInspector.ScopeChainSidebarPane.TreeElement.prototype.didResolveChildren_ = function(object) { this.removeChildren(); - var constructor = this.treeOutline.section.treeElementConstructor; + object = object.resolvedValue; for (var name in object) { this.appendChild(new constructor(object, name)); } }; -/**
+/** * @override */ WebInspector.StylePropertyTreeElement.prototype.toggleEnabled = @@ -705,3 +780,131 @@ WebInspector.Console.prototype._evalInInspectedWindow = function(expression) { // the command log message. return 'evaluating...'; }; + + +(function() { + var oldShow = WebInspector.ScriptsPanel.prototype.show; + WebInspector.ScriptsPanel.prototype.show = function() { + devtools.tools.getDebuggerAgent().initializeScriptsCache(); + oldShow.call(this); + }; +})(); + + +/** + * We don't use WebKit's BottomUpProfileDataGridTree, instead using + * our own (because BottomUpProfileDataGridTree's functionality is + * implemented in profile_view.js for V8's Tick Processor). + * + * @param {WebInspector.ProfileView} profileView Profile view. + * @param {devtools.profiler.ProfileView} profile Profile. + */ +WebInspector.BottomUpProfileDataGridTree = function(profileView, profile) { + return WebInspector.buildProfileDataGridTree_( + profileView, profile.heavyProfile); +}; + + +/** + * We don't use WebKit's TopDownProfileDataGridTree, instead using + * our own (because TopDownProfileDataGridTree's functionality is + * implemented in profile_view.js for V8's Tick Processor). + * + * @param {WebInspector.ProfileView} profileView Profile view. + * @param {devtools.profiler.ProfileView} profile Profile. + */ +WebInspector.TopDownProfileDataGridTree = function(profileView, profile) { + return WebInspector.buildProfileDataGridTree_( + profileView, profile.treeProfile); +}; + + +/** + * A helper function, checks whether a profile node has visible children. + * + * @param {devtools.profiler.ProfileView.Node} profileNode Profile node. + * @return {boolean} Whether a profile node has visible children. + */ +WebInspector.nodeHasChildren_ = function(profileNode) { + var children = profileNode.children; + for (var i = 0, n = children.length; i < n; ++i) { + if (children[i].visible) { + return true; + } + } + return false; +}; + + +/** + * Common code for populating a profiler grid node or a tree with + * given profile nodes. + * + * @param {WebInspector.ProfileDataGridNode| + * WebInspector.ProfileDataGridTree} viewNode Grid node or a tree. + * @param {WebInspector.ProfileView} profileView Profile view. + * @param {Array<devtools.profiler.ProfileView.Node>} children Profile nodes. + * @param {WebInspector.ProfileDataGridTree} owningTree Grid tree. + */ +WebInspector.populateNode_ = function( + viewNode, profileView, children, owningTree) { + for (var i = 0, n = children.length; i < n; ++i) { + var child = children[i]; + if (child.visible) { + viewNode.appendChild( + new WebInspector.ProfileDataGridNode( + profileView, child, owningTree, + WebInspector.nodeHasChildren_(child))); + } + } +}; + + +/** + * A helper function for building a profile grid tree. + * + * @param {WebInspector.ProfileView} profileview Profile view. + * @param {devtools.profiler.ProfileView} profile Profile. + * @return {WebInspector.ProfileDataGridTree} Profile grid tree. + */ +WebInspector.buildProfileDataGridTree_ = function(profileView, profile) { + var children = profile.head.children; + var dataGridTree = new WebInspector.ProfileDataGridTree( + profileView, profile.head); + WebInspector.populateNode_(dataGridTree, profileView, children, dataGridTree); + return dataGridTree; +}; + + +/** + * @override + */ +WebInspector.ProfileDataGridNode.prototype._populate = function(event) { + var children = this.profileNode.children; + WebInspector.populateNode_(this, this.profileView, children, this.tree); + this.removeEventListener("populate", this._populate, this); +}; + + +// As columns in data grid can't be changed after initialization, +// we need to intercept the constructor and modify columns upon creation. +(function InterceptDataGridForProfiler() { + var originalDataGrid = WebInspector.DataGrid; + WebInspector.DataGrid = function(columns) { + if (('average' in columns) && ('calls' in columns)) { + delete columns['average']; + delete columns['calls']; + } + return new originalDataGrid(columns); + }; +})(); + + +/** + * @override + * TODO(pfeldman): Add l10n. + */ +WebInspector.UIString = function(string) +{ + return String.vsprintf(string, Array.prototype.slice.call(arguments, 1)); +} diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js index d91ed1b..801d42e 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/devtools_host_stub.js @@ -13,18 +13,37 @@ RemoteDebuggerAgentStub = function() { }; -RemoteDebuggerAgentStub.prototype.DebugAttach = function() { +RemoteDebuggerAgentStub.prototype.DebugBreak = function() { }; -RemoteDebuggerAgentStub.prototype.DebugDetach = function() { +RemoteDebuggerAgentStub.prototype.GetContextId = function() { + RemoteDebuggerAgent.DidGetContextId(3); }; -RemoteDebuggerAgentStub.prototype.DebugCommand = function() { +RemoteDebuggerAgentStub.prototype.StopProfiling = function() { }; -RemoteDebuggerAgentStub.prototype.DebugBreak = function() { +RemoteDebuggerAgentStub.prototype.StartProfiling = function() { }; +RemoteDebuggerAgentStub.prototype.IsProfilingStarted = function() { + setTimeout(function() { + RemoteDebuggerAgent.DidIsProfilingStarted(true); + }, 100); +}; + +RemoteDebuggerAgentStub.prototype.GetLogLines = function(pos) { + if (pos < RemoteDebuggerAgentStub.ProfilerLogBuffer.length) { + setTimeout(function() { + RemoteDebuggerAgent.DidGetLogLines( + RemoteDebuggerAgentStub.ProfilerLogBuffer, + pos + RemoteDebuggerAgentStub.ProfilerLogBuffer.length); + }, + 100); + } else { + setTimeout(function() { RemoteDebuggerAgent.DidGetLogLines('', pos); }, 100); + } +}; /** * @constructor @@ -38,7 +57,7 @@ RemoteDomAgentStub.sendDocumentElement_ = function() { 1, // id 1, // type = Node.ELEMENT_NODE, 'HTML', // nodeName - '', // nodeValue + '', // nodeValue ['foo','bar'], // attributes 2, // childNodeCount ]); @@ -53,7 +72,7 @@ RemoteDomAgentStub.sendChildNodes_ = function(id) { 2, // id 1, // type = Node.ELEMENT_NODE, 'DIV', // nodeName - '', // nodeValue + '', // nodeValue ['foo','bar'], // attributes 1, // childNodeCount ], @@ -61,17 +80,17 @@ RemoteDomAgentStub.sendChildNodes_ = function(id) { 3, // id 3, // type = Node.TEXT_NODE, '', // nodeName - 'Text', // nodeValue + 'Text', // nodeValue ] ]); } else if (id == 2) { - RemoteDomAgent.SetChildNodes(id, + RemoteDomAgent.SetChildNodes(id, [ [ 4, // id 1, // type = Node.ELEMENT_NODE, 'span', // nodeName - '', // nodeValue + '', // nodeValue ['foo','bar'], // attributes 0, // childNodeCount ] @@ -154,7 +173,7 @@ RemoteToolsAgentStub.prototype.EvaluateJavaScript = function(callId, script) { }; -RemoteToolsAgentStub.prototype.ExecuteUtilityFunction = function(callId, +RemoteToolsAgentStub.prototype.ExecuteUtilityFunction = function(callId, functionName, nodeId, args) { setTimeout(function() { var result = []; @@ -193,7 +212,7 @@ RemoteToolsAgentStub.prototype.ExecuteUtilityFunction = function(callId, alert('Unexpected utility function:' + functionName); } RemoteToolsAgent.DidExecuteUtilityFunction(callId, - goog.json.serialize(result), ''); + JSON.stringify(result), ''); }, 0); }; @@ -201,7 +220,7 @@ RemoteToolsAgentStub.prototype.ExecuteUtilityFunction = function(callId, RemoteToolsAgentStub.prototype.GetNodePrototypes = function(callId, nodeId) { setTimeout(function() { RemoteToolsAgent.DidGetNodePrototypes(callId, - goog.json.serialize()); + JSON.stringify()); }, 0); }; @@ -210,6 +229,20 @@ RemoteToolsAgentStub.prototype.ClearConsoleMessages = function() { }; +RemoteDebuggerAgentStub.ProfilerLogBuffer = + 'code-creation,LazyCompile,0x1000,256,"test1 http://aaa.js:1"\n' + + 'code-creation,LazyCompile,0x2000,256,"test2 http://bbb.js:2"\n' + + 'code-creation,LazyCompile,0x3000,256,"test3 http://ccc.js:3"\n' + + 'tick,0x1010,0x0,3\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x3010,0x0,3,0x2020, 0x1010\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x2030,0x0,3,0x2020, 0x1010\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x1010,0x0,3\n'; + + /** * @constructor */ @@ -217,7 +250,7 @@ RemoteDebuggerCommandExecutorStub = function() { }; -RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand = function() { +RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand = function(cmd) { }; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js index 09ea809..2cf8904 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/dom_agent.js @@ -832,7 +832,7 @@ devtools.DomAgent.prototype.getNodePropertiesAsync = function(nodeId, var callbackId = this.utilityFunctionCallbackWrapper_(callback); RemoteToolsAgent.ExecuteUtilityFunction(callbackId, 'getProperties', nodeId, - goog.json.serialize([path, protoDepth])); + JSON.stringify([path, protoDepth])); }; @@ -861,7 +861,7 @@ devtools.DomAgent.prototype.getNodeStylesAsync = function(node, RemoteToolsAgent.ExecuteUtilityFunction(callbackId, 'getStyles', node.id_, - goog.json.serialize([authorOnly])); + JSON.stringify([authorOnly])); }; @@ -878,7 +878,7 @@ devtools.DomAgent.prototype.toggleNodeStyleAsync = function( RemoteToolsAgent.ExecuteUtilityFunction(callbackId, 'toggleNodeStyle', style.nodeId_, - goog.json.serialize([style.id_, enabled, name])); + JSON.stringify([style.id_, enabled, name])); }; @@ -896,7 +896,7 @@ devtools.DomAgent.prototype.applyStyleTextAsync = function( callbackId, 'applyStyleText', style.nodeId_, - goog.json.serialize([style.id_, name, styleText])); + JSON.stringify([style.id_, name, styleText])); }; @@ -914,7 +914,7 @@ devtools.DomAgent.prototype.setStylePropertyAsync = function( callbackId, 'setStyleProperty', node.id_, - goog.json.serialize([name, value])); + JSON.stringify([name, value])); }; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js index 83c94d5..5c1050a 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inject.js @@ -6,7 +6,6 @@ * @fileoverview Javascript that is being injected into the inspectable page * while debugging. */ -goog.require('goog.json'); goog.provide('devtools.Injected'); diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js index 633dee5..4188849 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector.js @@ -41,7 +41,7 @@ var Preferences = { } var WebInspector = { - resources: [], + resources: {}, resourceURLMap: {}, missingLocalizedStrings: {}, @@ -771,9 +771,18 @@ WebInspector.showDatabasesPanel = function() this.currentPanel = this.panels.databases; } -WebInspector.addResource = function(resource) +WebInspector.addResource = function(identifier, payload) { - this.resources.push(resource); + var resource = new WebInspector.Resource( + payload.requestHeaders, + payload.requestURL, + payload.host, + payload.path, + payload.lastPathComponent, + identifier, + payload.isMainResource, + payload.cached); + this.resources[identifier] = resource; this.resourceURLMap[resource.url] = resource; if (resource.mainResource) { @@ -785,24 +794,83 @@ WebInspector.addResource = function(resource) this.panels.resources.addResource(resource); } -WebInspector.removeResource = function(resource) +WebInspector.updateResource = function(identifier, payload) { + var resource = this.resources[identifier]; + if (!resource) + return; + + if (payload.didRequestChange) { + resource.url = payload.url; + resource.domain = payload.domain; + resource.path = payload.path; + resource.lastPathComponent = payload.lastPathComponent; + resource.requestHeaders = payload.requestHeaders; + resource.mainResource = payload.mainResource; + } + + if (payload.didResponseChange) { + resource.mimeType = payload.mimeType; + resource.suggestedFilename = payload.suggestedFilename; + resource.expectedContentLength = payload.expectedContentLength; + resource.statusCode = payload.statusCode; + resource.suggestedFilename = payload.suggestedFilename; + resource.responseHeaders = payload.responseHeaders; + } + + if (payload.didTypeChange) { + resource.type = payload.type; + } + + if (payload.didLengthChange) { + resource.contentLength = payload.contentLength; + } + + if (payload.didCompletionChange) { + resource.failed = payload.failed; + resource.finished = payload.finished; + } + + if (payload.didTimingChange) { + if (payload.startTime) + resource.startTime = payload.startTime; + if (payload.responseReceivedTime) + resource.responseReceivedTime = payload.responseReceivedTime; + if (payload.endTime) + resource.endTime = payload.endTime; + } +} + +WebInspector.removeResource = function(identifier) +{ + var resource = this.resources[identifier]; + if (!resource) + return; + resource.category.removeResource(resource); delete this.resourceURLMap[resource.url]; - - this.resources.remove(resource, true); + delete this.resources[identifier]; if (this.panels.resources) this.panels.resources.removeResource(resource); } -WebInspector.addDatabase = function(database) +WebInspector.addDatabase = function(payload) { + var database = new WebInspector.Database( + payload.database, + payload.domain, + payload.name, + payload.version); this.panels.databases.addDatabase(database); } -WebInspector.addDOMStorage = function(domStorage) +WebInspector.addDOMStorage = function(payload) { + var domStorage = new WebInspector.DOMStorage( + payload.domStorage, + payload.host, + payload.isLocalStorage); this.panels.databases.addDOMStorage(domStorage); } @@ -866,7 +934,7 @@ WebInspector.reset = function() for (var category in this.resourceCategories) this.resourceCategories[category].removeAllResources(); - this.resources = []; + this.resources = {}; this.resourceURLMap = {}; this.hoveredDOMNode = null; @@ -886,9 +954,17 @@ WebInspector.resourceURLChanged = function(resource, oldURL) this.resourceURLMap[resource.url] = resource; } -WebInspector.addMessageToConsole = function(msg) +WebInspector.addMessageToConsole = function(payload) { - this.console.addMessage(msg); + var consoleMessage = new WebInspector.ConsoleMessage( + payload.source, + payload.level, + payload.line, + payload.url, + payload.groupLevel, + payload.repeatCount); + consoleMessage.setMessageBody(Array.prototype.slice.call(arguments, 1)); + this.console.addMessage(consoleMessage); } WebInspector.addProfile = function(profile) @@ -1263,6 +1339,7 @@ WebInspector.MIMETypes = { "image/png": {2: true}, "image/gif": {2: true}, "image/bmp": {2: true}, + "image/vnd.microsoft.icon": {2: true}, "image/x-icon": {2: true}, "image/x-xbitmap": {2: true}, "font/ttf": {3: true}, diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js index 09238e2..dd4193c 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller.js @@ -302,9 +302,9 @@ devtools.InspectorController.prototype.pauseOnExceptions = function() { * @param {boolean} value True iff execution should be stopped in the debugger * on the exceptions. */ -devtools.InspectorController.prototype.setPauseOnExceptions = function(value) {
-};
-
+devtools.InspectorController.prototype.setPauseOnExceptions = function(value) { +}; + /** * Tells backend to resume execution. diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js index 45abbe2..2f6f65e7 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/inspector_controller_impl.js @@ -145,4 +145,20 @@ devtools.InspectorControllerImpl.prototype.setPauseOnExceptions = function( }; +/** + * @override + */ +devtools.InspectorControllerImpl.prototype.startProfiling = function() { + devtools.tools.getDebuggerAgent().startProfiling(); +}; + + +/** + * @override + */ +devtools.InspectorControllerImpl.prototype.stopProfiling = function() { + devtools.tools.getDebuggerAgent().stopProfiling(); +}; + + var InspectorController = new devtools.InspectorControllerImpl(); diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js index 64ef4a6..957e119 100644 --- a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/net_agent.js @@ -10,7 +10,6 @@ goog.provide('devtools.NetAgent'); devtools.NetAgent = function() { - this.resources_ = {}; this.id_for_url_ = {}; RemoteNetAgent.GetResourceContentResult = @@ -28,22 +27,11 @@ devtools.NetAgent = function() { * Resets dom agent to its initial state. */ devtools.NetAgent.prototype.reset = function() { - this.resources_ = {}; this.id_for_url_ = {}; }; /** - * Returns resource object for given identifier. - * @param {number} identifier Identifier to get resource for. - * @return {WebInspector.Resouce} Resulting resource. - */ -devtools.NetAgent.prototype.getResource = function(identifier) { - return this.resources_[identifier]; -}; - - -/** * Asynchronously queries for the resource content. * @param {number} identifier Resource identifier. * @param {function(string):undefined} opt_callback Callback to call when @@ -51,7 +39,7 @@ devtools.NetAgent.prototype.getResource = function(identifier) { */ devtools.NetAgent.prototype.getResourceContentAsync = function(identifier, opt_callback) { - var resource = this.resources_[identifier]; + var resource = WebInspector.resources[identifier]; if (!resource) { return; } @@ -71,20 +59,15 @@ devtools.NetAgent.prototype.getResourceContentAsync = function(identifier, */ devtools.NetAgent.prototype.willSendRequest = function(identifier, request) { // Resource object is already created. - var resource = this.resources_[identifier]; + var resource = WebInspector.resources[identifier]; if (resource) { return; } - var mainResource = false; - var cached = false; - var resource = new WebInspector.Resource(request.requestHeaders, - request.url, request.domain, request.path, request.lastPathComponent, - identifier, mainResource, cached); + WebInspector.addResource(identifier, request); + var resource = WebInspector.resources[identifier]; resource.startTime = request.startTime; - WebInspector.addResource(resource); - this.resources_[identifier] = resource; - this.id_for_url_[request.url] = identifier; + this.id_for_url_[resource.url] = identifier; }; @@ -93,7 +76,7 @@ devtools.NetAgent.prototype.willSendRequest = function(identifier, request) { * {@inheritDoc}. */ devtools.NetAgent.prototype.didReceiveResponse = function(identifier, response) { - var resource = this.resources_[identifier]; + var resource = WebInspector.resources[identifier]; if (!resource) { return; } @@ -130,11 +113,14 @@ devtools.NetAgent.prototype.didFinishLoading = function(identifier, value) { this.willSendRequest(identifier, value); this.didReceiveResponse(identifier, value); - var resource = this.resources_[identifier]; + var resource = WebInspector.resources[identifier]; if (!resource) { return; } resource.endTime = value.endTime; resource.finished = true; resource.failed = !!value.errorCode; + if (resource.mainResource) { + document.title = 'Developer Tools - ' + resource.url; + } }; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profile.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profile.js new file mode 100644 index 0000000..614c635 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profile.js @@ -0,0 +1,605 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Creates a profile object for processing profiling-related events + * and calculating function execution times. + * + * @constructor + */ +devtools.profiler.Profile = function() { + this.codeMap_ = new devtools.profiler.CodeMap(); + this.topDownTree_ = new devtools.profiler.CallTree(); + this.bottomUpTree_ = new devtools.profiler.CallTree(); +}; + + +/** + * Returns whether a function with the specified name must be skipped. + * Should be overriden by subclasses. + * + * @param {string} name Function name. + */ +devtools.profiler.Profile.prototype.skipThisFunction = function(name) { + return false; +}; + + +/** + * Enum for profiler operations that involve looking up existing + * code entries. + * + * @enum {number} + */ +devtools.profiler.Profile.Operation = { + MOVE: 0, + DELETE: 1, + TICK: 2 +}; + + +/** + * Called whenever the specified operation has failed finding a function + * containing the specified address. Should be overriden by subclasses. + * See the devtools.profiler.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. + */ +devtools.profiler.Profile.prototype.handleUnknownCode = function( + operation, addr, opt_stackPos) { +}; + + +/** + * Registers static (library) code entry. + * + * @param {string} name Code entry name. + * @param {number} startAddr Starting address. + * @param {number} endAddr Ending address. + */ +devtools.profiler.Profile.prototype.addStaticCode = function( + name, startAddr, endAddr) { + var entry = new devtools.profiler.CodeMap.CodeEntry( + endAddr - startAddr, name); + 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. + */ +devtools.profiler.Profile.prototype.addCode = function( + type, name, start, size) { + var entry = new devtools.profiler.Profile.DynamicCodeEntry(size, type, name); + 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. + */ +devtools.profiler.Profile.prototype.moveCode = function(from, to) { + try { + this.codeMap_.moveCode(from, to); + } catch (e) { + this.handleUnknownCode(devtools.profiler.Profile.Operation.MOVE, from); + } +}; + + +/** + * Reports about deletion of a dynamic code entry. + * + * @param {number} start Starting address. + */ +devtools.profiler.Profile.prototype.deleteCode = function(start) { + try { + this.codeMap_.deleteCode(start); + } catch (e) { + this.handleUnknownCode(devtools.profiler.Profile.Operation.DELETE, start); + } +}; + + +/** + * Records a tick event. Stack must contain a sequence of + * addresses starting with the program counter value. + * + * @param {Array<number>} stack Stack sample. + */ +devtools.profiler.Profile.prototype.recordTick = function(stack) { + var 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. + */ +devtools.profiler.Profile.prototype.resolveAndFilterFuncs_ = function(stack) { + var result = []; + for (var i = 0; i < stack.length; ++i) { + var entry = this.codeMap_.findEntry(stack[i]); + if (entry) { + var name = entry.getName(); + if (!this.skipThisFunction(name)) { + result.push(name); + } + } else { + this.handleUnknownCode( + devtools.profiler.Profile.Operation.TICK, stack[i], i); + } + } + return result; +}; + + +/** + * Performs a BF traversal of the top down call graph. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) { + this.topDownTree_.traverse(f); +}; + + +/** + * Performs a BF traversal of the bottom up call graph. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.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. + */ +devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_label) { + return this.getTreeProfile_(this.topDownTree_, opt_label); +}; + + +/** + * 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. + */ +devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_label) { + return this.getTreeProfile_(this.bottomUpTree_, opt_label); +}; + + +/** + * Helper function for calculating a tree profile. + * + * @param {devtools.profiler.Profile.CallTree} tree Call tree. + * @param {string} opt_label Node label. + */ +devtools.profiler.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 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. + */ +devtools.profiler.Profile.prototype.getFlatProfile = function(opt_label) { + var counters = new devtools.profiler.CallTree(); + var rootLabel = opt_label || devtools.profiler.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; + } + } + 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; + } + return counters; +}; + + +/** + * Creates a dynamic code entry. + * + * @param {number} size Code size. + * @param {string} type Code type. + * @param {string} name Function name. + * @constructor + */ +devtools.profiler.Profile.DynamicCodeEntry = function(size, type, name) { + devtools.profiler.CodeMap.CodeEntry.call(this, size, name); + this.type = type; +}; + + +/** + * Returns node name. + */ +devtools.profiler.Profile.DynamicCodeEntry.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 this.type + ': ' + name; +}; + + +/** + * Constructs a call graph. + * + * @constructor + */ +devtools.profiler.CallTree = function() { + this.root_ = new devtools.profiler.CallTree.Node( + devtools.profiler.CallTree.ROOT_NODE_LABEL); +}; + + +/** + * The label of the root node. + */ +devtools.profiler.CallTree.ROOT_NODE_LABEL = ''; + + +/** + * @private + */ +devtools.profiler.CallTree.prototype.totalsComputed_ = false; + + +/** + * Returns the tree root. + */ +devtools.profiler.CallTree.prototype.getRoot = function() { + return this.root_; +}; + + +/** + * Adds the specified call path, constructing nodes as necessary. + * + * @param {Array<string>} path Call path. + */ +devtools.profiler.CallTree.prototype.addPath = function(path) { + if (path.length == 0) { + return; + } + 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. + */ +devtools.profiler.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. + */ +devtools.profiler.CallTree.prototype.cloneSubtree = function(label) { + var subTree = new devtools.profiler.CallTree(); + this.traverse(function(node, parent) { + if (!parent && node.label != label) { + return null; + } + var child = (parent ? parent : subTree).findOrAddChild(node.label); + child.selfWeight += node.selfWeight; + return child; + }); + return subTree; +}; + + +/** + * Computes total weights in the call graph. + */ +devtools.profiler.CallTree.prototype.computeTotalWeights = function() { + if (this.totalsComputed_) { + return; + } + this.root_.computeTotalWeight(); + this.totalsComputed_ = true; +}; + + +/** + * 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(devtools.profiler.CallTree.Node, *)} f Visitor function. + * The second parameter is the result of calling 'f' on the parent node. + */ +devtools.profiler.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}); }); + pairsToProcess.concat(morePairsToProcess); + } +}; + + +/** + * Performs an indepth call graph traversal. + * + * @param {function(devtools.profiler.CallTree.Node)} enter A function called + * prior to visiting node's children. + * @param {function(devtools.profiler.CallTree.Node)} exit A function called + * after visiting node's children. + */ +devtools.profiler.CallTree.prototype.traverseInDepth = function(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 {devtools.profiler.CallTree.Node} opt_parent Node parent. + */ +devtools.profiler.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} + */ +devtools.profiler.CallTree.Node.prototype.selfWeight = 0; + + +/** + * Node total weight (includes weights of all children). + * @type {number} + */ +devtools.profiler.CallTree.Node.prototype.totalWeight = 0; + + +/** + * Adds a child node. + * + * @param {string} label Child node label. + */ +devtools.profiler.CallTree.Node.prototype.addChild = function(label) { + var child = new devtools.profiler.CallTree.Node(label, this); + this.children[label] = child; + return child; +}; + + +/** + * Computes node's total weight. + */ +devtools.profiler.CallTree.Node.prototype.computeTotalWeight = + function() { + var totalWeight = this.selfWeight; + this.forEachChild(function(child) { + totalWeight += child.computeTotalWeight(); }); + return this.totalWeight = totalWeight; +}; + + +/** + * Returns all node's children as an array. + */ +devtools.profiler.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. + */ +devtools.profiler.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. + */ +devtools.profiler.CallTree.Node.prototype.findOrAddChild = function(label) { + return this.findChild(label) || this.addChild(label); +}; + + +/** + * Calls the specified function for every child. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.CallTree.Node.prototype.forEachChild = function(f) { + for (var c in this.children) { + f(this.children[c]); + } +}; + + +/** + * Walks up from the current node up to the call tree root. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.CallTree.Node.prototype.walkUpToRoot = function(f) { + for (var 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(devtools.profiler.CallTree.Node)} opt_f Visitor function. + */ +devtools.profiler.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); + } + curr = child; + } + return curr; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profile_view.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profile_view.js new file mode 100644 index 0000000..9d196a3 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profile_view.js @@ -0,0 +1,251 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Creates a Profile View builder object. + * + * @param {number} samplingRate Number of ms between profiler ticks. + * @constructor + */ +devtools.profiler.ViewBuilder = function(samplingRate) { + this.samplingRate = samplingRate; +}; + + +/** + * Builds a profile view for the specified call tree. + * + * @param {devtools.profiler.CallTree} callTree A call tree. + * @param {boolean} opt_bottomUpViewWeights Whether remapping + * of self weights for a bottom up view is needed. + */ +devtools.profiler.ViewBuilder.prototype.buildView = function( + callTree, opt_bottomUpViewWeights) { + var head; + var samplingRate = this.samplingRate; + callTree.traverse(function(node, viewParent) { + var totalWeight = node.totalWeight * samplingRate; + var selfWeight = node.selfWeight * samplingRate; + if (opt_bottomUpViewWeights === true) { + if (viewParent === head) { + selfWeight = totalWeight; + } else { + selfWeight = 0; + } + } + var viewNode = new devtools.profiler.ProfileView.Node( + node.label, totalWeight, selfWeight, head); + if (viewParent) { + viewParent.addChild(viewNode); + } else { + head = viewNode; + } + return viewNode; + }); + var view = new devtools.profiler.ProfileView(head); + return view; +}; + + +/** + * Creates a Profile View object. It allows to perform sorting + * and filtering actions on the profile. Profile View mimicks + * the Profile object from WebKit's JSC profiler. + * + * @param {devtools.profiler.ProfileView.Node} head Head (root) node. + * @constructor + */ +devtools.profiler.ProfileView = function(head) { + this.head = head; + this.title = ''; + this.uid = ''; + this.heavyProfile = null; + this.treeProfile = null; + this.flatProfile = null; +}; + + +/** + * Sorts the profile view using the specified sort function. + * + * @param {function(devtools.profiler.ProfileView.Node, + * devtools.profiler.ProfileView.Node):number} sortFunc A sorting + * functions. Must comply with Array.sort sorting function requirements. + */ +devtools.profiler.ProfileView.prototype.sort = function(sortFunc) { + this.traverse(function (node) { + node.sortChildren(sortFunc); + }); +}; + + +/** + * Traverses profile view nodes in preorder. + * + * @param {function(devtools.profiler.ProfileView.Node)} f Visitor function. + */ +devtools.profiler.ProfileView.prototype.traverse = function(f) { + var nodesToTraverse = new ConsArray(); + nodesToTraverse.concat([this.head]); + while (!nodesToTraverse.atEnd()) { + var node = nodesToTraverse.next(); + f(node); + nodesToTraverse.concat(node.children); + } +}; + + +/** + * Constructs a Profile View node object. Each node object corresponds to + * a function call. + * + * @param {string} internalFuncName A fully qualified function name. + * @param {number} totalTime Amount of time that application spent in the + * corresponding function and its descendants (not that depending on + * profile they can be either callees or callers.) + * @param {number} selfTime Amount of time that application spent in the + * corresponding function only. + * @param {devtools.profiler.ProfileView.Node} head Profile view head. + * @constructor + */ +devtools.profiler.ProfileView.Node = function( + internalFuncName, totalTime, selfTime, head) { + this.callIdentifier = 0; + this.internalFuncName = internalFuncName; + this.initFuncInfo(); + this.totalTime = totalTime; + this.selfTime = selfTime; + this.head = head; + this.parent = null; + this.children = []; + this.visible = true; +}; + + +/** + * RegEx for stripping V8's prefixes of compiled functions. + */ +devtools.profiler.ProfileView.Node.FUNC_NAME_STRIP_RE = + /^(?:LazyCompile|Function): (.*)$/; + + +/** + * RegEx for extracting script source URL and line number. + */ +devtools.profiler.ProfileView.Node.FUNC_NAME_PARSE_RE = /^([^ ]+) (.*):(\d+)$/; + + +/** + * RegEx for removing protocol name from URL. + */ +devtools.profiler.ProfileView.Node.URL_PARSE_RE = /^(?:http:\/)?.*\/([^/]+)$/; + + +/** + * Inits 'functionName', 'url', and 'lineNumber' fields using 'internalFuncName' + * field. + */ +devtools.profiler.ProfileView.Node.prototype.initFuncInfo = function() { + var nodeAlias = devtools.profiler.ProfileView.Node; + this.functionName = this.internalFuncName; + + var strippedName = nodeAlias.FUNC_NAME_STRIP_RE.exec(this.functionName); + if (strippedName) { + this.functionName = strippedName[1]; + } + + var parsedName = nodeAlias.FUNC_NAME_PARSE_RE.exec(this.functionName); + if (parsedName) { + this.url = parsedName[2]; + var parsedUrl = nodeAlias.URL_PARSE_RE.exec(this.url); + if (parsedUrl) { + this.url = parsedUrl[1]; + } + this.functionName = parsedName[1]; + this.lineNumber = parsedName[3]; + } else { + this.url = ''; + this.lineNumber = 0; + } +}; + + +/** + * Returns a share of the function's total time in application's total time. + */ +devtools.profiler.ProfileView.Node.prototype.__defineGetter__( + 'totalPercent', + function() { return this.totalTime / + (this.head ? this.head.totalTime : this.totalTime) * 100.0; }); + + +/** + * Returns a share of the function's self time in application's total time. + */ +devtools.profiler.ProfileView.Node.prototype.__defineGetter__( + 'selfPercent', + function() { return this.selfTime / + (this.head ? this.head.totalTime : this.totalTime) * 100.0; }); + + +/** + * Returns a share of the function's total time in its parent's total time. + */ +devtools.profiler.ProfileView.Node.prototype.__defineGetter__( + 'parentTotalPercent', + function() { return this.totalTime / + (this.parent ? this.parent.totalTime : this.totalTime) * 100.0; }); + + +/** + * Adds a child to the node. + * + * @param {devtools.profiler.ProfileView.Node} node Child node. + */ +devtools.profiler.ProfileView.Node.prototype.addChild = function(node) { + node.parent = this; + this.children.push(node); +}; + + +/** + * Sorts all the node's children recursively. + * + * @param {function(devtools.profiler.ProfileView.Node, + * devtools.profiler.ProfileView.Node):number} sortFunc A sorting + * functions. Must comply with Array.sort sorting function requirements. + */ +devtools.profiler.ProfileView.Node.prototype.sortChildren = function( + sortFunc) { + this.children.sort(sortFunc); +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profiler_processor.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profiler_processor.js new file mode 100644 index 0000000..e290350 --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/profiler_processor.js @@ -0,0 +1,201 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Profiler processor is used to process log file produced + * by V8 and produce an internal profile representation which is used + * for building profile views in 'Profiles' tab. + */ +goog.provide('devtools.profiler.Processor'); + + +/** + * Ancestor of a profile object that leaves out only JS-related functions. + * @constructor + */ +devtools.profiler.JsProfile = function() { + devtools.profiler.Profile.call(this); +}; +goog.inherits(devtools.profiler.JsProfile, devtools.profiler.Profile); + + +/** + * @type {RegExp} + */ +devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/; + + +/** + * @override + */ +devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { + return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name); +}; + + +/** + * Profiler processor. Consumes profiler log and builds profile views. + * @constructor + */ +devtools.profiler.Processor = function() { + /** + * Current profile. + * @type {devtools.profiler.JsProfile} + */ + this.profile_ = new devtools.profiler.JsProfile(); + + /** + * Builder of profile views. + * @type {devtools.profiler.ViewBuilder} + */ + this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); + + /** + * Next profile id. + * @type {number} + */ + this.profileId_ = 1; +}; + + +/** + * A dispatch table for V8 profiler event log records. + * @private + */ +devtools.profiler.Processor.RecordsDispatch_ = { + 'code-creation': { parsers: [null, parseInt, parseInt, null], + processor: 'processCodeCreation_' }, + 'code-move': { parsers: [parseInt, parseInt], + processor: 'processCodeMove_' }, + 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete_' }, + 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], + processor: 'processTick_' }, + // Not used in DevTools Profiler. + 'profiler': null, + 'shared-library': null, + // Obsolete row types. + 'code-allocate': null, + 'begin-code-region': null, + 'end-code-region': null +}; + + +/** + * Processes a portion of V8 profiler event log. + * + * @param {string} chunk A portion of log. + */ +devtools.profiler.Processor.prototype.processLogChunk = function(chunk) { + this.processLog_(chunk.split('\n')); +}; + + +/** + * Processes a log lines. + * + * @param {Array<string>} lines Log lines. + * @private + */ +devtools.profiler.Processor.prototype.processLog_ = function(lines) { + var csvParser = new devtools.profiler.CsvParser(); + try { + for (var i = 0, n = lines.length; i < n; ++i) { + var line = lines[i]; + if (!line) { + continue; + } + var fields = csvParser.parseLine(line); + this.dispatchLogRow_(fields); + } + } catch (e) { + debugPrint('line ' + (i + 1) + ': ' + (e.message || e)); + throw e; + } +}; + + +/** + * Does a dispatch of a log record. + * + * @param {Array<string>} fields Log record. + * @private + */ +devtools.profiler.Processor.prototype.dispatchLogRow_ = function(fields) { + // Obtain the dispatch. + var command = fields[0]; + if (!(command in devtools.profiler.Processor.RecordsDispatch_)) { + throw new Error('unknown command: ' + command); + } + var dispatch = devtools.profiler.Processor.RecordsDispatch_[command]; + + if (dispatch === null) { + return; + } + + // Parse fields. + var parsedFields = []; + for (var i = 0; i < dispatch.parsers.length; ++i) { + var parser = dispatch.parsers[i]; + if (parser === null) { + parsedFields.push(fields[1 + i]); + } else if (typeof parser == 'function') { + parsedFields.push(parser(fields[1 + i])); + } else { + // var-args + parsedFields.push(fields.slice(1 + i)); + break; + } + } + + // Run the processor. + this[dispatch.processor].apply(this, parsedFields); +}; + + +devtools.profiler.Processor.prototype.processCodeCreation_ = function( + type, start, size, name) { + this.profile_.addCode(type, name, start, size); +}; + + +devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { + this.profile_.moveCode(from, to); +}; + + +devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { + this.profile_.deleteCode(start); +}; + + +devtools.profiler.Processor.prototype.processTick_ = function( + pc, sp, vmState, stack) { + var fullStack = [pc]; + for (var i = 0, n = stack.length; i < n; ++i) { + var frame = stack[i]; + // Leave only numbers starting with 0x. Filter possible 'overflow' string. + if (frame.charAt(0) == '0') { + fullStack.push(parseInt(frame, 16)); + } + } + this.profile_.recordTick(fullStack); +}; + + +/** + * Creates a profile for further displaying in ProfileView. + */ +devtools.profiler.Processor.prototype.createProfileForView = function() { + var profile = new devtools.profiler.ProfileView(); + profile.uid = this.profileId_++; + profile.title = UserInitiatedProfileName + '.' + profile.uid; + // A trick to cope with ProfileView.bottomUpProfileDataGridTree and + // ProfileView.topDownProfileDataGridTree behavior. + profile.head = profile; + profile.heavyProfile = this.viewBuilder_.buildView( + this.profile_.getBottomUpProfile(), true); + profile.treeProfile = this.viewBuilder_.buildView( + this.profile_.getTopDownProfile()); + return profile; +}; diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/splaytree.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/splaytree.js new file mode 100644 index 0000000..7b3af8b --- /dev/null +++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/splaytree.js @@ -0,0 +1,322 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// A namespace stub. It will become more clear how to declare it properly +// during integration of this script into Dev Tools. +var goog = goog || {}; +goog.structs = goog.structs || {}; + + +/** + * Constructs a Splay tree. A splay tree is a self-balancing binary + * search tree with the additional property that recently accessed + * elements are quick to access again. It performs basic operations + * such as insertion, look-up and removal in O(log(n)) amortized time. + * + * @constructor + */ +goog.structs.SplayTree = function() { +}; + + +/** + * Pointer to the root node of the tree. + * + * @type {goog.structs.SplayTree.Node} + * @private + */ +goog.structs.SplayTree.prototype.root_ = null; + + +/** + * @return {boolean} Whether the tree is empty. + */ +goog.structs.SplayTree.prototype.isEmpty = function() { + return !this.root_; +}; + + + +/** + * Inserts a node into the tree with the specified key and value if + * the tree does not already contain a node with the specified key. If + * the value is inserted, it becomes the root of the tree. + * + * @param {number} key Key to insert into the tree. + * @param {*} value Value to insert into the tree. + */ +goog.structs.SplayTree.prototype.insert = function(key, value) { + if (this.isEmpty()) { + this.root_ = new goog.structs.SplayTree.Node(key, value); + return; + } + // Splay on the key to move the last node on the search path for + // the key to the root of the tree. + this.splay_(key); + if (this.root_.key == key) { + return; + } + var node = new goog.structs.SplayTree.Node(key, value); + if (key > this.root_.key) { + node.left = this.root_; + node.right = this.root_.right; + this.root_.right = null; + } else { + node.right = this.root_; + node.left = this.root_.left; + this.root_.left = null; + } + this.root_ = node; +}; + + +/** + * Removes a node with the specified key from the tree if the tree + * contains a node with this key. The removed node is returned. If the + * key is not found, an exception is thrown. + * + * @param {number} key Key to find and remove from the tree. + * @return {goog.structs.SplayTree.Node} The removed node. + */ +goog.structs.SplayTree.prototype.remove = function(key) { + if (this.isEmpty()) { + throw Error('Key not found: ' + key); + } + this.splay_(key); + if (this.root_.key != key) { + throw Error('Key not found: ' + key); + } + var removed = this.root_; + if (!this.root_.left) { + this.root_ = this.root_.right; + } else { + var right = this.root_.right; + this.root_ = this.root_.left; + // Splay to make sure that the new root has an empty right child. + this.splay_(key); + // Insert the original right child as the right child of the new + // root. + this.root_.right = right; + } + return removed; +}; + + +/** + * Returns the node having the specified key or null if the tree doesn't contain + * a node with the specified key. + * + * @param {number} key Key to find in the tree. + * @return {goog.structs.SplayTree.Node} Node having the specified key. + */ +goog.structs.SplayTree.prototype.find = function(key) { + if (this.isEmpty()) { + return null; + } + this.splay_(key); + return this.root_.key == key ? this.root_ : null; +}; + + +/** + * @return {goog.structs.SplayTree.Node} Node having the minimum key value. + */ +goog.structs.SplayTree.prototype.findMin = function() { + if (this.isEmpty()) { + return null; + } + var current = this.root_; + while (current.left) { + current = current.left; + } + return current; +}; + + +/** + * @return {goog.structs.SplayTree.Node} Node having the maximum key value. + */ +goog.structs.SplayTree.prototype.findMax = function(opt_startNode) { + if (this.isEmpty()) { + return null; + } + var current = opt_startNode || this.root_; + while (current.right) { + current = current.right; + } + return current; +}; + + +/** + * @return {goog.structs.SplayTree.Node} Node having the maximum key value that + * is less or equal to the specified key value. + */ +goog.structs.SplayTree.prototype.findGreatestLessThan = function(key) { + if (this.isEmpty()) { + return null; + } + // Splay on the key to move the node with the given key or the last + // node on the search path to the top of the tree. + this.splay_(key); + // Now the result is either the root node or the greatest node in + // the left subtree. + if (this.root_.key <= key) { + return this.root_; + } else if (this.root_.left) { + return this.findMax(this.root_.left); + } else { + return null; + } +}; + + +/** + * @return {Array<*>} An array containing all the values of tree's nodes. + */ +goog.structs.SplayTree.prototype.exportValues = function() { + var result = []; + this.traverse_(function(node) { result.push(node.value); }); + return result; +}; + + +/** + * Perform the splay operation for the given key. Moves the node with + * the given key to the top of the tree. If no node has the given + * key, the last node on the search path is moved to the top of the + * tree. This is the simplified top-down splaying algorithm from: + * "Self-adjusting Binary Search Trees" by Sleator and Tarjan + * + * @param {number} key Key to splay the tree on. + * @private + */ +goog.structs.SplayTree.prototype.splay_ = function(key) { + if (this.isEmpty()) { + return; + } + // Create a dummy node. The use of the dummy node is a bit + // counter-intuitive: The right child of the dummy node will hold + // the L tree of the algorithm. The left child of the dummy node + // will hold the R tree of the algorithm. Using a dummy node, left + // and right will always be nodes and we avoid special cases. + var dummy, left, right; + dummy = left = right = new goog.structs.SplayTree.Node(null, null); + var current = this.root_; + while (true) { + if (key < current.key) { + if (!current.left) { + break; + } + if (key < current.left.key) { + // Rotate right. + var tmp = current.left; + current.left = tmp.right; + tmp.right = current; + current = tmp; + if (!current.left) { + break; + } + } + // Link right. + right.left = current; + right = current; + current = current.left; + } else if (key > current.key) { + if (!current.right) { + break; + } + if (key > current.right.key) { + // Rotate left. + var tmp = current.right; + current.right = tmp.left; + tmp.left = current; + current = tmp; + if (!current.right) { + break; + } + } + // Link left. + left.right = current; + left = current; + current = current.right; + } else { + break; + } + } + // Assemble. + left.right = current.left; + right.left = current.right; + current.left = dummy.right; + current.right = dummy.left; + this.root_ = current; +}; + + +/** + * Performs a preorder traversal of the tree. + * + * @param {function(goog.structs.SplayTree.Node)} f Visitor function. + * @private + */ +goog.structs.SplayTree.prototype.traverse_ = function(f) { + var nodesToVisit = [this.root_]; + while (nodesToVisit.length > 0) { + var node = nodesToVisit.shift(); + if (node == null) { + continue; + } + f(node); + nodesToVisit.push(node.left); + nodesToVisit.push(node.right); + } +}; + + +/** + * Constructs a Splay tree node. + * + * @param {number} key Key. + * @param {*} value Value. + */ +goog.structs.SplayTree.Node = function(key, value) { + this.key = key; + this.value = value; +}; + + +/** + * @type {goog.structs.SplayTree.Node} + */ +goog.structs.SplayTree.Node.prototype.left = null; + + +/** + * @type {goog.structs.SplayTree.Node} + */ +goog.structs.SplayTree.Node.prototype.right = null; diff --git a/chrome/tools/test/reference_build/chrome_linux/themes/default.pak b/chrome/tools/test/reference_build/chrome_linux/themes/default.pak Binary files differindex 73914be..3857cb18 100644 --- a/chrome/tools/test/reference_build/chrome_linux/themes/default.pak +++ b/chrome/tools/test/reference_build/chrome_linux/themes/default.pak |