Web Inspector: Include Garbage Collection Event in Timeline
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Oct 2015 02:15:56 +0000 (02:15 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Oct 2015 02:15:56 +0000 (02:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142510

Reviewed by Geoffrey Garen and Brian Burg.

Source/JavaScriptCore:

* CMakeLists.txt:
* DerivedSources.make:
* JavaScriptCore.xcodeproj/project.pbxproj:
Include new files in the build.

* heap/HeapObserver.h:
(JSC::HeapObserver::~HeapObserver):
* heap/Heap.cpp:
(JSC::Heap::willStartCollection):
(JSC::Heap::didFinishCollection):
* heap/Heap.h:
(JSC::Heap::addObserver):
(JSC::Heap::removeObserver):
Allow observers on heap to add hooks for starting / ending garbage collection.

* inspector/InspectorEnvironment.h:
* inspector/JSGlobalObjectInspectorController.cpp:
(Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
(Inspector::JSGlobalObjectInspectorController::vm):
* inspector/JSGlobalObjectInspectorController.h:
Access the VM through the InspectorEnvironment as it won't change.

* inspector/agents/InspectorHeapAgent.cpp: Added.
(Inspector::InspectorHeapAgent::InspectorHeapAgent):
(Inspector::InspectorHeapAgent::~InspectorHeapAgent):
(Inspector::InspectorHeapAgent::didCreateFrontendAndBackend):
(Inspector::InspectorHeapAgent::willDestroyFrontendAndBackend):
(Inspector::InspectorHeapAgent::enable):
(Inspector::InspectorHeapAgent::disable):
(Inspector::InspectorHeapAgent::gc):
(Inspector::protocolTypeForHeapOperation):
(Inspector::InspectorHeapAgent::willGarbageCollect):
(Inspector::InspectorHeapAgent::didGarbageCollect):
* inspector/agents/InspectorHeapAgent.h: Added.
* inspector/protocol/Heap.json: Added.
New domain and agent to handle tasks related to the JavaScriptCore heap.

Source/WebCore:

Tests: inspector/heap/garbageCollected.html
       inspector/heap/gc.html

* ForwardingHeaders/heap/HeapObserver.h: Added.
* ForwardingHeaders/inspector/agents/InspectorHeapAgent.h: Added.
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
Forwarding headers.

* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
(WebCore::InspectorController::vm):
* inspector/InspectorController.h:
* inspector/WorkerInspectorController.cpp:
(WebCore::WorkerInspectorController::vm):
* inspector/WorkerInspectorController.h:
Implement InspectorEnvironment::vm and create a Heap agent for the
Page inspector controller.

Source/WebInspectorUI:

* UserInterface/Base/Utilities.js:
(Array.prototype.partition):
Helper to partition an Array into two arrays.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Base/Main.js:
(WebInspector.loaded):
* UserInterface/Test.html:
* UserInterface/Test/Test.js:
(WebInspector.loaded):
* UserInterface/Protocol/HeapObserver.js: Added.
(WebInspector.HeapObserver.prototype.garbageCollected):
(WebInspector.HeapObserver):
Create the new observer and manager.

* UserInterface/Models/GarbageCollection.js: Added.
(WebInspector.GarbageCollection):
(WebInspector.GarbageCollection.fromPayload):
(WebInspector.GarbageCollection.prototype.get type):
(WebInspector.GarbageCollection.prototype.get startTime):
(WebInspector.GarbageCollection.prototype.get endTime):
(WebInspector.GarbageCollection.prototype.get duration):
Model object for Heap.GarbageCollection.

* UserInterface/Controllers/HeapManager.js: Added.
(WebInspector.HeapManager):
(WebInspector.HeapManager.prototype.garbageCollected):
Dispatch events with the GC object.

* UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager):
(WebInspector.TimelineManager.prototype._garbageCollected):
Include new GC Timeline Events as Script events.

* UserInterface/Views/ScriptTimelineOverviewGraph.js:
(WebInspector.ScriptTimelineOverviewGraph.prototype.updateLayout):
For the Script overview, make two sets of bars, one for Scripts and one for GCs.
The GCs bar will be overlaid on top of the the Scripts bar. This is particularly
useful since a GC can happen during script execution.

* UserInterface/Images/TimelineRecordGarbageCollection.svg: Added.
* UserInterface/Main.html:
* UserInterface/Models/ScriptTimelineRecord.js:
(WebInspector.ScriptTimelineRecord.prototype.isGarbageCollection):
(WebInspector.ScriptTimelineRecord.EventType.displayName):
* UserInterface/Views/ScriptTimelineDataGridNode.js:
(WebInspector.ScriptTimelineDataGridNode.prototype.get data):
(WebInspector.ScriptTimelineDataGridNode.prototype.createCellContent):
(WebInspector.ScriptTimelineDataGridNode):
* UserInterface/Views/ScriptTimelineView.js:
(WebInspector.ScriptTimelineView.prototype._processPendingRecords):
* UserInterface/Views/SourceCodeTimelineTreeElement.js:
(WebInspector.SourceCodeTimelineTreeElement):
* UserInterface/Views/TimelineIcons.css:
(.garbage-collection-profile-record .icon):
* UserInterface/Views/TimelineRecordBar.css:
(.timeline-record-bar.timeline-record-type-script.script-timeline-record-garbage-collected > .segment):
UI for GC events.

* UserInterface/Views/TimelineRecordBar.js:
(WebInspector.TimelineRecordBar.createCombinedBars):
Simplify by storing start time into a variable.

* UserInterface/Views/TimelineRecordTreeElement.js:
(WebInspector.TimelineRecordTreeElement):
Icon for GC events.

LayoutTests:

* inspector/heap/garbageCollected-expected.txt: Added.
* inspector/heap/garbageCollected.html: Added.
* inspector/heap/gc-expected.txt: Added.
* inspector/heap/gc.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191159 268f45cc-cd09-0410-ab3c-d52691b4dbfc

49 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/heap/garbageCollected-expected.txt [new file with mode: 0644]
LayoutTests/inspector/heap/garbageCollected.html [new file with mode: 0644]
LayoutTests/inspector/heap/gc-expected.txt [new file with mode: 0644]
LayoutTests/inspector/heap/gc.html [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/heap/HeapObserver.h [new file with mode: 0644]
Source/JavaScriptCore/heap/MarkedSpace.h
Source/JavaScriptCore/inspector/InspectorEnvironment.h
Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.cpp
Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.h
Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp [new file with mode: 0644]
Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.h [new file with mode: 0644]
Source/JavaScriptCore/inspector/protocol/Heap.json [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/ForwardingHeaders/heap/HeapObserver.h [new file with mode: 0644]
Source/WebCore/ForwardingHeaders/inspector/agents/InspectorHeapAgent.h [new file with mode: 0644]
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/inspector/InspectorController.cpp
Source/WebCore/inspector/InspectorController.h
Source/WebCore/inspector/WorkerInspectorController.cpp
Source/WebCore/inspector/WorkerInspectorController.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Base/Utilities.js
Source/WebInspectorUI/UserInterface/Controllers/HeapManager.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js
Source/WebInspectorUI/UserInterface/Images/TimelineRecordGarbageCollection.svg [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/GarbageCollection.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js
Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Test/Test.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineOverviewGraph.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js
Source/WebInspectorUI/UserInterface/Views/SourceCodeTimelineTreeElement.js
Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css
Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.css
Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js

index e41c2c1..213a230 100644 (file)
@@ -1,3 +1,15 @@
+2015-10-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include Garbage Collection Event in Timeline
+        https://bugs.webkit.org/show_bug.cgi?id=142510
+
+        Reviewed by Geoffrey Garen and Brian Burg.
+
+        * inspector/heap/garbageCollected-expected.txt: Added.
+        * inspector/heap/garbageCollected.html: Added.
+        * inspector/heap/gc-expected.txt: Added.
+        * inspector/heap/gc.html: Added.
+
 2015-10-15  Dean Jackson  <dino@apple.com>
 
         Remove deprecated function insertRule(), replace with appendRule()
diff --git a/LayoutTests/inspector/heap/garbageCollected-expected.txt b/LayoutTests/inspector/heap/garbageCollected-expected.txt
new file mode 100644 (file)
index 0000000..ea8c7fe
--- /dev/null
@@ -0,0 +1,7 @@
+Test for the Heap.garbageCollected event.
+
+
+== Running test suite: Heap.garbageCollected
+-- Running test case: TriggerGCs
+PASS: Should see both a Partial and Full Garbage Collection.
+
diff --git a/LayoutTests/inspector/heap/garbageCollected.html b/LayoutTests/inspector/heap/garbageCollected.html
new file mode 100644 (file)
index 0000000..52ee66f
--- /dev/null
@@ -0,0 +1,68 @@
+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+function triggerGCs()
+{
+    function allocateObjects() {
+        var list = [];
+        for (var i = 0; i < 100; ++i)
+            list.push({x:i});
+        return list;
+    }
+
+    function allocateLargeList() {
+        var largeList = [];
+        for (var i = 0; i < 100; ++i)
+            largeList.push(allocateObjects());
+        return largeList;
+    }
+
+    var partialList = [];
+    for (var i = 0; i < 100; ++i)
+        partialList.push(allocateLargeList());
+}
+
+function periodicallyTriggerGCs()
+{
+    setInterval(triggerGCs, 20);
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("Heap.garbageCollected");
+
+    suite.addTestCase({
+        name: "TriggerGCs",
+        description: "Evaluating allocation-heavy JavaScript should trigger Heap.garbageCollected events.",
+        test: (resolve, reject) => {
+            InspectorTest.evaluateInPage("periodicallyTriggerGCs()");
+
+            let seenFull = false;
+            let seenPartial = false;
+            WebInspector.heapManager.addEventListener(WebInspector.HeapManager.Event.GarbageCollected, (event) => {
+                if (seenFull && seenPartial)
+                    return;
+
+                if (event.data.collection.type === WebInspector.GarbageCollection.Type.Full)
+                    seenFull = true;
+                else if (event.data.collection.type === WebInspector.GarbageCollection.Type.Partial)
+                    seenPartial = true;
+
+                if (seenFull && seenPartial) {
+                    InspectorTest.log("PASS: Should see both a Partial and Full Garbage Collection.");
+                    resolve();
+                }
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test for the Heap.garbageCollected event.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/heap/gc-expected.txt b/LayoutTests/inspector/heap/gc-expected.txt
new file mode 100644 (file)
index 0000000..b406223
--- /dev/null
@@ -0,0 +1,8 @@
+Test for the Heap.gc command.
+
+
+== Running test suite: Heap.gc
+-- Running test case: TriggerGCShouldCreateGCEvent
+PASS: Event should have GarbageCollection data.
+PASS: GarbageCollection type should be Full.
+
diff --git a/LayoutTests/inspector/heap/gc.html b/LayoutTests/inspector/heap/gc.html
new file mode 100644 (file)
index 0000000..4478b8f
--- /dev/null
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("Heap.gc");
+
+    suite.addTestCase({
+        name: "TriggerGCShouldCreateGCEvent",
+        description: "Calling Heap.gc should trigger Heap.garbageCollected event if enabled.",
+        test: (resolve, reject) => {
+            HeapAgent.gc();
+            WebInspector.heapManager.addEventListener(WebInspector.HeapManager.Event.GarbageCollected, (event) => {
+                // Due to the asynchronous nature of Heap.garbageCollected events, we may see
+                // non-Full GC events before we see the Full collection triggered by HeapAgent.gc.
+                if (event.data.collection.type === WebInspector.GarbageCollection.Type.Full) {
+                    InspectorTest.expectThat(event.data.collection instanceof WebInspector.GarbageCollection, "Event should have GarbageCollection data.");
+                    InspectorTest.expectThat(event.data.collection.type === WebInspector.GarbageCollection.Type.Full, "GarbageCollection type should be Full.");
+                    resolve();
+                }
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test for the Heap.gc command.</p>
+</body>
+</html>
index fe79ca7..2c01dc8 100644 (file)
@@ -348,6 +348,7 @@ set(JavaScriptCore_SOURCES
     inspector/agents/InspectorAgent.cpp
     inspector/agents/InspectorConsoleAgent.cpp
     inspector/agents/InspectorDebuggerAgent.cpp
+    inspector/agents/InspectorHeapAgent.cpp
     inspector/agents/InspectorRuntimeAgent.cpp
     inspector/agents/JSGlobalObjectConsoleAgent.cpp
     inspector/agents/JSGlobalObjectDebuggerAgent.cpp
@@ -1029,6 +1030,7 @@ set(JavaScriptCore_INSPECTOR_DOMAINS
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Database.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Debugger.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/GenericTypes.json
+    ${JAVASCRIPTCORE_DIR}/inspector/protocol/Heap.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Inspector.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/LayerTree.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Network.json
index 0a76b84..2d7f657 100644 (file)
@@ -1,3 +1,47 @@
+2015-10-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include Garbage Collection Event in Timeline
+        https://bugs.webkit.org/show_bug.cgi?id=142510
+
+        Reviewed by Geoffrey Garen and Brian Burg.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        Include new files in the build.
+
+        * heap/HeapObserver.h:
+        (JSC::HeapObserver::~HeapObserver):
+        * heap/Heap.cpp:
+        (JSC::Heap::willStartCollection):
+        (JSC::Heap::didFinishCollection):
+        * heap/Heap.h:
+        (JSC::Heap::addObserver):
+        (JSC::Heap::removeObserver):
+        Allow observers on heap to add hooks for starting / ending garbage collection.
+
+        * inspector/InspectorEnvironment.h:
+        * inspector/JSGlobalObjectInspectorController.cpp:
+        (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
+        (Inspector::JSGlobalObjectInspectorController::vm):
+        * inspector/JSGlobalObjectInspectorController.h:
+        Access the VM through the InspectorEnvironment as it won't change.
+
+        * inspector/agents/InspectorHeapAgent.cpp: Added.
+        (Inspector::InspectorHeapAgent::InspectorHeapAgent):
+        (Inspector::InspectorHeapAgent::~InspectorHeapAgent):
+        (Inspector::InspectorHeapAgent::didCreateFrontendAndBackend):
+        (Inspector::InspectorHeapAgent::willDestroyFrontendAndBackend):
+        (Inspector::InspectorHeapAgent::enable):
+        (Inspector::InspectorHeapAgent::disable):
+        (Inspector::InspectorHeapAgent::gc):
+        (Inspector::protocolTypeForHeapOperation):
+        (Inspector::InspectorHeapAgent::willGarbageCollect):
+        (Inspector::InspectorHeapAgent::didGarbageCollect):
+        * inspector/agents/InspectorHeapAgent.h: Added.
+        * inspector/protocol/Heap.json: Added.
+        New domain and agent to handle tasks related to the JavaScriptCore heap.
+
 2015-10-15  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r191135.
index 1015ddc..04668de 100644 (file)
@@ -152,6 +152,7 @@ INSPECTOR_DOMAINS = \
     $(JavaScriptCore)/inspector/protocol/Database.json \
     $(JavaScriptCore)/inspector/protocol/Debugger.json \
     $(JavaScriptCore)/inspector/protocol/GenericTypes.json \
+    $(JavaScriptCore)/inspector/protocol/Heap.json \
     $(JavaScriptCore)/inspector/protocol/Inspector.json \
     $(JavaScriptCore)/inspector/protocol/LayerTree.json \
     $(JavaScriptCore)/inspector/protocol/Network.json \
index 5755cd4..1f3424f 100644 (file)
                A532438C18568335002ED692 /* InspectorProtocolObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438618568317002ED692 /* InspectorProtocolObjects.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */ = {isa = PBXBuildFile; fileRef = A5324391185696E6002ED692 /* generate-combined-inspector-json.py */; settings = {ATTRIBUTES = (Private, ); }; };
                A53243981856A489002ED692 /* CombinedDomains.json in Headers */ = {isa = PBXBuildFile; fileRef = A53243951856A475002ED692 /* CombinedDomains.json */; settings = {ATTRIBUTES = (Private, ); }; };
+               A5339EC61BB399A60054F005 /* InspectorHeapAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A5339EC51BB399900054F005 /* InspectorHeapAgent.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A5339EC71BB399A90054F005 /* InspectorHeapAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5339EC41BB399900054F005 /* InspectorHeapAgent.cpp */; };
+               A5339EC91BB4B4600054F005 /* HeapObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = A5339EC81BB4B4510054F005 /* HeapObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A53CE08518BC1A5600BEDF76 /* ConsolePrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */; };
                A53CE08618BC1A5600BEDF76 /* ConsolePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */; };
                A53CE08718BC1A5600BEDF76 /* JSConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A53CE08318BC1A5600BEDF76 /* JSConsole.cpp */; };
                A5324391185696E6002ED692 /* generate-combined-inspector-json.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "generate-combined-inspector-json.py"; sourceTree = "<group>"; };
                A53243951856A475002ED692 /* CombinedDomains.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = CombinedDomains.json; sourceTree = "<group>"; };
                A53243961856A475002ED692 /* InspectorBackendCommands.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InspectorBackendCommands.js; sourceTree = "<group>"; };
+               A5339EC41BB399900054F005 /* InspectorHeapAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorHeapAgent.cpp; sourceTree = "<group>"; };
+               A5339EC51BB399900054F005 /* InspectorHeapAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorHeapAgent.h; sourceTree = "<group>"; };
+               A5339EC81BB4B4510054F005 /* HeapObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapObserver.h; sourceTree = "<group>"; };
                A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConsolePrototype.cpp; sourceTree = "<group>"; };
                A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsolePrototype.h; sourceTree = "<group>"; };
                A53CE08318BC1A5600BEDF76 /* JSConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSConsole.cpp; sourceTree = "<group>"; };
                                0F32BD0F1BB34F190093A57F /* HeapHelperPool.h */,
                                C2DA778218E259990066FCB6 /* HeapInlines.h */,
                                2AD8932917E3868F00668276 /* HeapIterationScope.h */,
+                               A5339EC81BB4B4510054F005 /* HeapObserver.h */,
                                2A6F462517E959CE00C45C98 /* HeapOperation.h */,
                                14F97446138C853E00DA1C67 /* HeapRootVisitor.h */,
                                C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */,
                                A5FD0080189B191A00633231 /* InspectorConsoleAgent.h */,
                                A57D23E31890CEBF0031C7FA /* InspectorDebuggerAgent.cpp */,
                                A57D23E41890CEBF0031C7FA /* InspectorDebuggerAgent.h */,
+                               A5339EC41BB399900054F005 /* InspectorHeapAgent.cpp */,
+                               A5339EC51BB399900054F005 /* InspectorHeapAgent.h */,
                                A50E4B5D18809DD50068A46D /* InspectorRuntimeAgent.cpp */,
                                A50E4B5E18809DD50068A46D /* InspectorRuntimeAgent.h */,
                                A5FD0083189B1B7E00633231 /* JSGlobalObjectConsoleAgent.cpp */,
                                14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
                                C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */,
                                2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */,
+                               A5339EC91BB4B4600054F005 /* HeapObserver.h in Headers */,
                                2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */,
                                14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */,
                                C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */,
                                A5945595182479EB00CC3843 /* InspectorFrontendChannel.h in Headers */,
                                A532438A18568335002ED692 /* InspectorFrontendDispatchers.h in Headers */,
                                99F1A7011B98FBEC00463B26 /* InspectorFrontendRouter.h in Headers */,
+                               A5339EC61BB399A60054F005 /* InspectorHeapAgent.h in Headers */,
                                E35E03601B7AB43E0073AD2A /* InspectorInstrumentationObject.h in Headers */,
                                E33B3E261B7ABD750048DB2E /* InspectorInstrumentationObject.lut.h in Headers */,
                                A532438C18568335002ED692 /* InspectorProtocolObjects.h in Headers */,
                                A57D23E51890CEBF0031C7FA /* InspectorDebuggerAgent.cpp in Sources */,
                                A532438918568335002ED692 /* InspectorFrontendDispatchers.cpp in Sources */,
                                99F1A6FE1B8E6D9400463B26 /* InspectorFrontendRouter.cpp in Sources */,
+                               A5339EC71BB399A90054F005 /* InspectorHeapAgent.cpp in Sources */,
                                E35E035F1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp in Sources */,
                                A532438B18568335002ED692 /* InspectorProtocolObjects.cpp in Sources */,
                                A50E4B6118809DD50068A46D /* InspectorRuntimeAgent.cpp in Sources */,
index 6029ac8..55cc89f 100644 (file)
@@ -54,7 +54,6 @@
 #include <wtf/RAMSize.h>
 
 using namespace std;
-using namespace JSC;
 
 namespace JSC {
 
@@ -1158,6 +1157,9 @@ void Heap::willStartCollection(HeapOperation collectionType)
 
     if (m_edenActivityCallback)
         m_edenActivityCallback->willCollect();
+
+    for (auto* observer : m_observers)
+        observer->willGarbageCollect();
 }
 
 void Heap::flushOldStructureIDTables()
@@ -1306,6 +1308,7 @@ void Heap::didFinishCollection(double gcStartTime)
 {
     GCPHASE(FinishingCollection);
     double gcEndTime = WTF::monotonicallyIncreasingTime();
+    HeapOperation operation = m_operationInProgress;
     if (m_operationInProgress == FullCollection)
         m_lastFullGCLength = gcEndTime - gcStartTime;
     else
@@ -1329,6 +1332,9 @@ void Heap::didFinishCollection(double gcStartTime)
     RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection);
     m_operationInProgress = NoOperation;
     JAVASCRIPTCORE_GC_END();
+
+    for (auto* observer : m_observers)
+        observer->didGarbageCollect(operation);
 }
 
 void Heap::resumeCompilerThreads()
index 5bff0cb..e169ccc 100644 (file)
@@ -28,6 +28,7 @@
 #include "GCIncomingRefCountedSet.h"
 #include "HandleSet.h"
 #include "HandleStack.h"
+#include "HeapObserver.h"
 #include "HeapOperation.h"
 #include "JITStubRoutineSet.h"
 #include "ListableHandler.h"
 
 namespace JSC {
 
-class CopiedSpace;
 class CodeBlock;
-class ExecutableBase;
+class CopiedSpace;
 class EdenGCActivityCallback;
+class ExecutableBase;
 class FullGCActivityCallback;
 class GCActivityCallback;
 class GCAwareJITStubRoutine;
-class GlobalCodeBlock;
 class Heap;
 class HeapRootVisitor;
 class HeapVerifier;
 class IncrementalSweeper;
 class JITStubRoutine;
 class JSCell;
-class VM;
 class JSStack;
 class JSValue;
-class LiveObjectIterator;
 class LLIntOffsetsExtractor;
 class MarkedArgumentBuffer;
-class WeakGCHandlePool;
-class SlotVisitor;
+class VM;
 
 namespace DFG {
 class SpeculativeJIT;
@@ -134,6 +131,9 @@ public:
     JS_EXPORT_PRIVATE IncrementalSweeper* sweeper();
     JS_EXPORT_PRIVATE void setIncrementalSweeper(std::unique_ptr<IncrementalSweeper>);
 
+    void addObserver(HeapObserver* observer) { m_observers.append(observer); }
+    void removeObserver(HeapObserver* observer) { m_observers.removeFirst(observer); }
+
     // true if collection is in progress
     bool isCollecting();
     HeapOperation operationInProgress() { return m_operationInProgress; }
@@ -407,7 +407,9 @@ private:
     RefPtr<GCActivityCallback> m_edenActivityCallback;
     std::unique_ptr<IncrementalSweeper> m_sweeper;
     Vector<MarkedBlock*> m_blockSnapshot;
-    
+
+    Vector<HeapObserver*> m_observers;
+
     unsigned m_deferralDepth;
     Vector<DFG::Worklist*> m_suspendedCompilerWorklists;
 
diff --git a/Source/JavaScriptCore/heap/HeapObserver.h b/Source/JavaScriptCore/heap/HeapObserver.h
new file mode 100644 (file)
index 0000000..c4c282c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#ifndef HeapObserver_h
+#define HeapObserver_h
+
+#include "HeapOperation.h"
+
+namespace JSC {
+
+class HeapObserver {
+public:
+    virtual ~HeapObserver() { }
+    virtual void willGarbageCollect() = 0;
+    virtual void didGarbageCollect(HeapOperation) = 0;
+};
+
+} // namespace JSC
+
+#endif // HeapObserver_h
index 8619576..9982685 100644 (file)
@@ -35,7 +35,6 @@ namespace JSC {
 
 class Heap;
 class HeapIterationScope;
-class LiveObjectIterator;
 class LLIntOffsetsExtractor;
 
 struct ClearMarks : MarkedBlock::VoidFunctor {
index cb48771..75f2ea4 100644 (file)
@@ -35,6 +35,7 @@ class Stopwatch;
 namespace JSC {
 class Exception;
 class SourceCode;
+class VM;
 }
 
 namespace Inspector {
@@ -53,6 +54,7 @@ public:
     virtual void didCallInjectedScriptFunction(JSC::ExecState*) = 0;
     virtual void frontendInitialized() = 0;
     virtual Ref<WTF::Stopwatch> executionStopwatch() = 0;
+    virtual JSC::VM& vm() = 0;
 };
 
 } // namespace Inspector
index 989d2a6..4216043 100644 (file)
@@ -36,6 +36,7 @@
 #include "InspectorBackendDispatcher.h"
 #include "InspectorFrontendChannel.h"
 #include "InspectorFrontendRouter.h"
+#include "InspectorHeapAgent.h"
 #include "JSGlobalObject.h"
 #include "JSGlobalObjectConsoleAgent.h"
 #include "JSGlobalObjectConsoleClient.h"
@@ -62,13 +63,11 @@ using namespace JSC;
 namespace Inspector {
 
 JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObject& globalObject)
-    : m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
+    : m_globalObject(globalObject)
+    , m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
     , m_executionStopwatch(Stopwatch::create())
     , m_frontendRouter(FrontendRouter::create())
     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
-#if ENABLE(REMOTE_INSPECTOR)
-    , m_globalObject(globalObject)
-#endif
 {
     AgentContext baseContext = {
         *this,
@@ -86,9 +85,11 @@ JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObj
     auto runtimeAgent = std::make_unique<JSGlobalObjectRuntimeAgent>(context);
     auto consoleAgent = std::make_unique<JSGlobalObjectConsoleAgent>(context);
     auto debuggerAgent = std::make_unique<JSGlobalObjectDebuggerAgent>(context, consoleAgent.get());
+    auto heapAgent = std::make_unique<InspectorHeapAgent>(context);
 
     m_inspectorAgent = inspectorAgent.get();
     m_debuggerAgent = debuggerAgent.get();
+    m_heapAgent = heapAgent.get();
     m_consoleAgent = consoleAgent.get();
     m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent);
 
@@ -98,6 +99,7 @@ JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObj
     m_agents.append(WTF::move(runtimeAgent));
     m_agents.append(WTF::move(consoleAgent));
     m_agents.append(WTF::move(debuggerAgent));
+    m_agents.append(WTF::move(heapAgent));
 
     m_executionStopwatch->start();
 }
@@ -283,6 +285,11 @@ Ref<Stopwatch> JSGlobalObjectInspectorController::executionStopwatch()
     return m_executionStopwatch.copyRef();
 }
 
+VM& JSGlobalObjectInspectorController::vm()
+{
+    return m_globalObject.vm();
+}
+
 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
 void JSGlobalObjectInspectorController::appendExtraAgent(std::unique_ptr<InspectorAgentBase> agent)
 {
index 9b43051..f66ebe3 100644 (file)
@@ -41,7 +41,6 @@ namespace WTF {
 class Stopwatch;
 }
 
-
 namespace JSC {
 class ConsoleClient;
 class Exception;
@@ -58,6 +57,7 @@ class InjectedScriptManager;
 class InspectorAgent;
 class InspectorConsoleAgent;
 class InspectorDebuggerAgent;
+class InspectorHeapAgent;
 class JSGlobalObjectConsoleClient;
 class ScriptCallStack;
 
@@ -97,6 +97,7 @@ public:
     virtual void didCallInjectedScriptFunction(JSC::ExecState*) override { }
     virtual void frontendInitialized() override;
     virtual Ref<WTF::Stopwatch> executionStopwatch() override;
+    virtual JSC::VM& vm() override;
 
 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
     virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const override { return m_augmentingClient; } 
@@ -110,6 +111,7 @@ public:
 private:
     void appendAPIBacktrace(ScriptCallStack* callStack);
 
+    JSC::JSGlobalObject& m_globalObject;
     std::unique_ptr<InjectedScriptManager> m_injectedScriptManager;
     std::unique_ptr<JSGlobalObjectConsoleClient> m_consoleClient;
     Ref<WTF::Stopwatch> m_executionStopwatch;
@@ -118,6 +120,7 @@ private:
     InspectorAgent* m_inspectorAgent { nullptr };
     InspectorConsoleAgent* m_consoleAgent { nullptr };
     InspectorDebuggerAgent* m_debuggerAgent { nullptr };
+    InspectorHeapAgent* m_heapAgent { nullptr };
 
     Ref<FrontendRouter> m_frontendRouter;
     Ref<BackendDispatcher> m_backendDispatcher;
@@ -125,10 +128,6 @@ private:
     bool m_includeNativeCallStackWithExceptions { false };
     bool m_isAutomaticInspection { false };
 
-#if ENABLE(REMOTE_INSPECTOR)
-    JSC::JSGlobalObject& m_globalObject;
-#endif
-
 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
     AugmentableInspectorControllerClient* m_augmentingClient { nullptr };
 #endif
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp
new file mode 100644 (file)
index 0000000..0ad0e78
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 Apple 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.
+ */
+
+#include "config.h"
+#include "InspectorHeapAgent.h"
+
+#include "InspectorEnvironment.h"
+#include "VM.h"
+#include <wtf/RunLoop.h>
+#include <wtf/Stopwatch.h>
+
+using namespace JSC;
+
+namespace Inspector {
+
+InspectorHeapAgent::InspectorHeapAgent(AgentContext& context)
+    : InspectorAgentBase(ASCIILiteral("Heap"))
+    , m_frontendDispatcher(std::make_unique<HeapFrontendDispatcher>(context.frontendRouter))
+    , m_backendDispatcher(HeapBackendDispatcher::create(context.backendDispatcher, this))
+    , m_environment(context.environment)
+    , m_weakPtrFactory(this)
+{
+}
+
+InspectorHeapAgent::~InspectorHeapAgent()
+{
+}
+
+void InspectorHeapAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
+{
+}
+
+void InspectorHeapAgent::willDestroyFrontendAndBackend(DisconnectReason)
+{
+    ErrorString ignored;
+    disable(ignored);
+}
+
+void InspectorHeapAgent::enable(ErrorString&)
+{
+    if (m_enabled)
+        return;
+
+    m_enabled = true;
+
+    m_environment.vm().heap.addObserver(this);
+}
+
+void InspectorHeapAgent::disable(ErrorString&)
+{
+    if (!m_enabled)
+        return;
+
+    m_enabled = false;
+
+    m_environment.vm().heap.removeObserver(this);
+}
+
+void InspectorHeapAgent::gc(ErrorString&)
+{
+    VM& vm = m_environment.vm();
+    JSLockHolder lock(vm);
+    sanitizeStackForVM(&vm);
+    vm.heap.collectAllGarbage();
+}
+
+static Inspector::Protocol::Heap::GarbageCollection::Type protocolTypeForHeapOperation(HeapOperation operation)
+{
+    switch (operation) {
+    case FullCollection:
+        return Inspector::Protocol::Heap::GarbageCollection::Type::Full;
+    case EdenCollection:
+        return Inspector::Protocol::Heap::GarbageCollection::Type::Partial;
+    default:
+        ASSERT_NOT_REACHED();
+        return Inspector::Protocol::Heap::GarbageCollection::Type::Full;
+    }
+}
+
+void InspectorHeapAgent::willGarbageCollect()
+{
+    ASSERT(m_enabled);
+    ASSERT(std::isnan(m_gcStartTime));
+
+    m_gcStartTime = m_environment.executionStopwatch()->elapsedTime();
+}
+
+void InspectorHeapAgent::didGarbageCollect(HeapOperation operation)
+{
+    ASSERT(m_enabled);
+    ASSERT(!std::isnan(m_gcStartTime));
+
+    // FIXME: Include number of bytes freed by collection.
+
+    double startTime = m_gcStartTime;
+    double endTime = m_environment.executionStopwatch()->elapsedTime();
+
+    // Dispatch the event asynchronously because this method may be
+    // called between collection and sweeping and we don't want to
+    // create unexpected JavaScript allocations that the Sweeper does
+    // not expect to encounter. JavaScript allocations could happen
+    // with WebKitLegacy's in process inspector which shares the same
+    // VM as the inspected page.
+
+    auto weakThis = m_weakPtrFactory.createWeakPtr();
+    RunLoop::current().dispatch([weakThis, startTime, endTime, operation]() {
+        if (!weakThis)
+            return;
+
+        auto collection = Inspector::Protocol::Heap::GarbageCollection::create()
+            .setType(protocolTypeForHeapOperation(operation))
+            .setStartTime(startTime)
+            .setEndTime(endTime)
+            .release();
+
+        weakThis->m_frontendDispatcher->garbageCollected(WTF::move(collection));
+    });
+
+    m_gcStartTime = NAN;
+}
+
+} // namespace Inspector
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.h
new file mode 100644 (file)
index 0000000..8ca3c13
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 Apple 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.
+ */
+
+#ifndef InspectorHeapAgent_h
+#define InspectorHeapAgent_h
+
+#include "InspectorBackendDispatchers.h"
+#include "InspectorFrontendDispatchers.h"
+#include "heap/HeapObserver.h"
+#include "inspector/InspectorAgentBase.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/WeakPtr.h>
+
+namespace Inspector {
+
+typedef String ErrorString;
+
+class JS_EXPORT_PRIVATE InspectorHeapAgent final : public InspectorAgentBase, public HeapBackendDispatcherHandler, public JSC::HeapObserver {
+    WTF_MAKE_NONCOPYABLE(InspectorHeapAgent);
+public:
+    InspectorHeapAgent(AgentContext&);
+    virtual ~InspectorHeapAgent();
+
+    virtual void didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) override;
+    virtual void willDestroyFrontendAndBackend(DisconnectReason) override;
+
+    // HeapBackendDispatcherHandler
+    virtual void enable(ErrorString&) override;
+    virtual void disable(ErrorString&) override;
+    virtual void gc(ErrorString&) override;
+
+    // HeapObserver
+    virtual void willGarbageCollect() override;
+    virtual void didGarbageCollect(JSC::HeapOperation) override;
+
+private:
+    std::unique_ptr<HeapFrontendDispatcher> m_frontendDispatcher;
+    RefPtr<HeapBackendDispatcher> m_backendDispatcher;
+    InspectorEnvironment& m_environment;
+    WeakPtrFactory<InspectorHeapAgent> m_weakPtrFactory;
+    bool m_enabled { false };
+    double m_gcStartTime { NAN };
+};
+
+} // namespace Inspector
+
+#endif // InspectorHeapAgent_h
diff --git a/Source/JavaScriptCore/inspector/protocol/Heap.json b/Source/JavaScriptCore/inspector/protocol/Heap.json
new file mode 100644 (file)
index 0000000..eac3346
--- /dev/null
@@ -0,0 +1,39 @@
+{
+    "domain": "Heap",
+    "description": "Heap domain exposes JavaScript heap attributes and capabilities.",
+    "types": [
+        {
+            "id": "GarbageCollection",
+            "description": "Information about a garbage collection.",
+            "type": "object",
+            "properties": [
+                { "name": "type", "type": "string", "enum": ["full", "partial"], "description": "The type of garbage collection." },
+                { "name": "startTime", "type": "number" },
+                { "name": "endTime", "type": "number" }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "enable",
+            "description": "Enables Heap domain events."
+        },
+        {
+            "name": "disable",
+            "description": "Disables Heap domain events."
+        },
+        {
+            "name": "gc",
+            "description": "Trigger a full garbage collection."
+        }
+    ],
+    "events": [
+        {
+            "name": "garbageCollected",
+            "description": "Information about the garbage collection.",
+            "parameters": [
+                { "name": "collection", "type": "GarbageCollection" }
+            ]
+        }
+    ]
+}
index dfb2399..4fc67c0 100644 (file)
@@ -1,3 +1,29 @@
+2015-10-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include Garbage Collection Event in Timeline
+        https://bugs.webkit.org/show_bug.cgi?id=142510
+
+        Reviewed by Geoffrey Garen and Brian Burg.
+
+        Tests: inspector/heap/garbageCollected.html
+               inspector/heap/gc.html
+
+        * ForwardingHeaders/heap/HeapObserver.h: Added.
+        * ForwardingHeaders/inspector/agents/InspectorHeapAgent.h: Added.
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        Forwarding headers.
+
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        (WebCore::InspectorController::vm):
+        * inspector/InspectorController.h:
+        * inspector/WorkerInspectorController.cpp:
+        (WebCore::WorkerInspectorController::vm):
+        * inspector/WorkerInspectorController.h:
+        Implement InspectorEnvironment::vm and create a Heap agent for the
+        Page inspector controller.
+
 2015-10-15  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r191156.
diff --git a/Source/WebCore/ForwardingHeaders/heap/HeapObserver.h b/Source/WebCore/ForwardingHeaders/heap/HeapObserver.h
new file mode 100644 (file)
index 0000000..d8921c2
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_HeapObserver_h
+#define WebCore_FWD_HeapObserver_h
+#include <JavaScriptCore/HeapObserver.h>
+#endif
diff --git a/Source/WebCore/ForwardingHeaders/inspector/agents/InspectorHeapAgent.h b/Source/WebCore/ForwardingHeaders/inspector/agents/InspectorHeapAgent.h
new file mode 100644 (file)
index 0000000..995d6c1
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_InspectorHeapAgent_h
+#define WebCore_FWD_InspectorHeapAgent_h
+#include <JavaScriptCore/InspectorHeapAgent.h>
+#endif
index 40bf115..34a6575 100644 (file)
     <ClInclude Include="..\ForwardingHeaders\bindings\ScriptValue.h" />
     <ClInclude Include="..\ForwardingHeaders\heap\AllocationSpace.h" />
     <ClInclude Include="..\ForwardingHeaders\heap\Heap.h" />
+    <ClInclude Include="..\ForwardingHeaders\heap\HeapObserver.h" />
     <ClInclude Include="..\ForwardingHeaders\heap\SlotVisitor.h" />
     <ClInclude Include="..\ForwardingHeaders\heap\StrongInlines.h" />
     <ClInclude Include="..\ForwardingHeaders\heap\Weak.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorAgent.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorConsoleAgent.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorDebuggerAgent.h" />
+    <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorHeapAgent.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorRuntimeAgent.h" />
     <ClInclude Include="..\ForwardingHeaders\masm\X86Assembler.h" />
     <ClInclude Include="..\ForwardingHeaders\parser\SourceCode.h" />
index 0e8e512..ade8d1b 100644 (file)
     <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorDebuggerAgent.h">
       <Filter>ForwardingHeaders\inspector</Filter>
     </ClInclude>
+    <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorHeapAgent.h">
+      <Filter>ForwardingHeaders\inspector</Filter>
+    </ClInclude>
     <ClInclude Include="..\ForwardingHeaders\inspector\agents\InspectorRuntimeAgent.h">
       <Filter>ForwardingHeaders\inspector</Filter>
     </ClInclude>
     <ClInclude Include="..\ForwardingHeaders\heap\Heap.h">
       <Filter>ForwardingHeaders\heap</Filter>
     </ClInclude>
+    <ClInclude Include="..\ForwardingHeaders\heap\HeapObserver.h">
+      <Filter>ForwardingHeaders\heap</Filter>
+    </ClInclude>
     <ClInclude Include="..\ForwardingHeaders\heap\SlotVisitor.h">
       <Filter>ForwardingHeaders\heap</Filter>
     </ClInclude>
index 8112e55..9007511 100644 (file)
@@ -70,6 +70,7 @@
 #include <inspector/InspectorFrontendDispatchers.h>
 #include <inspector/InspectorFrontendRouter.h>
 #include <inspector/agents/InspectorAgent.h>
+#include <inspector/agents/InspectorHeapAgent.h>
 #include <profiler/LegacyProfiler.h>
 #include <runtime/JSLock.h>
 #include <wtf/Stopwatch.h>
@@ -170,6 +171,7 @@ InspectorController::InspectorController(Page& page, InspectorClient* inspectorC
     m_domDebuggerAgent = domDebuggerAgentPtr.get();
     m_agents.append(WTF::move(domDebuggerAgentPtr));
 
+    m_agents.append(std::make_unique<InspectorHeapAgent>(pageContext));
     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, pageAgent));
     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
@@ -474,6 +476,11 @@ Ref<Stopwatch> InspectorController::executionStopwatch()
     return m_executionStopwatch.copyRef();
 }
 
+JSC::VM& InspectorController::vm()
+{
+    return JSDOMWindowBase::commonVM();
+}
+
 void InspectorController::didComposite(Frame& frame)
 {
     InspectorInstrumentation::didComposite(frame);
index 51b9cb1..01e5c44 100644 (file)
@@ -131,6 +131,7 @@ public:
     virtual void didCallInjectedScriptFunction(JSC::ExecState*) override;
     virtual void frontendInitialized() override;
     virtual Ref<WTF::Stopwatch> executionStopwatch() override;
+    virtual JSC::VM& vm() override;
 
     WEBCORE_EXPORT void didComposite(Frame&);
 
index 66f9cb0..28cdec0 100644 (file)
@@ -36,6 +36,7 @@
 #include "InspectorInstrumentation.h"
 #include "InspectorTimelineAgent.h"
 #include "InstrumentingAgents.h"
+#include "JSDOMWindowBase.h"
 #include "JSMainThreadExecState.h"
 #include "WebInjectedScriptHost.h"
 #include "WebInjectedScriptManager.h"
@@ -51,6 +52,7 @@
 #include <inspector/InspectorFrontendRouter.h>
 #include <wtf/Stopwatch.h>
 
+using namespace JSC;
 using namespace Inspector;
 
 namespace WebCore {
@@ -195,4 +197,9 @@ Ref<Stopwatch> WorkerInspectorController::executionStopwatch()
     return m_executionStopwatch.copyRef();
 }
 
+VM& WorkerInspectorController::vm()
+{
+    return JSDOMWindowBase::commonVM();
+}
+
 } // namespace WebCore
index d8f26e5..7f42473 100644 (file)
@@ -75,6 +75,7 @@ public:
     virtual void didCallInjectedScriptFunction(JSC::ExecState*) override;
     virtual void frontendInitialized() override { }
     virtual Ref<WTF::Stopwatch> executionStopwatch() override;
+    virtual JSC::VM& vm() override;
 
 private:
     friend class InspectorInstrumentation;
index 36e28a9..cd95442 100644 (file)
@@ -1,3 +1,77 @@
+2015-10-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include Garbage Collection Event in Timeline
+        https://bugs.webkit.org/show_bug.cgi?id=142510
+
+        Reviewed by Geoffrey Garen and Brian Burg.
+
+        * UserInterface/Base/Utilities.js:
+        (Array.prototype.partition):
+        Helper to partition an Array into two arrays.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Base/Main.js:
+        (WebInspector.loaded):
+        * UserInterface/Test.html:
+        * UserInterface/Test/Test.js:
+        (WebInspector.loaded):
+        * UserInterface/Protocol/HeapObserver.js: Added.
+        (WebInspector.HeapObserver.prototype.garbageCollected):
+        (WebInspector.HeapObserver):
+        Create the new observer and manager.
+
+        * UserInterface/Models/GarbageCollection.js: Added.
+        (WebInspector.GarbageCollection):
+        (WebInspector.GarbageCollection.fromPayload):
+        (WebInspector.GarbageCollection.prototype.get type):
+        (WebInspector.GarbageCollection.prototype.get startTime):
+        (WebInspector.GarbageCollection.prototype.get endTime):
+        (WebInspector.GarbageCollection.prototype.get duration):
+        Model object for Heap.GarbageCollection.
+
+        * UserInterface/Controllers/HeapManager.js: Added.
+        (WebInspector.HeapManager):
+        (WebInspector.HeapManager.prototype.garbageCollected):
+        Dispatch events with the GC object.
+
+        * UserInterface/Controllers/TimelineManager.js:
+        (WebInspector.TimelineManager):
+        (WebInspector.TimelineManager.prototype._garbageCollected):
+        Include new GC Timeline Events as Script events.
+
+        * UserInterface/Views/ScriptTimelineOverviewGraph.js:
+        (WebInspector.ScriptTimelineOverviewGraph.prototype.updateLayout):
+        For the Script overview, make two sets of bars, one for Scripts and one for GCs.
+        The GCs bar will be overlaid on top of the the Scripts bar. This is particularly
+        useful since a GC can happen during script execution.
+
+        * UserInterface/Images/TimelineRecordGarbageCollection.svg: Added.
+        * UserInterface/Main.html:
+        * UserInterface/Models/ScriptTimelineRecord.js:
+        (WebInspector.ScriptTimelineRecord.prototype.isGarbageCollection):
+        (WebInspector.ScriptTimelineRecord.EventType.displayName):
+        * UserInterface/Views/ScriptTimelineDataGridNode.js:
+        (WebInspector.ScriptTimelineDataGridNode.prototype.get data):
+        (WebInspector.ScriptTimelineDataGridNode.prototype.createCellContent):
+        (WebInspector.ScriptTimelineDataGridNode):
+        * UserInterface/Views/ScriptTimelineView.js:
+        (WebInspector.ScriptTimelineView.prototype._processPendingRecords):
+        * UserInterface/Views/SourceCodeTimelineTreeElement.js:
+        (WebInspector.SourceCodeTimelineTreeElement):
+        * UserInterface/Views/TimelineIcons.css:
+        (.garbage-collection-profile-record .icon):
+        * UserInterface/Views/TimelineRecordBar.css:
+        (.timeline-record-bar.timeline-record-type-script.script-timeline-record-garbage-collected > .segment):
+        UI for GC events.
+
+        * UserInterface/Views/TimelineRecordBar.js:
+        (WebInspector.TimelineRecordBar.createCombinedBars):
+        Simplify by storing start time into a variable.
+
+        * UserInterface/Views/TimelineRecordTreeElement.js:
+        (WebInspector.TimelineRecordTreeElement):
+        Icon for GC events.
+
 2015-10-15  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r191135.
index e3656cc..7728a6a 100644 (file)
Binary files a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js and b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js differ
index e494a9a..ee49281 100644 (file)
@@ -68,6 +68,8 @@ WebInspector.loaded = function()
         InspectorBackend.registerDOMDispatcher(new WebInspector.DOMObserver);
     if (InspectorBackend.registerDebuggerDispatcher)
         InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerObserver);
+    if (InspectorBackend.registerHeapDispatcher)
+        InspectorBackend.registerHeapDispatcher(new WebInspector.HeapObserver);
     if (InspectorBackend.registerDatabaseDispatcher)
         InspectorBackend.registerDatabaseDispatcher(new WebInspector.DatabaseObserver);
     if (InspectorBackend.registerDOMStorageDispatcher)
@@ -108,6 +110,7 @@ WebInspector.loaded = function()
     this.issueManager = new WebInspector.IssueManager;
     this.analyzerManager = new WebInspector.AnalyzerManager;
     this.runtimeManager = new WebInspector.RuntimeManager;
+    this.heapManager = new WebInspector.HeapManager;
     this.applicationCacheManager = new WebInspector.ApplicationCacheManager;
     this.timelineManager = new WebInspector.TimelineManager;
     this.debuggerManager = new WebInspector.DebuggerManager;
index 5787c18..b31150c 100644 (file)
@@ -452,6 +452,23 @@ Object.defineProperty(Array.prototype, "keySet",
     }
 });
 
+Object.defineProperty(Array.prototype, "partition",
+{
+    value: function(callback)
+    {
+        let positive = [];
+        let negative = [];
+        for (let i = 0; i < this.length; ++i) {
+            let value = this[i];
+            if (callback(value))
+                positive.push(value);
+            else
+                negative.push(value);
+        }
+        return [positive, negative];
+    }
+});
+
 Object.defineProperty(String.prototype, "trimMiddle",
 {
     value: function(maxLength)
diff --git a/Source/WebInspectorUI/UserInterface/Controllers/HeapManager.js b/Source/WebInspectorUI/UserInterface/Controllers/HeapManager.js
new file mode 100644 (file)
index 0000000..bc3dba9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS 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 APPLE INC. OR ITS 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.HeapManager = class HeapManager extends WebInspector.Object
+{
+    constructor()
+    {
+        super();
+
+        if (window.HeapAgent)
+            HeapAgent.enable();
+    }
+
+    // Public
+
+    garbageCollected(payload)
+    {
+        // Called from WebInspector.HeapObserver.
+
+        let collection = WebInspector.GarbageCollection.fromPayload(payload);
+        this.dispatchEventToListeners(WebInspector.HeapManager.Event.GarbageCollected, {collection});
+    }
+};
+
+WebInspector.HeapManager.Event = {
+    GarbageCollected: "heap-manager-garbage-collected"
+};
index cd44a93..70ebd1c 100644 (file)
@@ -33,6 +33,8 @@ WebInspector.TimelineManager = class TimelineManager extends WebInspector.Object
         WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
         WebInspector.Frame.addEventListener(WebInspector.Frame.Event.ResourceWasAdded, this._resourceWasAdded, this);
 
+        WebInspector.heapManager.addEventListener(WebInspector.HeapManager.Event.GarbageCollected, this._garbageCollected, this);
+
         this._persistentNetworkTimeline = new WebInspector.NetworkTimeline;
 
         this._isCapturing = false;
@@ -593,6 +595,15 @@ WebInspector.TimelineManager = class TimelineManager extends WebInspector.Object
 
         this._addRecord(record);
     }
+
+    _garbageCollected(event)
+    {
+        if (!this._isCapturing)
+            return;
+
+        let collection = event.data.collection;
+        this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.GarbageCollected, collection.startTime, collection.endTime, null, null, collection));
+    }
 };
 
 WebInspector.TimelineManager.Event = {
diff --git a/Source/WebInspectorUI/UserInterface/Images/TimelineRecordGarbageCollection.svg b/Source/WebInspectorUI/UserInterface/Images/TimelineRecordGarbageCollection.svg
new file mode 100644 (file)
index 0000000..8e17df6
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2015 Apple Inc. All rights reserved. -->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+    <path fill="rgb(228, 198, 172)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 Z"/>
+    <path fill="rgb(186, 157, 132)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 M 13 2 C 13.550781 2 14 2.449219 14 3 L 14 13 C 14 13.550781 13.550781 14 13 14 L 3 14 C 2.449219 14 2 13.550781 2 13 L 2 3 C 2 2.449219 2.449219 2 3 2 L 13 2"/>
+    <path fill="rgb(186, 157, 132)" d="M 4.773438 11.542969 C 3.855469 10.621094 3.390625 9.347656 3.390625 7.769531 C 3.390625 6.15625 3.863281 4.878906 4.789062 3.964844 C 5.710938 3.054688 7.003906 2.59375 8.625 2.59375 C 9.570312 2.59375 10.519531 2.707031 11.441406 2.929688 C 11.890625 3.035156 12.210938 3.4375 12.210938 3.902344 L 12.210938 5.195312 C 12.210938 5.519531 12.050781 5.824219 11.789062 6.011719 C 11.613281 6.132812 11.410156 6.195312 11.207031 6.195312 C 11.097656 6.195312 10.984375 6.179688 10.878906 6.140625 C 10.015625 5.835938 9.308594 5.683594 8.769531 5.683594 C 8.058594 5.683594 7.753906 5.941406 7.589844 6.132812 C 7.296875 6.476562 7.148438 7.019531 7.148438 7.746094 C 7.148438 8.445312 7.308594 8.972656 7.621094 9.320312 C 7.808594 9.523438 8.148438 9.796875 8.921875 9.796875 C 9.542969 9.796875 10.1875 9.632812 10.839844 9.308594 C 10.980469 9.242188 11.132812 9.207031 11.285156 9.207031 C 11.46875 9.207031 11.648438 9.257812 11.8125 9.359375 C 12.105469 9.539062 12.285156 9.859375 12.285156 10.207031 L 12.285156 11.425781 C 12.285156 11.820312 12.050781 12.179688 11.691406 12.339844 C 10.792969 12.738281 9.730469 12.941406 8.527344 12.941406 C 6.957031 12.941406 5.691406 12.472656 4.773438 11.542969"/>
+    <path fill="white" d="M 11.285156 11.425781 C 10.515625 11.769531 9.597656 11.941406 8.527344 11.941406 C 7.226562 11.941406 6.210938 11.574219 5.484375 10.839844 C 4.757812 10.105469 4.394531 9.082031 4.394531 7.769531 C 4.394531 6.429688 4.757812 5.398438 5.492188 4.675781 C 6.222656 3.957031 7.269531 3.59375 8.625 3.59375 C 9.492188 3.59375 10.351562 3.695312 11.210938 3.902344 L 11.210938 5.195312 C 10.238281 4.855469 9.425781 4.683594 8.769531 4.683594 C 7.933594 4.683594 7.285156 4.949219 6.832031 5.484375 C 6.375 6.015625 6.148438 6.769531 6.148438 7.746094 C 6.148438 8.707031 6.394531 9.453125 6.882812 9.992188 C 7.371094 10.527344 8.050781 10.796875 8.921875 10.796875 C 9.703125 10.796875 10.488281 10.601562 11.285156 10.207031 Z"/>
+</svg>
index b0b4b59..5b48741 100644 (file)
     <script src="Protocol/DOMStorageObserver.js"></script>
     <script src="Protocol/DatabaseObserver.js"></script>
     <script src="Protocol/DebuggerObserver.js"></script>
+    <script src="Protocol/HeapObserver.js"></script>
     <script src="Protocol/InspectorBackend.js"></script>
     <script src="Protocol/InspectorFrontendAPI.js"></script>
     <script src="Protocol/InspectorObserver.js"></script>
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/Frame.js"></script>
+    <script src="Models/GarbageCollection.js"></script>
     <script src="Models/Geometry.js"></script>
     <script src="Models/Gradient.js"></script>
     <script src="Models/IndexedDatabase.js"></script>
     <script src="Controllers/FormatterContentBuilder.js"></script>
     <script src="Controllers/FormatterSourceMap.js"></script>
     <script src="Controllers/FrameResourceManager.js"></script>
+    <script src="Controllers/HeapManager.js"></script>
     <script src="Controllers/IssueManager.js"></script>
     <script src="Controllers/JavaScriptLogViewController.js"></script>
     <script src="Controllers/JavaScriptRuntimeCompletionProvider.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/GarbageCollection.js b/Source/WebInspectorUI/UserInterface/Models/GarbageCollection.js
new file mode 100644 (file)
index 0000000..9d063b1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS 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 APPLE INC. OR ITS 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.GarbageCollection = class GarbageCollection extends WebInspector.Object
+{
+    constructor(type, startTime, endTime)
+    {
+        super();
+
+        console.assert(endTime > startTime);
+
+        this._type = type;
+        this._startTime = startTime;
+        this._endTime = endTime;
+    }
+
+    // Static
+
+    static fromPayload(payload)
+    {
+        let type = WebInspector.GarbageCollection.Type.Full;
+        if (payload.type === HeapAgent.GarbageCollectionType.Partial)
+            type = WebInspector.GarbageCollection.Type.Partial;
+
+        return new WebInspector.GarbageCollection(type, payload.startTime, payload.endTime);
+    }
+
+    // Public
+
+    get type()
+    {
+        return this._type;
+    }
+
+    get startTime()
+    {
+        return this._startTime;
+    }
+
+    get endTime()
+    {
+        return this._endTime;
+    }
+
+    get duration()
+    {
+        return this._endTime - this._startTime;
+    }
+};
+
+WebInspector.GarbageCollection.Type = {
+    Partial: Symbol("Partial"),
+    Full: Symbol("Full")
+};
index ccb6da8..95267f4 100644 (file)
@@ -58,6 +58,11 @@ WebInspector.ScriptTimelineRecord = class ScriptTimelineRecord extends WebInspec
         return this._profile;
     }
 
+    isGarbageCollection()
+    {
+        return this._eventType === WebInspector.ScriptTimelineRecord.EventType.GarbageCollected;
+    }
+
     saveIdentityToCookie(cookie)
     {
         super.saveIdentityToCookie(cookie);
@@ -158,10 +163,11 @@ WebInspector.ScriptTimelineRecord.EventType = {
     AnimationFrameFired: "script-timeline-record-animation-frame-fired",
     AnimationFrameRequested: "script-timeline-record-animation-frame-requested",
     AnimationFrameCanceled: "script-timeline-record-animation-frame-canceled",
-    ConsoleProfileRecorded: "script-timeline-record-console-profile-recorded"
+    ConsoleProfileRecorded: "script-timeline-record-console-profile-recorded",
+    GarbageCollected: "script-timeline-record-garbage-collected"
 };
 
-WebInspector.ScriptTimelineRecord.EventType.displayName = function(eventType, details, includeTimerIdentifierInMainTitle)
+WebInspector.ScriptTimelineRecord.EventType.displayName = function(eventType, details, includeDetailsInMainTitle)
 {
     if (details && !WebInspector.ScriptTimelineRecord._eventDisplayNames) {
         // These display names are not localized because they closely represent
@@ -335,16 +341,27 @@ WebInspector.ScriptTimelineRecord.EventType.displayName = function(eventType, de
         if (details && (details instanceof String || typeof details === "string"))
             return WebInspector.UIString("“%s” Profile Recorded").format(details);
         return WebInspector.UIString("Console Profile Recorded");
+    case WebInspector.ScriptTimelineRecord.EventType.GarbageCollected:
+        console.assert(details);
+        if (details && (details instanceof WebInspector.GarbageCollection) && includeDetailsInMainTitle) {
+            switch (details.type) {
+            case WebInspector.GarbageCollection.Type.Partial:
+                return WebInspector.UIString("Partial Garbage Collection");
+            case WebInspector.GarbageCollection.Type.Full:
+                return WebInspector.UIString("Full Garbage Collection");
+            }
+        }
+        return WebInspector.UIString("Garbage Collection");
     case WebInspector.ScriptTimelineRecord.EventType.TimerFired:
-        if (details && includeTimerIdentifierInMainTitle)
+        if (details && includeDetailsInMainTitle)
             return WebInspector.UIString("Timer %s Fired").format(details);
         return WebInspector.UIString("Timer Fired");
     case WebInspector.ScriptTimelineRecord.EventType.TimerInstalled:
-        if (details && includeTimerIdentifierInMainTitle)
+        if (details && includeDetailsInMainTitle)
             return WebInspector.UIString("Timer %s Installed").format(details);
         return WebInspector.UIString("Timer Installed");
     case WebInspector.ScriptTimelineRecord.EventType.TimerRemoved:
-        if (details && includeTimerIdentifierInMainTitle)
+        if (details && includeDetailsInMainTitle)
             return WebInspector.UIString("Timer %s Removed").format(details);
         return WebInspector.UIString("Timer Removed");
     case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired:
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js
new file mode 100644 (file)
index 0000000..f04b300
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS 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 APPLE INC. OR ITS 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.HeapObserver = class HeapObserver
+{
+    // Events defined by the "Heap" domain.
+
+    garbageCollected(collection)
+    {
+        WebInspector.heapManager.garbageCollected(collection);
+    }
+};
index 87fc3ac..303fb07 100644 (file)
@@ -62,6 +62,7 @@
     <script src="Protocol/DOMObserver.js"></script>
     <script src="Protocol/DOMStorageObserver.js"></script>
     <script src="Protocol/DebuggerObserver.js"></script>
+    <script src="Protocol/HeapObserver.js"></script>
     <script src="Protocol/NetworkObserver.js"></script>
     <script src="Protocol/PageObserver.js"></script>
     <script src="Protocol/RemoteObject.js"></script>
@@ -98,6 +99,7 @@
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/Frame.js"></script>
+    <script src="Models/GarbageCollection.js"></script>
     <script src="Models/Geometry.js"></script>
     <script src="Models/IndexedDatabase.js"></script>
     <script src="Models/IndexedDatabaseObjectStore.js"></script>
     <script src="Controllers/DOMTreeManager.js"></script>
     <script src="Controllers/DebuggerManager.js"></script>
     <script src="Controllers/FrameResourceManager.js"></script>
+    <script src="Controllers/HeapManager.js"></script>
     <script src="Controllers/IssueManager.js"></script>
     <script src="Controllers/LogManager.js"></script>
     <script src="Controllers/ProbeManager.js"></script>
index 7b28d55..c99be99 100644 (file)
@@ -41,6 +41,7 @@ WebInspector.loaded = function()
     InspectorBackend.registerDOMDispatcher(new WebInspector.DOMObserver);
     InspectorBackend.registerNetworkDispatcher(new WebInspector.NetworkObserver);
     InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerObserver);
+    InspectorBackend.registerHeapDispatcher(new WebInspector.HeapObserver);
     InspectorBackend.registerTimelineDispatcher(new WebInspector.TimelineObserver);
     InspectorBackend.registerCSSDispatcher(new WebInspector.CSSObserver);
     InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver);
@@ -54,6 +55,7 @@ WebInspector.loaded = function()
     this.logManager = new WebInspector.LogManager;
     this.issueManager = new WebInspector.IssueManager;
     this.runtimeManager = new WebInspector.RuntimeManager;
+    this.heapManager = new WebInspector.HeapManager;
     this.timelineManager = new WebInspector.TimelineManager;
     this.debuggerManager = new WebInspector.DebuggerManager;
     this.probeManager = new WebInspector.ProbeManager;
index 0354042..16af821 100644 (file)
@@ -77,8 +77,15 @@ WebInspector.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode exten
             }
         }
 
-        return {eventType: this._record.eventType, startTime, selfTime: duration, totalTime: duration,
-            averageTime: duration, callCount: 1, location: callFrameOrSourceCodeLocation};
+        return {
+            eventType: this._record.eventType,
+            startTime,
+            selfTime: duration,
+            totalTime: duration,
+            averageTime: duration,
+            callCount: NaN,
+            location: callFrameOrSourceCodeLocation
+        };
     }
 
     updateRangeTimes(startTime, endTime)
@@ -124,6 +131,9 @@ WebInspector.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode exten
         case "totalTime":
         case "averageTime":
             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value, true);
+
+        case "callCount":
+            return isNaN(value) ? emptyValuePlaceholderString : value;
         }
 
         return super.createCellContent(columnIdentifier, cell);
index 71ee9a1..451a4f5 100644 (file)
@@ -73,7 +73,11 @@ WebInspector.ScriptTimelineOverviewGraph = class ScriptTimelineOverviewGraph ext
             ++recordBarIndex;
         }
 
-        WebInspector.TimelineRecordBar.createCombinedBars(this._scriptTimeline.records, secondsPerPixel, this, createBar.bind(this));
+        // Create bars for non-GC records and GC records.
+        let [gcRecords, nonGCRecords] = this._scriptTimeline.records.partition((x) => x.isGarbageCollection());
+        let boundCreateBar = createBar.bind(this);
+        WebInspector.TimelineRecordBar.createCombinedBars(nonGCRecords, secondsPerPixel, this, boundCreateBar);
+        WebInspector.TimelineRecordBar.createCombinedBars(gcRecords, secondsPerPixel, this, boundCreateBar);
 
         // Remove the remaining unused TimelineRecordBars.
         for (; recordBarIndex < this._timelineRecordBars.length; ++recordBarIndex) {
index 9e0a544..48e5052 100644 (file)
@@ -224,6 +224,10 @@ WebInspector.ScriptTimelineView = class ScriptTimelineView extends WebInspector.
         if (!this._pendingRecords.length)
             return;
 
+        let zeroTime = this.zeroTime;
+        let startTime = this.startTime;
+        let endTime = this.endTime;
+
         for (var scriptTimelineRecord of this._pendingRecords) {
             var rootNodes = [];
             if (scriptTimelineRecord.profile) {
@@ -231,15 +235,11 @@ WebInspector.ScriptTimelineView = class ScriptTimelineView extends WebInspector.
                 rootNodes = scriptTimelineRecord.profile.topDownRootNodes;
             }
 
-            var zeroTime = this.zeroTime;
-            var treeElement = new WebInspector.TimelineRecordTreeElement(scriptTimelineRecord, WebInspector.SourceCodeLocation.NameStyle.Short, rootNodes.length);
+            var treeElement = new WebInspector.TimelineRecordTreeElement(scriptTimelineRecord, WebInspector.SourceCodeLocation.NameStyle.Short, true);
             var dataGridNode = new WebInspector.ScriptTimelineDataGridNode(scriptTimelineRecord, zeroTime);
 
             this._dataGrid.addRowInSortOrder(treeElement, dataGridNode);
 
-            var startTime = this.startTime;
-            var endTime = this.endTime;
-
             for (var profileNode of rootNodes) {
                 var profileNodeTreeElement = new WebInspector.ProfileNodeTreeElement(profileNode, this);
                 var profileNodeDataGridNode = new WebInspector.ProfileNodeDataGridNode(profileNode, zeroTime, startTime, endTime);
index 1d3580a..162b57b 100644 (file)
 
 WebInspector.SourceCodeTimelineTreeElement = class SourceCodeTimelineTreeElement extends WebInspector.TimelineRecordTreeElement
 {
-    constructor(sourceCodeTimeline, subtitleNameStyle, includeTimerIdentifierInMainTitle)
+    constructor(sourceCodeTimeline, subtitleNameStyle, includeDetailsInMainTitle)
     {
         console.assert(sourceCodeTimeline);
 
         subtitleNameStyle = subtitleNameStyle || WebInspector.SourceCodeLocation.NameStyle.None;
 
-        super(sourceCodeTimeline.records[0], subtitleNameStyle, includeTimerIdentifierInMainTitle, sourceCodeTimeline.sourceCodeLocation, sourceCodeTimeline);
+        super(sourceCodeTimeline.records[0], subtitleNameStyle, includeDetailsInMainTitle, sourceCodeTimeline.sourceCodeLocation, sourceCodeTimeline);
 
         this._sourceCodeTimeline = sourceCodeTimeline;
     }
index 49b1f4b..f0ea290 100644 (file)
     content: url(../Images/TimelineRecordConsoleProfile.svg);
 }
 
+.garbage-collection-profile-record .icon {
+    content: url(../Images/TimelineRecordGarbageCollection.svg);
+}
+
 .timer-record .icon {
     content: url(../Images/TimelineRecordTimer.svg);
 }
index 45d5dfe..46bbea4 100644 (file)
@@ -98,3 +98,8 @@
     background-color: hsl(269, 65%, 74%);
     border-color: hsl(273, 33%, 58%);
 }
+
+.timeline-record-bar.timeline-record-type-script.script-timeline-record-garbage-collected > .segment {
+    background-color: hsl(23, 69%, 73%);
+    border-color: hsl(11, 54%, 62%);    
+}
index 263ad22..5560ea8 100644 (file)
@@ -134,21 +134,23 @@ WebInspector.TimelineRecordBar = class TimelineRecordBar extends WebInspector.Ob
         var startTimeProperty = usesActiveStartTime ? "activeStartTime" : "startTime";
 
         for (var record of visibleRecords) {
+            var startTime = record[startTimeProperty];
+
             // Check if the previous record is far enough away to create the active bar. We also create it now if the current record has no active state time.
-            if (!isNaN(activeStartTime) && (activeStartTime + Math.max(activeEndTime - activeStartTime, minimumDuration) + minimumMargin <= record[startTimeProperty]
-                || (isNaN(record[startTimeProperty]) && !isNaN(activeEndTime)))) {
+            if (!isNaN(activeStartTime) && (activeStartTime + Math.max(activeEndTime - activeStartTime, minimumDuration) + minimumMargin <= startTime
+                || (isNaN(startTime) && !isNaN(activeEndTime)))) {
                 createBarCallback(activeRecords, WebInspector.TimelineRecordBar.RenderMode.ActiveOnly);
                 activeRecords = [];
                 activeStartTime = NaN;
                 activeEndTime = NaN;
             }
 
-            if (isNaN(record[startTimeProperty]))
+            if (isNaN(startTime))
                 continue;
 
             // If this is a new bar, peg the start time.
             if (isNaN(activeStartTime))
-                activeStartTime = record[startTimeProperty];
+                activeStartTime = startTime;
 
             // Update the end time to be the maximum we encounter. activeEndTime might be NaN, so "|| 0" to prevent Math.max from returning NaN.
             if (!isNaN(record.endTime))
index d311f4b..54b871f 100644 (file)
@@ -25,7 +25,7 @@
 
 WebInspector.TimelineRecordTreeElement = class TimelineRecordTreeElement extends WebInspector.GeneralTreeElement
 {
-    constructor(timelineRecord, subtitleNameStyle, includeTimerIdentifierInMainTitle, sourceCodeLocation, representedObject)
+    constructor(timelineRecord, subtitleNameStyle, includeDetailsInMainTitle, sourceCodeLocation, representedObject)
     {
         console.assert(timelineRecord);
 
@@ -72,7 +72,7 @@ WebInspector.TimelineRecordTreeElement = class TimelineRecordTreeElement extends
             break;
 
         case WebInspector.TimelineRecord.Type.Script:
-            title = WebInspector.ScriptTimelineRecord.EventType.displayName(timelineRecord.eventType, timelineRecord.details, includeTimerIdentifierInMainTitle);
+            title = WebInspector.ScriptTimelineRecord.EventType.displayName(timelineRecord.eventType, timelineRecord.details, includeDetailsInMainTitle);
 
             switch (timelineRecord.eventType) {
             case WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated:
@@ -87,6 +87,9 @@ WebInspector.TimelineRecordTreeElement = class TimelineRecordTreeElement extends
             case WebInspector.ScriptTimelineRecord.EventType.ConsoleProfileRecorded:
                 iconStyleClass = WebInspector.TimelineRecordTreeElement.ConsoleProfileIconStyleClass;
                 break;
+            case WebInspector.ScriptTimelineRecord.EventType.GarbageCollected:
+                iconStyleClass = WebInspector.TimelineRecordTreeElement.GarbageCollectionIconStyleClass;
+                break;
             case WebInspector.ScriptTimelineRecord.EventType.TimerFired:
             case WebInspector.ScriptTimelineRecord.EventType.TimerInstalled:
             case WebInspector.ScriptTimelineRecord.EventType.TimerRemoved:
@@ -168,3 +171,4 @@ WebInspector.TimelineRecordTreeElement.TimerRecordIconStyleClass = "timer-record
 WebInspector.TimelineRecordTreeElement.AnimationRecordIconStyleClass = "animation-record";
 WebInspector.TimelineRecordTreeElement.ProbeRecordIconStyleClass = "probe-record";
 WebInspector.TimelineRecordTreeElement.ConsoleProfileIconStyleClass = "console-profile-record";
+WebInspector.TimelineRecordTreeElement.GarbageCollectionIconStyleClass = "garbage-collection-profile-record";