Title: [194242] trunk
Revision
194242
Author
[email protected]
Date
2015-12-17 15:37:48 -0800 (Thu, 17 Dec 2015)

Log Message

Web Inspector: Add JSContext Script Profiling
https://bugs.webkit.org/show_bug.cgi?id=151899

Reviewed by Brian Burg.

Source/_javascript_Core:

Extend JSC::Debugger to include a profiling client interface
that the Inspector can implement to be told about script execution
entry and exit points. Add new profiledCall/Evaluate/Construct
methods that are entry points that will notify the profiling
client if it exists.

By putting the profiling client on Debugger it avoids having
special code paths for a JSGlobalObject being JSContext inspected
or a JSGlobalObject in a Page being Web inspected. In either case
the JSGlobalObject can go through its debugger() which always
reaches the correct inspector instance.

* CMakeLists.txt:
* DerivedSources.make:
* _javascript_Core.xcodeproj/project.pbxproj:
Handle new files.

* runtime/CallData.cpp:
(JSC::profiledCall):
* runtime/CallData.h:
* runtime/Completion.cpp:
(JSC::profiledEvaluate):
* runtime/Completion.h:
(JSC::profiledEvaluate):
* runtime/ConstructData.cpp:
(JSC::profiledConstruct):
* runtime/ConstructData.h:
(JSC::profiledConstruct):
Create profiled versions of interpreter entry points. If a profiler client is
available, this will automatically inform it of entry/exit. Include a reason
why this is being profiled. Currently all reasons in _javascript_Core are enumerated
(API, Microtask) and Other is to be used by WebCore or future clients.

* debugger/ScriptProfilingScope.h: Added.
(JSC::ScriptProfilingScope::ScriptProfilingScope):
(JSC::ScriptProfilingScope::~ScriptProfilingScope):
(JSC::ScriptProfilingScope::shouldStartProfile):
(JSC::ScriptProfilingScope::shouldEndProfile):
At profiled entry points inform the profiling client if needed.

* API/JSBase.cpp:
(JSEvaluateScript):
* API/JSObjectRef.cpp:
(JSObjectCallAsFunction):
(JSObjectCallAsConstructor):
* runtime/JSJob.cpp:
(JSC::JSJobMicrotask::run):
Use the profiled functions for API and Microtask execution entry points.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::hasProfiler):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::hasProfiler):
Extend hasProfiler to also check the new Debugger script profiler.

* debugger/Debugger.cpp:
(JSC::Debugger::setProfilingClient):
(JSC::Debugger::willEvaluateScript):
(JSC::Debugger::didEvaluateScript):
* debugger/Debugger.h:
Pass through to the profiling client.

* inspector/protocol/ScriptProfiler.json: Added.
* inspector/agents/InspectorScriptProfilerAgent.cpp: Added.
(Inspector::InspectorScriptProfilerAgent::InspectorScriptProfilerAgent):
(Inspector::InspectorScriptProfilerAgent::~InspectorScriptProfilerAgent):
(Inspector::InspectorScriptProfilerAgent::didCreateFrontendAndBackend):
(Inspector::InspectorScriptProfilerAgent::willDestroyFrontendAndBackend):
(Inspector::InspectorScriptProfilerAgent::startTracking):
(Inspector::InspectorScriptProfilerAgent::stopTracking):
(Inspector::InspectorScriptProfilerAgent::isAlreadyProfiling):
(Inspector::InspectorScriptProfilerAgent::willEvaluateScript):
(Inspector::InspectorScriptProfilerAgent::didEvaluateScript):
(Inspector::toProtocol):
(Inspector::InspectorScriptProfilerAgent::addEvent):
(Inspector::buildAggregateCallInfoInspectorObject):
(Inspector::buildInspectorObject):
(Inspector::buildProfileInspectorObject):
(Inspector::InspectorScriptProfilerAgent::trackingComplete):
* inspector/agents/InspectorScriptProfilerAgent.h: Added.
New ScriptProfiler domain to just turn on / off script profiling.
It introduces a start/update/complete event model which we want
to include in new domains.

* inspector/InspectorEnvironment.h:
* inspector/InjectedScriptBase.cpp:
(Inspector::InjectedScriptBase::callFunctionWithEvalEnabled):
Simplify this now that we want it to be the same for all clients.

* inspector/JSGlobalObjectInspectorController.h:
* inspector/JSGlobalObjectInspectorController.cpp:
(Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
Create the new agent.

* inspector/InspectorProtocolTypes.h:
(Inspector::Protocol::Array::addItem):
Allow pushing a double onto a Protocol::Array.

Source/WebCore:

Tests: inspector/script-profiler/event-type-API.html
       inspector/script-profiler/event-type-Microtask.html
       inspector/script-profiler/tracking.html

* ForwardingHeaders/inspector/agents/InspectorScriptProfilerAgent.h: Added.

* inspector/InspectorController.h:
* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
Create the new agent, even if we don't use it yet for Page inspection.

(WebCore::InspectorController::willCallInjectedScriptFunction): Deleted.
(WebCore::InspectorController::didCallInjectedScriptFunction): Deleted.
No longer needed, implementation was pushed up into InjectedScriptBase.

* inspector/InspectorCSSAgent.cpp:
(WebCore::InspectorCSSAgent::buildArrayForMatchedRuleList):
* inspector/InspectorReplayAgent.cpp:
(WebCore::buildInspectorObjectForSession):
Disambiguate types.

Source/WebInspectorUI:

Enable the Timeline tab for JSContext inspection. Currently only
JSContext inspection will use the ScriptProfiler domain, it will
be enabled for Page inspection in a follow-up.

First pass at the UI creates basic ScriptTimelineRecords for
ScriptProfiler events. At the end of recording, when profiles
are downloaded, it attaches profiles to the timeline records
and refreshes the Scripts timeline.

* UserInterface/Base/Main.js:
(WebInspector.loaded):
* UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager):
(WebInspector.TimelineManager.defaultInstruments):
(WebInspector.TimelineManager.prototype.computeElapsedTime):
(WebInspector.TimelineManager.prototype.scriptProfilerIsTracking):
(WebInspector.TimelineManager.prototype._loadNewRecording):
(WebInspector.TimelineManager.prototype._mainResourceDidChange):
(WebInspector.TimelineManager.prototype._resourceWasAdded):
(WebInspector.TimelineManager.prototype._garbageCollected):
(WebInspector.TimelineManager.prototype._addRecord): Deleted.
* UserInterface/Main.html:
* UserInterface/Models/Instrument.js:
(WebInspector.Instrument.startLegacyTimelineAgent):
* UserInterface/Models/ScriptInstrument.js:
(WebInspector.ScriptInstrument.prototype.startInstrumentation):
(WebInspector.ScriptInstrument.prototype.stopInstrumentation):
(WebInspector.ScriptInstrument):
* UserInterface/Models/ScriptTimelineRecord.js:
(WebInspector.ScriptTimelineRecord.prototype.get profilePayload):
(WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload):
(WebInspector.ScriptTimelineRecord):
(WebInspector.ScriptTimelineRecord.EventType.displayName):
* UserInterface/Models/Timeline.js:
(WebInspector.Timeline.prototype.refresh):
* UserInterface/Models/TimelineRecording.js:
(WebInspector.TimelineRecording.sourceCodeTimelinesSupported):
(WebInspector.TimelineRecording.prototype.timelineForRecordType):
(WebInspector.TimelineRecording.prototype.addRecord):
* UserInterface/Protocol/ScriptProfilerObserver.js: Copied from Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js.
(WebInspector.ScriptProfilerObserver.prototype.trackingStart):
(WebInspector.ScriptProfilerObserver.prototype.trackingUpdate):
(WebInspector.ScriptProfilerObserver.prototype.trackingComplete):
(WebInspector.ScriptProfilerObserver):
* UserInterface/Views/ScriptTimelineView.js:
(WebInspector.ScriptTimelineView):
(WebInspector.ScriptTimelineView.prototype._processPendingRecords):
(WebInspector.ScriptTimelineView.prototype._scriptTimelineRecordRefreshed):
* UserInterface/Views/TimelineRecordTreeElement.js:
(WebInspector.TimelineRecordTreeElement):
* UserInterface/Views/TimelineTabContentView.js:
(WebInspector.TimelineTabContentView.isTabAllowed):

LayoutTests:

* inspector/script-profiler/event-type-API-expected.txt: Added.
* inspector/script-profiler/event-type-API.html: Added.
* inspector/script-profiler/event-type-Microtask-expected.txt: Added.
* inspector/script-profiler/event-type-Microtask.html: Added.
* inspector/script-profiler/tracking-expected.txt: Added.
* inspector/script-profiler/tracking.html: Added.
Tests for the new ScriptProfiler domain.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (194241 => 194242)


--- trunk/LayoutTests/ChangeLog	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/LayoutTests/ChangeLog	2015-12-17 23:37:48 UTC (rev 194242)
@@ -1,3 +1,18 @@
+2015-12-16  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Add JSContext Script Profiling
+        https://bugs.webkit.org/show_bug.cgi?id=151899
+
+        Reviewed by Brian Burg.
+
+        * inspector/script-profiler/event-type-API-expected.txt: Added.
+        * inspector/script-profiler/event-type-API.html: Added.
+        * inspector/script-profiler/event-type-Microtask-expected.txt: Added.
+        * inspector/script-profiler/event-type-Microtask.html: Added.
+        * inspector/script-profiler/tracking-expected.txt: Added.
+        * inspector/script-profiler/tracking.html: Added.
+        Tests for the new ScriptProfiler domain.
+
 2015-12-17  Ryan Haddad  <[email protected]>
 
         Marking fast/media/mq-* tests as failing on ios-simulator

Added: trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt (0 => 194242)


--- trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: line 1: Log from API Evaluated Script
+Tests for generating a ScriptProfiler.Event with ScriptProfiler.EventType.API type.
+
+
+== Running test suite: ScriptProfiler.EventType.API
+-- Running test case: TrackingSession
+ScriptProfiler.trackingStart
+ScriptProfiler.trackingUpdate
+PASS: Event type should be API.
+ScriptProfiler.trackingComplete
+PASS: Profiles should exist when complete.
+PASS: Should be 1 profile for this session.
+

Added: trunk/LayoutTests/inspector/script-profiler/event-type-API.html (0 => 194242)


--- trunk/LayoutTests/inspector/script-profiler/event-type-API.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-API.html	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function triggerAPIScript() {
+    testRunner.evaluateScriptInIsolatedWorld(0, "console.log('Log from API Evaluated Script')");
+}
+
+function test()
+{
+    let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.EventType.API");
+
+    suite.addTestCase({
+        name: "TrackingSession",
+        description: "Start a tracking session that includes an API event type.",
+        test: function(resolve, reject) {
+            
+            InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingStart"}).then((messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingStart");
+            });
+
+            InspectorProtocol.addEventListener("ScriptProfiler.trackingUpdate", (messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingUpdate");
+                ProtocolTest.expectThat(messageObject.params.event.type === "API", "Event type should be API.");
+            });
+
+            InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingComplete");
+                ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
+                ProtocolTest.expectThat(messageObject.params.profiles.length === 1, "Should be 1 profile for this session.");
+                resolve();
+            });
+
+            InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+            ProtocolTest.evaluateInPage("triggerAPIScript();"); // This ultimately uses the JSEvaluateScript API on the Page's context.
+            InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {});
+        }
+    });
+
+    // FIXME: <https://webkit.org/b/152193> Web Inspector: Separate Debugger enable state from being attached
+    // Debugger should not need to be enabled for profiling to work.
+    InspectorProtocol.sendCommand("Debugger.enable", {});
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Tests for generating a ScriptProfiler.Event with ScriptProfiler.EventType.API type.</p>
+</body>
+</html>

Added: trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt (0 => 194242)


--- trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: line 8: Promise Microtask Fired
+Tests for generating a ScriptProfiler.Event with ScriptProfiler.EventType.Microtask type.
+
+
+== Running test suite: ScriptProfiler.EventType.Microtask
+-- Running test case: TrackingSession
+ScriptProfiler.trackingStart
+ScriptProfiler.trackingUpdate
+PASS: Event type should be Microtask.
+ScriptProfiler.trackingComplete
+PASS: Profiles should exist when complete.
+PASS: Should be 1 profile for this session.
+

Added: trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html (0 => 194242)


--- trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function triggerMicrotask() {
+    Promise.resolve(100).then(function() {
+        console.log("Promise Microtask Fired");
+    });
+}
+
+function test()
+{
+    let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.EventType.Microtask");
+
+    suite.addTestCase({
+        name: "TrackingSession",
+        description: "Start a tracking session that includes a Microtask event type.",
+        test: function(resolve, reject) {
+            InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingStart"}).then((messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingStart");
+            });
+
+            InspectorProtocol.addEventListener("ScriptProfiler.trackingUpdate", (messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingUpdate");
+                ProtocolTest.expectThat(messageObject.params.event.type === "Microtask", "Event type should be Microtask.");
+            });
+
+            InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingComplete");
+                ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
+                ProtocolTest.expectThat(messageObject.params.profiles.length === 1, "Should be 1 profile for this session.");
+                resolve();
+            });
+
+            InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+            ProtocolTest.evaluateInPage("triggerMicrotask()");
+            InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {});
+        }
+    });
+
+    // FIXME: <https://webkit.org/b/152193> Web Inspector: Separate Debugger enable state from being attached
+    // Debugger should not need to be enabled for profiling to work.
+    InspectorProtocol.sendCommand("Debugger.enable", {});
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Tests for generating a ScriptProfiler.Event with ScriptProfiler.EventType.Microtask type.</p>
+</body>
+</html>

Added: trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt (0 => 194242)


--- trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,11 @@
+Tests that ScriptProfiler.startTracking and ScriptProfiler.stopTracking trigger trackingStart and trackingComplete events.
+
+
+== Running test suite: ScriptProfiler.startTracking and ScriptProfiler.stopTracking
+-- Running test case: StartAndStopTracking
+ScriptProfiler.trackingStart
+PASS: Should have a timestamp when starting.
+ScriptProfiler.trackingComplete
+PASS: Profiles should exist when complete.
+PASS: Should be no profiles for this session.
+

Added: trunk/LayoutTests/inspector/script-profiler/tracking.html (0 => 194242)


--- trunk/LayoutTests/inspector/script-profiler/tracking.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/script-profiler/tracking.html	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+    let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.startTracking and ScriptProfiler.stopTracking");
+
+    suite.addTestCase({
+        name: "StartAndStopTracking",
+        description: "Start and stop the ScriptProfiler should cause trackingStart and trackingComplete events.",
+        test: function(resolve, reject) {
+            InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingStart"}).then((messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingStart");
+                ProtocolTest.expectThat(typeof messageObject.params.timestamp === "number", "Should have a timestamp when starting.");
+            });
+
+            InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+                ProtocolTest.log("ScriptProfiler.trackingComplete");
+                ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
+                ProtocolTest.expectThat(!messageObject.params.profiles.length, "Should be no profiles for this session.");
+                resolve();
+            });
+
+            InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+            InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {});
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Tests that ScriptProfiler.startTracking and ScriptProfiler.stopTracking trigger trackingStart and trackingComplete events.</p>
+</body>
+</html>

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (194241 => 194242)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2015-12-17 23:37:48 UTC (rev 194242)
@@ -234,3 +234,6 @@
 
 # ASAN test only fails on WK1:
 webgl/1.0.3/151055_asan.html [ Failure ]
+
+# Lacking WK1 TestRunner API that evaluates _javascript_ through JSC APIs and not WebCore APIs
+inspector/script-profiler/event-type-API.html

Modified: trunk/Source/_javascript_Core/API/JSBase.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/API/JSBase.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/API/JSBase.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -65,7 +65,7 @@
     SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first()));
 
     NakedPtr<Exception> evaluationException;
-    JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, evaluationException);
+    JSValue returnValue = profiledEvaluate(globalObject->globalExec(), ProfilingReason::API, source, jsThisObject, evaluationException);
 
     if (evaluationException) {
         if (exception)

Modified: trunk/Source/_javascript_Core/API/JSObjectRef.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/API/JSObjectRef.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/API/JSObjectRef.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -556,7 +556,7 @@
     if (callType == CallTypeNone)
         return 0;
 
-    JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
+    JSValueRef result = toRef(exec, profiledCall(exec, ProfilingReason::API, jsObject, callType, callData, jsThisObject, argList));
     if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
     return result;
@@ -589,7 +589,8 @@
     MarkedArgumentBuffer argList;
     for (size_t i = 0; i < argumentCount; i++)
         argList.append(toJS(exec, arguments[i]));
-    JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
+
+    JSObjectRef result = toRef(profiledConstruct(exec, ProfilingReason::API, jsObject, constructType, constructData, argList));
     if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
     return result;

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (194241 => 194242)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2015-12-17 23:37:48 UTC (rev 194242)
@@ -429,6 +429,7 @@
     inspector/agents/InspectorDebuggerAgent.cpp
     inspector/agents/InspectorHeapAgent.cpp
     inspector/agents/InspectorRuntimeAgent.cpp
+    inspector/agents/InspectorScriptProfilerAgent.cpp
     inspector/agents/JSGlobalObjectConsoleAgent.cpp
     inspector/agents/JSGlobalObjectDebuggerAgent.cpp
     inspector/agents/JSGlobalObjectRuntimeAgent.cpp
@@ -1174,6 +1175,7 @@
     ${_javascript_CORE_DIR}/inspector/protocol/OverlayTypes.json
     ${_javascript_CORE_DIR}/inspector/protocol/Page.json
     ${_javascript_CORE_DIR}/inspector/protocol/Runtime.json
+    ${_javascript_CORE_DIR}/inspector/protocol/ScriptProfiler.json
     ${_javascript_CORE_DIR}/inspector/protocol/Timeline.json
 )
 

Modified: trunk/Source/_javascript_Core/ChangeLog (194241 => 194242)


--- trunk/Source/_javascript_Core/ChangeLog	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-12-17 23:37:48 UTC (rev 194242)
@@ -1,3 +1,108 @@
+2015-12-16  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Add JSContext Script Profiling
+        https://bugs.webkit.org/show_bug.cgi?id=151899
+
+        Reviewed by Brian Burg.
+
+        Extend JSC::Debugger to include a profiling client interface
+        that the Inspector can implement to be told about script execution
+        entry and exit points. Add new profiledCall/Evaluate/Construct
+        methods that are entry points that will notify the profiling
+        client if it exists.
+
+        By putting the profiling client on Debugger it avoids having
+        special code paths for a JSGlobalObject being JSContext inspected
+        or a JSGlobalObject in a Page being Web inspected. In either case
+        the JSGlobalObject can go through its debugger() which always
+        reaches the correct inspector instance.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        Handle new files.
+
+        * runtime/CallData.cpp:
+        (JSC::profiledCall):
+        * runtime/CallData.h:
+        * runtime/Completion.cpp:
+        (JSC::profiledEvaluate):
+        * runtime/Completion.h:
+        (JSC::profiledEvaluate):
+        * runtime/ConstructData.cpp:
+        (JSC::profiledConstruct):
+        * runtime/ConstructData.h:
+        (JSC::profiledConstruct):
+        Create profiled versions of interpreter entry points. If a profiler client is
+        available, this will automatically inform it of entry/exit. Include a reason
+        why this is being profiled. Currently all reasons in _javascript_Core are enumerated
+        (API, Microtask) and Other is to be used by WebCore or future clients.
+
+        * debugger/ScriptProfilingScope.h: Added.
+        (JSC::ScriptProfilingScope::ScriptProfilingScope):
+        (JSC::ScriptProfilingScope::~ScriptProfilingScope):
+        (JSC::ScriptProfilingScope::shouldStartProfile):
+        (JSC::ScriptProfilingScope::shouldEndProfile):
+        At profiled entry points inform the profiling client if needed.
+
+        * API/JSBase.cpp:
+        (JSEvaluateScript):
+        * API/JSObjectRef.cpp:
+        (JSObjectCallAsFunction):
+        (JSObjectCallAsConstructor):
+        * runtime/JSJob.cpp:
+        (JSC::JSJobMicrotask::run):
+        Use the profiled functions for API and Microtask execution entry points.
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::hasProfiler):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::hasProfiler):
+        Extend hasProfiler to also check the new Debugger script profiler.
+
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::setProfilingClient):
+        (JSC::Debugger::willEvaluateScript):
+        (JSC::Debugger::didEvaluateScript):
+        * debugger/Debugger.h:
+        Pass through to the profiling client.
+
+        * inspector/protocol/ScriptProfiler.json: Added.
+        * inspector/agents/InspectorScriptProfilerAgent.cpp: Added.
+        (Inspector::InspectorScriptProfilerAgent::InspectorScriptProfilerAgent):
+        (Inspector::InspectorScriptProfilerAgent::~InspectorScriptProfilerAgent):
+        (Inspector::InspectorScriptProfilerAgent::didCreateFrontendAndBackend):
+        (Inspector::InspectorScriptProfilerAgent::willDestroyFrontendAndBackend):
+        (Inspector::InspectorScriptProfilerAgent::startTracking):
+        (Inspector::InspectorScriptProfilerAgent::stopTracking):
+        (Inspector::InspectorScriptProfilerAgent::isAlreadyProfiling):
+        (Inspector::InspectorScriptProfilerAgent::willEvaluateScript):
+        (Inspector::InspectorScriptProfilerAgent::didEvaluateScript):
+        (Inspector::toProtocol):
+        (Inspector::InspectorScriptProfilerAgent::addEvent):
+        (Inspector::buildAggregateCallInfoInspectorObject):
+        (Inspector::buildInspectorObject):
+        (Inspector::buildProfileInspectorObject):
+        (Inspector::InspectorScriptProfilerAgent::trackingComplete):
+        * inspector/agents/InspectorScriptProfilerAgent.h: Added.
+        New ScriptProfiler domain to just turn on / off script profiling.
+        It introduces a start/update/complete event model which we want
+        to include in new domains.
+
+        * inspector/InspectorEnvironment.h:
+        * inspector/InjectedScriptBase.cpp:
+        (Inspector::InjectedScriptBase::callFunctionWithEvalEnabled):
+        Simplify this now that we want it to be the same for all clients.
+
+        * inspector/JSGlobalObjectInspectorController.h:
+        * inspector/JSGlobalObjectInspectorController.cpp:
+        (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
+        Create the new agent.
+
+        * inspector/InspectorProtocolTypes.h:
+        (Inspector::Protocol::Array::addItem):
+        Allow pushing a double onto a Protocol::Array.
+
 2015-12-17  Yusuke Suzuki  <[email protected]>
 
         [ES6] Handle new_generator_func / new_generator_func_exp in DFG / FTL

Modified: trunk/Source/_javascript_Core/DerivedSources.make (194241 => 194242)


--- trunk/Source/_javascript_Core/DerivedSources.make	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/DerivedSources.make	2015-12-17 23:37:48 UTC (rev 194242)
@@ -194,6 +194,7 @@
     $(_javascript_Core)/inspector/protocol/OverlayTypes.json \
     $(_javascript_Core)/inspector/protocol/Page.json \
     $(_javascript_Core)/inspector/protocol/Runtime.json \
+    $(_javascript_Core)/inspector/protocol/ScriptProfiler.json \
     $(_javascript_Core)/inspector/protocol/Timeline.json \
 #
 

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (194241 => 194242)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-12-17 23:37:48 UTC (rev 194242)
@@ -1554,6 +1554,9 @@
 		A54CF2FA184EAEDA00237F19 /* ScriptObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A54CF2F8184EAEDA00237F19 /* ScriptObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A54E8EB018BFFBBB00556D28 /* GCSegmentedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A343F7418A1748B0039B085 /* GCSegmentedArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A54E8EB118BFFBBE00556D28 /* GCSegmentedArrayInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A343F7718A1749D0039B085 /* GCSegmentedArrayInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		A55165D21BDF0B98003B75C1 /* InspectorScriptProfilerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A55165D01BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.cpp */; };
+		A55165D31BDF0B9E003B75C1 /* InspectorScriptProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A55165D11BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		A55165D51BDF135A003B75C1 /* ScriptProfilingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = A55165D41BDF134D003B75C1 /* ScriptProfilingScope.h */; };
 		A552C37F1ADDB8FE00139726 /* JSRemoteInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A552C37D1ADDB8FE00139726 /* JSRemoteInspector.cpp */; };
 		A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A55D93A5185012A800400DED /* ScriptFunctionCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A55D93A3185012A800400DED /* ScriptFunctionCall.cpp */; };
@@ -3725,6 +3728,9 @@
 		A54CF2F3184EAB2400237F19 /* ScriptValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptValue.h; sourceTree = "<group>"; };
 		A54CF2F7184EAEDA00237F19 /* ScriptObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptObject.cpp; sourceTree = "<group>"; };
 		A54CF2F8184EAEDA00237F19 /* ScriptObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptObject.h; sourceTree = "<group>"; };
+		A55165D01BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorScriptProfilerAgent.cpp; sourceTree = "<group>"; };
+		A55165D11BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorScriptProfilerAgent.h; sourceTree = "<group>"; };
+		A55165D41BDF134D003B75C1 /* ScriptProfilingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptProfilingScope.h; sourceTree = "<group>"; };
 		A552C37D1ADDB8FE00139726 /* JSRemoteInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSRemoteInspector.cpp; sourceTree = "<group>"; };
 		A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRemoteInspector.h; sourceTree = "<group>"; };
 		A55D93A3185012A800400DED /* ScriptFunctionCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptFunctionCall.cpp; sourceTree = "<group>"; };
@@ -5223,6 +5229,7 @@
 				FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */,
 				0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */,
 				0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */,
+				A55165D41BDF134D003B75C1 /* ScriptProfilingScope.h */,
 			);
 			path = debugger;
 			sourceTree = "<group>";
@@ -6594,6 +6601,8 @@
 				A5339EC51BB399900054F005 /* InspectorHeapAgent.h */,
 				A50E4B5D18809DD50068A46D /* InspectorRuntimeAgent.cpp */,
 				A50E4B5E18809DD50068A46D /* InspectorRuntimeAgent.h */,
+				A55165D01BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.cpp */,
+				A55165D11BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.h */,
 				A5FD0083189B1B7E00633231 /* JSGlobalObjectConsoleAgent.cpp */,
 				A5FD0084189B1B7E00633231 /* JSGlobalObjectConsoleAgent.h */,
 				A57D23E71891B0770031C7FA /* JSGlobalObjectDebuggerAgent.cpp */,
@@ -7458,6 +7467,7 @@
 				A125846E1B45A36000CC7F6C /* IntlNumberFormatConstructor.lut.h in Headers */,
 				A1D793011B43864B004516F5 /* IntlNumberFormatPrototype.h in Headers */,
 				A125846F1B45A36000CC7F6C /* IntlNumberFormatPrototype.lut.h in Headers */,
+				A55165D31BDF0B9E003B75C1 /* InspectorScriptProfilerAgent.h in Headers */,
 				A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */,
 				860BD801148EA6F200112B2F /* Intrinsic.h in Headers */,
 				FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */,
@@ -7659,6 +7669,7 @@
 				0F4680D314BBD16700BFE272 /* LLIntData.h in Headers */,
 				0F38B01217CF078300B144D3 /* LLIntEntrypoint.h in Headers */,
 				0F4680A314BA7F8D00BFE272 /* LLIntExceptions.h in Headers */,
+				A55165D51BDF135A003B75C1 /* ScriptProfilingScope.h in Headers */,
 				0F4680CB14BBB17200BFE272 /* LLIntOfflineAsmConfig.h in Headers */,
 				FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */,
 				0F4680A514BA7F8D00BFE272 /* LLIntSlowPaths.h in Headers */,
@@ -8846,6 +8857,7 @@
 				0F235BDC17178E1C00690C7F /* FTLOSRExit.cpp in Sources */,
 				0F235BDF17178E1C00690C7F /* FTLOSRExitCompiler.cpp in Sources */,
 				0FEA0A2A1709629600BB722C /* FTLOutput.cpp in Sources */,
