Diff
Modified: trunk/LayoutTests/ChangeLog (218717 => 218718)
--- trunk/LayoutTests/ChangeLog 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/LayoutTests/ChangeLog 2017-06-22 21:12:01 UTC (rev 218718)
@@ -1,3 +1,20 @@
+2017-06-22 Joseph Pecoraro <[email protected]>
+
+ Web Inspector: Pausing with a deep call stack can be very slow, avoid eagerly generating object previews
+ https://bugs.webkit.org/show_bug.cgi?id=173698
+
+ Reviewed by Matt Baker.
+
+ * inspector/runtime/getPreview-expected.txt: Added.
+ * inspector/runtime/getPreview.html: Added.
+ Test the new protocol command `Runtime.getPreview` as well as the frontend
+ model method RemoteObject.prototype.updatePreview which uses it with its
+ own slightly different semantics about when it should be used.
+
+ * inspector/debugger/tail-deleted-frames-this-value.html:
+ This test used `CallFrame.thisObject.preview` so rewrite it to first
+ load the preview and then check values with it.
+
2017-06-22 Ryan Haddad <[email protected]>
Skip fast/forms/file/input-file-write-files-using-open-panel.html on ios-wk2.
Modified: trunk/LayoutTests/inspector/debugger/tail-deleted-frames-this-value.html (218717 => 218718)
--- trunk/LayoutTests/inspector/debugger/tail-deleted-frames-this-value.html 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/LayoutTests/inspector/debugger/tail-deleted-frames-this-value.html 2017-06-22 21:12:01 UTC (rev 218718)
@@ -44,23 +44,36 @@
InspectorTest.assert(callFrames.length >= expectedFrames.length);
- for (let i = 0; i < expectedFrames.length; i++) {
- let callFrame = callFrames[i];
- let expectedFrame = expectedFrames[i];
- InspectorTest.log("Expected frame: " + JSON.stringify(expectedFrame));
- InspectorTest.assert(callFrame.functionName === expectedFrame.functionName);
- InspectorTest.assert(callFrame.isTailDeleted === expectedFrame.isTailDeleted);
-
- let thisObject = callFrame.thisObject;
- let properties = thisObject.preview.propertyPreviews;
- InspectorTest.assert(properties.length === 1);
- let prop = properties[0];
- InspectorTest.expectThat(expectedFrame.thisValue[0] === prop.name, `'this' value should have expected property: ${expectedFrame.thisValue[0]}`);
- InspectorTest.assert('' + expectedFrame.thisValue[1] === prop.value, `'this' value object should have expected property value: ${expectedFrame.thisValue[1]}`);
- InspectorTest.pass(`Call Frame ${i} 'this' value is correct.`);
+ // Resolve a thisObject preview on each of the CallFrames.
+ let promises = [];
+ for (let callFrame of callFrames) {
+ InspectorTest.assert(!callFrame.thisObject.preview, "thisObject should not have a preview");
+ if (callFrame.thisObject.canLoadPreview()) {
+ promises.push(new Promise((resolve, reject) => {
+ callFrame.thisObject.updatePreview(resolve);
+ }));
+ }
}
- WebInspector.debuggerManager.resume();
+ Promise.all(promises).then(() => {
+ for (let i = 0; i < expectedFrames.length; i++) {
+ let callFrame = callFrames[i];
+ let expectedFrame = expectedFrames[i];
+ InspectorTest.log("Expected frame: " + JSON.stringify(expectedFrame));
+ InspectorTest.assert(callFrame.functionName === expectedFrame.functionName);
+ InspectorTest.assert(callFrame.isTailDeleted === expectedFrame.isTailDeleted);
+
+ let thisObject = callFrame.thisObject;
+ let properties = thisObject.preview.propertyPreviews;
+ InspectorTest.assert(properties.length === 1);
+ let prop = properties[0];
+ InspectorTest.expectThat(expectedFrame.thisValue[0] === prop.name, `'this' value should have expected property: ${expectedFrame.thisValue[0]}`);
+ InspectorTest.assert('' + expectedFrame.thisValue[1] === prop.value, `'this' value object should have expected property value: ${expectedFrame.thisValue[1]}`);
+ InspectorTest.pass(`Call Frame ${i} 'this' value is correct.`);
+ }
+
+ WebInspector.debuggerManager.resume();
+ });
});
WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, function(event) {
Added: trunk/LayoutTests/inspector/runtime/getPreview-expected.txt (0 => 218718)
--- trunk/LayoutTests/inspector/runtime/getPreview-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/runtime/getPreview-expected.txt 2017-06-22 21:12:01 UTC (rev 218718)
@@ -0,0 +1,51 @@
+Tests for the Runtime.getPreview command and associated RemoteObject.prototype.updatePreview.
+
+
+== Running test suite: Runtime.getPreview
+-- Running test case: RemoteObject.updatePreview.ObjectWithoutPreview
+PASS: RemoteObject should not have a preview.
+PASS: RemoteObject should be able to load a preview.
+PASS: RemoteObject.updatePreview should produce an ObjectPreview.
+PASS: RemoteObject.preview should be the same object as the callback.
+PASS: Preview should have 2 properties.
+
+-- Running test case: RemoteObject.updatePreview.ObjectWithPreview
+PASS: RemoteObject should have a preview.
+PASS: RemoteObject should be able to load a preview.
+PASS: Original preview should have 3 properties.
+PASS: RemoteObject.updatePreview should produce an ObjectPreview.
+PASS: RemoteObject.preview should be the same object as the callback.
+PASS: Preview should now have 4 properties.
+
+-- Running test case: RemoteObject.updatePreview.NonObject
+PASS: Should not be able to load a preview for a boolean RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a boolean RemoteObject.
+PASS: Should not be able to load a preview for a number RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a number RemoteObject.
+PASS: Should not be able to load a preview for a string RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a string RemoteObject.
+PASS: Should not be able to load a preview for a fake object RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a fake object RemoteObject.
+
+-- Running test case: RemoteObject.updatePreview.Symbol
+PASS: Should not be able to load a preview for a symbol RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a symbol RemoteObject.
+
+-- Running test case: RemoteObject.updatePreview.Function
+PASS: Should not be able to load a preview for a function RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a function RemoteObject.
+
+-- Running test case: RemoteObject.updatePreview.Null
+PASS: Should not be able to load a preview for a null RemoteObject.
+PASS: RemoteObject.updatePreview should return null for a null RemoteObject.
+
+-- Running test case: Runtime.getPreview.Symbol
+{"type":"symbol","description":"Symbol(Symbol.iterator)","lossless":true}
+
+-- Running test case: Runtime.getPreview.Function
+{"type":"function","description":"function f() {}","lossless":true}
+
+-- Running test case: Runtime.getPreview.InvalidObjectId
+PASS: Should produce an error.
+Error: Could not find InjectedScript for objectId
+
Added: trunk/LayoutTests/inspector/runtime/getPreview.html (0 => 218718)
--- trunk/LayoutTests/inspector/runtime/getPreview.html (rev 0)
+++ trunk/LayoutTests/inspector/runtime/getPreview.html 2017-06-22 21:12:01 UTC (rev 218718)
@@ -0,0 +1,170 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+ let suite = InspectorTest.createAsyncSuite("Runtime.getPreview");
+
+ // ------ RemoteObject.prototype.updatePreview
+
+ suite.addTestCase({
+ name: "RemoteObject.updatePreview.ObjectWithoutPreview",
+ description: "Should be able to update the preview of a RemoteObject without a preview.",
+ test(resolve, reject) {
+ RuntimeAgent.evaluate.invoke({_expression_: `({a:1, b:2})`, objectGroup: "test", generatePreview: false}, (error, remoteObjectPayload) => {
+ InspectorTest.assert(!error, "Should not be a protocol error.");
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ InspectorTest.expectThat(!remoteObject.preview, "RemoteObject should not have a preview.");
+ InspectorTest.expectThat(remoteObject.canLoadPreview(), "RemoteObject should be able to load a preview.");
+ remoteObject.updatePreview((preview) => {
+ InspectorTest.expectThat(preview instanceof WebInspector.ObjectPreview, "RemoteObject.updatePreview should produce an ObjectPreview.");
+ InspectorTest.expectEqual(remoteObject.preview, preview, "RemoteObject.preview should be the same object as the callback.");
+ InspectorTest.expectEqual(remoteObject.preview.propertyPreviews.length, 2, "Preview should have 2 properties.");
+ resolve();
+ });
+ });
+ }
+ });
+
+ suite.addTestCase({
+ name: "RemoteObject.updatePreview.ObjectWithPreview",
+ description: "Should be able to update the preview of a RemoteObject with a preview.",
+ test(resolve, reject) {
+ RuntimeAgent.evaluate.invoke({_expression_: `window.alpha = ({a:1, b:2, c:3})`, objectGroup: "test", generatePreview: true}, (error, remoteObjectPayload) => {
+ InspectorTest.assert(!error, "Should not be a protocol error.");
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ let originalPreview = remoteObject.preview;
+ InspectorTest.expectThat(remoteObject.preview, "RemoteObject should have a preview.");
+ InspectorTest.expectThat(remoteObject.canLoadPreview(), "RemoteObject should be able to load a preview.");
+ InspectorTest.expectEqual(originalPreview.propertyPreviews.length, 3, "Original preview should have 3 properties.");
+ InspectorTest.evaluateInPage(`window.alpha.d = 4`, () => {
+ remoteObject.updatePreview((preview) => {
+ InspectorTest.expectThat(preview instanceof WebInspector.ObjectPreview, "RemoteObject.updatePreview should produce an ObjectPreview.");
+ InspectorTest.expectEqual(remoteObject.preview, preview, "RemoteObject.preview should be the same object as the callback.");
+ InspectorTest.expectEqual(remoteObject.preview.propertyPreviews.length, 4, "Preview should now have 4 properties.");
+ resolve();
+ });
+ });
+ });
+ }
+ });
+
+ suite.addTestCase({
+ name: "RemoteObject.updatePreview.NonObject",
+ description: "Non-object RemoteObjects should not request a preview.",
+ test(resolve, reject) {
+ function testRemoteObject(remoteObject, preferredTypeName) {
+ InspectorTest.expectThat(!remoteObject.canLoadPreview(), `Should not be able to load a preview for a ${preferredTypeName || remoteObject.type} RemoteObject.`);
+ remoteObject.updatePreview((preview) => {
+ InspectorTest.expectNull(preview, `RemoteObject.updatePreview should return null for a ${preferredTypeName || remoteObject.type} RemoteObject.`);
+ });
+ }
+
+ testRemoteObject(WebInspector.RemoteObject.fromPrimitiveValue(true));
+ testRemoteObject(WebInspector.RemoteObject.fromPrimitiveValue(100));
+ testRemoteObject(WebInspector.RemoteObject.fromPrimitiveValue("str"));
+ testRemoteObject(WebInspector.RemoteObject.createFakeRemoteObject(), "fake object");
+ InspectorBackend.runAfterPendingDispatches(resolve);
+ }
+ });
+
+ suite.addTestCase({
+ name: "RemoteObject.updatePreview.Symbol",
+ description: "Non-object RemoteObjects should not request a preview.",
+ test(resolve, reject) {
+ InspectorTest.evaluateInPage(`Symbol.iterator`, (error, remoteObjectPayload) => {
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ InspectorTest.expectThat(!remoteObject.canLoadPreview(), `Should not be able to load a preview for a ${remoteObject.type} RemoteObject.`);
+ remoteObject.updatePreview((preview) => {
+ InspectorTest.expectNull(preview, `RemoteObject.updatePreview should return null for a ${remoteObject.type} RemoteObject.`);
+ resolve();
+ });
+ });
+ }
+ });
+
+ suite.addTestCase({
+ name: "RemoteObject.updatePreview.Function",
+ description: "Non-object RemoteObjects should not request a preview.",
+ test(resolve, reject) {
+ InspectorTest.evaluateInPage(`function f() {}; f`, (error, remoteObjectPayload) => {
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ InspectorTest.expectThat(!remoteObject.canLoadPreview(), `Should not be able to load a preview for a ${remoteObject.type} RemoteObject.`);
+ remoteObject.updatePreview((preview) => {
+ InspectorTest.expectNull(preview, `RemoteObject.updatePreview should return null for a ${remoteObject.type} RemoteObject.`);
+ resolve();
+ });
+ });
+ }
+ });
+
+ suite.addTestCase({
+ name: "RemoteObject.updatePreview.Null",
+ description: "Non-object RemoteObjects should not request a preview.",
+ test(resolve, reject) {
+ InspectorTest.evaluateInPage(`null`, (error, remoteObjectPayload) => {
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ InspectorTest.expectThat(!remoteObject.canLoadPreview(), `Should not be able to load a preview for a ${remoteObject.subtype} RemoteObject.`);
+ remoteObject.updatePreview((preview) => {
+ InspectorTest.expectNull(preview, `RemoteObject.updatePreview should return null for a ${remoteObject.subtype} RemoteObject.`);
+ resolve();
+ });
+ });
+ }
+ });
+
+ // ------ Runtime.getPreview
+
+ suite.addTestCase({
+ name: "Runtime.getPreview.Symbol",
+ description: "Runtime.getPreview should return an empty preview for non-objects.",
+ test(resolve, reject) {
+ InspectorTest.evaluateInPage(`Symbol.iterator`, (error, remoteObjectPayload) => {
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ RuntimeAgent.getPreview(remoteObject.objectId, (error, result) => {
+ InspectorTest.log(JSON.stringify(result));
+ resolve();
+ });
+ });
+ }
+ });
+
+ suite.addTestCase({
+ name: "Runtime.getPreview.Function",
+ description: "Runtime.getPreview should return an empty preview for non-objects.",
+ test(resolve, reject) {
+ InspectorTest.evaluateInPage(`function f() {}; f`, (error, remoteObjectPayload) => {
+ let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+ RuntimeAgent.getPreview(remoteObject.objectId, (error, result) => {
+ InspectorTest.log(JSON.stringify(result));
+ resolve();
+ });
+ });
+ }
+ });
+
+ // ------
+
+ suite.addTestCase({
+ name: "Runtime.getPreview.InvalidObjectId",
+ description: "Invalid objectId should produce and error.",
+ test(resolve, reject) {
+ const objectId = "DOES_NOT_EXIST";
+ RuntimeAgent.getPreview(objectId, (error) => {
+ InspectorTest.expectThat(error, "Should produce an error.");
+ InspectorTest.log("Error: " + error);
+ resolve();
+ });
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Tests for the Runtime.getPreview command and associated RemoteObject.prototype.updatePreview.</p>
+</body>
+</html>
Modified: trunk/Source/_javascript_Core/ChangeLog (218717 => 218718)
--- trunk/Source/_javascript_Core/ChangeLog 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-06-22 21:12:01 UTC (rev 218718)
@@ -1,5 +1,47 @@
2017-06-22 Joseph Pecoraro <[email protected]>
+ Web Inspector: Pausing with a deep call stack can be very slow, avoid eagerly generating object previews
+ https://bugs.webkit.org/show_bug.cgi?id=173698
+
+ Reviewed by Matt Baker.
+
+ When pausing in a deep call stack the majority of the time spent in _javascript_Core
+ when preparing Inspector pause information is spent generating object previews for
+ the `thisObject` of each of the call frames. In some cases, this could be more
+ than 95% of the time generating pause information. In the common case, only one of
+ these (the top frame) will ever be seen by users. This change avoids eagerly
+ generating object previews up front and let the frontend request previews if they
+ are needed.
+
+ This introduces the `Runtime.getPreview` protocol command. This can be used to:
+
+ - Get a preview for a RemoteObject that did not have a preview but could.
+ - Update a preview for a RemoteObject that had a preview.
+
+ This patch only uses it for the first case, but the second is valid and may be
+ something we want to do in the future.
+
+ * inspector/protocol/Runtime.json:
+ A new command to get an up to date preview for an object.
+
+ * inspector/InjectedScript.h:
+ * inspector/InjectedScript.cpp:
+ (Inspector::InjectedScript::getPreview):
+ * inspector/agents/InspectorRuntimeAgent.cpp:
+ (Inspector::InspectorRuntimeAgent::getPreview):
+ * inspector/agents/InspectorRuntimeAgent.h:
+ Plumbing for the new command.
+
+ * inspector/InjectedScriptSource.js:
+ (InjectedScript.prototype.getPreview):
+ Implementation just uses the existing helper.
+
+ (InjectedScript.CallFrameProxy):
+ Do not generate a preview for the this object as it may not be shown.
+ Let the frontend request a preview if it wants or needs one.
+
+2017-06-22 Joseph Pecoraro <[email protected]>
+
Web Inspector: Remove stale "rawScopes" concept that was never available in JSC
https://bugs.webkit.org/show_bug.cgi?id=173686
Modified: trunk/Source/_javascript_Core/inspector/InjectedScript.cpp (218717 => 218718)
--- trunk/Source/_javascript_Core/inspector/InjectedScript.cpp 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/inspector/InjectedScript.cpp 2017-06-22 21:12:01 UTC (rev 218718)
@@ -125,6 +125,22 @@
*result = BindingTraits<Inspector::Protocol::Debugger::FunctionDetails>::runtimeCast(WTFMove(resultValue));
}
+void InjectedScript::getPreview(ErrorString& errorString, const String& objectId, RefPtr<Protocol::Runtime::ObjectPreview>* result)
+{
+ Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getPreview"), inspectorEnvironment()->functionCallHandler());
+ function.appendArgument(objectId);
+
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::Type::Object) {
+ if (!resultValue->asString(errorString))
+ errorString = ASCIILiteral("Internal error");
+ return;
+ }
+
+ *result = BindingTraits<Inspector::Protocol::Runtime::ObjectPreview>::runtimeCast(WTFMove(resultValue));
+}
+
void InjectedScript::getProperties(ErrorString& errorString, const String& objectId, bool ownProperties, bool generatePreview, RefPtr<Array<Inspector::Protocol::Runtime::PropertyDescriptor>>* properties)
{
Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getProperties"), inspectorEnvironment()->functionCallHandler());
Modified: trunk/Source/_javascript_Core/inspector/InjectedScript.h (218717 => 218718)
--- trunk/Source/_javascript_Core/inspector/InjectedScript.h 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/inspector/InjectedScript.h 2017-06-22 21:12:01 UTC (rev 218718)
@@ -56,6 +56,7 @@
void evaluateOnCallFrame(ErrorString&, JSC::JSValue callFrames, const String& callFrameId, const String& _expression_, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex);
void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>* result);
void functionDetails(ErrorString&, JSC::JSValue, RefPtr<Protocol::Debugger::FunctionDetails>* result);
+ void getPreview(ErrorString&, const String& objectId, RefPtr<Protocol::Runtime::ObjectPreview>* result);
void getProperties(ErrorString&, const String& objectId, bool ownProperties, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::PropertyDescriptor>>* result);
void getDisplayableProperties(ErrorString&, const String& objectId, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::PropertyDescriptor>>* result);
void getInternalProperties(ErrorString&, const String& objectId, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::InternalPropertyDescriptor>>* result);
Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js (218717 => 218718)
--- trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js 2017-06-22 21:12:01 UTC (rev 218718)
@@ -234,6 +234,14 @@
return result;
},
+ getPreview: function(objectId)
+ {
+ let parsedObjectId = this._parseObjectId(objectId);
+ let object = this._objectForId(parsedObjectId);
+
+ return InjectedScript.RemoteObject.createObjectPreviewForValue(object, true);
+ },
+
_getProperties: function(objectId, collectionMode, generatePreview, nativeGettersAsValues)
{
var parsedObjectId = this._parseObjectId(objectId);
@@ -464,7 +472,7 @@
commandLineAPI = new BasicCommandLineAPI(isEvalOnCallFrame ? object : null);
}
- var result = evalFunction.call(object, _expression_, commandLineAPI);
+ var result = evalFunction.call(object, _expression_, commandLineAPI);
if (saveResult)
this._saveResult(result);
return result;
@@ -1298,7 +1306,7 @@
this.functionName = callFrame.functionName;
this.location = {scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column};
this.scopeChain = this._wrapScopeChain(callFrame);
- this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace", false, true);
+ this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace");
this.isTailDeleted = callFrame.isTailDeleted;
}
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp (218717 => 218718)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp 2017-06-22 21:12:01 UTC (rev 218718)
@@ -158,6 +158,23 @@
}
}
+void InspectorRuntimeAgent::getPreview(ErrorString& errorString, const String& objectId, RefPtr<Inspector::Protocol::Runtime::ObjectPreview>& preview)
+{
+ InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId);
+ if (injectedScript.hasNoValue()) {
+ errorString = ASCIILiteral("Could not find InjectedScript for objectId");
+ return;
+ }
+
+ ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
+ muteConsole();
+
+ injectedScript.getPreview(errorString, objectId, &preview);
+
+ unmuteConsole();
+ setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState);
+}
+
void InspectorRuntimeAgent::getProperties(ErrorString& errorString, const String& objectId, const bool* const ownProperties, const bool* const generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties)
{
InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId);
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.h (218717 => 218718)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.h 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.h 2017-06-22 21:12:01 UTC (rev 218718)
@@ -62,6 +62,7 @@
void evaluate(ErrorString&, const String& _expression_, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* const executionContextId, const bool* const returnByValue, const bool* const generatePreview, const bool* const saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) final;
void callFunctionOn(ErrorString&, const String& objectId, const String& _expression_, const Inspector::InspectorArray* optionalArguments, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* const generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown) final;
void releaseObject(ErrorString&, const ErrorString& objectId) final;
+ void getPreview(ErrorString&, const String& objectId, RefPtr<Inspector::Protocol::Runtime::ObjectPreview>&) final;
void getProperties(ErrorString&, const String& objectId, const bool* const ownProperties, const bool* const generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) final;
void getDisplayableProperties(ErrorString&, const String& objectId, const bool* const generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) final;
void getCollectionEntries(ErrorString&, const String& objectId, const String* const objectGroup, const int* const startIndex, const int* const numberToFetch, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::CollectionEntry>>& entries) final;
Modified: trunk/Source/_javascript_Core/inspector/protocol/Runtime.json (218717 => 218718)
--- trunk/Source/_javascript_Core/inspector/protocol/Runtime.json 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/_javascript_Core/inspector/protocol/Runtime.json 2017-06-22 21:12:01 UTC (rev 218718)
@@ -243,6 +243,16 @@
"description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object."
},
{
+ "name": "getPreview",
+ "description": "Returns a preview for the given object.",
+ "parameters": [
+ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return a preview for." }
+ ],
+ "returns": [
+ { "name": "preview", "$ref": "ObjectPreview" }
+ ]
+ },
+ {
"name": "getProperties",
"parameters": [
{ "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." },
Modified: trunk/Source/WebInspectorUI/ChangeLog (218717 => 218718)
--- trunk/Source/WebInspectorUI/ChangeLog 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/WebInspectorUI/ChangeLog 2017-06-22 21:12:01 UTC (rev 218718)
@@ -1,3 +1,30 @@
+2017-06-22 Joseph Pecoraro <[email protected]>
+
+ Web Inspector: Pausing with a deep call stack can be very slow, avoid eagerly generating object previews
+ https://bugs.webkit.org/show_bug.cgi?id=173698
+
+ Reviewed by Matt Baker.
+
+ Introduce RemoteObject.prototype.updatePreview which can be used to update
+ the preview of a RemoteObject with a current view for the object. Currently
+ we only use this to fetch the preview that we did not have for the `thisObject`
+ in the scope chain sidebar. However this could be used generically to update
+ a RemoteObject's preview (ObjectPreview) at any time.
+
+ * UserInterface/Protocol/RemoteObject.js:
+ (WebInspector.RemoteObject.prototype.canLoadPreview):
+ (WebInspector.RemoteObject.prototype.updatePreview):
+ Allow a RemoteObject to update its preview property. Since this only makes
+ sense on certain Object values include a helper to know when it is appropriate
+ to fetch a preview.
+
+ * UserInterface/Views/ObjectTreePropertyTreeElement.js:
+ (WebInspector.ObjectTreePropertyTreeElement.prototype._createTitlePropertyStyle):
+ (WebInspector.ObjectTreePropertyTreeElement.prototype._loadPreviewLazilyIfNeeded):
+ If the object being shown in the sidebar does not have a preview but can load a
+ preview then attempt to load it lazily. This is the case for the `thisObject`
+ which is injected into an ObjectTree in the scope chain sidebar.
+
2017-06-22 Fujii Hironori <[email protected]>
[GTK] Web Inspector: Add icon for Canvas.svg
Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js (218717 => 218718)
--- trunk/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js 2017-06-22 21:12:01 UTC (rev 218718)
@@ -231,6 +231,45 @@
return "_value" in this;
}
+ canLoadPreview()
+ {
+ if (this._failedToLoadPreview)
+ return false;
+
+ if (this._type !== "object")
+ return false;
+
+ if (!this._objectId || this._isSymbol() || this._isFakeObject())
+ return false;
+
+ return true;
+ }
+
+ updatePreview(callback)
+ {
+ if (!this.canLoadPreview()) {
+ callback(null);
+ return;
+ }
+
+ if (!RuntimeAgent.getPreview) {
+ this._failedToLoadPreview = true;
+ callback(null);
+ return;
+ }
+
+ this._target.RuntimeAgent.getPreview(this._objectId, (error, payload) => {
+ if (error) {
+ this._failedToLoadPreview = true;
+ callback(null);
+ return;
+ }
+
+ this._preview = WebInspector.ObjectPreview.fromPayload(payload);
+ callback(this._preview);
+ });
+ }
+
getOwnPropertyDescriptors(callback)
{
this._getPropertyDescriptors(true, callback);
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js (218717 => 218718)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js 2017-06-22 21:06:29 UTC (rev 218717)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js 2017-06-22 21:12:01 UTC (rev 218718)
@@ -160,6 +160,8 @@
this._previewView = new WebInspector.ObjectPreviewView(resolvedValue.preview);
valueOrGetterElement = this._previewView.element;
} else {
+ this._loadPreviewLazilyIfNeeded();
+
valueOrGetterElement = WebInspector.FormattedValue.createElementForRemoteObject(resolvedValue, this.hadError());
// Special case a function property string.
@@ -220,6 +222,22 @@
return container;
}
+ _loadPreviewLazilyIfNeeded()
+ {
+ let resolvedValue = this.resolvedValue();
+ if (!resolvedValue.canLoadPreview())
+ return;
+
+ resolvedValue.updatePreview((preview) => {
+ if (preview) {
+ this.mainTitle = this._titleFragment();
+
+ if (this.expanded)
+ this._previewView.showTitle();
+ }
+ });
+ }
+
_alwaysDisplayAsProperty()
{
// Constructor, though a function, is often better treated as an expandable object.