Chromium Code Reviews| 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 1584 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, |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1632 | 1654 |
| 1633 | 1655 |
| 1634 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, | 1656 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| 1635 int children_count, | 1657 int children_count, |
| 1636 int retainers_count) { | 1658 int retainers_count) { |
| 1637 if (object == kInternalRootObject) { | 1659 if (object == kInternalRootObject) { |
| 1638 ASSERT(retainers_count == 0); | 1660 ASSERT(retainers_count == 0); |
| 1639 return snapshot_->AddRootEntry(children_count); | 1661 return snapshot_->AddRootEntry(children_count); |
| 1640 } else if (object == kGcRootsObject) { | 1662 } else if (object == kGcRootsObject) { |
| 1641 return snapshot_->AddGcRootsEntry(children_count, retainers_count); | 1663 return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
| 1664 } else if (object->IsJSGlobalObject()) { | |
| 1665 const char* tag = objects_tags_.GetTag(object); | |
| 1666 const char* name = collection_->names()->GetName( | |
| 1667 GetConstructorNameForHeapProfile( | |
| 1668 JSObject::cast(object))); | |
|
Vitaly Repeshko
2011/05/29 23:01:34
nit: Fits on the previous line?
mnaganov (inactive)
2011/05/30 14:20:42
Done.
| |
| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1773 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); | 1808 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); |
| 1774 } | 1809 } |
| 1775 } | 1810 } |
| 1776 static void MarkVisitedField(HeapObject* obj, int offset) { | 1811 static void MarkVisitedField(HeapObject* obj, int offset) { |
| 1777 if (offset < 0) return; | 1812 if (offset < 0) return; |
| 1778 Address field = obj->address() + offset; | 1813 Address field = obj->address() + offset; |
| 1779 ASSERT(!Memory::Object_at(field)->IsFailure()); | 1814 ASSERT(!Memory::Object_at(field)->IsFailure()); |
| 1780 ASSERT(Memory::Object_at(field)->IsHeapObject()); | 1815 ASSERT(Memory::Object_at(field)->IsHeapObject()); |
| 1781 *field |= kFailureTag; | 1816 *field |= kFailureTag; |
| 1782 } | 1817 } |
| 1818 | |
| 1783 private: | 1819 private: |
| 1784 bool CheckVisitedAndUnmark(Object** field) { | 1820 bool CheckVisitedAndUnmark(Object** field) { |
| 1785 if ((*field)->IsFailure()) { | 1821 if ((*field)->IsFailure()) { |
| 1786 intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask; | 1822 intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask; |
| 1787 *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag); | 1823 *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag); |
| 1788 ASSERT((*field)->IsHeapObject()); | 1824 ASSERT((*field)->IsHeapObject()); |
| 1789 return true; | 1825 return true; |
| 1790 } | 1826 } |
| 1791 return false; | 1827 return false; |
| 1792 } | 1828 } |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2199 HeapEntry* child_entry = GetEntry(child_obj); | 2235 HeapEntry* child_entry = GetEntry(child_obj); |
| 2200 if (child_entry != NULL) { | 2236 if (child_entry != NULL) { |
| 2201 filler_->SetIndexedAutoIndexReference( | 2237 filler_->SetIndexedAutoIndexReference( |
| 2202 HeapGraphEdge::kElement, | 2238 HeapGraphEdge::kElement, |
| 2203 kGcRootsObject, snapshot_->gc_roots(), | 2239 kGcRootsObject, snapshot_->gc_roots(), |
| 2204 child_obj, child_entry); | 2240 child_obj, child_entry); |
| 2205 } | 2241 } |
| 2206 } | 2242 } |
| 2207 | 2243 |
| 2208 | 2244 |
| 2245 class GlobalObjectsCounter : public ObjectVisitor { | |
| 2246 public: | |
| 2247 GlobalObjectsCounter() : count_(0) {} | |
| 2248 void VisitPointers(Object** start, Object** end) { | |
|
Vitaly Repeshko
2011/05/29 23:01:34
nit: virtual
mnaganov (inactive)
2011/05/30 14:20:42
Done.
| |
| 2249 for (Object** p = start; p < end; p++) { | |
| 2250 if ((*p)->IsGlobalContext()) | |
| 2251 ++count_; | |
| 2252 } | |
| 2253 } | |
| 2254 int count() { return count_; } | |
| 2255 | |
| 2256 private: | |
| 2257 int count_; | |
| 2258 }; | |
| 2259 | |
| 2260 | |
| 2261 class GlobalObjectsEnumerator : public ObjectVisitor { | |
| 2262 public: | |
| 2263 explicit GlobalObjectsEnumerator(int length) | |
| 2264 : length_(length), | |
| 2265 count_(0), | |
| 2266 objects_(NewArray<Handle<JSGlobalObject> >(length)) {} | |
| 2267 ~GlobalObjectsEnumerator() { | |
| 2268 DeleteArray(objects_); | |
| 2269 } | |
| 2270 void VisitPointers(Object** start, Object** end) { | |
|
Vitaly Repeshko
2011/05/29 23:01:34
nit: virtual
mnaganov (inactive)
2011/05/30 14:20:42
Done.
| |
| 2271 for (Object** p = start; count_ < length_ && p < end; p++) { | |
| 2272 if ((*p)->IsGlobalContext()) { | |
| 2273 Context* context = Context::cast(*p); | |
| 2274 JSObject* proxy = context->global_proxy(); | |
| 2275 if (proxy->IsJSGlobalProxy()) { | |
|
Vitaly Repeshko
2011/05/29 23:01:34
Given that this loop has more conditions than its
mnaganov (inactive)
2011/05/30 14:20:42
Fixed by eliminating the counter class.
| |
| 2276 Object* global = proxy->map()->prototype(); | |
| 2277 if (global->IsJSGlobalObject()) | |
|
Vitaly Repeshko
2011/05/29 23:01:34
nit: {}
mnaganov (inactive)
2011/05/30 14:20:42
Done.
| |
| 2278 objects_[count_++] = | |
| 2279 Handle<JSGlobalObject>(JSGlobalObject::cast(global)); | |
| 2280 } | |
| 2281 } | |
| 2282 } | |
| 2283 } | |
| 2284 int count() { return count_; } | |
| 2285 Handle<JSGlobalObject>* objects() { return objects_; } | |
| 2286 | |
| 2287 private: | |
| 2288 const int length_; | |
| 2289 int count_; | |
| 2290 Handle<JSGlobalObject>* objects_; | |
|
Vitaly Repeshko
2011/05/29 23:01:34
Can we use a growable collection of handles (e.g.
mnaganov (inactive)
2011/05/30 14:20:42
Sure. Sorry, I forgot about their existence.
| |
| 2291 }; | |
| 2292 | |
| 2293 | |
| 2294 // Modifies heap. Must not be run during heap traversal. | |
| 2295 void V8HeapExplorer::TagGlobalObjects() { | |
|
Vitaly Repeshko
2011/05/29 23:01:34
Random idea. I don't know how flexible we want to
mnaganov (inactive)
2011/05/30 14:20:42
Let's discuss it later.
| |
| 2296 Isolate* isolate = Isolate::Current(); | |
| 2297 GlobalObjectsCounter counter; | |
| 2298 isolate->global_handles()->IterateAllRoots(&counter); | |
| 2299 GlobalObjectsEnumerator enumerator(counter.count()); | |
| 2300 isolate->global_handles()->IterateAllRoots(&enumerator); | |
| 2301 Handle<String> document_string = | |
| 2302 isolate->factory()->NewStringFromAscii(CStrVector("document")); | |
| 2303 Handle<String> url_string = | |
| 2304 isolate->factory()->NewStringFromAscii(CStrVector("URL")); | |
| 2305 const char** urls = NewArray<const char*>(counter.count()); | |
| 2306 for (int i = 0; i < counter.count(); ++i) { | |
| 2307 urls[i] = NULL; | |
| 2308 Handle<JSGlobalObject>& go = enumerator.objects()[i]; | |
|
Vitaly Repeshko
2011/05/29 23:01:34
Reference is not needed here. "go" is too short.
mnaganov (inactive)
2011/05/30 14:20:42
Removed ref. s/go/global_obj/
| |
| 2309 Object* obj_document = go->GetPropertyNoExceptionThrown(*document_string); | |
|
Vitaly Repeshko
2011/05/29 23:01:34
This is not safe, because it asserts on failure/ex
mnaganov (inactive)
2011/05/30 14:20:42
Done.
| |
| 2310 if (obj_document->IsJSObject()) { | |
| 2311 JSObject* document = JSObject::cast(obj_document); | |
| 2312 Object* obj_url = document->GetProperty(*url_string)->ToObjectUnchecked(); | |
|
Vitaly Repeshko
2011/05/29 23:01:34
Also asserts on failure/exception.
mnaganov (inactive)
2011/05/30 14:20:42
Done.
| |
| 2313 if (obj_url->IsString()) { | |
| 2314 urls[i] = collection_->names()->GetName(String::cast(obj_url)); | |
| 2315 } | |
| 2316 } | |
| 2317 } | |
| 2318 | |
| 2319 AssertNoAllocation no_allocation; | |
| 2320 for (int i = 0; i < counter.count(); ++i) { | |
| 2321 objects_tags_.SetTag(*enumerator.objects()[i], urls[i]); | |
| 2322 } | |
| 2323 | |
| 2324 DeleteArray(urls); | |
| 2325 } | |
| 2326 | |
| 2327 | |
| 2209 class GlobalHandlesExtractor : public ObjectVisitor { | 2328 class GlobalHandlesExtractor : public ObjectVisitor { |
| 2210 public: | 2329 public: |
| 2211 explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) | 2330 explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) |
| 2212 : explorer_(explorer) {} | 2331 : explorer_(explorer) {} |
| 2213 virtual ~GlobalHandlesExtractor() {} | 2332 virtual ~GlobalHandlesExtractor() {} |
| 2214 virtual void VisitPointers(Object** start, Object** end) { | 2333 virtual void VisitPointers(Object** start, Object** end) { |
| 2215 UNREACHABLE(); | 2334 UNREACHABLE(); |
| 2216 } | 2335 } |
| 2217 virtual void VisitEmbedderReference(Object** p, uint16_t class_id) { | 2336 virtual void VisitEmbedderReference(Object** p, uint16_t class_id) { |
| 2218 explorer_->VisitSubtreeWrapper(p, class_id); | 2337 explorer_->VisitSubtreeWrapper(p, class_id); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2441 HeapEntry*) { | 2560 HeapEntry*) { |
| 2442 entries_->CountReference(parent_ptr, child_ptr); | 2561 entries_->CountReference(parent_ptr, child_ptr); |
| 2443 } | 2562 } |
| 2444 void SetNamedAutoIndexReference(HeapGraphEdge::Type, | 2563 void SetNamedAutoIndexReference(HeapGraphEdge::Type, |
| 2445 HeapThing parent_ptr, | 2564 HeapThing parent_ptr, |
| 2446 HeapEntry*, | 2565 HeapEntry*, |
| 2447 HeapThing child_ptr, | 2566 HeapThing child_ptr, |
| 2448 HeapEntry*) { | 2567 HeapEntry*) { |
| 2449 entries_->CountReference(parent_ptr, child_ptr); | 2568 entries_->CountReference(parent_ptr, child_ptr); |
| 2450 } | 2569 } |
| 2570 | |
| 2451 private: | 2571 private: |
| 2452 HeapEntriesMap* entries_; | 2572 HeapEntriesMap* entries_; |
| 2453 }; | 2573 }; |
| 2454 | 2574 |
| 2455 | 2575 |
| 2456 class SnapshotFiller : public SnapshotFillerInterface { | 2576 class SnapshotFiller : public SnapshotFillerInterface { |
| 2457 public: | 2577 public: |
| 2458 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) | 2578 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
| 2459 : snapshot_(snapshot), | 2579 : snapshot_(snapshot), |
| 2460 collection_(snapshot->collection()), | 2580 collection_(snapshot->collection()), |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2512 HeapEntry* child_entry) { | 2632 HeapEntry* child_entry) { |
| 2513 int child_index, retainer_index; | 2633 int child_index, retainer_index; |
| 2514 entries_->CountReference( | 2634 entries_->CountReference( |
| 2515 parent_ptr, child_ptr, &child_index, &retainer_index); | 2635 parent_ptr, child_ptr, &child_index, &retainer_index); |
| 2516 parent_entry->SetNamedReference(type, | 2636 parent_entry->SetNamedReference(type, |
| 2517 child_index, | 2637 child_index, |
| 2518 collection_->names()->GetName(child_index + 1), | 2638 collection_->names()->GetName(child_index + 1), |
| 2519 child_entry, | 2639 child_entry, |
| 2520 retainer_index); | 2640 retainer_index); |
| 2521 } | 2641 } |
| 2642 | |
| 2522 private: | 2643 private: |
| 2523 HeapSnapshot* snapshot_; | 2644 HeapSnapshot* snapshot_; |
| 2524 HeapSnapshotsCollection* collection_; | 2645 HeapSnapshotsCollection* collection_; |
| 2525 HeapEntriesMap* entries_; | 2646 HeapEntriesMap* entries_; |
| 2526 }; | 2647 }; |
| 2527 | 2648 |
| 2528 | 2649 |
| 2529 bool HeapSnapshotGenerator::GenerateSnapshot() { | 2650 bool HeapSnapshotGenerator::GenerateSnapshot() { |
| 2651 v8_heap_explorer_.TagGlobalObjects(); | |
| 2652 | |
| 2530 AssertNoAllocation no_alloc; | 2653 AssertNoAllocation no_alloc; |
| 2531 | 2654 |
| 2532 SetProgressTotal(4); // 2 passes + dominators + sizes. | 2655 SetProgressTotal(4); // 2 passes + dominators + sizes. |
| 2533 | 2656 |
| 2534 // Pass 1. Iterate heap contents to count entries and references. | 2657 // Pass 1. Iterate heap contents to count entries and references. |
| 2535 if (!CountEntriesAndReferences()) return false; | 2658 if (!CountEntriesAndReferences()) return false; |
| 2536 | 2659 |
| 2537 // Allocate and fill entries in the snapshot, allocate references. | 2660 // Allocate and fill entries in the snapshot, allocate references. |
| 2538 snapshot_->AllocateEntries(entries_.entries_count(), | 2661 snapshot_->AllocateEntries(entries_.entries_count(), |
| 2539 entries_.total_children_count(), | 2662 entries_.total_children_count(), |
| (...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3089 | 3212 |
| 3090 | 3213 |
| 3091 String* GetConstructorNameForHeapProfile(JSObject* object) { | 3214 String* GetConstructorNameForHeapProfile(JSObject* object) { |
| 3092 if (object->IsJSFunction()) return HEAP->closure_symbol(); | 3215 if (object->IsJSFunction()) return HEAP->closure_symbol(); |
| 3093 return object->constructor_name(); | 3216 return object->constructor_name(); |
| 3094 } | 3217 } |
| 3095 | 3218 |
| 3096 } } // namespace v8::internal | 3219 } } // namespace v8::internal |
| 3097 | 3220 |
| 3098 #endif // ENABLE_LOGGING_AND_PROFILING | 3221 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |