| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1078 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1089 + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT | 1089 + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT |
| 1090 } | 1090 } |
| 1091 | 1091 |
| 1092 | 1092 |
| 1093 class RetainedSizeCalculator { | 1093 class RetainedSizeCalculator { |
| 1094 public: | 1094 public: |
| 1095 RetainedSizeCalculator() | 1095 RetainedSizeCalculator() |
| 1096 : retained_size_(0) { | 1096 : retained_size_(0) { |
| 1097 } | 1097 } |
| 1098 | 1098 |
| 1099 int reained_size() const { return retained_size_; } | 1099 int retained_size() const { return retained_size_; } |
| 1100 | 1100 |
| 1101 void Apply(HeapEntry** entry_ptr) { | 1101 void Apply(HeapEntry** entry_ptr) { |
| 1102 if ((*entry_ptr)->painted_reachable()) { | 1102 if ((*entry_ptr)->painted_reachable()) { |
| 1103 retained_size_ += (*entry_ptr)->self_size(); | 1103 retained_size_ += (*entry_ptr)->self_size(); |
| 1104 } | 1104 } |
| 1105 } | 1105 } |
| 1106 | 1106 |
| 1107 private: | 1107 private: |
| 1108 int retained_size_; | 1108 int retained_size_; |
| 1109 }; | 1109 }; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1130 HeapEntry* child = children[i].to(); | 1130 HeapEntry* child = children[i].to(); |
| 1131 if (child != this && child->not_painted_reachable_from_others()) { | 1131 if (child != this && child->not_painted_reachable_from_others()) { |
| 1132 list.Add(child); | 1132 list.Add(child); |
| 1133 child->paint_reachable_from_others(); | 1133 child->paint_reachable_from_others(); |
| 1134 } | 1134 } |
| 1135 } | 1135 } |
| 1136 } | 1136 } |
| 1137 | 1137 |
| 1138 RetainedSizeCalculator ret_size_calc; | 1138 RetainedSizeCalculator ret_size_calc; |
| 1139 snapshot()->IterateEntries(&ret_size_calc); | 1139 snapshot()->IterateEntries(&ret_size_calc); |
| 1140 retained_size_ = ret_size_calc.reained_size(); | 1140 retained_size_ = ret_size_calc.retained_size(); |
| 1141 ASSERT((retained_size_ & kExactRetainedSizeTag) == 0); | 1141 ASSERT((retained_size_ & kExactRetainedSizeTag) == 0); |
| 1142 retained_size_ |= kExactRetainedSizeTag; | 1142 retained_size_ |= kExactRetainedSizeTag; |
| 1143 } | 1143 } |
| 1144 | 1144 |
| 1145 | 1145 |
| 1146 // It is very important to keep objects that form a heap snapshot | 1146 // It is very important to keep objects that form a heap snapshot |
| 1147 // as small as possible. | 1147 // as small as possible. |
| 1148 namespace { // Avoid littering the global namespace. | 1148 namespace { // Avoid littering the global namespace. |
| 1149 | 1149 |
| 1150 template <size_t ptr_size> struct SnapshotSizeConstants; | 1150 template <size_t ptr_size> struct SnapshotSizeConstants; |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 if (!obj->IsHeapObject()) return; | 1595 if (!obj->IsHeapObject()) return; |
| 1596 HeapObject* object = HeapObject::cast(obj); | 1596 HeapObject* object = HeapObject::cast(obj); |
| 1597 HashMap::Entry* cache_entry = | 1597 HashMap::Entry* cache_entry = |
| 1598 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); | 1598 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| 1599 if (cache_entry->value == NULL) { | 1599 if (cache_entry->value == NULL) { |
| 1600 cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; | 1600 cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; |
| 1601 } | 1601 } |
| 1602 } | 1602 } |
| 1603 | 1603 |
| 1604 | 1604 |
| 1605 const char* HeapObjectsSet::GetTag(Object* obj) { |
| 1606 HeapObject* object = HeapObject::cast(obj); |
| 1607 HashMap::Entry* cache_entry = |
| 1608 entries_.Lookup(object, HeapEntriesMap::Hash(object), false); |
| 1609 if (cache_entry != NULL |
| 1610 && cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) { |
| 1611 return reinterpret_cast<const char*>(cache_entry->value); |
| 1612 } else { |
| 1613 return NULL; |
| 1614 } |
| 1615 } |
| 1616 |
| 1617 |
| 1618 void HeapObjectsSet::SetTag(Object* obj, const char* tag) { |
| 1619 if (!obj->IsHeapObject()) return; |
| 1620 HeapObject* object = HeapObject::cast(obj); |
| 1621 HashMap::Entry* cache_entry = |
| 1622 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| 1623 cache_entry->value = const_cast<char*>(tag); |
| 1624 } |
| 1625 |
| 1626 |
| 1605 HeapObject *const V8HeapExplorer::kInternalRootObject = | 1627 HeapObject *const V8HeapExplorer::kInternalRootObject = |
| 1606 reinterpret_cast<HeapObject*>( | 1628 reinterpret_cast<HeapObject*>( |
| 1607 static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId)); | 1629 static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId)); |
| 1608 HeapObject *const V8HeapExplorer::kGcRootsObject = | 1630 HeapObject *const V8HeapExplorer::kGcRootsObject = |
| 1609 reinterpret_cast<HeapObject*>( | 1631 reinterpret_cast<HeapObject*>( |
| 1610 static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId)); | 1632 static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId)); |
| 1611 | 1633 |
| 1612 | 1634 |
| 1613 V8HeapExplorer::V8HeapExplorer( | 1635 V8HeapExplorer::V8HeapExplorer( |
| 1614 HeapSnapshot* snapshot, | 1636 HeapSnapshot* snapshot, |
| 1615 SnapshottingProgressReportingInterface* progress) | 1637 SnapshottingProgressReportingInterface* progress) |
| 1616 : snapshot_(snapshot), | 1638 : heap_(Isolate::Current()->heap()), |
| 1639 snapshot_(snapshot), |
| 1617 collection_(snapshot_->collection()), | 1640 collection_(snapshot_->collection()), |
| 1618 progress_(progress), | 1641 progress_(progress), |
| 1619 filler_(NULL) { | 1642 filler_(NULL) { |
| 1620 } | 1643 } |
| 1621 | 1644 |
| 1622 | 1645 |
| 1623 V8HeapExplorer::~V8HeapExplorer() { | 1646 V8HeapExplorer::~V8HeapExplorer() { |
| 1624 } | 1647 } |
| 1625 | 1648 |
| 1626 | 1649 |
| 1627 HeapEntry* V8HeapExplorer::AllocateEntry( | 1650 HeapEntry* V8HeapExplorer::AllocateEntry( |
| 1628 HeapThing ptr, int children_count, int retainers_count) { | 1651 HeapThing ptr, int children_count, int retainers_count) { |
| 1629 return AddEntry( | 1652 return AddEntry( |
| 1630 reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count); | 1653 reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count); |
| 1631 } | 1654 } |
| 1632 | 1655 |
| 1633 | 1656 |
| 1634 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, | 1657 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| 1635 int children_count, | 1658 int children_count, |
| 1636 int retainers_count) { | 1659 int retainers_count) { |
| 1637 if (object == kInternalRootObject) { | 1660 if (object == kInternalRootObject) { |
| 1638 ASSERT(retainers_count == 0); | 1661 ASSERT(retainers_count == 0); |
| 1639 return snapshot_->AddRootEntry(children_count); | 1662 return snapshot_->AddRootEntry(children_count); |
| 1640 } else if (object == kGcRootsObject) { | 1663 } else if (object == kGcRootsObject) { |
| 1641 return snapshot_->AddGcRootsEntry(children_count, retainers_count); | 1664 return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
| 1665 } else if (object->IsJSGlobalObject()) { |
| 1666 const char* tag = objects_tags_.GetTag(object); |
| 1667 const char* name = collection_->names()->GetName( |
| 1668 GetConstructorNameForHeapProfile(JSObject::cast(object))); |
| 1669 if (tag != NULL) { |
| 1670 name = collection_->names()->GetFormatted("%s / %s", name, tag); |
| 1671 } |
| 1672 return AddEntry(object, |
| 1673 HeapEntry::kObject, |
| 1674 name, |
| 1675 children_count, |
| 1676 retainers_count); |
| 1642 } else if (object->IsJSFunction()) { | 1677 } else if (object->IsJSFunction()) { |
| 1643 JSFunction* func = JSFunction::cast(object); | 1678 JSFunction* func = JSFunction::cast(object); |
| 1644 SharedFunctionInfo* shared = func->shared(); | 1679 SharedFunctionInfo* shared = func->shared(); |
| 1645 return AddEntry(object, | 1680 return AddEntry(object, |
| 1646 HeapEntry::kClosure, | 1681 HeapEntry::kClosure, |
| 1647 collection_->names()->GetName(String::cast(shared->name())), | 1682 collection_->names()->GetName(String::cast(shared->name())), |
| 1648 children_count, | 1683 children_count, |
| 1649 retainers_count); | 1684 retainers_count); |
| 1650 } else if (object->IsJSRegExp()) { | 1685 } else if (object->IsJSRegExp()) { |
| 1651 JSRegExp* re = JSRegExp::cast(object); | 1686 JSRegExp* re = JSRegExp::cast(object); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1684 } else if (object->IsScript()) { | 1719 } else if (object->IsScript()) { |
| 1685 Script* script = Script::cast(object); | 1720 Script* script = Script::cast(object); |
| 1686 return AddEntry(object, | 1721 return AddEntry(object, |
| 1687 HeapEntry::kCode, | 1722 HeapEntry::kCode, |
| 1688 script->name()->IsString() ? | 1723 script->name()->IsString() ? |
| 1689 collection_->names()->GetName( | 1724 collection_->names()->GetName( |
| 1690 String::cast(script->name())) | 1725 String::cast(script->name())) |
| 1691 : "", | 1726 : "", |
| 1692 children_count, | 1727 children_count, |
| 1693 retainers_count); | 1728 retainers_count); |
| 1694 } else if (object->IsFixedArray() || object->IsByteArray()) { | 1729 } else if (object->IsFixedArray() || |
| 1730 object->IsFixedDoubleArray() || |
| 1731 object->IsByteArray() || |
| 1732 object->IsExternalArray()) { |
| 1733 const char* tag = objects_tags_.GetTag(object); |
| 1695 return AddEntry(object, | 1734 return AddEntry(object, |
| 1696 HeapEntry::kArray, | 1735 HeapEntry::kArray, |
| 1697 "", | 1736 tag != NULL ? tag : "", |
| 1698 children_count, | 1737 children_count, |
| 1699 retainers_count); | 1738 retainers_count); |
| 1700 } else if (object->IsHeapNumber()) { | 1739 } else if (object->IsHeapNumber()) { |
| 1701 return AddEntry(object, | 1740 return AddEntry(object, |
| 1702 HeapEntry::kHeapNumber, | 1741 HeapEntry::kHeapNumber, |
| 1703 "number", | 1742 "number", |
| 1704 children_count, | 1743 children_count, |
| 1705 retainers_count); | 1744 retainers_count); |
| 1706 } | 1745 } |
| 1707 return AddEntry(object, | 1746 return AddEntry(object, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1772 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); | 1811 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); |
| 1773 } | 1812 } |
| 1774 } | 1813 } |
| 1775 static void MarkVisitedField(HeapObject* obj, int offset) { | 1814 static void MarkVisitedField(HeapObject* obj, int offset) { |
| 1776 if (offset < 0) return; | 1815 if (offset < 0) return; |
| 1777 Address field = obj->address() + offset; | 1816 Address field = obj->address() + offset; |
| 1778 ASSERT(!Memory::Object_at(field)->IsFailure()); | 1817 ASSERT(!Memory::Object_at(field)->IsFailure()); |
| 1779 ASSERT(Memory::Object_at(field)->IsHeapObject()); | 1818 ASSERT(Memory::Object_at(field)->IsHeapObject()); |
| 1780 *field |= kFailureTag; | 1819 *field |= kFailureTag; |
| 1781 } | 1820 } |
| 1821 |
| 1782 private: | 1822 private: |
| 1783 bool CheckVisitedAndUnmark(Object** field) { | 1823 bool CheckVisitedAndUnmark(Object** field) { |
| 1784 if ((*field)->IsFailure()) { | 1824 if ((*field)->IsFailure()) { |
| 1785 intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask; | 1825 intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask; |
| 1786 *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag); | 1826 *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag); |
| 1787 ASSERT((*field)->IsHeapObject()); | 1827 ASSERT((*field)->IsHeapObject()); |
| 1788 return true; | 1828 return true; |
| 1789 } | 1829 } |
| 1790 return false; | 1830 return false; |
| 1791 } | 1831 } |
| 1792 V8HeapExplorer* generator_; | 1832 V8HeapExplorer* generator_; |
| 1793 HeapObject* parent_obj_; | 1833 HeapObject* parent_obj_; |
| 1794 HeapEntry* parent_; | 1834 HeapEntry* parent_; |
| 1795 int next_index_; | 1835 int next_index_; |
| 1796 }; | 1836 }; |
| 1797 | 1837 |
| 1798 | 1838 |
| 1799 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { | 1839 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| 1800 HeapEntry* entry = GetEntry(obj); | 1840 HeapEntry* entry = GetEntry(obj); |
| 1801 if (entry == NULL) return; // No interest in this object. | 1841 if (entry == NULL) return; // No interest in this object. |
| 1802 | 1842 |
| 1843 bool extract_indexed_refs = true; |
| 1803 if (obj->IsJSGlobalProxy()) { | 1844 if (obj->IsJSGlobalProxy()) { |
| 1804 // We need to reference JS global objects from snapshot's root. | 1845 // We need to reference JS global objects from snapshot's root. |
| 1805 // We use JSGlobalProxy because this is what embedder (e.g. browser) | 1846 // We use JSGlobalProxy because this is what embedder (e.g. browser) |
| 1806 // uses for the global object. | 1847 // uses for the global object. |
| 1807 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); | 1848 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| 1808 SetRootShortcutReference(proxy->map()->prototype()); | 1849 SetRootShortcutReference(proxy->map()->prototype()); |
| 1809 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); | |
| 1810 IndexedReferencesExtractor refs_extractor(this, obj, entry); | |
| 1811 obj->Iterate(&refs_extractor); | |
| 1812 } else if (obj->IsJSObject()) { | 1850 } else if (obj->IsJSObject()) { |
| 1813 JSObject* js_obj = JSObject::cast(obj); | 1851 JSObject* js_obj = JSObject::cast(obj); |
| 1814 ExtractClosureReferences(js_obj, entry); | 1852 ExtractClosureReferences(js_obj, entry); |
| 1815 ExtractPropertyReferences(js_obj, entry); | 1853 ExtractPropertyReferences(js_obj, entry); |
| 1816 ExtractElementReferences(js_obj, entry); | 1854 ExtractElementReferences(js_obj, entry); |
| 1817 ExtractInternalReferences(js_obj, entry); | 1855 ExtractInternalReferences(js_obj, entry); |
| 1818 SetPropertyReference( | 1856 SetPropertyReference( |
| 1819 obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype()); | 1857 obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); |
| 1820 if (obj->IsJSFunction()) { | 1858 if (obj->IsJSFunction()) { |
| 1821 JSFunction* js_fun = JSFunction::cast(js_obj); | 1859 JSFunction* js_fun = JSFunction::cast(js_obj); |
| 1822 Object* proto_or_map = js_fun->prototype_or_initial_map(); | 1860 Object* proto_or_map = js_fun->prototype_or_initial_map(); |
| 1823 if (!proto_or_map->IsTheHole()) { | 1861 if (!proto_or_map->IsTheHole()) { |
| 1824 if (!proto_or_map->IsMap()) { | 1862 if (!proto_or_map->IsMap()) { |
| 1825 SetPropertyReference( | 1863 SetPropertyReference( |
| 1826 obj, entry, | 1864 obj, entry, |
| 1827 HEAP->prototype_symbol(), proto_or_map, | 1865 heap_->prototype_symbol(), proto_or_map, |
| 1828 JSFunction::kPrototypeOrInitialMapOffset); | 1866 JSFunction::kPrototypeOrInitialMapOffset); |
| 1829 } else { | 1867 } else { |
| 1830 SetPropertyReference( | 1868 SetPropertyReference( |
| 1831 obj, entry, | 1869 obj, entry, |
| 1832 HEAP->prototype_symbol(), js_fun->prototype()); | 1870 heap_->prototype_symbol(), js_fun->prototype()); |
| 1833 } | 1871 } |
| 1834 } | 1872 } |
| 1835 SetInternalReference(js_fun, entry, | 1873 SetInternalReference(js_fun, entry, |
| 1836 "shared", js_fun->shared(), | 1874 "shared", js_fun->shared(), |
| 1837 JSFunction::kSharedFunctionInfoOffset); | 1875 JSFunction::kSharedFunctionInfoOffset); |
| 1876 TagObject(js_fun->unchecked_context(), "(context)"); |
| 1838 SetInternalReference(js_fun, entry, | 1877 SetInternalReference(js_fun, entry, |
| 1839 "context", js_fun->unchecked_context(), | 1878 "context", js_fun->unchecked_context(), |
| 1840 JSFunction::kContextOffset); | 1879 JSFunction::kContextOffset); |
| 1880 TagObject(js_fun->literals(), "(function literals)"); |
| 1841 SetInternalReference(js_fun, entry, | 1881 SetInternalReference(js_fun, entry, |
| 1842 "literals", js_fun->literals(), | 1882 "literals", js_fun->literals(), |
| 1843 JSFunction::kLiteralsOffset); | 1883 JSFunction::kLiteralsOffset); |
| 1844 } | 1884 } |
| 1885 TagObject(js_obj->properties(), "(object properties)"); |
| 1845 SetInternalReference(obj, entry, | 1886 SetInternalReference(obj, entry, |
| 1846 "properties", js_obj->properties(), | 1887 "properties", js_obj->properties(), |
| 1847 JSObject::kPropertiesOffset); | 1888 JSObject::kPropertiesOffset); |
| 1889 TagObject(js_obj->elements(), "(object elements)"); |
| 1848 SetInternalReference(obj, entry, | 1890 SetInternalReference(obj, entry, |
| 1849 "elements", js_obj->elements(), | 1891 "elements", js_obj->elements(), |
| 1850 JSObject::kElementsOffset); | 1892 JSObject::kElementsOffset); |
| 1851 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); | |
| 1852 IndexedReferencesExtractor refs_extractor(this, obj, entry); | |
| 1853 obj->Iterate(&refs_extractor); | |
| 1854 } else if (obj->IsString()) { | 1893 } else if (obj->IsString()) { |
| 1855 if (obj->IsConsString()) { | 1894 if (obj->IsConsString()) { |
| 1856 ConsString* cs = ConsString::cast(obj); | 1895 ConsString* cs = ConsString::cast(obj); |
| 1857 SetInternalReference(obj, entry, 1, cs->first()); | 1896 SetInternalReference(obj, entry, 1, cs->first()); |
| 1858 SetInternalReference(obj, entry, 2, cs->second()); | 1897 SetInternalReference(obj, entry, 2, cs->second()); |
| 1859 } | 1898 } |
| 1899 extract_indexed_refs = false; |
| 1900 } else if (obj->IsGlobalContext()) { |
| 1901 Context* context = Context::cast(obj); |
| 1902 TagObject(context->jsfunction_result_caches(), |
| 1903 "(context func. result caches)"); |
| 1904 TagObject(context->normalized_map_cache(), "(context norm. map cache)"); |
| 1905 TagObject(context->runtime_context(), "(runtime context)"); |
| 1906 TagObject(context->map_cache(), "(context map cache)"); |
| 1907 TagObject(context->data(), "(context data)"); |
| 1860 } else if (obj->IsMap()) { | 1908 } else if (obj->IsMap()) { |
| 1861 Map* map = Map::cast(obj); | 1909 Map* map = Map::cast(obj); |
| 1862 SetInternalReference(obj, entry, | 1910 SetInternalReference(obj, entry, |
| 1863 "prototype", map->prototype(), Map::kPrototypeOffset); | 1911 "prototype", map->prototype(), Map::kPrototypeOffset); |
| 1864 SetInternalReference(obj, entry, | 1912 SetInternalReference(obj, entry, |
| 1865 "constructor", map->constructor(), | 1913 "constructor", map->constructor(), |
| 1866 Map::kConstructorOffset); | 1914 Map::kConstructorOffset); |
| 1867 if (!map->instance_descriptors()->IsEmpty()) { | 1915 if (!map->instance_descriptors()->IsEmpty()) { |
| 1916 TagObject(map->instance_descriptors(), "(map descriptors)"); |
| 1868 SetInternalReference(obj, entry, | 1917 SetInternalReference(obj, entry, |
| 1869 "descriptors", map->instance_descriptors(), | 1918 "descriptors", map->instance_descriptors(), |
| 1870 Map::kInstanceDescriptorsOrBitField3Offset); | 1919 Map::kInstanceDescriptorsOrBitField3Offset); |
| 1871 } | 1920 } |
| 1921 if (map->prototype_transitions() != heap_->empty_fixed_array()) { |
| 1922 TagObject(map->prototype_transitions(), "(prototype transitions)"); |
| 1923 SetInternalReference(obj, |
| 1924 entry, |
| 1925 "prototype_transitions", |
| 1926 map->prototype_transitions(), |
| 1927 Map::kPrototypeTransitionsOffset); |
| 1928 } |
| 1872 SetInternalReference(obj, entry, | 1929 SetInternalReference(obj, entry, |
| 1873 "code_cache", map->code_cache(), | 1930 "code_cache", map->code_cache(), |
| 1874 Map::kCodeCacheOffset); | 1931 Map::kCodeCacheOffset); |
| 1875 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); | |
| 1876 IndexedReferencesExtractor refs_extractor(this, obj, entry); | |
| 1877 obj->Iterate(&refs_extractor); | |
| 1878 } else if (obj->IsSharedFunctionInfo()) { | 1932 } else if (obj->IsSharedFunctionInfo()) { |
| 1879 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); | 1933 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); |
| 1880 SetInternalReference(obj, entry, | 1934 SetInternalReference(obj, entry, |
| 1881 "name", shared->name(), | 1935 "name", shared->name(), |
| 1882 SharedFunctionInfo::kNameOffset); | 1936 SharedFunctionInfo::kNameOffset); |
| 1883 SetInternalReference(obj, entry, | 1937 SetInternalReference(obj, entry, |
| 1884 "code", shared->unchecked_code(), | 1938 "code", shared->unchecked_code(), |
| 1885 SharedFunctionInfo::kCodeOffset); | 1939 SharedFunctionInfo::kCodeOffset); |
| 1940 TagObject(shared->scope_info(), "(function scope info)"); |
| 1941 SetInternalReference(obj, entry, |
| 1942 "scope_info", shared->scope_info(), |
| 1943 SharedFunctionInfo::kScopeInfoOffset); |
| 1886 SetInternalReference(obj, entry, | 1944 SetInternalReference(obj, entry, |
| 1887 "instance_class_name", shared->instance_class_name(), | 1945 "instance_class_name", shared->instance_class_name(), |
| 1888 SharedFunctionInfo::kInstanceClassNameOffset); | 1946 SharedFunctionInfo::kInstanceClassNameOffset); |
| 1889 SetInternalReference(obj, entry, | 1947 SetInternalReference(obj, entry, |
| 1890 "script", shared->script(), | 1948 "script", shared->script(), |
| 1891 SharedFunctionInfo::kScriptOffset); | 1949 SharedFunctionInfo::kScriptOffset); |
| 1892 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); | 1950 } else if (obj->IsScript()) { |
| 1893 IndexedReferencesExtractor refs_extractor(this, obj, entry); | 1951 Script* script = Script::cast(obj); |
| 1894 obj->Iterate(&refs_extractor); | 1952 SetInternalReference(obj, entry, |
| 1895 } else { | 1953 "source", script->source(), |
| 1954 Script::kSourceOffset); |
| 1955 SetInternalReference(obj, entry, |
| 1956 "name", script->name(), |
| 1957 Script::kNameOffset); |
| 1958 SetInternalReference(obj, entry, |
| 1959 "data", script->data(), |
| 1960 Script::kDataOffset); |
| 1961 SetInternalReference(obj, entry, |
| 1962 "context_data", script->context_data(), |
| 1963 Script::kContextOffset); |
| 1964 TagObject(script->line_ends(), "(script line ends)"); |
| 1965 SetInternalReference(obj, entry, |
| 1966 "line_ends", script->line_ends(), |
| 1967 Script::kLineEndsOffset); |
| 1968 } else if (obj->IsDescriptorArray()) { |
| 1969 DescriptorArray* desc_array = DescriptorArray::cast(obj); |
| 1970 if (desc_array->length() > DescriptorArray::kContentArrayIndex) { |
| 1971 Object* content_array = |
| 1972 desc_array->get(DescriptorArray::kContentArrayIndex); |
| 1973 TagObject(content_array, "(map descriptor content)"); |
| 1974 SetInternalReference(obj, entry, |
| 1975 "content", content_array, |
| 1976 FixedArray::OffsetOfElementAt( |
| 1977 DescriptorArray::kContentArrayIndex)); |
| 1978 } |
| 1979 } else if (obj->IsCodeCache()) { |
| 1980 CodeCache* code_cache = CodeCache::cast(obj); |
| 1981 TagObject(code_cache->default_cache(), "(default code cache)"); |
| 1982 SetInternalReference(obj, entry, |
| 1983 "default_cache", code_cache->default_cache(), |
| 1984 CodeCache::kDefaultCacheOffset); |
| 1985 TagObject(code_cache->normal_type_cache(), "(code type cache)"); |
| 1986 SetInternalReference(obj, entry, |
| 1987 "type_cache", code_cache->normal_type_cache(), |
| 1988 CodeCache::kNormalTypeCacheOffset); |
| 1989 } else if (obj->IsCode()) { |
| 1990 Code* code = Code::cast(obj); |
| 1991 TagObject(code->unchecked_relocation_info(), "(code relocation info)"); |
| 1992 TagObject(code->unchecked_deoptimization_data(), "(code deopt data)"); |
| 1993 } |
| 1994 if (extract_indexed_refs) { |
| 1896 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); | 1995 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
| 1897 IndexedReferencesExtractor refs_extractor(this, obj, entry); | 1996 IndexedReferencesExtractor refs_extractor(this, obj, entry); |
| 1898 obj->Iterate(&refs_extractor); | 1997 obj->Iterate(&refs_extractor); |
| 1899 } | 1998 } |
| 1900 } | 1999 } |
| 1901 | 2000 |
| 1902 | 2001 |
| 1903 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, | 2002 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, |
| 1904 HeapEntry* entry) { | 2003 HeapEntry* entry) { |
| 1905 if (js_obj->IsJSFunction()) { | 2004 if (js_obj->IsJSFunction()) { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2028 private: | 2127 private: |
| 2029 V8HeapExplorer* explorer_; | 2128 V8HeapExplorer* explorer_; |
| 2030 }; | 2129 }; |
| 2031 | 2130 |
| 2032 | 2131 |
| 2033 bool V8HeapExplorer::IterateAndExtractReferences( | 2132 bool V8HeapExplorer::IterateAndExtractReferences( |
| 2034 HeapIterator* iterator, | 2133 HeapIterator* iterator, |
| 2035 SnapshotFillerInterface* filler) { | 2134 SnapshotFillerInterface* filler) { |
| 2036 filler_ = filler; | 2135 filler_ = filler; |
| 2037 bool interrupted = false; | 2136 bool interrupted = false; |
| 2137 |
| 2038 // Heap iteration with filtering must be finished in any case. | 2138 // Heap iteration with filtering must be finished in any case. |
| 2039 for (HeapObject* obj = iterator->Next(); | 2139 for (HeapObject* obj = iterator->Next(); |
| 2040 obj != NULL; | 2140 obj != NULL; |
| 2041 obj = iterator->Next(), progress_->ProgressStep()) { | 2141 obj = iterator->Next(), progress_->ProgressStep()) { |
| 2042 if (!interrupted) { | 2142 if (!interrupted) { |
| 2043 ExtractReferences(obj); | 2143 ExtractReferences(obj); |
| 2044 if (!progress_->ProgressReport(false)) interrupted = true; | 2144 if (!progress_->ProgressReport(false)) interrupted = true; |
| 2045 } | 2145 } |
| 2046 } | 2146 } |
| 2047 if (interrupted) { | 2147 if (interrupted) { |
| 2048 filler_ = NULL; | 2148 filler_ = NULL; |
| 2049 return false; | 2149 return false; |
| 2050 } | 2150 } |
| 2051 SetRootGcRootsReference(); | 2151 SetRootGcRootsReference(); |
| 2052 RootsReferencesExtractor extractor(this); | 2152 RootsReferencesExtractor extractor(this); |
| 2053 HEAP->IterateRoots(&extractor, VISIT_ALL); | 2153 heap_->IterateRoots(&extractor, VISIT_ALL); |
| 2054 filler_ = NULL; | 2154 filler_ = NULL; |
| 2055 return progress_->ProgressReport(false); | 2155 return progress_->ProgressReport(false); |
| 2056 } | 2156 } |
| 2057 | 2157 |
| 2058 | 2158 |
| 2059 void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, | 2159 void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, |
| 2060 HeapEntry* parent_entry, | 2160 HeapEntry* parent_entry, |
| 2061 String* reference_name, | 2161 String* reference_name, |
| 2062 Object* child_obj) { | 2162 Object* child_obj) { |
| 2063 HeapEntry* child_entry = GetEntry(child_obj); | 2163 HeapEntry* child_entry = GetEntry(child_obj); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2198 HeapEntry* child_entry = GetEntry(child_obj); | 2298 HeapEntry* child_entry = GetEntry(child_obj); |
| 2199 if (child_entry != NULL) { | 2299 if (child_entry != NULL) { |
| 2200 filler_->SetIndexedAutoIndexReference( | 2300 filler_->SetIndexedAutoIndexReference( |
| 2201 HeapGraphEdge::kElement, | 2301 HeapGraphEdge::kElement, |
| 2202 kGcRootsObject, snapshot_->gc_roots(), | 2302 kGcRootsObject, snapshot_->gc_roots(), |
| 2203 child_obj, child_entry); | 2303 child_obj, child_entry); |
| 2204 } | 2304 } |
| 2205 } | 2305 } |
| 2206 | 2306 |
| 2207 | 2307 |
| 2308 void V8HeapExplorer::TagObject(Object* obj, const char* tag) { |
| 2309 if (obj->IsHeapObject() && |
| 2310 !obj->IsOddball() && |
| 2311 obj != heap_->raw_unchecked_empty_byte_array() && |
| 2312 obj != heap_->raw_unchecked_empty_fixed_array() && |
| 2313 obj != heap_->raw_unchecked_empty_fixed_double_array() && |
| 2314 obj != heap_->raw_unchecked_empty_descriptor_array()) { |
| 2315 objects_tags_.SetTag(obj, tag); |
| 2316 } |
| 2317 } |
| 2318 |
| 2319 |
| 2320 class GlobalObjectsEnumerator : public ObjectVisitor { |
| 2321 public: |
| 2322 virtual void VisitPointers(Object** start, Object** end) { |
| 2323 for (Object** p = start; p < end; p++) { |
| 2324 if ((*p)->IsGlobalContext()) { |
| 2325 Context* context = Context::cast(*p); |
| 2326 JSObject* proxy = context->global_proxy(); |
| 2327 if (proxy->IsJSGlobalProxy()) { |
| 2328 Object* global = proxy->map()->prototype(); |
| 2329 if (global->IsJSGlobalObject()) { |
| 2330 objects_.Add(Handle<JSGlobalObject>(JSGlobalObject::cast(global))); |
| 2331 } |
| 2332 } |
| 2333 } |
| 2334 } |
| 2335 } |
| 2336 int count() { return objects_.length(); } |
| 2337 Handle<JSGlobalObject>& at(int i) { return objects_[i]; } |
| 2338 |
| 2339 private: |
| 2340 List<Handle<JSGlobalObject> > objects_; |
| 2341 }; |
| 2342 |
| 2343 |
| 2344 // Modifies heap. Must not be run during heap traversal. |
| 2345 void V8HeapExplorer::TagGlobalObjects() { |
| 2346 Isolate* isolate = Isolate::Current(); |
| 2347 GlobalObjectsEnumerator enumerator; |
| 2348 isolate->global_handles()->IterateAllRoots(&enumerator); |
| 2349 Handle<String> document_string = |
| 2350 isolate->factory()->NewStringFromAscii(CStrVector("document")); |
| 2351 Handle<String> url_string = |
| 2352 isolate->factory()->NewStringFromAscii(CStrVector("URL")); |
| 2353 const char** urls = NewArray<const char*>(enumerator.count()); |
| 2354 for (int i = 0, l = enumerator.count(); i < l; ++i) { |
| 2355 urls[i] = NULL; |
| 2356 Handle<JSGlobalObject> global_obj = enumerator.at(i); |
| 2357 Object* obj_document; |
| 2358 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && |
| 2359 obj_document->IsJSObject()) { |
| 2360 JSObject* document = JSObject::cast(obj_document); |
| 2361 Object* obj_url; |
| 2362 if (document->GetProperty(*url_string)->ToObject(&obj_url) && |
| 2363 obj_url->IsString()) { |
| 2364 urls[i] = collection_->names()->GetName(String::cast(obj_url)); |
| 2365 } |
| 2366 } |
| 2367 } |
| 2368 |
| 2369 AssertNoAllocation no_allocation; |
| 2370 for (int i = 0, l = enumerator.count(); i < l; ++i) { |
| 2371 objects_tags_.SetTag(*enumerator.at(i), urls[i]); |
| 2372 } |
| 2373 |
| 2374 DeleteArray(urls); |
| 2375 } |
| 2376 |
| 2377 |
| 2208 class GlobalHandlesExtractor : public ObjectVisitor { | 2378 class GlobalHandlesExtractor : public ObjectVisitor { |
| 2209 public: | 2379 public: |
| 2210 explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) | 2380 explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) |
| 2211 : explorer_(explorer) {} | 2381 : explorer_(explorer) {} |
| 2212 virtual ~GlobalHandlesExtractor() {} | 2382 virtual ~GlobalHandlesExtractor() {} |
| 2213 virtual void VisitPointers(Object** start, Object** end) { | 2383 virtual void VisitPointers(Object** start, Object** end) { |
| 2214 UNREACHABLE(); | 2384 UNREACHABLE(); |
| 2215 } | 2385 } |
| 2216 virtual void VisitEmbedderReference(Object** p, uint16_t class_id) { | 2386 virtual void VisitEmbedderReference(Object** p, uint16_t class_id) { |
| 2217 explorer_->VisitSubtreeWrapper(p, class_id); | 2387 explorer_->VisitSubtreeWrapper(p, class_id); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2440 HeapEntry*) { | 2610 HeapEntry*) { |
| 2441 entries_->CountReference(parent_ptr, child_ptr); | 2611 entries_->CountReference(parent_ptr, child_ptr); |
| 2442 } | 2612 } |
| 2443 void SetNamedAutoIndexReference(HeapGraphEdge::Type, | 2613 void SetNamedAutoIndexReference(HeapGraphEdge::Type, |
| 2444 HeapThing parent_ptr, | 2614 HeapThing parent_ptr, |
| 2445 HeapEntry*, | 2615 HeapEntry*, |
| 2446 HeapThing child_ptr, | 2616 HeapThing child_ptr, |
| 2447 HeapEntry*) { | 2617 HeapEntry*) { |
| 2448 entries_->CountReference(parent_ptr, child_ptr); | 2618 entries_->CountReference(parent_ptr, child_ptr); |
| 2449 } | 2619 } |
| 2620 |
| 2450 private: | 2621 private: |
| 2451 HeapEntriesMap* entries_; | 2622 HeapEntriesMap* entries_; |
| 2452 }; | 2623 }; |
| 2453 | 2624 |
| 2454 | 2625 |
| 2455 class SnapshotFiller : public SnapshotFillerInterface { | 2626 class SnapshotFiller : public SnapshotFillerInterface { |
| 2456 public: | 2627 public: |
| 2457 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) | 2628 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
| 2458 : snapshot_(snapshot), | 2629 : snapshot_(snapshot), |
| 2459 collection_(snapshot->collection()), | 2630 collection_(snapshot->collection()), |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2511 HeapEntry* child_entry) { | 2682 HeapEntry* child_entry) { |
| 2512 int child_index, retainer_index; | 2683 int child_index, retainer_index; |
| 2513 entries_->CountReference( | 2684 entries_->CountReference( |
| 2514 parent_ptr, child_ptr, &child_index, &retainer_index); | 2685 parent_ptr, child_ptr, &child_index, &retainer_index); |
| 2515 parent_entry->SetNamedReference(type, | 2686 parent_entry->SetNamedReference(type, |
| 2516 child_index, | 2687 child_index, |
| 2517 collection_->names()->GetName(child_index + 1), | 2688 collection_->names()->GetName(child_index + 1), |
| 2518 child_entry, | 2689 child_entry, |
| 2519 retainer_index); | 2690 retainer_index); |
| 2520 } | 2691 } |
| 2692 |
| 2521 private: | 2693 private: |
| 2522 HeapSnapshot* snapshot_; | 2694 HeapSnapshot* snapshot_; |
| 2523 HeapSnapshotsCollection* collection_; | 2695 HeapSnapshotsCollection* collection_; |
| 2524 HeapEntriesMap* entries_; | 2696 HeapEntriesMap* entries_; |
| 2525 }; | 2697 }; |
| 2526 | 2698 |
| 2527 | 2699 |
| 2528 bool HeapSnapshotGenerator::GenerateSnapshot() { | 2700 bool HeapSnapshotGenerator::GenerateSnapshot() { |
| 2701 v8_heap_explorer_.TagGlobalObjects(); |
| 2702 |
| 2703 // TODO(gc) Profiler assumes that any object that is in the heap after |
| 2704 // full GC is reachable from the root when computing dominators. |
| 2705 // This is not true for weakly reachable objects. |
| 2706 // As a temporary solution we call GC twice. |
| 2707 Isolate::Current()->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask); |
| 2708 Isolate::Current()->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask); |
| 2709 |
| 2710 // Iterator creation should follow TagGlobalObjects as it can allocate. |
| 2529 HeapIterator set_progress_heap_iterator; | 2711 HeapIterator set_progress_heap_iterator; |
| 2530 HeapIterator count_entries_heap_iterator; | 2712 HeapIterator count_entries_heap_iterator; |
| 2531 HeapIterator fill_references_heap_iterator; | 2713 HeapIterator fill_references_heap_iterator; |
| 2714 |
| 2532 AssertNoAllocation no_alloc; | 2715 AssertNoAllocation no_alloc; |
| 2533 | 2716 |
| 2534 SetProgressTotal(&set_progress_heap_iterator, | 2717 SetProgressTotal(&set_progress_heap_iterator, |
| 2535 4); // 2 passes + dominators + sizes. | 2718 4); // 2 passes + dominators + sizes. |
| 2536 | 2719 |
| 2537 // Pass 1. Iterate heap contents to count entries and references. | 2720 // Pass 1. Iterate heap contents to count entries and references. |
| 2538 if (!CountEntriesAndReferences(&count_entries_heap_iterator)) return false; | 2721 if (!CountEntriesAndReferences(&count_entries_heap_iterator)) return false; |
| 2539 | 2722 |
| 2540 // Allocate and fill entries in the snapshot, allocate references. | 2723 // Allocate and fill entries in the snapshot, allocate references. |
| 2541 snapshot_->AllocateEntries(entries_.entries_count(), | 2724 snapshot_->AllocateEntries(entries_.entries_count(), |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3093 | 3276 |
| 3094 | 3277 |
| 3095 String* GetConstructorNameForHeapProfile(JSObject* object) { | 3278 String* GetConstructorNameForHeapProfile(JSObject* object) { |
| 3096 if (object->IsJSFunction()) return HEAP->closure_symbol(); | 3279 if (object->IsJSFunction()) return HEAP->closure_symbol(); |
| 3097 return object->constructor_name(); | 3280 return object->constructor_name(); |
| 3098 } | 3281 } |
| 3099 | 3282 |
| 3100 } } // namespace v8::internal | 3283 } } // namespace v8::internal |
| 3101 | 3284 |
| 3102 #endif // ENABLE_LOGGING_AND_PROFILING | 3285 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |