Changeset 241784 in webkit
- Timestamp:
- Feb 19, 2019 4:07:28 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r241756 r241784 1 2019-02-19 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Improve ES6 Class instances in Heap Snapshot instances view 4 https://bugs.webkit.org/show_bug.cgi?id=172848 5 <rdar://problem/25709212> 6 7 Reviewed by Mark Lam. 8 9 * typeProfiler/inheritance.js: 10 Rewrite the test slightly for clarity. The hoisting was confusing. 11 12 * heapProfiler/class-names.js: Added. 13 (MyES5Class): 14 (MyES6Class): 15 (MyES6Subclass): 16 Test object types and improved class names. 17 18 * heapProfiler/driver/driver.js: 19 (CheapHeapSnapshotNode): 20 (CheapHeapSnapshot): 21 (createCheapHeapSnapshot): 22 (HeapSnapshot): 23 (createHeapSnapshot): 24 Update snapshot parsing from version 1 to version 2. 25 1 26 2019-02-18 Dominik Infuehr <dinfuehr@igalia.com> 2 27 -
trunk/JSTests/heapProfiler/basic-nodes.js
r197489 r241784 1 var SimpleObject = $vm.SimpleObject; 2 1 3 load("./driver/driver.js"); 2 4 -
trunk/JSTests/heapProfiler/driver/driver.js
r217843 r241784 10 10 // Lazily creates node and edge objects off of indexes into these lists. 11 11 12 // [<0:id>, <1:size>, <2:classNameTableIndex>, <3: internal>, <4:firstEdgeIndex>];12 // [<0:id>, <1:size>, <2:classNameTableIndex>, <3:flags>, <4:firstEdgeIndex>]; 13 13 const nodeFieldCount = 5; 14 14 const nodeIdOffset = 0; 15 15 const nodeSizeOffset = 1; 16 16 const nodeClassNameOffset = 2; 17 const node InternalOffset = 3;17 const nodeFlagsOffset = 3; 18 18 const nodeFirstEdgeOffset = 4; 19 19 const nodeNoEdgeValue = 0xffffffff; // UINT_MAX 20 21 // Node Flags. 22 const internalFlagMask = (1 << 0); 23 const objectTypeMask = (1 << 1); 20 24 21 25 // [<0:fromId>, <1:toId>, <2:typeTableIndex>, <3:edgeDataIndexOrEdgeNameIndex>] … … 36 40 this.size = nodes[nodeIndex + nodeSizeOffset]; 37 41 this.className = snapshot.classNameFromTableIndex(nodes[nodeIndex + nodeClassNameOffset]); 38 this.internal = nodes[nodeIndex + nodeInternalOffset] ? true : false; 42 43 let flags = nodes[nodeIndex + nodeFlagsOffset]; 44 this.internal = flags & internalFlagMask ? true : false; 45 this.isObjectType = flags & objectTypeMask ? true : false; 39 46 40 47 this.outgoingEdges = []; … … 92 99 this._nodes[n++] = nodes[i++]; // size 93 100 this._nodes[n++] = nodes[i++]; // classNameTableIndex 94 this._nodes[n++] = nodes[i++]; // internal101 this._nodes[n++] = nodes[i++]; // flags 95 102 this._nodes[n++] = nodeNoEdgeValue; 96 103 } … … 155 162 156 163 let {version, nodes, nodeClassNames, edges, edgeTypes} = json; 157 assert(version === 1, "Heap Snapshot payload should be version 1");164 assert(version === 2, "Heap Snapshot payload should be version 2"); 158 165 assert(nodes.length, "Heap Snapshot should have nodes"); 159 166 assert(nodeClassNames.length, "Heap Snapshot should have nodeClassNames"); … … 211 218 let size = nodes[i++]; 212 219 let classNameIndex = nodes[i++]; 213 let internal = nodes[i++]; 220 let flags = nodes[i++]; 221 let internal = flags & internalFlagMask ? true : false; 214 222 215 223 let node = new HeapSnapshotNode(id, nodeClassNames[classNameIndex], size, internal); … … 257 265 258 266 let {version, nodes, nodeClassNames, edges, edgeTypes} = json; 259 assert(version === 1, "Heap Snapshot payload should be version 1");267 assert(version === 2, "Heap Snapshot payload should be version 2"); 260 268 assert(nodes.length, "Heap Snapshot should have nodes"); 261 269 assert(nodeClassNames.length, "Heap Snapshot should have nodeClassNames"); -
trunk/JSTests/heapProfiler/variable-edge-types.js
r197712 r241784 1 var SimpleObject = $vm.SimpleObject; 2 1 3 load("./driver/driver.js"); 2 4 -
trunk/JSTests/typeProfiler/inheritance.js
r225129 r241784 5 5 function wrapper() 6 6 { 7 8 function A() { }; 9 function B() { }; 10 function C() { }; 7 11 8 12 var theA = new A; … … 17 21 var secondB = Object.create(theB); 18 22 19 function A() { }; 20 function B() { }; B.prototype.__proto__ = A.prototype; 21 function C() { }; C.prototype.__proto__ = A.prototype; 23 B.prototype.__proto__ = A.prototype; 24 C.prototype.__proto__ = A.prototype; 22 25 23 26 } -
trunk/LayoutTests/ChangeLog
r241780 r241784 1 2019-02-19 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Improve ES6 Class instances in Heap Snapshot instances view 4 https://bugs.webkit.org/show_bug.cgi?id=172848 5 <rdar://problem/25709212> 6 7 Reviewed by Mark Lam. 8 9 * inspector/unit-tests/heap-snapshot-expected.txt: 10 * inspector/unit-tests/heap-snapshot.html: 11 Update for the new node flag. 12 1 13 2019-02-19 Ryosuke Niwa <rniwa@webkit.org> 2 14 -
trunk/LayoutTests/inspector/unit-tests/heap-snapshot-expected.txt
r217843 r241784 24 24 PASS: Node size should match. 25 25 PASS: Node internal state should match. 26 PASS: Node isObjectType state should match. 26 27 PASS: Node gcRoot state should match. 27 28 PASS: Node retainedSize should at least be the size. -
trunk/LayoutTests/inspector/unit-tests/heap-snapshot.html
r220119 r241784 10 10 WI.TestHeapSnapshotNode = class TestHeapSnapshotNode 11 11 { 12 constructor(identifier, className, size, internal)12 constructor(identifier, className, size, flags) 13 13 { 14 14 this.id = identifier; 15 15 this.className = className; 16 16 this.size = size; 17 this.internal = internal; 17 this.internal = flags & (1 << 0) ? true : false; 18 this.isObjectType = flags & (1 << 1) ? true : false; 18 19 this.gcRoot = false; 19 20 this.outgoingEdges = []; … … 60 61 let size = nodes[i++]; 61 62 let classNameIndex = nodes[i++]; 62 let internal= nodes[i++];63 64 let node = new WI.TestHeapSnapshotNode(id, nodeClassNames[classNameIndex], size, !!internal);63 let flags = nodes[i++]; 64 65 let node = new WI.TestHeapSnapshotNode(id, nodeClassNames[classNameIndex], size, flags); 65 66 nodeMap.set(id, node); 66 67 processedNodes.push(node); … … 128 129 && node1.className === node2.className 129 130 && node1.internal === node2.internal 131 && node1.isObjectType === node2.isObjectType 130 132 && node1.gcRoot === node2.gcRoot; 131 133 } … … 190 192 InspectorTest.expectThat(heapSnapshotNode.size === testSnapshotNodeForWindowObject.size, "Node size should match."); 191 193 InspectorTest.expectThat(heapSnapshotNode.internal === testSnapshotNodeForWindowObject.internal, "Node internal state should match."); 194 InspectorTest.expectThat(heapSnapshotNode.isObjectType === testSnapshotNodeForWindowObject.isObjectType, "Node isObjectType state should match."); 192 195 InspectorTest.expectThat(heapSnapshotNode.gcRoot === testSnapshotNodeForWindowObject.gcRoot, "Node gcRoot state should match."); 193 196 InspectorTest.expectThat(heapSnapshotNode.retainedSize >= heapSnapshotNode.size, "Node retainedSize should at least be the size."); -
trunk/Source/JavaScriptCore/ChangeLog
r241783 r241784 1 2019-02-19 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Improve ES6 Class instances in Heap Snapshot instances view 4 https://bugs.webkit.org/show_bug.cgi?id=172848 5 <rdar://problem/25709212> 6 7 Reviewed by Mark Lam. 8 9 * heap/HeapSnapshotBuilder.h: 10 * heap/HeapSnapshotBuilder.cpp: 11 Update the snapshot version. Change the node's 0 | 1 internal value 12 to be a 32bit bit flag. This is nice in that it is both compatible 13 with the previous snapshot version and the same size. We can use more 14 flags in the future. 15 16 (JSC::HeapSnapshotBuilder::json): 17 In cases where the classInfo gives us "Object" check for a better 18 class name by checking (o).__proto__.constructor.name. We avoid this 19 check in cases where (o).hasOwnProperty("constructor") which is the 20 case for most Foo.prototype objects. Otherwise this would get the 21 name of the Foo superclass for the Foo.prototype object. 22 23 * runtime/JSObject.cpp: 24 (JSC::JSObject::calculatedClassName): 25 Handle some possible edge cases that were not handled before, such as 26 a JSObject without a GlobalObject or an object which doesn't 27 have a default getPrototype. Try to make the code a little clearer. 28 1 29 2019-02-19 Robin Morisset <rmorisset@apple.com> 2 30 -
trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp
r241751 r241784 1 1 /* 2 * Copyright (C) 2016 Apple Inc. All rights reserved.2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 21 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 24 */ 25 25 … … 80 80 { 81 81 ASSERT(m_profiler.activeSnapshotBuilder() == this); 82 82 83 83 ASSERT(Heap::isMarked(cell)); 84 84 … … 178 178 // 179 179 // { 180 // "version": 1.0,180 // "version": 2, 181 181 // "type": "Inspector", 182 // // [<address>, <labelIndex>, <wrapped Eddress>] only present in GCDebuggingSnapshot-type snapshots182 // // [<address>, <labelIndex>, <wrappedAddress>] only present in GCDebuggingSnapshot-type snapshots 183 183 // "nodes": [ 184 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, < internal>185 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, < internal>184 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <flags> 185 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <flags> 186 186 // ... 187 187 // ], … … 205 205 // 206 206 // { 207 // "version": 1.0,207 // "version": 2, 208 208 // "type": "GCDebugging", 209 209 // "nodes": [ 210 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, < internal>, <labelIndex>, <cellEddress>, <wrappedEddress>,211 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, < internal>, <labelIndex>, <cellEddress>, <wrappedEddress>,210 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <flags>, <labelIndex>, <cellEddress>, <wrappedAddress>, 211 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <flags>, <labelIndex>, <cellEddress>, <wrappedAddress>, 212 212 // ... 213 213 // ], … … 241 241 // - index into the "nodeClassNames" list. 242 242 // 243 // <internal> 244 // - 0 = false, 1 = true. 243 // <flags> 244 // - 0b0000 - no flags 245 // - 0b0001 - internal instance 246 // - 0b0010 - Object subclassification 245 247 // 246 248 // <edgeTypeIndex> … … 254 256 // <rootReasonIndex> 255 257 // - index into the "labels" list. 258 259 enum class NodeFlags { 260 Internal = 1 << 0, 261 ObjectSubtype = 1 << 1, 262 }; 256 263 257 264 static uint8_t edgeTypeToNumber(EdgeType type) … … 359 366 360 367 // Build a list of used class names. 361 HashMap< const char*, unsigned> classNameIndexes;362 classNameIndexes.set("<root>" , 0);368 HashMap<String, unsigned> classNameIndexes; 369 classNameIndexes.set("<root>"_s, 0); 363 370 unsigned nextClassNameIndex = 1; 364 371 … … 379 386 return; 380 387 388 unsigned flags = 0; 389 381 390 allowedNodeIdentifiers.set(node.cell, node.identifier); 382 391 383 auto result = classNameIndexes.add(node.cell->classInfo(vm)->className, nextClassNameIndex); 392 String className = node.cell->classInfo(vm)->className; 393 if (node.cell->isObject() && className == JSObject::info()->className) { 394 flags |= NodeFlags::ObjectSubtype; 395 396 // Skip calculating a class name if this object has a `constructor` own property. 397 // These cases are typically F.prototype objects and we want to treat these as 398 // "Object" in snapshots and not get the name of the prototype's parent. 399 JSObject* object = asObject(node.cell); 400 if (JSGlobalObject* globalObject = object->globalObject(vm)) { 401 ExecState* exec = globalObject->globalExec(); 402 PropertySlot slot(object, PropertySlot::InternalMethodType::VMInquiry); 403 if (!object->getOwnPropertySlot(object, exec, vm.propertyNames->constructor, slot)) 404 className = JSObject::calculatedClassName(object); 405 } 406 } 407 408 auto result = classNameIndexes.add(className, nextClassNameIndex); 384 409 if (result.isNewEntry) 385 410 nextClassNameIndex++; 386 411 unsigned classNameIndex = result.iterator->value; 387 412 388 bool isInternal = false;389 413 void* wrappedAddress = 0; 390 414 unsigned labelIndex = 0; 391 415 if (!node.cell->isString()) { 392 416 Structure* structure = node.cell->structure(vm); 393 isInternal = !structure || !structure->globalObject(); 417 if (!structure || !structure->globalObject()) 418 flags |= NodeFlags::Internal; 394 419 395 420 if (m_snapshotType == SnapshotType::GCDebuggingSnapshot) { … … 405 430 } 406 431 } 407 432 408 433 String description = descriptionForCell(node.cell); 409 434 if (description.length()) { … … 419 444 labelIndex = result.iterator->value; 420 445 } 421 446 422 447 wrappedAddress = m_wrappedObjectPointers.get(node.cell); 423 448 } 424 449 } 425 450 426 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, < internal>, [<labelIndex>, <cellEddress>, <wrappedEddress>]451 // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <flags>, [<labelIndex>, <cellEddress>, <wrappedAddress>] 427 452 json.append(','); 428 453 json.appendNumber(node.identifier); … … 432 457 json.appendNumber(classNameIndex); 433 458 json.append(','); 434 json.append (isInternal ? '1' : '0');459 json.appendNumber(flags); 435 460 if (m_snapshotType == SnapshotType::GCDebuggingSnapshot) { 436 461 json.append(','); … … 480 505 481 506 // version 482 json.appendLiteral("\"version\": 1");507 json.appendLiteral("\"version\":2"); 483 508 484 509 // type … … 507 532 json.appendLiteral("\"nodeClassNames\":"); 508 533 json.append('['); 509 Vector< const char *> orderedClassNames(classNameIndexes.size());534 Vector<String> orderedClassNames(classNameIndexes.size()); 510 535 for (auto& entry : classNameIndexes) 511 536 orderedClassNames[entry.value] = entry.key; … … 604 629 json.appendLiteral("\"roots\":"); 605 630 json.append('['); 606 631 607 632 HeapSnapshot* snapshot = m_profiler.mostRecentSnapshot(); 608 633 … … 620 645 firstNode = false; 621 646 json.appendNumber(snapshotNode.value().identifier); 622 647 623 648 // Maybe we should just always encode the root names. 624 649 const char* rootName = rootTypeToString(it.value.markReason); -
trunk/Source/JavaScriptCore/runtime/JSObject.cpp
r240951 r241784 525 525 String JSObject::calculatedClassName(JSObject* object) 526 526 { 527 String prototypeFunctionName; 528 auto globalObject = object->globalObject(); 527 String constructorFunctionName; 528 auto* structure = object->structure(); 529 auto* globalObject = structure->globalObject(); 529 530 VM& vm = globalObject->vm(); 530 531 auto scope = DECLARE_CATCH_SCOPE(vm); 531 532 ExecState* exec = globalObject->globalExec(); 533 PropertySlot slot(object->getPrototypeDirect(vm), PropertySlot::InternalMethodType::VMInquiry); 534 PropertyName constructor(vm.propertyNames->constructor); 535 if (object->getPropertySlot(exec, constructor, slot)) { 532 auto* exec = globalObject->globalExec(); 533 534 // Check for a display name of obj.constructor. 535 // This is useful to get `Foo` for the `(class Foo).prototype` object. 536 PropertySlot slot(object, PropertySlot::InternalMethodType::VMInquiry); 537 if (object->getOwnPropertySlot(object, exec, vm.propertyNames->constructor, slot)) { 536 538 EXCEPTION_ASSERT(!scope.exception()); 537 539 if (slot.isValue()) { 538 JSValue constructorValue = slot.getValue(exec, constructor); 539 if (constructorValue.isCell()) { 540 if (JSCell* constructorCell = constructorValue.asCell()) { 541 if (JSObject* ctorObject = constructorCell->getObject()) { 542 if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(vm, ctorObject)) 543 prototypeFunctionName = constructorFunction->calculatedDisplayName(vm); 544 else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(vm, ctorObject)) 545 prototypeFunctionName = constructorFunction->calculatedDisplayName(vm); 540 if (JSObject* ctorObject = jsDynamicCast<JSObject*>(vm, slot.getValue(exec, vm.propertyNames->constructor))) { 541 if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(vm, ctorObject)) 542 constructorFunctionName = constructorFunction->calculatedDisplayName(vm); 543 else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(vm, ctorObject)) 544 constructorFunctionName = constructorFunction->calculatedDisplayName(vm); 545 } 546 } 547 } 548 549 EXCEPTION_ASSERT(!scope.exception() || constructorFunctionName.isNull()); 550 if (UNLIKELY(scope.exception())) 551 scope.clearException(); 552 553 // Get the display name of obj.__proto__.constructor. 554 // This is useful to get `Foo` for a `new Foo` object. 555 if (constructorFunctionName.isNull()) { 556 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype; 557 if (LIKELY(structure->classInfo()->methodTable.getPrototype == defaultGetPrototype)) { 558 JSValue protoValue = object->getPrototypeDirect(vm); 559 if (protoValue.isObject()) { 560 JSObject* protoObject = asObject(protoValue); 561 PropertySlot slot(protoValue, PropertySlot::InternalMethodType::VMInquiry); 562 if (protoObject->getPropertySlot(exec, vm.propertyNames->constructor, slot)) { 563 EXCEPTION_ASSERT(!scope.exception()); 564 if (slot.isValue()) { 565 if (JSObject* ctorObject = jsDynamicCast<JSObject*>(vm, slot.getValue(exec, vm.propertyNames->constructor))) { 566 if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(vm, ctorObject)) 567 constructorFunctionName = constructorFunction->calculatedDisplayName(vm); 568 else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(vm, ctorObject)) 569 constructorFunctionName = constructorFunction->calculatedDisplayName(vm); 570 } 546 571 } 547 572 } … … 549 574 } 550 575 } 551 EXCEPTION_ASSERT(!scope.exception() || prototypeFunctionName.isNull()); 576 577 EXCEPTION_ASSERT(!scope.exception() || constructorFunctionName.isNull()); 552 578 if (UNLIKELY(scope.exception())) 553 579 scope.clearException(); 554 580 555 if ( prototypeFunctionName.isNull() || prototypeFunctionName == "Object") {581 if (constructorFunctionName.isNull() || constructorFunctionName == "Object") { 556 582 String tableClassName = object->methodTable(vm)->className(object, vm); 557 583 if (!tableClassName.isNull() && tableClassName != "Object") … … 562 588 return classInfoName; 563 589 564 if ( prototypeFunctionName.isNull())590 if (constructorFunctionName.isNull()) 565 591 return "Object"_s; 566 592 } 567 593 568 return prototypeFunctionName;594 return constructorFunctionName; 569 595 } 570 596 -
trunk/Source/WebInspectorUI/ChangeLog
r241757 r241784 1 2019-02-19 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Improve ES6 Class instances in Heap Snapshot instances view 4 https://bugs.webkit.org/show_bug.cgi?id=172848 5 <rdar://problem/25709212> 6 7 Reviewed by Mark Lam. 8 9 * UserInterface/Workers/HeapSnapshot/HeapSnapshot.js: 10 (HeapSnapshot): 11 Support the new snapshot version. The only thing that changes are the 12 node flags, and its actually completely compatible with version 1. 13 14 (HeapSnapshot.updateCategoriesAndMetadata): 15 List the count of object type instances in each class category. 16 17 (HeapSnapshot.prototype.serializeNode): 18 Include whether or not the node is an object type. 19 20 * UserInterface/Proxies/HeapSnapshotNodeProxy.js: 21 (WebInspector.HeapSnapshotNodeProxy): 22 (WebInspector.HeapSnapshotNodeProxy.deserialize): 23 Add a new Node isObjectType property based on the new data. 24 25 * UserInterface/Views/HeapSnapshotClassDataGridNode.js: 26 (WebInspector.HeapSnapshotClassDataGridNode.prototype.createCellContent): 27 * UserInterface/Views/HeapSnapshotClusterContentView.js: 28 (WebInspector.HeapSnapshotClusterContentView.iconStyleClassNameForClassName): 29 If a class contains 50% or more object type instances then treat it as such 30 instead of defaulting to native. 31 32 * UserInterface/Views/HeapSnapshotDataGridTree.js: 33 (WebInspector.HeapSnapshotInstancesDataGridTree.prototype.populateTopLevel): 34 * UserInterface/Views/HeapSnapshotInstanceDataGridNode.js: 35 (WebInspector.HeapSnapshotInstanceDataGridNode.prototype.createCellContent): 36 We can be more specific than the default if the individual instance is 37 known to be an object type. 38 1 39 2019-02-19 Joseph Pecoraro <pecoraro@apple.com> 2 40 -
trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js
r220119 r241784 26 26 WI.HeapSnapshotNodeProxy = class HeapSnapshotNodeProxy 27 27 { 28 constructor(snapshotObjectId, identifier, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren)28 constructor(snapshotObjectId, {id, className, size, retainedSize, internal, isObjectType, gcRoot, dead, dominatorNodeIdentifier, hasChildren}) 29 29 { 30 30 this._proxyObjectId = snapshotObjectId; 31 31 32 this.id = id entifier;32 this.id = id; 33 33 this.className = className; 34 34 this.size = size; 35 35 this.retainedSize = retainedSize; 36 36 this.internal = internal; 37 this.isObjectType = isObjectType; 37 38 this.gcRoot = gcRoot; 38 39 this.dead = dead; … … 45 46 static deserialize(objectId, serializedNode) 46 47 { 47 let {id, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren} = serializedNode; 48 return new WI.HeapSnapshotNodeProxy(objectId, id, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren); 48 return new WI.HeapSnapshotNodeProxy(objectId, serializedNode); 49 49 } 50 50 -
trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js
r220119 r241784 61 61 62 62 if (columnIdentifier === "className") { 63 let {className} = this._data; 63 const internal = false; 64 let {className, isObjectSubcategory} = this._data; 64 65 let fragment = document.createDocumentFragment(); 65 66 let iconElement = fragment.appendChild(document.createElement("img")); 66 iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className ));67 iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className, internal, isObjectSubcategory)); 67 68 let nameElement = fragment.appendChild(document.createElement("span")); 68 69 nameElement.classList.add("class-name"); -
trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClusterContentView.js
r220119 r241784 59 59 // Static 60 60 61 static iconStyleClassNameForClassName(className, internal )61 static iconStyleClassNameForClassName(className, internal, isObjectType) 62 62 { 63 63 if (internal) 64 64 return "native"; 65 if (isObjectType) 66 return "object"; 65 67 66 68 switch (className) { -
trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js
r241216 r241784 219 219 let skipInternalOnlyObjects = !WI.settings.debugShowInternalObjectsInHeapSnapshot.value; 220 220 221 for (let [className, {size, retainedSize, count, internalCount, deadCount}] of this.heapSnapshot.categories) { 221 for (let [className, {size, retainedSize, count, internalCount, deadCount, objectCount}] of this.heapSnapshot.categories) { 222 console.assert(count > 0); 223 222 224 // Possibly skip internal only classes. 223 225 if (skipInternalOnlyObjects && count === internalCount) … … 229 231 continue; 230 232 231 this.appendChild(new WI.HeapSnapshotClassDataGridNode({className, size, retainedSize, count: liveCount}, this)); 233 // If over half of the objects with this class name are Object sub-types, treat this as an Object category. 234 // This can happen if the page has a JavaScript Class with the same name as a native class. 235 let isObjectSubcategory = (objectCount / count) > 0.5; 236 237 this.appendChild(new WI.HeapSnapshotClassDataGridNode({className, size, retainedSize, isObjectSubcategory, count: liveCount}, this)); 232 238 } 233 239 -
trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotInstanceDataGridNode.js
r220119 r241784 147 147 148 148 if (columnIdentifier === "className") { 149 let {className, id, internal } = this._node;149 let {className, id, internal, isObjectType} = this._node; 150 150 let containerElement = document.createElement("span"); 151 151 containerElement.addEventListener("contextmenu", this._contextMenuHandler.bind(this)); 152 152 153 153 let iconElement = containerElement.appendChild(document.createElement("img")); 154 iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className, internal ));154 iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className, internal, isObjectType)); 155 155 156 156 if (this._edge) { … … 411 411 412 412 let iconElement = containerElement.appendChild(document.createElement("img")); 413 iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(node.className, node.internal ));413 iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(node.className, node.internal, node.isObjectType)); 414 414 415 415 let classNameElement = containerElement.appendChild(document.createElement("span")); -
trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js
r241219 r241784 31 31 32 32 // nodes 33 // [<0:id>, <1:size>, <2:classNameTableIndex>, <3: internal>]33 // [<0:id>, <1:size>, <2:classNameTableIndex>, <3:flags>] 34 34 const nodeFieldCount = 4; 35 35 const nodeIdOffset = 0; 36 36 const nodeSizeOffset = 1; 37 37 const nodeClassNameOffset = 2; 38 const node InternalOffset = 3;38 const nodeFlagsOffset = 3; 39 39 const gcDebuggingNodeFieldCount = 7; 40 41 // node flags 42 const internalFlagsMask = (1 << 0); 43 const objectTypeMask = (1 << 1); 40 44 41 45 // edges … … 52 56 const rootNodeIdentifier = 0; 53 57 58 // Version Differences: 59 // - In Version 1, node[3] now named <flags> was the value 0 or 1 indicating not-internal or internal. 60 // - In Version 2, this became a bitmask so multiple flags could be included without modifying the size. 61 // 54 62 // Terminology: 55 63 // - `nodeIndex` is an index into the `nodes` list. … … 86 94 87 95 let {version, type, nodes, nodeClassNames, edges, edgeTypes, edgeNames} = json; 88 console.assert(version === 1 , "Expect JavaScriptCore Heap Snapshot version 1");96 console.assert(version === 1 || version === 2, "Expect JavaScriptCore Heap Snapshot version 1 or 2"); 89 97 console.assert(!type || (type === "Inspector" || type === "GCDebugging"), "Expect an Inspector / GCDebugging Heap Snapshot"); 90 98 … … 166 174 let size = nodes[nodeIndex + nodeSizeOffset]; 167 175 let retainedSize = nodeOrdinalToRetainedSizes[nodeOrdinal]; 168 let internal = nodes[nodeIndex + nodeInternalOffset] ? true : false;176 let flags = nodes[nodeIndex + nodeFlagsOffset]; 169 177 let dead = nodeOrdinalIsDead[nodeOrdinal] ? true : false; 170 178 171 179 let category = categories[className]; 172 180 if (!category) 173 category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0 };181 category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0, objectCount: 0}; 174 182 175 183 category.size += size; 176 184 category.retainedSize += retainedSize; 177 185 category.count += 1; 178 if ( internal)186 if (flags & internalFlagsMask) 179 187 category.internalCount += 1; 188 if (flags & objectTypeMask) 189 category.objectCount += 1; 180 190 if (dead) 181 191 category.deadCount += 1; … … 423 433 let edgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; 424 434 let hasChildren = this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; 435 let nodeFlags = this._nodes[nodeIndex + nodeFlagsOffset]; 425 436 426 437 let dominatorNodeOrdinal = this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal]; … … 433 444 size: this._nodes[nodeIndex + nodeSizeOffset], 434 445 retainedSize: this._nodeOrdinalToRetainedSizes[nodeOrdinal], 435 internal: this._nodes[nodeIndex + nodeInternalOffset] ? true : false, 446 internal: nodeFlags & internalFlagsMask ? true : false, 447 isObjectType: nodeFlags & objectTypeMask ? true : false, 436 448 gcRoot: this._nodeOrdinalIsGCRoot[nodeOrdinal] ? true : false, 437 449 dead: this._nodeOrdinalIsDead[nodeOrdinal] ? true : false, … … 760 772 let fromNodeOrdinal = this._incomingNodes[incomingEdgeIndex]; 761 773 let fromNodeIndex = fromNodeOrdinal * this._nodeFieldCount; 762 let fromNodeIsInternal = this._nodes[fromNodeIndex + node InternalOffset];774 let fromNodeIsInternal = this._nodes[fromNodeIndex + nodeFlagsOffset] & internalFlagsMask; 763 775 if (fromNodeIsInternal) 764 776 continue; -
trunk/Tools/GCHeapInspector/heap-analysis/HeapSnapshot.js
r235271 r241784 31 31 32 32 // nodes 33 // [<0:id>, <1:size>, <2:classNameTableIndex>, <3: internal>, <4:labelIndex>, <5:address>, <6:wrapped address>]34 let nodeFieldCount = 7;33 // [<0:id>, <1:size>, <2:classNameTableIndex>, <3:flags>, <4:labelIndex>, <5:address>, <6:wrapped address>] 34 const nodeFieldCount = 7; 35 35 const nodeIdOffset = 0; 36 36 const nodeSizeOffset = 1; 37 37 const nodeClassNameOffset = 2; 38 const node InternalOffset = 3;38 const nodeFlagsOffset = 3; 39 39 const nodeLabelOffset = 4; 40 40 const nodeAddressOffset = 5; 41 41 const nodeWrappedAddressOffset = 6; 42 43 // node flags 44 const internalFlagsMask = (1 << 0); 45 const objectTypeMask = (1 << 1); 42 46 43 47 // edges … … 94 98 95 99 let {version, type, nodes, nodeClassNames, edges, edgeTypes, edgeNames, roots, labels} = json; 96 console.assert(version === 1 , "Expect JavaScriptCore Heap Snapshot version 1");100 console.assert(version === 1 || version === 2, "Expect JavaScriptCore Heap Snapshot version 1 or 2"); 97 101 console.assert(type === "GCDebugging", "Expect a GCDebugging-type snapshot"); 98 102 … … 200 204 let size = nodes[nodeIndex + nodeSizeOffset]; 201 205 let retainedSize = nodeOrdinalToRetainedSizes[nodeOrdinal]; 202 let internal = nodes[nodeIndex + nodeInternalOffset] ? true : false;206 let flags = nodes[nodeIndex + nodeFlagsOffset]; 203 207 let dead = nodeOrdinalIsDead[nodeOrdinal] ? true : false; 204 208 205 209 let category = categories[className]; 206 210 if (!category) 207 category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0 };211 category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0, objectCount: 0}; 208 212 209 213 category.size += size; 210 214 category.retainedSize += retainedSize; 211 215 category.count += 1; 212 if ( internal)216 if (flags & internalFlagsMask) 213 217 category.internalCount += 1; 218 if (flags & objectTypeMask) 219 category.objectCount += 1; 214 220 if (dead) 215 221 category.deadCount += 1; … … 479 485 let edgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; 480 486 let hasChildren = this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; 487 let nodeFlags = this._nodes[nodeIndex + nodeFlagsOffset]; 481 488 482 489 let dominatorNodeOrdinal = this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal]; … … 489 496 size: this._nodes[nodeIndex + nodeSizeOffset], 490 497 retainedSize: this._nodeOrdinalToRetainedSizes[nodeOrdinal], 491 internal: this._nodes[nodeIndex + nodeInternalOffset] ? true : false, 498 internal: nodeFlags & internalFlagsMask ? true : false, 499 isObjectType: nodeFlags & objectTypeMask ? true : false, 492 500 gcRoot: this._nodeOrdinalIsGCRoot[nodeOrdinal] ? true : false, 493 501 markedRoot : this._rootIdentifierToReasons.has(nodeIdentifier), … … 830 838 let fromNodeOrdinal = this._incomingNodes[incomingEdgeIndex]; 831 839 let fromNodeIndex = fromNodeOrdinal * nodeFieldCount; 832 // let fromNodeIsInternal = this._nodes[fromNodeIndex + nodeInternalOffset];833 // if (fromNodeIsInternal)834 // continue;835 840 836 841 let edgeIndex = this._incomingEdges[incomingEdgeIndex];
Note: See TracChangeset
for help on using the changeset viewer.