+				A55165D21BDF0B98003B75C1 /* InspectorScriptProfilerAgent.cpp in Sources */,
 				0F485329187DFDEC0083B687 /* FTLRecoveryOpcode.cpp in Sources */,
 				0FCEFAAB1804C13E00472CE4 /* FTLSaveRestore.cpp in Sources */,
 				0F25F1B1181635F300522F39 /* FTLSlowPathCall.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/debugger/Debugger.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/debugger/Debugger.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/debugger/Debugger.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -226,6 +226,24 @@
         codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
 }
 
+void Debugger::setProfilingClient(ProfilingClient* client)
+{
+    ASSERT(!!m_profilingClient != !!client);
+    m_profilingClient = client;
+
+    recompileAllJSFunctions();
+}
+
+double Debugger::willEvaluateScript(JSGlobalObject& globalObject)
+{
+    return m_profilingClient->willEvaluateScript(globalObject);
+}
+
+void Debugger::didEvaluateScript(JSGlobalObject& globalObject, double startTime, ProfilingReason reason)
+{
+    m_profilingClient->didEvaluateScript(globalObject, startTime, reason);
+}
+
 void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot)
 {
     ScriptExecutable* executable = codeBlock->ownerScriptExecutable();

Modified: trunk/Source/_javascript_Core/debugger/Debugger.h (194241 => 194242)


--- trunk/Source/_javascript_Core/debugger/Debugger.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/debugger/Debugger.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -23,6 +23,7 @@
 #define Debugger_h
 
 #include "Breakpoint.h"
+#include "CallData.h"
 #include "DebuggerCallFrame.h"
 #include "DebuggerPrimitives.h"
 #include "JSCJSValue.h"
@@ -127,6 +128,20 @@
 
     void registerCodeBlock(CodeBlock*);
 
+    class ProfilingClient {
+    public:
+        virtual ~ProfilingClient() { }
+        virtual bool isAlreadyProfiling() const = 0;
+        virtual double willEvaluateScript(JSGlobalObject&) = 0;
+        virtual void didEvaluateScript(JSGlobalObject&, double startTime, ProfilingReason) = 0;
+    };
+
+    void setProfilingClient(ProfilingClient*);
+    bool hasProfilingClient() const { return m_profilingClient != nullptr; }
+    bool isAlreadyProfiling() const { return m_profilingClient && m_profilingClient->isAlreadyProfiling(); }
+    double willEvaluateScript(JSGlobalObject&);
+    void didEvaluateScript(JSGlobalObject&, double startTime, ProfilingReason);
+
 protected:
     virtual bool needPauseHandling(JSGlobalObject*) { return false; }
     virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { }
@@ -215,6 +230,8 @@
 
     RefPtr<JSC::DebuggerCallFrame> m_currentDebuggerCallFrame;
 
+    ProfilingClient* m_profilingClient { nullptr };
+
     friend class DebuggerPausedScope;
     friend class TemporaryPausedState;
     friend class LLIntOffsetsExtractor;

Added: trunk/Source/_javascript_Core/debugger/ScriptProfilingScope.h (0 => 194242)


--- trunk/Source/_javascript_Core/debugger/ScriptProfilingScope.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/debugger/ScriptProfilingScope.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,93 @@
+/*
+ * 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 ScriptProfilingScope_h
+#define ScriptProfilingScope_h
+
+#include "Debugger.h"
+#include "JSGlobalObject.h"
+#include <wtf/Optional.h>
+
+namespace JSC {
+
+class ScriptProfilingScope {
+public:
+    ScriptProfilingScope(JSGlobalObject* globalObject, ProfilingReason reason)
+        : m_globalObject(globalObject)
+        , m_reason(reason)
+    {
+        if (shouldStartProfile())
+            m_startTime = m_globalObject->debugger()->willEvaluateScript(*m_globalObject);
+    }
+
+    ~ScriptProfilingScope()
+    {
+        if (shouldEndProfile())
+            m_globalObject->debugger()->didEvaluateScript(*m_globalObject, m_startTime.value(), m_reason);
+    }
+
+private:
+    bool shouldStartProfile() const
+    {
+        if (!m_globalObject)
+            return false;
+
+        if (!m_globalObject->hasDebugger())
+            return false;
+
+        if (!m_globalObject->debugger()->hasProfilingClient())
+            return false;
+
+        if (m_globalObject->debugger()->isAlreadyProfiling())
+            return false;
+
+        return true;
+    }
+
+    bool shouldEndProfile() const
+    {
+        // Did not start a profile.
+        if (!m_startTime)
+            return false;
+
+        // Debugger may have been removed.
+        if (!m_globalObject->hasDebugger())
+            return false;
+
+        // Profiling Client may have been removed.
+        if (!m_globalObject->debugger()->hasProfilingClient())
+            return false;
+
+        return true;
+    }
+
+    JSGlobalObject* m_globalObject { nullptr };
+    Optional<double> m_startTime;
+    ProfilingReason m_reason;
+};
+
+}
+
+#endif // ScriptProfilingScope_h

Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptBase.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/inspector/InjectedScriptBase.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptBase.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -36,6 +36,7 @@
 #include "InspectorValues.h"
 #include "JSCInlines.h"
 #include "JSGlobalObject.h"
+#include "LegacyProfiler.h"
 #include "ScriptFunctionCall.h"
 #include <wtf/text/WTFString.h>
 
@@ -70,19 +71,16 @@
 
 Deprecated::ScriptValue InjectedScriptBase::callFunctionWithEvalEnabled(Deprecated::ScriptFunctionCall& function, bool& hadException) const
 {
-    if (m_environment)
-        m_environment->willCallInjectedScriptFunction(m_injectedScriptObject.scriptState(), name(), 1);
-
     JSC::ExecState* scriptState = m_injectedScriptObject.scriptState();
-    Deprecated::ScriptValue resultValue;
+    JSC::LegacyProfiler::profiler()->suspendProfiling(scriptState);
 
+    Deprecated::ScriptValue resultValue;
     {
         JSC::DebuggerEvalEnabler evalEnabler(scriptState);
         resultValue = function.call(hadException);
     }
 
-    if (m_environment)
-        m_environment->didCallInjectedScriptFunction(m_injectedScriptObject.scriptState());
+    JSC::LegacyProfiler::profiler()->unsuspendProfiling(scriptState);
 
     return resultValue;
 }

Modified: trunk/Source/_javascript_Core/inspector/InspectorEnvironment.h (194241 => 194242)


--- trunk/Source/_javascript_Core/inspector/InspectorEnvironment.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/inspector/InspectorEnvironment.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -51,8 +51,6 @@
     virtual bool canAccessInspectedScriptState(JSC::ExecState*) const = 0;
     virtual InspectorFunctionCallHandler functionCallHandler() const = 0;
     virtual InspectorEvaluateHandler evaluateHandler() const = 0;
-    virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String& scriptName, int scriptLine) = 0;
-    virtual void didCallInjectedScriptFunction(JSC::ExecState*) = 0;
     virtual void frontendInitialized() = 0;
     virtual Ref<WTF::Stopwatch> executionStopwatch() = 0;
     virtual ScriptDebugServer& scriptDebugServer() = 0;

Modified: trunk/Source/_javascript_Core/inspector/InspectorProtocolTypes.h (194241 => 194242)


--- trunk/Source/_javascript_Core/inspector/InspectorProtocolTypes.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/inspector/InspectorProtocolTypes.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -93,7 +93,12 @@
     {
         openAccessors().pushInteger(value);
     }
-    
+
+    void addItem(double value)
+    {
+        openAccessors().pushDouble(value);
+    }
+
     static Ref<Array<T>> create()
     {
         return adoptRef(*new Array<T>());

Modified: trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -37,6 +37,7 @@
 #include "InspectorFrontendChannel.h"
 #include "InspectorFrontendRouter.h"
 #include "InspectorHeapAgent.h"
+#include "InspectorScriptProfilerAgent.h"
 #include "JSGlobalObject.h"
 #include "JSGlobalObjectConsoleAgent.h"
 #include "JSGlobalObjectConsoleClient.h"
@@ -97,6 +98,7 @@
     m_agents.append(WTF::move(consoleAgent));
     m_agents.append(WTF::move(debuggerAgent));
     m_agents.append(std::make_unique<InspectorHeapAgent>(context));
+    m_agents.append(std::make_unique<InspectorScriptProfilerAgent>(context));
 
     m_executionStopwatch->start();
 }

Modified: trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.h (194241 => 194242)


--- trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -55,6 +55,7 @@
 class InspectorConsoleAgent;
 class InspectorDebuggerAgent;
 class InspectorHeapAgent;
+class InspectorScriptProfilerAgent;
 class JSGlobalObjectConsoleClient;
 class ScriptCallStack;
 
@@ -90,8 +91,6 @@
     virtual bool canAccessInspectedScriptState(JSC::ExecState*) const override { return true; }
     virtual InspectorFunctionCallHandler functionCallHandler() const override;
     virtual InspectorEvaluateHandler evaluateHandler() const override;
-    virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String&, int) override { }
-    virtual void didCallInjectedScriptFunction(JSC::ExecState*) override { }
     virtual void frontendInitialized() override;
     virtual Ref<WTF::Stopwatch> executionStopwatch() override;
     virtual JSGlobalObjectScriptDebugServer& scriptDebugServer() override;

Added: trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.cpp (0 => 194242)


--- trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "InspectorScriptProfilerAgent.h"
+
+#include "InspectorEnvironment.h"
+#include "LegacyProfiler.h"
+#include <wtf/RunLoop.h>
+#include <wtf/Stopwatch.h>
+
+using namespace JSC;
+
+namespace Inspector {
+
+InspectorScriptProfilerAgent::InspectorScriptProfilerAgent(AgentContext& context)
+    : InspectorAgentBase(ASCIILiteral("ScriptProfiler"))
+    , m_frontendDispatcher(std::make_unique<ScriptProfilerFrontendDispatcher>(context.frontendRouter))
+    , m_backendDispatcher(ScriptProfilerBackendDispatcher::create(context.backendDispatcher, this))
+    , m_environment(context.environment)
+{
+}
+
+InspectorScriptProfilerAgent::~InspectorScriptProfilerAgent()
+{
+}
+
+void InspectorScriptProfilerAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
+{
+}
+
+void InspectorScriptProfilerAgent::willDestroyFrontendAndBackend(DisconnectReason)
+{
+    ErrorString ignored;
+    stopTracking(ignored);
+}
+
+void InspectorScriptProfilerAgent::startTracking(ErrorString&, const bool* profile)
+{
+    if (m_tracking)
+        return;
+
+    m_tracking = true;
+
+    if (profile && *profile)
+        m_enableLegacyProfiler = true;
+
+    m_environment.scriptDebugServer().setProfilingClient(this);
+
+    m_frontendDispatcher->trackingStart(m_environment.executionStopwatch()->elapsedTime());
+}
+
+void InspectorScriptProfilerAgent::stopTracking(ErrorString&)
+{
+    if (!m_tracking)
+        return;
+
+    m_tracking = false;
+    m_enableLegacyProfiler = false;
+    m_activeEvaluateScript = false;
+
+    m_environment.scriptDebugServer().setProfilingClient(nullptr);
+
+    trackingComplete();
+}
+
+bool InspectorScriptProfilerAgent::isAlreadyProfiling() const
+{
+    return m_activeEvaluateScript;
+}
+
+double InspectorScriptProfilerAgent::willEvaluateScript(JSGlobalObject& globalObject)
+{
+    m_activeEvaluateScript = true;
+
+    if (m_enableLegacyProfiler)
+        LegacyProfiler::profiler()->startProfiling(globalObject.globalExec(), ASCIILiteral("ScriptProfiler"), m_environment.executionStopwatch());
+
+    return m_environment.executionStopwatch()->elapsedTime();
+}
+
+void InspectorScriptProfilerAgent::didEvaluateScript(JSGlobalObject& globalObject, double startTime, ProfilingReason reason)
+{
+    m_activeEvaluateScript = false;
+
+    if (m_enableLegacyProfiler)
+        m_profiles.append(LegacyProfiler::profiler()->stopProfiling(globalObject.globalExec(), ASCIILiteral("ScriptProfiler")));
+
+    double endTime = m_environment.executionStopwatch()->elapsedTime();
+
+    addEvent(startTime, endTime, reason);
+}
+
+static Inspector::Protocol::ScriptProfiler::EventType toProtocol(ProfilingReason reason)
+{
+    switch (reason) {
+    case ProfilingReason::API:
+        return Inspector::Protocol::ScriptProfiler::EventType::API;
+    case ProfilingReason::Microtask:
+        return Inspector::Protocol::ScriptProfiler::EventType::Microtask;
+    case ProfilingReason::Other:
+        return Inspector::Protocol::ScriptProfiler::EventType::Other;
+    }
+
+    ASSERT_NOT_REACHED();
+    return Inspector::Protocol::ScriptProfiler::EventType::Other;
+}
+
+void InspectorScriptProfilerAgent::addEvent(double startTime, double endTime, ProfilingReason reason)
+{
+    ASSERT(endTime >= startTime);
+
+    auto event = Inspector::Protocol::ScriptProfiler::Event::create()
+        .setStartTime(startTime)
+        .setEndTime(endTime)
+        .setType(toProtocol(reason))
+        .release();
+
+    m_frontendDispatcher->trackingUpdate(WTF::move(event));
+}
+
+static Ref<Protocol::Timeline::CPUProfileNodeAggregateCallInfo> buildAggregateCallInfoInspectorObject(const JSC::ProfileNode* node)
+{
+    double startTime = node->calls()[0].startTime();
+    double endTime = node->calls().last().startTime() + node->calls().last().elapsedTime();
+
+    double totalTime = 0;
+    for (const JSC::ProfileNode::Call& call : node->calls())
+        totalTime += call.elapsedTime();
+
+    return Protocol::Timeline::CPUProfileNodeAggregateCallInfo::create()
+        .setCallCount(node->calls().size())
+        .setStartTime(startTime)
+        .setEndTime(endTime)
+        .setTotalTime(totalTime)
+        .release();
+}
+
+static Ref<Protocol::Timeline::CPUProfileNode> buildInspectorObject(const JSC::ProfileNode* node)
+{
+    auto result = Protocol::Timeline::CPUProfileNode::create()
+        .setId(node->id())
+        .setCallInfo(buildAggregateCallInfoInspectorObject(node))
+        .release();
+
+    if (!node->functionName().isEmpty())
+        result->setFunctionName(node->functionName());
+
+    if (!node->url().isEmpty()) {
+        result->setUrl(node->url());
+        result->setLineNumber(node->lineNumber());
+        result->setColumnNumber(node->columnNumber());
+    }
+
+    if (!node->children().isEmpty()) {
+        auto children = Protocol::Array<Protocol::Timeline::CPUProfileNode>::create();
+        for (RefPtr<JSC::ProfileNode> profileNode : node->children())
+            children->addItem(buildInspectorObject(profileNode.get()));
+        result->setChildren(WTF::move(children));
+    }
+
+    return WTF::move(result);
+}
+
+static Ref<Protocol::Timeline::CPUProfile> buildProfileInspectorObject(const JSC::Profile* profile)
+{
+    auto rootNodes = Protocol::Array<Protocol::Timeline::CPUProfileNode>::create();
+    for (RefPtr<JSC::ProfileNode> profileNode : profile->rootNode()->children())
+        rootNodes->addItem(buildInspectorObject(profileNode.get()));
+
+    return Protocol::Timeline::CPUProfile::create()
+        .setRootNodes(WTF::move(rootNodes))
+        .release();
+}
+
+void InspectorScriptProfilerAgent::trackingComplete()
+{
+    RefPtr<Inspector::Protocol::Array<InspectorValue>> profiles = Inspector::Protocol::Array<InspectorValue>::create();
+    for (auto& profile : m_profiles) {
+        Ref<InspectorValue> value = buildProfileInspectorObject(profile.get());
+        profiles->addItem(WTF::move(value));
+    }
+
+    m_frontendDispatcher->trackingComplete(profiles);
+
+    m_profiles.clear();
+}
+
+} // namespace Inspector

Added: trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.h (0 => 194242)


--- trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,82 @@
+/*
+ * 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 InspectorScriptProfilerAgent_h
+#define InspectorScriptProfilerAgent_h
+
+#include "InspectorBackendDispatchers.h"
+#include "InspectorFrontendDispatchers.h"
+#include "inspector/InspectorAgentBase.h"
+#include "inspector/ScriptDebugServer.h"
+#include <wtf/Noncopyable.h>
+
+namespace JSC {
+class Profile;
+}
+
+namespace Inspector {
+
+typedef String ErrorString;
+
+class JS_EXPORT_PRIVATE InspectorScriptProfilerAgent final : public InspectorAgentBase, public ScriptProfilerBackendDispatcherHandler, public JSC::Debugger::ProfilingClient {
+    WTF_MAKE_NONCOPYABLE(InspectorScriptProfilerAgent);
+public:
+    InspectorScriptProfilerAgent(AgentContext&);
+    virtual ~InspectorScriptProfilerAgent();
+
+    virtual void didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) override;
+    virtual void willDestroyFrontendAndBackend(DisconnectReason) override;
+
+    // ScriptProfilerBackendDispatcherHandler
+    virtual void startTracking(ErrorString&, const bool* profile) override;
+    virtual void stopTracking(ErrorString&) override;
+
+    // Debugger::ProfilingClient
+    virtual bool isAlreadyProfiling() const override;
+    virtual double willEvaluateScript(JSC::JSGlobalObject&) override;
+    virtual void didEvaluateScript(JSC::JSGlobalObject&, double, JSC::ProfilingReason) override;
+
+private:
+    struct Event {
+        Event(double start, double end) : startTime(start), endTime(end) { }
+        double startTime { 0 };
+        double endTime { 0 };
+    };
+
+    void addEvent(double startTime, double endTime, JSC::ProfilingReason);
+    void trackingComplete();
+
+    std::unique_ptr<ScriptProfilerFrontendDispatcher> m_frontendDispatcher;
+    RefPtr<ScriptProfilerBackendDispatcher> m_backendDispatcher;
+    Vector<RefPtr<JSC::Profile>> m_profiles;
+    InspectorEnvironment& m_environment;
+    bool m_tracking { false };
+    bool m_enableLegacyProfiler { false };
+    bool m_activeEvaluateScript { false };
+};
+
+} // namespace Inspector
+
+#endif // InspectorScriptProfilerAgent_h

Added: trunk/Source/_javascript_Core/inspector/protocol/ScriptProfiler.json (0 => 194242)


--- trunk/Source/_javascript_Core/inspector/protocol/ScriptProfiler.json	                        (rev 0)
+++ trunk/Source/_javascript_Core/inspector/protocol/ScriptProfiler.json	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,56 @@
+{
+    "domain": "ScriptProfiler",
+    "description": "Profiler domain exposes _javascript_ evaluation timing and profiling.",
+    "types": [
+        {
+            "id": "EventType",
+            "type": "string",
+            "enum": ["API", "Microtask", "Other"]
+        },
+        {
+            "id": "Event",
+            "type": "object",
+            "properties": [
+                { "name": "startTime", "type": "number" },
+                { "name": "endTime", "type": "number" },
+                { "name": "type", "$ref": "EventType" }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "startTracking",
+            "description": "Start tracking script evaluations.",
+            "parameters": [
+                { "name": "profile", "type": "boolean", "optional": true, "description": "Profile script evaluations, defaults to false." }
+            ]
+        },
+        {
+            "name": "stopTracking",
+            "description": "Stop tracking script evaluations. This will produce a `trackingComplete` event."
+        }
+    ],
+    "events": [
+        {
+            "name": "trackingStart",
+            "description": "Tracking started.",
+            "parameters": [
+                { "name": "timestamp", "type": "number" }
+            ]
+        },
+        {
+            "name": "trackingUpdate",
+            "description": "While tracking is enabled the backend will periodically update the frontend with event data. The data includes tuples.",
+            "parameters": [
+                { "name": "event", "$ref": "Event" }
+            ]
+        },
+        {
+            "name": "trackingComplete",
+            "description": "When tracking is complete the backend will send any buffered data, such as profiling information.",
+            "parameters": [
+                { "name": "profiles", "type": "array", "items": { "type": "any" }, "optional": true }
+            ]
+        }
+    ]
+}

Modified: trunk/Source/_javascript_Core/runtime/CallData.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/CallData.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/CallData.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -28,8 +28,9 @@
 
 #include "Executable.h"
 #include "Interpreter.h"
+#include "JSCInlines.h"
 #include "JSFunction.h"
-#include "JSCInlines.h"
+#include "ScriptProfilingScope.h"
 
 namespace JSC {
 
@@ -51,4 +52,16 @@
     return result;
 }
 
+JSValue profiledCall(ExecState* exec, ProfilingReason reason, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
+{
+    ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
+    return call(exec, functionObject, callType, callData, thisValue, args);
+}
+
+JSValue profiledCall(ExecState* exec, ProfilingReason reason, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, NakedPtr<Exception>& returnedException)
+{
+    ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
+    return call(exec, functionObject, callType, callData, thisValue, args, returnedException);
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/CallData.h (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/CallData.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/CallData.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -59,9 +59,18 @@
     } js;
 };
 
+enum class ProfilingReason {
+    API,
+    Microtask,
+    Other
+};
+
 JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
 JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, NakedPtr<Exception>& returnedException);
 
+JS_EXPORT_PRIVATE JSValue profiledCall(ExecState*, ProfilingReason, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
+JS_EXPORT_PRIVATE JSValue profiledCall(ExecState*, ProfilingReason, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, NakedPtr<Exception>& returnedException);
+
 } // namespace JSC
 
 #endif // CallData_h

Modified: trunk/Source/_javascript_Core/runtime/Completion.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/Completion.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/Completion.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -37,6 +37,7 @@
 #include "ModuleAnalyzer.h"
 #include "ModuleLoaderObject.h"
 #include "Parser.h"
+#include "ScriptProfilingScope.h"
 #include <wtf/WTFThreadData.h>
 
 namespace JSC {
@@ -113,6 +114,12 @@
     return result;
 }
 
+JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
+{
+    ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
+    return evaluate(exec, source, thisValue, returnedException);
+}
+
 static JSValue identifierToJSValue(VM& vm, const Identifier& identifier)
 {
     if (identifier.isSymbol())

Modified: trunk/Source/_javascript_Core/runtime/Completion.h (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/Completion.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/Completion.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -23,6 +23,7 @@
 #ifndef Completion_h
 #define Completion_h
 
+#include "CallData.h"
 #include "JSCJSValue.h"
 #include <wtf/NakedPtr.h>
 
@@ -39,6 +40,7 @@
 JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&);
 JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
 JS_EXPORT_PRIVATE bool checkModuleSyntax(ExecState*, const SourceCode&, ParserError&);
+
 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);
 inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue())
 {
@@ -46,6 +48,13 @@
     return evaluate(exec, sourceCode, thisValue, unused);
 }
 
+JS_EXPORT_PRIVATE JSValue profiledEvaluate(ExecState*, ProfilingReason, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);
+inline JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& sourceCode, JSValue thisValue = JSValue())
+{
+    NakedPtr<Exception> unused;
+    return profiledEvaluate(exec, reason, sourceCode, thisValue, unused);
+}
+
 // Load the module source and evaluate it.
 JS_EXPORT_PRIVATE JSInternalPromise* loadAndEvaluateModule(ExecState*, const String& moduleName);
 JS_EXPORT_PRIVATE JSInternalPromise* loadAndEvaluateModule(ExecState*, const SourceCode&);

Modified: trunk/Source/_javascript_Core/runtime/ConstructData.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/ConstructData.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/ConstructData.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -28,9 +28,10 @@
 
 #include "Executable.h"
 #include "Interpreter.h"
+#include "JSCInlines.h"
 #include "JSFunction.h"
 #include "JSGlobalObject.h"
-#include "JSCInlines.h"
+#include "ScriptProfilingScope.h"
 
 namespace JSC {
 
@@ -40,4 +41,10 @@
     return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args, newTarget);
 }
 
+JSObject* profiledConstruct(ExecState* exec, ProfilingReason reason, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
+{
+    ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
+    return construct(exec, constructorObject, constructType, constructData, args, newTarget);
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/ConstructData.h (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/ConstructData.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/ConstructData.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -63,6 +63,13 @@
     return construct(exec, constructorObject, constructType, constructData, args, constructorObject);
 }
 
+JS_EXPORT_PRIVATE JSObject* profiledConstruct(ExecState*, ProfilingReason, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
+
+ALWAYS_INLINE JSObject* profiledConstruct(ExecState* exec, ProfilingReason reason, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+    return profiledConstruct(exec, reason, constructorObject, constructType, constructData, args, constructorObject);
+}
+
 } // namespace JSC
 
 #endif // ConstructData_h

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -598,6 +598,14 @@
     resetPrototype(vm, prototype());
 }
 
+bool JSGlobalObject::hasProfiler() const
+{
+    if (m_debugger && m_debugger->hasProfilingClient())
+        return true;
+
+    return globalObjectMethodTable()->supportsProfiling(this);
+}
+
 void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
 {
     JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -358,7 +358,7 @@
     DECLARE_EXPORT_INFO;
 
     bool hasDebugger() const { return m_debugger; }
-    bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); }
+    bool hasProfiler() const;
     const RuntimeFlags& runtimeFlags() const { return m_runtimeFlags; }
 
 protected:

Modified: trunk/Source/_javascript_Core/runtime/JSJob.cpp (194241 => 194242)


--- trunk/Source/_javascript_Core/runtime/JSJob.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/_javascript_Core/runtime/JSJob.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -70,7 +70,7 @@
     MarkedArgumentBuffer handlerArguments;
     for (unsigned index = 0, length = m_arguments->length(); index < length; ++index)
         handlerArguments.append(m_arguments->JSArray::get(exec, index));
-    call(exec, m_job.get(), handlerCallType, handlerCallData, jsUndefined(), handlerArguments);
+    profiledCall(exec, ProfilingReason::Microtask, m_job.get(), handlerCallType, handlerCallData, jsUndefined(), handlerArguments);
 }
 
 } // namespace JSC

Modified: trunk/Source/WebCore/ChangeLog (194241 => 194242)


--- trunk/Source/WebCore/ChangeLog	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebCore/ChangeLog	2015-12-17 23:37:48 UTC (rev 194242)
@@ -1,3 +1,31 @@
+2015-12-16  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Add JSContext Script Profiling
+        https://bugs.webkit.org/show_bug.cgi?id=151899
+
+        Reviewed by Brian Burg.
+
+        Tests: inspector/script-profiler/event-type-API.html
+               inspector/script-profiler/event-type-Microtask.html
+               inspector/script-profiler/tracking.html
+
+        * ForwardingHeaders/inspector/agents/InspectorScriptProfilerAgent.h: Added.
+
+        * inspector/InspectorController.h:
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        Create the new agent, even if we don't use it yet for Page inspection.
+
+        (WebCore::InspectorController::willCallInjectedScriptFunction): Deleted.
+        (WebCore::InspectorController::didCallInjectedScriptFunction): Deleted.
+        No longer needed, implementation was pushed up into InjectedScriptBase.
+
+        * inspector/InspectorCSSAgent.cpp:
+        (WebCore::InspectorCSSAgent::buildArrayForMatchedRuleList):
+        * inspector/InspectorReplayAgent.cpp:
+        (WebCore::buildInspectorObjectForSession):
+        Disambiguate types.
+
 2015-12-17  Brady Eidson  <[email protected]>
 
         Modern IDB: Refactor open/delete requests to exist in the same queue.

Added: trunk/Source/WebCore/ForwardingHeaders/inspector/agents/InspectorScriptProfilerAgent.h (0 => 194242)


--- trunk/Source/WebCore/ForwardingHeaders/inspector/agents/InspectorScriptProfilerAgent.h	                        (rev 0)
+++ trunk/Source/WebCore/ForwardingHeaders/inspector/agents/InspectorScriptProfilerAgent.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_InspectorScriptProfilerAgent_h
+#define WebCore_FWD_InspectorScriptProfilerAgent_h
+#include <_javascript_Core/InspectorScriptProfilerAgent.h>
+#endif

Modified: trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp (194241 => 194242)


--- trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -1047,7 +1047,7 @@
 
         auto matchingSelectors = Inspector::Protocol::Array<int>::create();
         const CSSSelectorList& selectorList = matchedRule->selectorList();
-        long index = 0;
+        int index = 0;
         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
             unsigned ignoredSpecificity;
             bool matched = selectorChecker.match(selector, element, context, ignoredSpecificity);

Modified: trunk/Source/WebCore/inspector/InspectorController.cpp (194241 => 194242)


--- trunk/Source/WebCore/inspector/InspectorController.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebCore/inspector/InspectorController.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -70,6 +70,7 @@
 #include <inspector/InspectorFrontendRouter.h>
 #include <inspector/agents/InspectorAgent.h>
 #include <inspector/agents/InspectorHeapAgent.h>
+#include <inspector/agents/InspectorScriptProfilerAgent.h>
 #include <profiler/LegacyProfiler.h>
 #include <runtime/JSLock.h>
 #include <wtf/Stopwatch.h>
@@ -167,6 +168,7 @@
 
     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, m_domAgent, debuggerAgent));
     m_agents.append(std::make_unique<InspectorHeapAgent>(pageContext));
+    m_agents.append(std::make_unique<InspectorScriptProfilerAgent>(pageContext));
     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, pageAgent));
     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
 
@@ -444,16 +446,6 @@
     return WebCore::evaluateHandlerFromAnyThread;
 }
 
-void InspectorController::willCallInjectedScriptFunction(JSC::ExecState* scriptState, const String&, int)
-{
-    LegacyProfiler::profiler()->suspendProfiling(scriptState);
-}
-
-void InspectorController::didCallInjectedScriptFunction(JSC::ExecState* scriptState)
-{
-    LegacyProfiler::profiler()->unsuspendProfiling(scriptState);
-}
-
 void InspectorController::frontendInitialized()
 {
 #if ENABLE(REMOTE_INSPECTOR)

Modified: trunk/Source/WebCore/inspector/InspectorController.h (194241 => 194242)


--- trunk/Source/WebCore/inspector/InspectorController.h	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebCore/inspector/InspectorController.h	2015-12-17 23:37:48 UTC (rev 194242)
@@ -121,8 +121,6 @@
     virtual bool canAccessInspectedScriptState(JSC::ExecState*) const override;
     virtual Inspector::InspectorFunctionCallHandler functionCallHandler() const override;
     virtual Inspector::InspectorEvaluateHandler evaluateHandler() const override;
-    virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String& scriptName, int scriptLine) override;
-    virtual void didCallInjectedScriptFunction(JSC::ExecState*) override;
     virtual void frontendInitialized() override;
     virtual Ref<WTF::Stopwatch> executionStopwatch() override;
     virtual PageScriptDebugServer& scriptDebugServer() override;

Modified: trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp (194241 => 194242)


--- trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp	2015-12-17 23:37:48 UTC (rev 194242)
@@ -77,7 +77,7 @@
     auto segments = Inspector::Protocol::Array<SegmentIdentifier>::create();
 
     for (auto& segment : *session)
-        segments->addItem(segment->identifier());
+        segments->addItem(static_cast<int>(segment->identifier()));
 
     return Inspector::Protocol::Replay::ReplaySession::create()
         .setId(session->identifier())

Modified: trunk/Source/WebInspectorUI/ChangeLog (194241 => 194242)


--- trunk/Source/WebInspectorUI/ChangeLog	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/ChangeLog	2015-12-17 23:37:48 UTC (rev 194242)
@@ -1,3 +1,63 @@
+2015-12-16  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Add JSContext Script Profiling
+        https://bugs.webkit.org/show_bug.cgi?id=151899
+
+        Reviewed by Brian Burg.
+
+        Enable the Timeline tab for JSContext inspection. Currently only
+        JSContext inspection will use the ScriptProfiler domain, it will
+        be enabled for Page inspection in a follow-up.
+
+        First pass at the UI creates basic ScriptTimelineRecords for
+        ScriptProfiler events. At the end of recording, when profiles
+        are downloaded, it attaches profiles to the timeline records
+        and refreshes the Scripts timeline.
+
+        * UserInterface/Base/Main.js:
+        (WebInspector.loaded):
+        * UserInterface/Controllers/TimelineManager.js:
+        (WebInspector.TimelineManager):
+        (WebInspector.TimelineManager.defaultInstruments):
+        (WebInspector.TimelineManager.prototype.computeElapsedTime):
+        (WebInspector.TimelineManager.prototype.scriptProfilerIsTracking):
+        (WebInspector.TimelineManager.prototype._loadNewRecording):
+        (WebInspector.TimelineManager.prototype._mainResourceDidChange):
+        (WebInspector.TimelineManager.prototype._resourceWasAdded):
+        (WebInspector.TimelineManager.prototype._garbageCollected):
+        (WebInspector.TimelineManager.prototype._addRecord): Deleted.
+        * UserInterface/Main.html:
+        * UserInterface/Models/Instrument.js:
+        (WebInspector.Instrument.startLegacyTimelineAgent):
+        * UserInterface/Models/ScriptInstrument.js:
+        (WebInspector.ScriptInstrument.prototype.startInstrumentation):
+        (WebInspector.ScriptInstrument.prototype.stopInstrumentation):
+        (WebInspector.ScriptInstrument):
+        * UserInterface/Models/ScriptTimelineRecord.js:
+        (WebInspector.ScriptTimelineRecord.prototype.get profilePayload):
+        (WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload):
+        (WebInspector.ScriptTimelineRecord):
+        (WebInspector.ScriptTimelineRecord.EventType.displayName):
+        * UserInterface/Models/Timeline.js:
+        (WebInspector.Timeline.prototype.refresh):
+        * UserInterface/Models/TimelineRecording.js:
+        (WebInspector.TimelineRecording.sourceCodeTimelinesSupported):
+        (WebInspector.TimelineRecording.prototype.timelineForRecordType):
+        (WebInspector.TimelineRecording.prototype.addRecord):
+        * UserInterface/Protocol/ScriptProfilerObserver.js: Copied from Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js.
+        (WebInspector.ScriptProfilerObserver.prototype.trackingStart):
+        (WebInspector.ScriptProfilerObserver.prototype.trackingUpdate):
+        (WebInspector.ScriptProfilerObserver.prototype.trackingComplete):
+        (WebInspector.ScriptProfilerObserver):
+        * UserInterface/Views/ScriptTimelineView.js:
+        (WebInspector.ScriptTimelineView):
+        (WebInspector.ScriptTimelineView.prototype._processPendingRecords):
+        (WebInspector.ScriptTimelineView.prototype._scriptTimelineRecordRefreshed):
+        * UserInterface/Views/TimelineRecordTreeElement.js:
+        (WebInspector.TimelineRecordTreeElement):
+        * UserInterface/Views/TimelineTabContentView.js:
+        (WebInspector.TimelineTabContentView.isTabAllowed):
+
 2015-12-17  Matt Baker  <[email protected]>
 
         Web Inspector: REGRESSION (r193913): Popover covers completion suggestions

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -391,6 +391,7 @@
 localizedStrings["Memory: %s"] = "Memory: %s";
 localizedStrings["Message"] = "Message";
 localizedStrings["Method"] = "Method";
+localizedStrings["Microtask Dispatched"] = "Microtask Dispatched";
 localizedStrings["Min"] = "Min";
 localizedStrings["Mixed"] = "Mixed";
 localizedStrings["Module Code"] = "Module Code";

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Main.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Base/Main.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Main.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -76,6 +76,8 @@
         InspectorBackend.registerDOMStorageDispatcher(new WebInspector.DOMStorageObserver);
     if (InspectorBackend.registerApplicationCacheDispatcher)
         InspectorBackend.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheObserver);
+    if (InspectorBackend.registerScriptProfilerDispatcher)
+        InspectorBackend.registerScriptProfilerDispatcher(new WebInspector.ScriptProfilerObserver);
     if (InspectorBackend.registerTimelineDispatcher)
         InspectorBackend.registerTimelineDispatcher(new WebInspector.TimelineObserver);
     if (InspectorBackend.registerCSSDispatcher)

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -42,6 +42,8 @@
         this._autoCapturingMainResource = null;
         this._boundStopCapturing = this.stopCapturing.bind(this);
 
+        this._scriptProfileRecords = null;
+
         this.reset();
     }
 
@@ -49,6 +51,9 @@
 
     static defaultInstruments()
     {
+        if (WebInspector.debuggableType === WebInspector.DebuggableType._javascript_)
+            return [new WebInspector.ScriptInstrument];
+
         let defaults = [
             new WebInspector.NetworkInstrument,
             new WebInspector.LayoutInstrument,
@@ -153,6 +158,11 @@
         return this._activeRecording.computeElapsedTime(timestamp);
     }
 
+    scriptProfilerIsTracking()
+    {
+        return this._scriptProfileRecords !== null;
+    }
+
     // Protected
 
     capturingStarted(startTime)
@@ -499,7 +509,7 @@
         this._activeRecording.addRecord(record);
 
         // Only worry about dead time after the load event.
-        if (!isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
+        if (WebInspector.frameResourceManager.mainFrame && isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
             this._resetAutoRecordingDeadTimeTimeout();
     }
 
@@ -610,6 +620,36 @@
         let collection = event.data.collection;
         this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.GarbageCollected, collection.startTime, collection.endTime, null, null, collection));
     }
+
+    scriptProfilerTrackingStarted(timestamp)
+    {
+        this._scriptProfileRecords = [];
+
+        this.capturingStarted(timestamp);
+    }
+
+    scriptProfilerTrackingUpdated(event)
+    {
+        let {startTime, endTime, type} = event;
+        let scriptRecordType = type === ScriptProfilerAgent.EventType.Microtask ? WebInspector.ScriptTimelineRecord.EventType.MicrotaskDispatched : WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated;
+        let record = new WebInspector.ScriptTimelineRecord(scriptRecordType, startTime, endTime, null, null, null, null);
+        this._scriptProfileRecords.push(record);
+        this._addRecord(record);
+    }
+
+    scriptProfilerTrackingCompleted(profiles)
+    {
+        if (profiles) {
+            console.assert(this._scriptProfileRecords.length === profiles.length, this._scriptProfileRecords.length, profiles.length);
+            for (let i = 0; i < this._scriptProfileRecords.length; ++i)
+                this._scriptProfileRecords[i].setProfilePayload(profiles[i]);
+        }
+
+        this._scriptProfileRecords = null;
+
+        let timeline = this.activeRecording.timelineForRecordType(WebInspector.TimelineRecord.Type.Script);
+        timeline.refresh();
+    }
 };
 
 WebInspector.TimelineManager.Event = {

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2015-12-17 23:37:48 UTC (rev 194242)
@@ -248,6 +248,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
 
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Instrument.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Instrument.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Instrument.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -29,6 +29,8 @@
 
     static startLegacyTimelineAgent()
     {
+        console.assert(window.TimelineAgent, "Attempted to start legacy timeline agent without TimelineAgent.");
+
         if (WebInspector.Instrument._legacyTimelineAgentStarted)
             return;
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -31,4 +31,32 @@
     {
         return WebInspector.TimelineRecord.Type.Script;
     }
+
+    startInstrumentation()
+    {
+        // COMPATIBILITY (iOS 9): Legacy backends did not have ScriptProfilerAgent. They use TimelineAgent.
+        // FIXME: ScriptProfilerAgent is only enabled for _javascript_ debuggables until we transition TimelineAgent for Web debuggables.
+        if (!window.ScriptProfilerAgent || WebInspector.debuggableType !== WebInspector.DebuggableType._javascript_) {
+            super.startInstrumentation();
+            return;
+        }
+
+        // FIXME: Make this some UI visible option.
+        const includeProfiles = true;
+
+        ScriptProfilerAgent.startTracking(includeProfiles);
+    }
+
+    stopInstrumentation()
+    {
+        // COMPATIBILITY (iOS 9): Legacy backends did not have ScriptProfilerAgent. They use TimelineAgent.
+        // FIXME: ScriptProfilerAgent is only enabled for _javascript_ debuggables until we transition TimelineAgent for Web debuggables.
+        if (!window.ScriptProfilerAgent || WebInspector.debuggableType !== WebInspector.DebuggableType._javascript_) {
+            super.stopInstrumentation();
+            return;
+        }
+
+        ScriptProfilerAgent.stopTracking();
+    }
+
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -71,6 +71,11 @@
         cookie[WebInspector.ScriptTimelineRecord.DetailsCookieKey] = this._details;
     }
 
+    setProfilePayload(profilePayload)
+    {
+        this._profilePayload = profilePayload;
+    }
+
     // Private
 
     _initializeProfileFromPayload(payload)
@@ -155,7 +160,8 @@
 
 WebInspector.ScriptTimelineRecord.EventType = {
     ScriptEvaluated: "script-timeline-record-script-evaluated",
-    EventDispatched: "script-timeline-record-event-dispatch",
+    MicrotaskDispatched: "script-timeline-record-microtask-dispatched",
+    EventDispatched: "script-timeline-record-event-dispatched",
     ProbeSampleRecorded: "script-timeline-record-probe-sample-recorded",
     TimerFired: "script-timeline-record-timer-fired",
     TimerInstalled: "script-timeline-record-timer-installed",
@@ -164,7 +170,7 @@
     AnimationFrameRequested: "script-timeline-record-animation-frame-requested",
     AnimationFrameCanceled: "script-timeline-record-animation-frame-canceled",
     ConsoleProfileRecorded: "script-timeline-record-console-profile-recorded",
-    GarbageCollected: "script-timeline-record-garbage-collected"
+    GarbageCollected: "script-timeline-record-garbage-collected",
 };
 
 WebInspector.ScriptTimelineRecord.EventType.displayName = function(eventType, details, includeDetailsInMainTitle)
@@ -328,12 +334,13 @@
     switch(eventType) {
     case WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated:
         return WebInspector.UIString("Script Evaluated");
+    case WebInspector.ScriptTimelineRecord.EventType.MicrotaskDispatched:
+        return WebInspector.UIString("Microtask Dispatched");
     case WebInspector.ScriptTimelineRecord.EventType.EventDispatched:
         if (details && (details instanceof String || typeof details === "string")) {
             var eventDisplayName = WebInspector.ScriptTimelineRecord._eventDisplayNames.get(details) || details.capitalize();
             return WebInspector.UIString("%s Event Dispatched").format(eventDisplayName);
         }
-
         return WebInspector.UIString("Event Dispatched");
     case WebInspector.ScriptTimelineRecord.EventType.ProbeSampleRecorded:
         return WebInspector.UIString("Probe Sample Recorded");

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -95,6 +95,11 @@
         cookie[WebInspector.Timeline.TimelineTypeCookieKey] = this._type;
     }
 
+    refresh()
+    {
+        this.dispatchEventToListeners(WebInspector.Timeline.Event.Refreshed);
+    }
+
     // Private
 
     _updateTimesIfNeeded(record)
@@ -124,7 +129,8 @@
 WebInspector.Timeline.Event = {
     Reset: "timeline-reset",
     RecordAdded: "timeline-record-added",
-    TimesUpdated: "timeline-times-updated"
+    TimesUpdated: "timeline-times-updated",
+    Refreshed: "timeline-refreshed",
 };
 
 WebInspector.Timeline.TimelineTypeCookieKey = "timeline-type";

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -55,6 +55,13 @@
         this.reset(true);
     }
 
+    // Static
+
+    static sourceCodeTimelinesSupported()
+    {
+        return WebInspector.debuggableType === WebInspector.DebuggableType.Web;
+    }
+
     // Public
 
     get displayName()
@@ -172,6 +179,11 @@
         return this._timelines.get(instrument.timelineRecordType);
     }
 
+    timelineForRecordType(recordType)
+    {
+        return this._timelines.get(recordType);
+    }
+
     addInstrument(instrument)
     {
         console.assert(instrument instanceof WebInspector.Instrument, instrument);
@@ -216,6 +228,9 @@
         if (record.type === WebInspector.TimelineRecord.Type.Network || record.type === WebInspector.TimelineRecord.Type.RenderingFrame)
             return;
 
+        if (!WebInspector.TimelineRecording.sourceCodeTimelinesSupported())
+            return;
+
         // Add the record to the source code timelines.
         var activeMainResource = WebInspector.frameResourceManager.mainFrame.provisionalMainResource || WebInspector.frameResourceManager.mainFrame.mainResource;
         var sourceCode = record.sourceCodeLocation ? record.sourceCodeLocation.sourceCode : activeMainResource;

Copied: trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js (from rev 194241, trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js) (0 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -0,0 +1,44 @@
+/*
+ * 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.ScriptProfilerObserver = class ScriptProfilerObserver
+{
+    // Events defined by the "ScriptProfiler" domain.
+
+    trackingStart(timestamp)
+    {
+        WebInspector.timelineManager.scriptProfilerTrackingStarted(timestamp);
+    }
+
+    trackingUpdate(event)
+    {
+        WebInspector.timelineManager.scriptProfilerTrackingUpdated(event);
+    }
+
+    trackingComplete(profiles)
+    {
+        WebInspector.timelineManager.scriptProfilerTrackingCompleted(profiles);
+    }
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -71,6 +71,7 @@
         this.addSubview(this._dataGrid);
 
         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
+        timeline.addEventListener(WebInspector.Timeline.Event.Refreshed, this._scriptTimelineRecordRefreshed, this);
 
         this._pendingRecords = [];
     }
@@ -217,6 +218,9 @@
 
     _processPendingRecords()
     {
+        if (WebInspector.timelineManager.scriptProfilerIsTracking())
+            return;
+
         if (!this._pendingRecords.length)
             return;
 
@@ -256,6 +260,11 @@
         this.needsLayout();
     }
 
+    _scriptTimelineRecordRefreshed(event)
+    {
+        this.needsLayout();
+    }
+
     _dataGridFiltersDidChange(event)
     {
         this.timelineSidebarPanel.updateFilter();

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -79,6 +79,7 @@
             case WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated:
                 iconStyleClass = WebInspector.TimelineRecordTreeElement.EvaluatedRecordIconStyleClass;
                 break;
+            case WebInspector.ScriptTimelineRecord.EventType.MicrotaskDispatched:
             case WebInspector.ScriptTimelineRecord.EventType.EventDispatched:
                 iconStyleClass = WebInspector.TimelineRecordTreeElement.EventRecordIconStyleClass;
                 break;

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js (194241 => 194242)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js	2015-12-17 23:29:53 UTC (rev 194241)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js	2015-12-17 23:37:48 UTC (rev 194242)
@@ -44,7 +44,7 @@
 
     static isTabAllowed()
     {
-        return !!window.TimelineAgent;
+        return !!window.TimelineAgent || !!window.ScriptProfilerAgent;
     }
 
     // Public
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to