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