Changeset 179019 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Jan 23, 2015, 12:05:44 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r179015 r179019 1 2015-01-23 Joseph Pecoraro <[email protected]> 2 3 Web Inspector: Object Previews in the Console 4 https://bugs.webkit.org/show_bug.cgi?id=129204 5 6 Reviewed by Timothy Hatcher. 7 8 Update the very old, unused object preview code. Part of this comes from 9 the earlier WebKit legacy implementation, and the Blink implementation. 10 11 A RemoteObject may include a preview, if it is asked for, and if the 12 RemoteObject is an object. Previews are a shallow (single level) list 13 of a limited number of properties on the object. The previewed 14 properties are always stringified (even if primatives). Previews are 15 limited to just 5 properties or 100 indices. Previews are marked 16 as lossless if they are a complete snapshot of the object. 17 18 There is a path to make previews two levels deep, that is currently 19 unused but should soon be used for tables (e.g. IndexedDB). 20 21 * inspector/InjectedScriptSource.js: 22 - Move some code off of InjectedScript to be generic functions 23 usable by RemoteObject as well. 24 - Update preview generation to use 25 26 * inspector/protocol/Runtime.json: 27 - Add a new type, "accessor" for preview objects. This represents 28 a getter / setter. We currently don't get the value. 29 1 30 2015-01-23 Michael Saboff <[email protected]> 2 31 -
trunk/Source/JavaScriptCore/inspector/InjectedScriptSource.js
r178875 r179019 1 1 /* 2 2 * Copyright (C) 2007, 2014 Apple Inc. All rights reserved. 3 * Copyright (C) 2013 Google Inc. All rights reserved. 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 34 35 var Object = {}.constructor; 35 36 37 function toString(obj) 38 { 39 return "" + obj; 40 } 41 42 function isUInt32(obj) 43 { 44 if (typeof obj === "number") 45 return obj >>> 0 === obj && (obj > 0 || 1 / obj > 0); 46 return "" + (obj >>> 0) === obj; 47 } 48 36 49 var InjectedScript = function() 37 50 { … … 81 94 result.value = object; 82 95 else 83 result.description = t his._toString(object);96 result.description = toString(object); 84 97 return result; 85 98 }, … … 324 337 var remoteObject = this._wrapObject(value, objectGroup); 325 338 try { 326 remoteObject.description = t his._toString(value);339 remoteObject.description = toString(value); 327 340 } catch (e) {} 328 341 return { … … 480 493 // - ownProperties - only own properties and __proto__ 481 494 // - ownAndGetterProperties - own properties, __proto__, and getters in the prototype chain 482 // - neither - get all properties in the prototype chain , exclude__proto__495 // - neither - get all properties in the prototype chain and __proto__ 483 496 484 497 var descriptors = []; … … 612 625 } 613 626 614 // If owning frame has navigated to somewhere else window properties will be undefined.615 627 return null; 616 628 }, … … 624 636 625 637 if (subtype === "regexp") 626 return t his._toString(obj);638 return toString(obj); 627 639 628 640 if (subtype === "date") 629 return t his._toString(obj);641 return toString(obj); 630 642 631 643 if (subtype === "error") 632 return t his._toString(obj);644 return toString(obj); 633 645 634 646 if (subtype === "node") { … … 656 668 // NodeList in JSC is a function, check for array prior to this. 657 669 if (typeof obj === "function") 658 return t his._toString(obj);659 660 // FIXME: Can we remove this?670 return toString(obj); 671 672 // If Object, try for a better name from the constructor. 661 673 if (className === "Object") { 662 // In Chromium DOM wrapper prototypes will have Object as their constructor name,663 // get the real DOM wrapper name from the constructor property.664 674 var constructorName = obj.constructor && obj.constructor.name; 665 675 if (constructorName) 666 676 return constructorName; 667 677 } 678 668 679 return className; 669 },670 671 _toString: function(obj)672 {673 // We don't use String(obj) because inspectedGlobalObject.String is undefined if owning frame navigated to another page.674 return "" + obj;675 680 } 676 681 } … … 709 714 this.description = injectedScript._describe(object); 710 715 711 if (generatePreview && (this.type === "object" || injectedScript._isHTMLAllCollection(object)))716 if (generatePreview && this.type === "object") 712 717 this.preview = this._generatePreview(object, undefined, columnNames); 713 718 } … … 728 733 indexes: isTableRowsRequest ? 1000 : Math.max(100, firstLevelKeysCount) 729 734 }; 730 for (var o = object; injectedScript._isDefined(o); o = o.__proto__) 731 this._generateProtoPreview(o, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys); 735 736 try { 737 // All properties. 738 var descriptors = injectedScript._propertyDescriptors(object); 739 this._appendPropertyDescriptors(preview, descriptors, propertiesThreshold, secondLevelKeys); 740 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) 741 return preview; 742 743 // FIXME: Internal properties. 744 // FIXME: Map/Set/Iterator entries. 745 } catch (e) { 746 preview.lossless = false; 747 } 748 732 749 return preview; 733 750 }, 734 751 735 _generateProtoPreview: function(object, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys) 736 { 737 var propertyNames = firstLevelKeys ? firstLevelKeys : Object.keys(object); 738 try { 739 for (var i = 0; i < propertyNames.length; ++i) { 740 if (!propertiesThreshold.properties || !propertiesThreshold.indexes) { 752 _appendPropertyDescriptors: function(preview, descriptors, propertiesThreshold, secondLevelKeys) 753 { 754 for (var descriptor of descriptors) { 755 // Seen enough. 756 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) 757 break; 758 759 // Error in descriptor. 760 if (descriptor.wasThrown) { 761 preview.lossless = false; 762 continue; 763 } 764 765 // Do not show "__proto__" in preview. 766 var name = descriptor.name; 767 if (name === "__proto__") 768 continue; 769 770 // Do not show "length" on array like objects in preview. 771 if (this.subtype === "array" && name === "length") 772 continue; 773 774 // Do not show non-enumerable non-own properties. Special case to allow array indexes that may be on the prototype. 775 if (!descriptor.enumerable && !descriptor.isOwn && !(this.subtype === "array" && isUInt32(name))) 776 continue; 777 778 // Getter/setter. 779 if (!("value" in descriptor)) { 780 preview.lossless = false; 781 this._appendPropertyPreview(preview, {name: name, type: "accessor"}, propertiesThreshold); 782 continue; 783 } 784 785 // Null value. 786 var value = descriptor.value; 787 if (value === null) { 788 this._appendPropertyPreview(preview, {name: name, type: "object", subtype: "null", value: "null"}, propertiesThreshold); 789 continue; 790 } 791 792 // Ignore non-enumerable functions. 793 var type = typeof value; 794 if (!descriptor.enumerable && type === "function") 795 continue; 796 797 // Fix type of document.all. 798 if (type === "undefined" && injectedScript._isHTMLAllCollection(value)) 799 type = "object"; 800 801 // Primitive. 802 const maxLength = 100; 803 if (InjectedScript.primitiveTypes[type]) { 804 if (type === "string" && value.length > maxLength) { 805 value = this._abbreviateString(value, maxLength, true); 806 preview.lossless = false; 807 } 808 this._appendPropertyPreview(preview, {name: name, type: type, value: toString(value)}, propertiesThreshold); 809 continue; 810 } 811 812 // Object. 813 var property = {name: name, type: type}; 814 var subtype = injectedScript._subtype(value); 815 if (subtype) 816 property.subtype = subtype; 817 818 // Second level. 819 if (secondLevelKeys === null || secondLevelKeys) { 820 var subPreview = this._generatePreview(value, secondLevelKeys || undefined, undefined); 821 property.valuePreview = subPreview; 822 if (!subPreview.lossless) 823 preview.lossless = false; 824 if (subPreview.overflow) 741 825 preview.overflow = true; 742 preview.lossless = false; 743 break; 744 } 745 var name = propertyNames[i]; 746 if (this.subtype === "array" && name === "length") 747 continue; 748 749 var descriptor = Object.getOwnPropertyDescriptor(object, name); 750 if (!("value" in descriptor) || !descriptor.enumerable) { 751 preview.lossless = false; 752 continue; 753 } 754 755 var value = descriptor.value; 756 if (value === null) { 757 this._appendPropertyPreview(preview, { name: name, type: "object", value: "null" }, propertiesThreshold); 758 continue; 759 } 760 761 const maxLength = 100; 762 var type = typeof value; 763 764 if (InjectedScript.primitiveTypes[type]) { 765 if (type === "string") { 766 if (value.length > maxLength) { 767 value = this._abbreviateString(value, maxLength, true); 768 preview.lossless = false; 769 } 770 value = value.replace(/\n/g, "\u21B5"); 771 } 772 this._appendPropertyPreview(preview, { name: name, type: type, value: value + "" }, propertiesThreshold); 773 continue; 774 } 775 776 if (secondLevelKeys === null || secondLevelKeys) { 777 var subPreview = this._generatePreview(value, secondLevelKeys || undefined); 778 var property = { name: name, type: type, valuePreview: subPreview }; 779 this._appendPropertyPreview(preview, property, propertiesThreshold); 780 if (!subPreview.lossless) 781 preview.lossless = false; 782 if (subPreview.overflow) 783 preview.overflow = true; 784 continue; 785 } 786 787 preview.lossless = false; 788 789 var subtype = injectedScript._subtype(value); 826 } else { 790 827 var description = ""; 791 828 if (type !== "function") 792 829 description = this._abbreviateString(injectedScript._describe(value), maxLength, subtype === "regexp"); 793 794 var property = { name: name, type: type, value: description }; 795 if (subtype) 796 property.subtype = subtype; 797 this._appendPropertyPreview(preview, property, propertiesThreshold); 798 } 799 } catch (e) { 830 property.value = description; 831 preview.lossless = false; 832 } 833 834 this._appendPropertyPreview(preview, property, propertiesThreshold); 800 835 } 801 836 }, … … 803 838 _appendPropertyPreview: function(preview, property, propertiesThreshold) 804 839 { 805 if (isNaN(property.name)) 840 if (toString(property.name >>> 0) === property.name) 841 propertiesThreshold.indexes--; 842 else 806 843 propertiesThreshold.properties--; 807 else 808 propertiesThreshold.indexes--; 844 845 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) { 846 preview.overflow = true; 847 preview.lossless = false; 848 return; 849 } 850 809 851 preview.properties.push(property); 810 852 }, -
trunk/Source/JavaScriptCore/inspector/protocol/Runtime.json
r178768 r179019 19 19 { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, 20 20 { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, 21 { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview contain sing abbreviated property values." }21 { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for <code>object</code> type values only." } 22 22 ] 23 23 }, … … 37 37 "properties": [ 38 38 { "name": "name", "type": "string", "description": "Property name." }, 39 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean"], "description": "Object type." }, 39 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "accessor"], "description": "Object type." }, 40 { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }, 40 41 { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." }, 41 { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." }, 42 { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error"], "description": "Object subtype hint. Specified for <code>object</code> type values only." } 42 { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." } 43 43 ] 44 44 },
Note:
See TracChangeset
for help on using the changeset viewer.