From 12fd0bcb40b78a4949ffae5e38cd14f9ff493312 Mon Sep 17 00:00:00 2001 From: "commit-queue@webkit.org" Date: Thu, 5 Mar 2015 02:27:23 +0000 Subject: [PATCH] Web Inspector: Array/Collection Sizes should be visible and distinct https://bugs.webkit.org/show_bug.cgi?id=142254 Patch by Joseph Pecoraro on 2015-03-04 Reviewed by Timothy Hatcher. Source/JavaScriptCore: * runtime/WeakMapData.h: (JSC::WeakMapData::size): * inspector/JSInjectedScriptHost.cpp: (Inspector::JSInjectedScriptHost::weakMapSize): * inspector/JSInjectedScriptHost.h: * inspector/JSInjectedScriptHostPrototype.cpp: (Inspector::JSInjectedScriptHostPrototype::finishCreation): (Inspector::jsInjectedScriptHostPrototypeFunctionWeakMapSize): Add a way to get a WeakMap's size. * inspector/protocol/Runtime.json: Include size in RemoteObject and ObjectPreview. * inspector/InjectedScriptSource.js: Set the size of RemoteObjects and previews if they are array/collection types. Source/WebInspectorUI: * UserInterface/Models/ObjectPreview.js: (WebInspector.ObjectPreview): (WebInspector.ObjectPreview.fromPayload): (WebInspector.ObjectPreview.prototype.get size): (WebInspector.ObjectPreview.prototype.hasSize): * UserInterface/Protocol/RemoteObject.js: (WebInspector.RemoteObject): (WebInspector.RemoteObject.fromPrimitiveValue): (WebInspector.RemoteObject.fromPayload): (WebInspector.RemoteObject.prototype.get size): (WebInspector.RemoteObject.prototype.hasSize): Check if this type has a size and get the size. Gracefully handle construction for legacy protocols. * UserInterface/Views/ObjectPreviewView.css: (.object-preview > .size): * UserInterface/Views/FormattedValue.css: (:matches(.formatted-array, .formatted-map, .formatted-set, .formatted-weakmap) > .size): Style the array/collection size. * UserInterface/Views/ObjectPreviewView.js: (WebInspector.ObjectPreviewView): * UserInterface/Views/FormattedValue.js: (WebInspector.FormattedValue.createElementForTypesAndValue): (WebInspector.FormattedValue.createElementForRemoteObject): (WebInspector.FormattedValue.createElementForObjectPreview): (WebInspector.FormattedValue.createElementForPropertyPreview): Add an element showing the array/collection size. * UserInterface/Views/ObjectTreePropertyTreeElement.js: (WebInspector.ObjectTreePropertyTreeElement.prototype): Remove special handling for Array sizes now that this is handled earlier. * UserInterface/Controllers/StorageManager.js: (WebInspector.StorageManager.prototype.processData): (WebInspector.StorageManager.prototype.requestIndexedDatabaseData): Fix what looks like broken RemoteObject construction. LayoutTests: * inspector-protocol/runtime/getProperties-expected.txt: * inspector/model/remote-object-expected.txt: * inspector/model/remote-object.html: Update tests now that RemoteObjects and Previews may have an explicit size. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181061 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- LayoutTests/ChangeLog | 12 ++ .../runtime/getProperties-expected.txt | 4 +- .../inspector/model/remote-object-expected.txt | 189 +++++++++++++-------- LayoutTests/inspector/model/remote-object.html | 11 +- Source/JavaScriptCore/ChangeLog | 24 +++ .../inspector/InjectedScriptSource.js | 15 +- .../inspector/JSInjectedScriptHost.cpp | 13 ++ .../inspector/JSInjectedScriptHost.h | 1 + .../inspector/JSInjectedScriptHostPrototype.cpp | 13 ++ .../JavaScriptCore/inspector/protocol/Runtime.json | 4 +- Source/JavaScriptCore/runtime/WeakMapData.h | 2 + Source/WebInspectorUI/ChangeLog | 45 +++++ .../UserInterface/Controllers/StorageManager.js | 6 +- .../UserInterface/Models/ObjectPreview.js | 25 ++- .../UserInterface/Protocol/RemoteObject.js | 28 ++- .../UserInterface/Views/FormattedValue.css | 5 + .../UserInterface/Views/FormattedValue.js | 16 +- .../UserInterface/Views/ObjectPreviewView.css | 5 + .../UserInterface/Views/ObjectPreviewView.js | 6 + .../Views/ObjectTreePropertyTreeElement.js | 2 +- 20 files changed, 331 insertions(+), 95 deletions(-) diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 28c5dbd..f340f75 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,15 @@ +2015-03-04 Joseph Pecoraro + + Web Inspector: Array/Collection Sizes should be visible and distinct + https://bugs.webkit.org/show_bug.cgi?id=142254 + + Reviewed by Timothy Hatcher. + + * inspector-protocol/runtime/getProperties-expected.txt: + * inspector/model/remote-object-expected.txt: + * inspector/model/remote-object.html: + Update tests now that RemoteObjects and Previews may have an explicit size. + 2015-03-04 Timothy Horton should show the file size as detail text below the icon diff --git a/LayoutTests/inspector-protocol/runtime/getProperties-expected.txt b/LayoutTests/inspector-protocol/runtime/getProperties-expected.txt index 16d63f9..078d0da 100644 --- a/LayoutTests/inspector-protocol/runtime/getProperties-expected.txt +++ b/LayoutTests/inspector-protocol/runtime/getProperties-expected.txt @@ -2,7 +2,7 @@ Properties of Object(5) __proto__ object Number foo string cat Properties of array - __proto__ object Array[0] + __proto__ object Array 0 string red 1 string green 2 string blue @@ -16,7 +16,7 @@ Properties of Bound function length number 0 name string Number Internal properties - boundArgs object Array[1] + boundArgs object Array boundThis object Object targetFunction function function Number() { [native code] diff --git a/LayoutTests/inspector/model/remote-object-expected.txt b/LayoutTests/inspector/model/remote-object-expected.txt index 1e98d4f..66589bd 100644 --- a/LayoutTests/inspector/model/remote-object-expected.txt +++ b/LayoutTests/inspector/model/remote-object-expected.txt @@ -517,13 +517,15 @@ EXPRESSION: [] "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[0]", + "_description": "Array", + "_size": 0, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[0]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 0, "_properties": [], "_entries": null } @@ -535,13 +537,15 @@ EXPRESSION: [1, 2] "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[2]", + "_description": "Array", + "_size": 2, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[2]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 2, "_properties": [ { "_name": "0", @@ -564,31 +568,33 @@ EXPRESSION: [[1],[2],[3]] "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[3]", + "_description": "Array", + "_size": 3, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[3]", + "_description": "Array", "_lossless": false, "_overflow": false, + "_size": 3, "_properties": [ { "_name": "0", "_type": "object", "_subtype": "array", - "_value": "Array[1]" + "_value": "Array" }, { "_name": "1", "_type": "object", "_subtype": "array", - "_value": "Array[1]" + "_value": "Array" }, { "_name": "2", "_type": "object", "_subtype": "array", - "_value": "Array[1]" + "_value": "Array" } ], "_entries": null @@ -601,13 +607,15 @@ EXPRESSION: [true, 1, 1.234, 'string', /regex/] "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[5]", + "_description": "Array", + "_size": 5, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[5]", + "_description": "Array", "_lossless": false, "_overflow": false, + "_size": 5, "_properties": [ { "_name": "0", @@ -646,13 +654,15 @@ EXPRESSION: [{a:1}, {b:2}, {c:2}] "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[3]", + "_description": "Array", + "_size": 3, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[3]", + "_description": "Array", "_lossless": false, "_overflow": false, + "_size": 3, "_properties": [ { "_name": "0", @@ -680,19 +690,21 @@ EXPRESSION: [[{a:1}, {b:2}, {c:2}]] "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[1]", + "_description": "Array", + "_size": 1, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[1]", + "_description": "Array", "_lossless": false, "_overflow": false, + "_size": 1, "_properties": [ { "_name": "0", "_type": "object", "_subtype": "array", - "_value": "Array[3]" + "_value": "Array" } ], "_entries": null @@ -705,13 +717,15 @@ EXPRESSION: arr = []; arr.length = 100; arr "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[100]", + "_description": "Array", + "_size": 100, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[100]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 100, "_properties": [], "_entries": null } @@ -723,13 +737,15 @@ EXPRESSION: arr = []; arr.length = 100; arr.fill(1) "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[100]", + "_description": "Array", + "_size": 100, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[100]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 100, "_properties": [ { "_name": "0", @@ -1242,13 +1258,15 @@ EXPRESSION: arr = []; arr.length = 100; arr[10] = 1; arr "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Array[100]", + "_description": "Array", + "_size": 100, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Array[100]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 100, "_properties": [ { "_name": "10", @@ -1266,13 +1284,15 @@ EXPRESSION: a = null; (function() { a = arguments; })(1, '2', /3/); a "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Arguments[3]", + "_description": "Arguments", + "_size": 3, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Arguments[3]", + "_description": "Arguments", "_lossless": false, "_overflow": false, + "_size": 3, "_properties": [ { "_name": "0", @@ -1301,13 +1321,15 @@ EXPRESSION: new Int32Array(new ArrayBuffer(16)) "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Int32Array[4]", + "_description": "Int32Array", + "_size": 4, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Int32Array[4]", + "_description": "Int32Array", "_lossless": false, "_overflow": false, + "_size": 4, "_properties": [ { "_name": "0", @@ -1355,13 +1377,15 @@ EXPRESSION: var intArray = new Int32Array(new ArrayBuffer(16)); for (var i = 0; "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "Int32Array[4]", + "_description": "Int32Array", + "_size": 4, "_preview": { "_type": "object", "_subtype": "array", - "_description": "Int32Array[4]", + "_description": "Int32Array", "_lossless": false, "_overflow": false, + "_size": 4, "_properties": [ { "_name": "0", @@ -1894,13 +1918,15 @@ EXPRESSION: document.head.children "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "HTMLCollection[3]", + "_description": "HTMLCollection", + "_size": 3, "_preview": { "_type": "object", "_subtype": "array", - "_description": "HTMLCollection[3]", + "_description": "HTMLCollection", "_lossless": false, "_overflow": false, + "_size": 3, "_properties": [ { "_name": "0", @@ -1941,13 +1967,15 @@ EXPRESSION: document.getElementsByClassName('my-test') "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "NodeList[3]", + "_description": "NodeList", + "_size": 3, "_preview": { "_type": "object", "_subtype": "array", - "_description": "NodeList[3]", + "_description": "NodeList", "_lossless": false, "_overflow": false, + "_size": 3, "_properties": [ { "_name": "0", @@ -1988,13 +2016,15 @@ EXPRESSION: document.querySelectorAll('.my-test') "_type": "object", "_subtype": "array", "_objectId": "", - "_description": "NodeList[3]", + "_description": "NodeList", + "_size": 3, "_preview": { "_type": "object", "_subtype": "array", - "_description": "NodeList[3]", + "_description": "NodeList", "_lossless": false, "_overflow": false, + "_size": 3, "_properties": [ { "_name": "0", @@ -2152,50 +2182,20 @@ EXPRESSION: error = null; try { document.createTextNode('').splitText(100); } ca } ----------------------------------------------------- -EXPRESSION: Object.seal({}) -{ - "_type": "object", - "_objectId": "", - "_description": "Object", - "_preview": { - "_type": "object", - "_description": "Object", - "_lossless": true, - "_overflow": false, - "_properties": [], - "_entries": null - } -} - ------------------------------------------------------ -EXPRESSION: Object.freeze({}) -{ - "_type": "object", - "_objectId": "", - "_description": "Object", - "_preview": { - "_type": "object", - "_description": "Object", - "_lossless": true, - "_overflow": false, - "_properties": [], - "_entries": null - } -} - ------------------------------------------------------ EXPRESSION: new Map { "_type": "object", "_subtype": "map", "_objectId": "", "_description": "Map", + "_size": 0, "_preview": { "_type": "object", "_subtype": "map", "_description": "Map", "_lossless": true, "_overflow": false, + "_size": 0, "_properties": [], "_entries": [] } @@ -2208,12 +2208,14 @@ EXPRESSION: map = new Map; map.set(1, 2); map.set('key', 'value'); map "_subtype": "map", "_objectId": "", "_description": "Map", + "_size": 2, "_preview": { "_type": "object", "_subtype": "map", "_description": "Map", "_lossless": true, "_overflow": false, + "_size": 2, "_properties": [], "_entries": [ { @@ -2263,12 +2265,14 @@ EXPRESSION: map = new Map; map.set({a:1}, {b:2}); map.set(document.body, [1,2]); "_subtype": "map", "_objectId": "", "_description": "Map", + "_size": 2, "_preview": { "_type": "object", "_subtype": "map", "_description": "Map", "_lossless": true, "_overflow": false, + "_size": 2, "_properties": [], "_entries": [ { @@ -2340,9 +2344,10 @@ EXPRESSION: map = new Map; map.set({a:1}, {b:2}); map.set(document.body, [1,2]); "_value": { "_type": "object", "_subtype": "array", - "_description": "Array[2]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 2, "_properties": [ { "_name": "0", @@ -2369,12 +2374,14 @@ EXPRESSION: map = new Map; for (var i = 0; i <= 100; i++) map.set(i, i); map "_subtype": "map", "_objectId": "", "_description": "Map", + "_size": 101, "_preview": { "_type": "object", "_subtype": "map", "_description": "Map", "_lossless": false, "_overflow": true, + "_size": 101, "_properties": [], "_entries": [ { @@ -2478,12 +2485,14 @@ EXPRESSION: map = new WeakMap; strongKey = {id:1}; map.set(strongKey, [1,2]); ma "_subtype": "weakmap", "_objectId": "", "_description": "WeakMap", + "_size": 1, "_preview": { "_type": "object", "_subtype": "weakmap", "_description": "WeakMap", "_lossless": true, "_overflow": false, + "_size": 1, "_properties": [], "_entries": [ { @@ -2504,9 +2513,10 @@ EXPRESSION: map = new WeakMap; strongKey = {id:1}; map.set(strongKey, [1,2]); ma "_value": { "_type": "object", "_subtype": "array", - "_description": "Array[2]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 2, "_properties": [ { "_name": "0", @@ -2533,12 +2543,14 @@ EXPRESSION: new Set "_subtype": "set", "_objectId": "", "_description": "Set", + "_size": 0, "_preview": { "_type": "object", "_subtype": "set", "_description": "Set", "_lossless": true, "_overflow": false, + "_size": 0, "_properties": [], "_entries": [] } @@ -2551,12 +2563,14 @@ EXPRESSION: set = new Set; set.add(1); set.add(2); set.add('key'); set "_subtype": "set", "_objectId": "", "_description": "Set", + "_size": 3, "_preview": { "_type": "object", "_subtype": "set", "_description": "Set", "_lossless": true, "_overflow": false, + "_size": 3, "_properties": [], "_entries": [ { @@ -2600,12 +2614,14 @@ EXPRESSION: set = new Set; set.add({a:1}); set.add(document.body); set.add([1,2] "_subtype": "set", "_objectId": "", "_description": "Set", + "_size": 3, "_preview": { "_type": "object", "_subtype": "set", "_description": "Set", "_lossless": true, "_overflow": false, + "_size": 3, "_properties": [], "_entries": [ { @@ -2665,9 +2681,10 @@ EXPRESSION: set = new Set; set.add({a:1}); set.add(document.body); set.add([1,2] "_value": { "_type": "object", "_subtype": "array", - "_description": "Array[2]", + "_description": "Array", "_lossless": true, "_overflow": false, + "_size": 2, "_properties": [ { "_name": "0", @@ -2694,12 +2711,14 @@ EXPRESSION: set = new Set; for (var i = 0; i <= 100; i++) set.add(i); set "_subtype": "set", "_objectId": "", "_description": "Set", + "_size": 101, "_preview": { "_type": "object", "_subtype": "set", "_description": "Set", "_lossless": false, "_overflow": true, + "_size": 101, "_properties": [], "_entries": [ { @@ -2895,3 +2914,35 @@ EXPRESSION: Promise.resolve({result:1}) } } +----------------------------------------------------- +EXPRESSION: Object.seal({}) +{ + "_type": "object", + "_objectId": "", + "_description": "Object", + "_preview": { + "_type": "object", + "_description": "Object", + "_lossless": true, + "_overflow": false, + "_properties": [], + "_entries": null + } +} + +----------------------------------------------------- +EXPRESSION: Object.freeze({}) +{ + "_type": "object", + "_objectId": "", + "_description": "Object", + "_preview": { + "_type": "object", + "_description": "Object", + "_lossless": true, + "_overflow": false, + "_properties": [], + "_entries": null + } +} + diff --git a/LayoutTests/inspector/model/remote-object.html b/LayoutTests/inspector/model/remote-object.html index bb6204d..ae0f52d 100644 --- a/LayoutTests/inspector/model/remote-object.html +++ b/LayoutTests/inspector/model/remote-object.html @@ -116,12 +116,6 @@ function test() {expression: "error = null; try { eval('if()'); } catch (e) { error = e; }; error"}, {expression: "error = null; try { document.createTextNode('').splitText(100); } catch (e) { error = e; }; error"}, - // Improveable: - - // Sealed / Frozen objects. - {expression: "Object.seal({})"}, - {expression: "Object.freeze({})"}, - // Map / WeakMap {expression: "new Map"}, {expression: "map = new Map; map.set(1, 2); map.set('key', 'value'); map"}, @@ -142,6 +136,11 @@ function test() {expression: "Promise.resolve()"}, {expression: "Promise.resolve({result:1})"}, + // Improveable: + + // Sealed / Frozen objects. + {expression: "Object.seal({})"}, + {expression: "Object.freeze({})"}, ]; if (!window.WebInspector) { diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 064df8d..6d3e9af 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,27 @@ +2015-03-04 Joseph Pecoraro + + Web Inspector: Array/Collection Sizes should be visible and distinct + https://bugs.webkit.org/show_bug.cgi?id=142254 + + Reviewed by Timothy Hatcher. + + * runtime/WeakMapData.h: + (JSC::WeakMapData::size): + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::weakMapSize): + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + (Inspector::jsInjectedScriptHostPrototypeFunctionWeakMapSize): + Add a way to get a WeakMap's size. + + * inspector/protocol/Runtime.json: + Include size in RemoteObject and ObjectPreview. + + * inspector/InjectedScriptSource.js: + Set the size of RemoteObjects and previews if they + are array/collection types. + 2015-03-04 Andreas Kling GC should compute stack bounds and dump registers at the earliest opportunity. diff --git a/Source/JavaScriptCore/inspector/InjectedScriptSource.js b/Source/JavaScriptCore/inspector/InjectedScriptSource.js index 029e56d..8b362fe 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptSource.js +++ b/Source/JavaScriptCore/inspector/InjectedScriptSource.js @@ -768,11 +768,8 @@ InjectedScript.prototype = { } var className = InjectedScriptHost.internalConstructorName(obj); - if (subtype === "array") { - if (typeof obj.length === "number") - className += "[" + obj.length + "]"; + if (subtype === "array") return className; - } // NodeList in JSC is a function, check for array prior to this. if (typeof obj === "function") @@ -904,6 +901,13 @@ InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, this.className = InjectedScriptHost.internalConstructorName(object); this.description = injectedScript._describe(object); + if (subtype === "array") + this.size = typeof object.length === "number" ? object.length : 0; + else if (subtype === "set" || subtype === "map") + this.size = object.size; + else if (subtype === "weakmap") + this.size = InjectedScriptHost.weakMapSize(object); + if (generatePreview && this.type === "object") this.preview = this._generatePreview(object, undefined, columnNames); } @@ -925,6 +929,9 @@ InjectedScript.RemoteObject.prototype = { } } + if ("size" in this) + preview.size = this.size; + return preview; }, diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp index d29d36f..83b204f 100644 --- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp +++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp @@ -253,6 +253,19 @@ JSValue JSInjectedScriptHost::getInternalProperties(ExecState* exec) return jsUndefined(); } +JSValue JSInjectedScriptHost::weakMapSize(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue value = exec->uncheckedArgument(0); + JSWeakMap* weakMap = jsDynamicCast(value); + if (!weakMap) + return jsUndefined(); + + return jsNumber(weakMap->weakMapData()->size()); +} + JSValue JSInjectedScriptHost::weakMapEntries(ExecState* exec) { if (exec->argumentCount() < 1) diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h index ff11e52..8c8d8b0 100644 --- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h +++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h @@ -65,6 +65,7 @@ public: JSC::JSValue subtype(JSC::ExecState*); JSC::JSValue functionDetails(JSC::ExecState*); JSC::JSValue getInternalProperties(JSC::ExecState*); + JSC::JSValue weakMapSize(JSC::ExecState*); JSC::JSValue weakMapEntries(JSC::ExecState*); protected: diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp index b069073..2f857ff 100644 --- a/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp +++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp @@ -43,6 +43,7 @@ static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionFunctio static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionGetInternalProperties(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionInternalConstructorName(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapSize(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapEntries(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeAttributeEvaluate(ExecState*); @@ -60,6 +61,7 @@ void JSInjectedScriptHostPrototype::finishCreation(VM& vm, JSGlobalObject* globa JSC_NATIVE_FUNCTION("getInternalProperties", jsInjectedScriptHostPrototypeFunctionGetInternalProperties, DontEnum, 1); JSC_NATIVE_FUNCTION("internalConstructorName", jsInjectedScriptHostPrototypeFunctionInternalConstructorName, DontEnum, 1); JSC_NATIVE_FUNCTION("isHTMLAllCollection", jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection, DontEnum, 1); + JSC_NATIVE_FUNCTION("weakMapSize", jsInjectedScriptHostPrototypeFunctionWeakMapSize, DontEnum, 1); JSC_NATIVE_FUNCTION("weakMapEntries", jsInjectedScriptHostPrototypeFunctionWeakMapEntries, DontEnum, 1); Identifier evaluateIdentifier(&vm, "evaluate"); @@ -102,6 +104,17 @@ EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIsHTMLAllColle return JSValue::encode(castedThis->isHTMLAllCollection(exec)); } +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapSize(ExecState* exec) +{ + JSValue thisValue = exec->thisValue(); + JSInjectedScriptHost* castedThis = jsDynamicCast(thisValue); + if (!castedThis) + return throwVMTypeError(exec); + + ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); + return JSValue::encode(castedThis->weakMapSize(exec)); +} + EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapEntries(ExecState* exec) { JSValue thisValue = exec->thisValue(); diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json index 16ca013..69fe926 100644 --- a/Source/JavaScriptCore/inspector/protocol/Runtime.json +++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json @@ -18,6 +18,7 @@ { "name": "value", "type": "any", "optional": true, "description": "Remote object value (in case of primitive values or JSON values if it was requested)." }, { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, + { "name": "size", "type": "integer", "optional": true, "description": "Size of the array/collection. Specified for array/map/set/weakmap object type values only." }, { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only." } ] }, @@ -32,7 +33,8 @@ { "name": "lossless", "type": "boolean", "description": "Determines whether preview is lossless (contains all information of the original object)." }, { "name": "overflow", "type": "boolean", "optional": true, "description": "True iff some of the properties of the original did not fit." }, { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "optional": true, "description": "List of the properties." }, - { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for map and set subtype values only." } + { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for map and set subtype values only." }, + { "name": "size", "type": "integer", "optional": true, "description": "Size of the array/collection. Specified for array/map/set/weakmap object type values only." } ] }, { diff --git a/Source/JavaScriptCore/runtime/WeakMapData.h b/Source/JavaScriptCore/runtime/WeakMapData.h index 68ea46f..45336c2 100644 --- a/Source/JavaScriptCore/runtime/WeakMapData.h +++ b/Source/JavaScriptCore/runtime/WeakMapData.h @@ -67,6 +67,8 @@ public: MapType::const_iterator begin() const { return m_map.begin(); } MapType::const_iterator end() const { return m_map.end(); } + int size() const { return m_map.size(); } + private: WeakMapData(VM&); static void destroy(JSCell*); diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog index 0d95bd5..0b9d4a0 100644 --- a/Source/WebInspectorUI/ChangeLog +++ b/Source/WebInspectorUI/ChangeLog @@ -1,3 +1,48 @@ +2015-03-04 Joseph Pecoraro + + Web Inspector: Array/Collection Sizes should be visible and distinct + https://bugs.webkit.org/show_bug.cgi?id=142254 + + Reviewed by Timothy Hatcher. + + * UserInterface/Models/ObjectPreview.js: + (WebInspector.ObjectPreview): + (WebInspector.ObjectPreview.fromPayload): + (WebInspector.ObjectPreview.prototype.get size): + (WebInspector.ObjectPreview.prototype.hasSize): + * UserInterface/Protocol/RemoteObject.js: + (WebInspector.RemoteObject): + (WebInspector.RemoteObject.fromPrimitiveValue): + (WebInspector.RemoteObject.fromPayload): + (WebInspector.RemoteObject.prototype.get size): + (WebInspector.RemoteObject.prototype.hasSize): + Check if this type has a size and get the size. + Gracefully handle construction for legacy protocols. + + * UserInterface/Views/ObjectPreviewView.css: + (.object-preview > .size): + * UserInterface/Views/FormattedValue.css: + (:matches(.formatted-array, .formatted-map, .formatted-set, .formatted-weakmap) > .size): + Style the array/collection size. + + * UserInterface/Views/ObjectPreviewView.js: + (WebInspector.ObjectPreviewView): + * UserInterface/Views/FormattedValue.js: + (WebInspector.FormattedValue.createElementForTypesAndValue): + (WebInspector.FormattedValue.createElementForRemoteObject): + (WebInspector.FormattedValue.createElementForObjectPreview): + (WebInspector.FormattedValue.createElementForPropertyPreview): + Add an element showing the array/collection size. + + * UserInterface/Views/ObjectTreePropertyTreeElement.js: + (WebInspector.ObjectTreePropertyTreeElement.prototype): + Remove special handling for Array sizes now that this is handled earlier. + + * UserInterface/Controllers/StorageManager.js: + (WebInspector.StorageManager.prototype.processData): + (WebInspector.StorageManager.prototype.requestIndexedDatabaseData): + Fix what looks like broken RemoteObject construction. + 2015-03-04 Brian J. Burg Web Inspector: TimelineViews should be displayed in a ContentViewContainer diff --git a/Source/WebInspectorUI/UserInterface/Controllers/StorageManager.js b/Source/WebInspectorUI/UserInterface/Controllers/StorageManager.js index a23942e..29f35c7 100644 --- a/Source/WebInspectorUI/UserInterface/Controllers/StorageManager.js +++ b/Source/WebInspectorUI/UserInterface/Controllers/StorageManager.js @@ -150,9 +150,9 @@ WebInspector.StorageManager.prototype = { for (var entryPayload of entryPayloads) { var entry = {}; - entry.primaryKey = new WebInspector.RemoteObject.fromPayload(entryPayload.primaryKey); - entry.key = new WebInspector.RemoteObject.fromPayload(entryPayload.key); - entry.value = new WebInspector.RemoteObject.fromPayload(entryPayload.value); + entry.primaryKey = WebInspector.RemoteObject.fromPayload(entryPayload.primaryKey); + entry.key = WebInspector.RemoteObject.fromPayload(entryPayload.key); + entry.value = WebInspector.RemoteObject.fromPayload(entryPayload.value); entries.push(entry); } diff --git a/Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js b/Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js index f96b83b..8a029b8 100644 --- a/Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js +++ b/Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js @@ -23,7 +23,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.ObjectPreview = function(type, subtype, description, lossless, overflow, properties, entries) +WebInspector.ObjectPreview = function(type, subtype, description, lossless, overflow, properties, entries, size) { WebInspector.Object.call(this); @@ -37,6 +37,7 @@ WebInspector.ObjectPreview = function(type, subtype, description, lossless, over this._description = description || ""; this._lossless = lossless; this._overflow = overflow || false; + this._size = size; this._properties = properties || null; this._entries = entries || null; @@ -50,7 +51,17 @@ WebInspector.ObjectPreview.fromPayload = function(payload) if (payload.entries) payload.entries = payload.entries.map(function(entry) { return WebInspector.CollectionEntryPreview.fromPayload(entry); }); - return new WebInspector.ObjectPreview(payload.type, payload.subtype, payload.description, payload.lossless, payload.overflow, payload.properties, payload.entries); + if (payload.subtype === "array") { + // COMPATIBILITY (iOS 8): Runtime.ObjectPreview did not have size property, + // instead it was tacked onto the end of the description, like "Array[#]". + var match = payload.description.match(/\[(\d+)\]$/); + if (match) { + payload.size = parseInt(match[1]); + payload.description = payload.description.replace(/\[\d+\]$/, ""); + } + } + + return new WebInspector.ObjectPreview(payload.type, payload.subtype, payload.description, payload.lossless, payload.overflow, payload.properties, payload.entries, payload.size); }; WebInspector.ObjectPreview.prototype = { @@ -92,5 +103,15 @@ WebInspector.ObjectPreview.prototype = { get collectionEntryPreviews() { return this._entries; + }, + + get size() + { + return this._size; + }, + + hasSize: function() + { + return this._size !== undefined && (this._subtype === "array" || this._subtype === "set" || this._subtype === "map" || this._subtype === "weakmap"); } }; diff --git a/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js b/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js index 3d3f941..b90a4b2 100644 --- a/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js +++ b/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.RemoteObject = function(objectId, type, subtype, value, description, preview) +WebInspector.RemoteObject = function(objectId, type, subtype, value, description, size, preview) { // No superclass. @@ -47,6 +47,7 @@ WebInspector.RemoteObject = function(objectId, type, subtype, value, description this._objectId = objectId; this._description = description; this._hasChildren = type !== "symbol"; + this._size = size; this._preview = preview; } else { // Primitive or null. @@ -61,13 +62,23 @@ WebInspector.RemoteObject = function(objectId, type, subtype, value, description WebInspector.RemoteObject.fromPrimitiveValue = function(value) { - return new WebInspector.RemoteObject(undefined, typeof value, undefined, value); + return new WebInspector.RemoteObject(undefined, typeof value, undefined, undefined, value); }; WebInspector.RemoteObject.fromPayload = function(payload) { console.assert(typeof payload === "object", "Remote object payload should only be an object"); + if (payload.subtype === "array") { + // COMPATIBILITY (iOS 8): Runtime.RemoteObject did not have size property, + // instead it was tacked onto the end of the description, like "Array[#]". + var match = payload.description.match(/\[(\d+)\]$/); + if (match) { + payload.size = parseInt(match[1]); + payload.description = payload.description.replace(/\[\d+\]$/, ""); + } + } + if (payload.preview) { // COMPATIBILITY (iOS 8): iOS 7 and 8 did not have type/subtype/description on // Runtime.ObjectPreview. Copy them over from the RemoteObject. @@ -75,11 +86,12 @@ WebInspector.RemoteObject.fromPayload = function(payload) payload.preview.type = payload.type; payload.preview.subtype = payload.subtype; payload.preview.description = payload.description; + payload.preview.size = payload.size; } payload.preview = WebInspector.ObjectPreview.fromPayload(payload.preview); } - return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview); + return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.size, payload.preview); }; WebInspector.RemoteObject.createCallArgument = function(valueOrObject) @@ -151,11 +163,21 @@ WebInspector.RemoteObject.prototype = { return this._value; }, + get size() + { + return this._size || 0; + }, + get preview() { return this._preview; }, + hasSize: function() + { + return this.isArray() || this.isCollectionType(); + }, + hasValue: function() { return "_value" in this; diff --git a/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css b/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css index be33119..d29451a 100644 --- a/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css +++ b/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css @@ -30,6 +30,11 @@ color: black; } +:matches(.formatted-array, .formatted-map, .formatted-set, .formatted-weakmap) > .size { + font-style: normal; + color: hsl(0, 0%, 67%); +} + .formatted-node > ol { display: block !important; } diff --git a/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js b/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js index ee2a130..094b1f8 100644 --- a/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js +++ b/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js @@ -69,7 +69,7 @@ WebInspector.FormattedValue.createElementForNode = function(object) return span; }; -WebInspector.FormattedValue.createElementForTypesAndValue = function(type, subtype, displayString, isPreview, hadException) +WebInspector.FormattedValue.createElementForTypesAndValue = function(type, subtype, displayString, size, isPreview, hadException) { var span = document.createElement("span"); span.classList.add(WebInspector.FormattedValue.classNameForTypes(type, subtype)); @@ -94,22 +94,30 @@ WebInspector.FormattedValue.createElementForTypesAndValue = function(type, subty // Everything else, the description/value string. span.textContent = displayString; + + // If there is a size, include it. + if (size !== undefined && (subtype === "array" || subtype === "set" || subtype === "map" || subtype === "weakmap")) { + var sizeElement = span.appendChild(document.createElement("span")); + sizeElement.className = "size"; + sizeElement.textContent = " (" + size + ")"; + } + return span; }; WebInspector.FormattedValue.createElementForRemoteObject = function(object, hadException) { - return WebInspector.FormattedValue.createElementForTypesAndValue(object.type, object.subtype, object.description, false, hadException); + return WebInspector.FormattedValue.createElementForTypesAndValue(object.type, object.subtype, object.description, object.size, false, hadException); }; WebInspector.FormattedValue.createElementForObjectPreview = function(objectPreview) { - return WebInspector.FormattedValue.createElementForTypesAndValue(objectPreview.type, objectPreview.subtype, objectPreview.description, true, false); + return WebInspector.FormattedValue.createElementForTypesAndValue(objectPreview.type, objectPreview.subtype, objectPreview.description, objectPreview.size, true, false); }; WebInspector.FormattedValue.createElementForPropertyPreview = function(propertyPreview) { - return WebInspector.FormattedValue.createElementForTypesAndValue(propertyPreview.type, propertyPreview.subtype, propertyPreview.value, true, false); + return WebInspector.FormattedValue.createElementForTypesAndValue(propertyPreview.type, propertyPreview.subtype, propertyPreview.value, undefined, true, false); }; WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject = function(object, propertyPath) diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css b/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css index 2da3e6e..7fddde8 100644 --- a/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css +++ b/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css @@ -38,3 +38,8 @@ .object-preview .name { color: rgb(136, 19, 145); } + +.object-preview > .size { + font-style: normal; + color: hsl(0, 0%, 67%); +} diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js b/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js index 0af32f6..4f9909f 100644 --- a/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js +++ b/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js @@ -44,6 +44,12 @@ WebInspector.ObjectPreviewView = function(preview, mode) this._titleElement.hidden = true; this._initTitleElement(); + if (this._preview.hasSize()) { + var sizeElement = this._element.appendChild(document.createElement("span")); + sizeElement.className = "size"; + sizeElement.textContent = " (" + this._preview.size + ")"; + } + if (this._lossless) this._element.classList.add("lossless"); }; diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js index 2e61d15..98fffee 100644 --- a/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js +++ b/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js @@ -375,7 +375,7 @@ WebInspector.ObjectTreePropertyTreeElement.prototype = { if (value.subtype === "regexp") return "RegExp"; - return value.description.replace(/\[\d+\]$/, "").replace(/Prototype$/, ""); + return value.description.replace(/Prototype$/, ""); }, _propertyPathString: function(propertyPath) -- 1.8.3.1