From d570ed3a13456d857b3436eedcc6e526c1c7b10f Mon Sep 17 00:00:00 2001 From: "yurys@chromium.org" Date: Tue, 21 Feb 2012 16:14:19 +0000 Subject: [PATCH] Web Inspector: timeline hangs on a page with deep chain of nested events. https://bugs.webkit.org/show_bug.cgi?id=79106 Use stack of states instead of recursive calls when traversing records tree to avoid stack overflow. Reviewed by Pavel Feldman. * inspector/front-end/TimelineOverviewPane.js: (WebInspector.TimelineOverviewPane.prototype._forAllRecords): * inspector/front-end/TimelinePanel.js: (WebInspector.TimelinePanel.prototype._filterRecords): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108355 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/WebCore/ChangeLog | 15 ++++++ .../inspector/front-end/TimelineOverviewPane.js | 15 ++++-- .../WebCore/inspector/front-end/TimelinePanel.js | 57 +++++++++++++--------- 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 668ffde..ec3a378 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,18 @@ +2012-02-21 Yury Semikhatsky + + Web Inspector: timeline hangs on a page with deep chain of nested events. + https://bugs.webkit.org/show_bug.cgi?id=79106 + + Use stack of states instead of recursive calls when traversing records tree to + avoid stack overflow. + + Reviewed by Pavel Feldman. + + * inspector/front-end/TimelineOverviewPane.js: + (WebInspector.TimelineOverviewPane.prototype._forAllRecords): + * inspector/front-end/TimelinePanel.js: + (WebInspector.TimelinePanel.prototype._filterRecords): + 2012-02-21 Pavel Feldman Web Inspector: [crash] upon style modification after navigation diff --git a/Source/WebCore/inspector/front-end/TimelineOverviewPane.js b/Source/WebCore/inspector/front-end/TimelineOverviewPane.js index aa8c275..b37d8c0 100644 --- a/Source/WebCore/inspector/front-end/TimelineOverviewPane.js +++ b/Source/WebCore/inspector/front-end/TimelineOverviewPane.js @@ -126,9 +126,18 @@ WebInspector.TimelineOverviewPane.prototype = { { if (!recordsArray) return; - for (var i = 0; i < recordsArray.length; ++i) { - callback(recordsArray[i]); - this._forAllRecords(recordsArray[i].children, callback); + var stack = [{array: recordsArray, index: 0}]; + while (stack.length) { + var entry = stack[stack.length - 1]; + var records = entry.array; + if (entry.index < records.length) { + var record = records[entry.index]; + callback(record); + if (record.children) + stack.push({array: record.children, index: 0}); + ++entry.index; + } else + stack.pop(); } }, diff --git a/Source/WebCore/inspector/front-end/TimelinePanel.js b/Source/WebCore/inspector/front-end/TimelinePanel.js index 3dab0fa..5d0b7f7 100644 --- a/Source/WebCore/inspector/front-end/TimelinePanel.js +++ b/Source/WebCore/inspector/front-end/TimelinePanel.js @@ -672,34 +672,43 @@ WebInspector.TimelinePanel.prototype = { this._calculator.calculateWindow(); }, - /** - * @param {boolean=} parentIsCollapsed - */ - _addToRecordsWindow: function(record, recordsWindow, parentIsCollapsed) - { - if (!this._showShortEvents && !record.isLong()) - return; - var percentages = this._calculator.computeBarGraphPercentages(record); - if (percentages.start < 100 && percentages.endWithChildren >= 0 && !record.category.hidden) { - ++this._rootRecord._visibleRecordsCount; - ++record.parent._invisibleChildrenCount; - if (!parentIsCollapsed) - recordsWindow.push(record); - } - - var index = recordsWindow.length; - record._invisibleChildrenCount = 0; - for (var i = 0; i < record.children.length; ++i) - this._addToRecordsWindow(record.children[i], recordsWindow, parentIsCollapsed || record.collapsed); - record._visibleChildrenCount = recordsWindow.length - index; - }, - _filterRecords: function() { var recordsInWindow = []; this._rootRecord._visibleRecordsCount = 0; - for (var i = 0; i < this._rootRecord.children.length; ++i) - this._addToRecordsWindow(this._rootRecord.children[i], recordsInWindow); + + var stack = [{children: this._rootRecord.children, index: 0, parentIsCollapsed: false}]; + while (stack.length) { + var entry = stack[stack.length - 1]; + var records = entry.children; + if (records && entry.index < records.length) { + var record = records[entry.index]; + ++entry.index; + + if (!this._showShortEvents && !record.isLong()) + continue; + var percentages = this._calculator.computeBarGraphPercentages(record); + if (percentages.start < 100 && percentages.endWithChildren >= 0 && !record.category.hidden) { + ++this._rootRecord._visibleRecordsCount; + ++record.parent._invisibleChildrenCount; + if (!entry.parentIsCollapsed) + recordsInWindow.push(record); + } + + record._invisibleChildrenCount = 0; + + stack.push({children: record.children, + index: 0, + parentIsCollapsed: (entry.parentIsCollapsed || record.collapsed), + parentRecord: record, + windowLengthBeforeChildrenTraversal: recordsInWindow.length}); + } else { + stack.pop(); + if (entry.parentRecord) + entry.parentRecord._visibleChildrenCount = recordsInWindow.length - entry.windowLengthBeforeChildrenTraversal; + } + } + return recordsInWindow; }, -- 2.7.4