OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 939 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
950 index_ = index; | 950 index_ = index; |
951 to_ = to; | 951 to_ = to; |
952 } | 952 } |
953 | 953 |
954 | 954 |
955 void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { | 955 void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
956 Init(child_index, kElement, index, to); | 956 Init(child_index, kElement, index, to); |
957 } | 957 } |
958 | 958 |
959 | 959 |
960 HeapEntry* HeapGraphEdge::From() { | |
961 return reinterpret_cast<HeapEntry*>(this - child_index_) - 1; | |
962 } | |
963 | |
964 | |
965 void HeapEntry::Init(HeapSnapshot* snapshot, | 960 void HeapEntry::Init(HeapSnapshot* snapshot, |
966 Type type, | 961 Type type, |
967 const char* name, | 962 const char* name, |
968 SnapshotObjectId id, | 963 SnapshotObjectId id, |
969 int self_size, | 964 int self_size, |
970 int children_count, | 965 int children_count, |
971 int retainers_count) { | 966 int retainers_count) { |
972 snapshot_ = snapshot; | 967 snapshot_ = snapshot; |
973 type_ = type; | 968 type_ = type; |
974 painted_ = false; | 969 painted_ = false; |
970 reachable_from_window_ = false; | |
975 name_ = name; | 971 name_ = name; |
976 self_size_ = self_size; | 972 self_size_ = self_size; |
977 retained_size_ = 0; | 973 retained_size_ = 0; |
978 entry_index_ = -1; | 974 entry_index_ = -1; |
979 children_count_ = children_count; | 975 children_count_ = children_count; |
980 retainers_count_ = retainers_count; | 976 retainers_count_ = retainers_count; |
981 dominator_ = NULL; | 977 dominator_ = NULL; |
982 id_ = id; | 978 id_ = id; |
983 } | 979 } |
984 | 980 |
(...skipping 1026 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2011 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { | 2007 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
2012 HeapEntry* entry = GetEntry(obj); | 2008 HeapEntry* entry = GetEntry(obj); |
2013 if (entry == NULL) return; // No interest in this object. | 2009 if (entry == NULL) return; // No interest in this object. |
2014 | 2010 |
2015 bool extract_indexed_refs = true; | 2011 bool extract_indexed_refs = true; |
2016 if (obj->IsJSGlobalProxy()) { | 2012 if (obj->IsJSGlobalProxy()) { |
2017 // We need to reference JS global objects from snapshot's root. | 2013 // We need to reference JS global objects from snapshot's root. |
2018 // We use JSGlobalProxy because this is what embedder (e.g. browser) | 2014 // We use JSGlobalProxy because this is what embedder (e.g. browser) |
2019 // uses for the global object. | 2015 // uses for the global object. |
2020 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); | 2016 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
2021 SetRootShortcutReference(proxy->map()->prototype()); | 2017 SetWindowReference(proxy->map()->prototype()); |
2022 } else if (obj->IsJSObject()) { | 2018 } else if (obj->IsJSObject()) { |
2023 JSObject* js_obj = JSObject::cast(obj); | 2019 JSObject* js_obj = JSObject::cast(obj); |
2024 ExtractClosureReferences(js_obj, entry); | 2020 ExtractClosureReferences(js_obj, entry); |
2025 ExtractPropertyReferences(js_obj, entry); | 2021 ExtractPropertyReferences(js_obj, entry); |
2026 ExtractElementReferences(js_obj, entry); | 2022 ExtractElementReferences(js_obj, entry); |
2027 ExtractInternalReferences(js_obj, entry); | 2023 ExtractInternalReferences(js_obj, entry); |
2028 SetPropertyReference( | 2024 SetPropertyReference( |
2029 obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); | 2025 obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); |
2030 if (obj->IsJSFunction()) { | 2026 if (obj->IsJSFunction()) { |
2031 JSFunction* js_fun = JSFunction::cast(js_obj); | 2027 JSFunction* js_fun = JSFunction::cast(js_obj); |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2279 break; | 2275 break; |
2280 } | 2276 } |
2281 } | 2277 } |
2282 } else { | 2278 } else { |
2283 StringDictionary* dictionary = js_obj->property_dictionary(); | 2279 StringDictionary* dictionary = js_obj->property_dictionary(); |
2284 int length = dictionary->Capacity(); | 2280 int length = dictionary->Capacity(); |
2285 for (int i = 0; i < length; ++i) { | 2281 for (int i = 0; i < length; ++i) { |
2286 Object* k = dictionary->KeyAt(i); | 2282 Object* k = dictionary->KeyAt(i); |
2287 if (dictionary->IsKey(k)) { | 2283 if (dictionary->IsKey(k)) { |
2288 Object* target = dictionary->ValueAt(i); | 2284 Object* target = dictionary->ValueAt(i); |
2289 SetPropertyReference( | |
2290 js_obj, entry, String::cast(k), target); | |
2291 // We assume that global objects can only have slow properties. | 2285 // We assume that global objects can only have slow properties. |
2292 if (target->IsJSGlobalPropertyCell()) { | 2286 Object* value = target->IsJSGlobalPropertyCell() |
2293 SetPropertyShortcutReference(js_obj, | 2287 ? JSGlobalPropertyCell::cast(target)->value() |
2294 entry, | 2288 : target; |
2295 String::cast(k), | 2289 if (String::cast(k)->length() > 0) { |
2296 JSGlobalPropertyCell::cast( | 2290 SetPropertyReference(js_obj, entry, String::cast(k), value); |
2297 target)->value()); | 2291 } else { |
2292 TagObject(value, "(hidden properties)"); | |
2293 SetInternalReference(js_obj, entry, "hidden_properties", value); | |
2298 } | 2294 } |
2299 } | 2295 } |
2300 } | 2296 } |
2301 } | 2297 } |
2302 } | 2298 } |
2303 | 2299 |
2304 | 2300 |
2305 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, | 2301 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
2306 HeapEntry* entry) { | 2302 HeapEntry* entry) { |
2307 if (js_obj->HasFastElements()) { | 2303 if (js_obj->HasFastElements()) { |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2656 | 2652 |
2657 | 2653 |
2658 void V8HeapExplorer::SetRootGcRootsReference() { | 2654 void V8HeapExplorer::SetRootGcRootsReference() { |
2659 filler_->SetIndexedAutoIndexReference( | 2655 filler_->SetIndexedAutoIndexReference( |
2660 HeapGraphEdge::kElement, | 2656 HeapGraphEdge::kElement, |
2661 kInternalRootObject, snapshot_->root(), | 2657 kInternalRootObject, snapshot_->root(), |
2662 kGcRootsObject, snapshot_->gc_roots()); | 2658 kGcRootsObject, snapshot_->gc_roots()); |
2663 } | 2659 } |
2664 | 2660 |
2665 | 2661 |
2666 void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { | 2662 void V8HeapExplorer::SetWindowReference(Object* child_obj) { |
2667 HeapEntry* child_entry = GetEntry(child_obj); | 2663 HeapEntry* child_entry = GetEntry(child_obj); |
2668 ASSERT(child_entry != NULL); | 2664 ASSERT(child_entry != NULL); |
2669 filler_->SetNamedAutoIndexReference( | 2665 filler_->SetNamedAutoIndexReference( |
2670 HeapGraphEdge::kShortcut, | 2666 HeapGraphEdge::kShortcut, |
2671 kInternalRootObject, snapshot_->root(), | 2667 kInternalRootObject, snapshot_->root(), |
2672 child_obj, child_entry); | 2668 child_obj, child_entry); |
2673 } | 2669 } |
2674 | 2670 |
2675 | 2671 |
2676 void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { | 2672 void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2738 isolate->factory()->NewStringFromAscii(CStrVector("document")); | 2734 isolate->factory()->NewStringFromAscii(CStrVector("document")); |
2739 Handle<String> url_string = | 2735 Handle<String> url_string = |
2740 isolate->factory()->NewStringFromAscii(CStrVector("URL")); | 2736 isolate->factory()->NewStringFromAscii(CStrVector("URL")); |
2741 const char** urls = NewArray<const char*>(enumerator.count()); | 2737 const char** urls = NewArray<const char*>(enumerator.count()); |
2742 for (int i = 0, l = enumerator.count(); i < l; ++i) { | 2738 for (int i = 0, l = enumerator.count(); i < l; ++i) { |
2743 urls[i] = NULL; | 2739 urls[i] = NULL; |
2744 HandleScope scope; | 2740 HandleScope scope; |
2745 Handle<JSGlobalObject> global_obj = enumerator.at(i); | 2741 Handle<JSGlobalObject> global_obj = enumerator.at(i); |
2746 Object* obj_document; | 2742 Object* obj_document; |
2747 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && | 2743 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && |
2748 obj_document->IsJSObject()) { | 2744 obj_document->IsJSObject()) { |
2749 JSObject* document = JSObject::cast(obj_document); | 2745 JSObject* document = JSObject::cast(obj_document); |
2750 Object* obj_url; | 2746 Object* obj_url; |
2751 if (document->GetProperty(*url_string)->ToObject(&obj_url) && | 2747 if (document->GetProperty(*url_string)->ToObject(&obj_url) && |
2752 obj_url->IsString()) { | 2748 obj_url->IsString()) { |
2753 urls[i] = collection_->names()->GetName(String::cast(obj_url)); | 2749 urls[i] = collection_->names()->GetName(String::cast(obj_url)); |
2754 } | 2750 } |
2755 } | 2751 } |
2756 } | 2752 } |
2757 | 2753 |
2758 AssertNoAllocation no_allocation; | 2754 AssertNoAllocation no_allocation; |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3292 // in turn may relocate objects in property maps thus changing the heap | 3288 // in turn may relocate objects in property maps thus changing the heap |
3293 // layout and affecting retainer counts. This is not acceptable because | 3289 // layout and affecting retainer counts. This is not acceptable because |
3294 // number of retainers must not change between count and fill passes. | 3290 // number of retainers must not change between count and fill passes. |
3295 // To avoid this there's a separate postpass that set object names. | 3291 // To avoid this there's a separate postpass that set object names. |
3296 return v8_heap_explorer_.IterateAndExtractReferences(&filler) | 3292 return v8_heap_explorer_.IterateAndExtractReferences(&filler) |
3297 && dom_explorer_.IterateAndExtractReferences(&filler) | 3293 && dom_explorer_.IterateAndExtractReferences(&filler) |
3298 && v8_heap_explorer_.IterateAndSetObjectNames(&filler); | 3294 && v8_heap_explorer_.IterateAndSetObjectNames(&filler); |
3299 } | 3295 } |
3300 | 3296 |
3301 | 3297 |
3302 void HeapSnapshotGenerator::FillReversePostorderIndexes( | 3298 bool HeapSnapshotGenerator::IsWindowReference(const HeapGraphEdge& edge) { |
3299 ASSERT(edge.from() == snapshot_->root()); | |
3300 return edge.type() == HeapGraphEdge::kShortcut; | |
3301 } | |
3302 | |
3303 | |
3304 void HeapSnapshotGenerator::MarkWindowReachableObjects() { | |
3305 List<HeapEntry*> worklist; | |
3306 | |
3307 Vector<HeapGraphEdge> children = snapshot_->root()->children(); | |
3308 for (int i = 0; i < children.length(); ++i) { | |
3309 if (IsWindowReference(children[i])) { | |
3310 worklist.Add(children[i].to()); | |
3311 } | |
3312 } | |
3313 | |
3314 while (!worklist.is_empty()) { | |
3315 HeapEntry* entry = worklist.RemoveLast(); | |
3316 if (entry->reachable_from_window()) continue; | |
3317 entry->set_reachable_from_window(); | |
3318 Vector<HeapGraphEdge> children = entry->children(); | |
3319 for (int i = 0; i < children.length(); ++i) { | |
3320 HeapEntry* child = children[i].to(); | |
3321 if (!child->reachable_from_window()) { | |
3322 worklist.Add(child); | |
3323 } | |
3324 } | |
3325 } | |
3326 } | |
3327 | |
3328 | |
3329 static bool IsRetainingEdge(HeapGraphEdge* edge) { | |
3330 if (edge->type() == HeapGraphEdge::kShortcut) return false; | |
3331 // The edge is not retaining if it goes from system domain | |
3332 // (i.e. an object not reachable from window) to the user domain | |
3333 // (i.e. a reachable object). | |
3334 return edge->from()->reachable_from_window() | |
3335 || !edge->to()->reachable_from_window(); | |
3336 } | |
3337 | |
3338 | |
3339 void HeapSnapshotGenerator::FillPostorderIndexes( | |
yurys
2012/04/16 13:23:37
I think it is still reverse postorder, isn't it?
alexeif
2012/04/16 13:37:23
Why reverse? I think it's direct postorder.
yurys
2012/04/16 13:41:01
From http://en.wikipedia.org/wiki/Tree_traversal#P
alexeif
2012/04/16 13:45:00
The children is not ordered in our case. So speaki
| |
3303 Vector<HeapEntry*>* entries) { | 3340 Vector<HeapEntry*>* entries) { |
3304 snapshot_->ClearPaint(); | 3341 snapshot_->ClearPaint(); |
3305 int current_entry = 0; | 3342 int current_entry = 0; |
3306 List<HeapEntry*> nodes_to_visit; | 3343 List<HeapEntry*> nodes_to_visit; |
3307 nodes_to_visit.Add(snapshot_->root()); | 3344 HeapEntry* root = snapshot_->root(); |
3345 nodes_to_visit.Add(root); | |
3308 snapshot_->root()->paint(); | 3346 snapshot_->root()->paint(); |
3309 while (!nodes_to_visit.is_empty()) { | 3347 while (!nodes_to_visit.is_empty()) { |
3310 HeapEntry* entry = nodes_to_visit.last(); | 3348 HeapEntry* entry = nodes_to_visit.last(); |
3311 Vector<HeapGraphEdge> children = entry->children(); | 3349 Vector<HeapGraphEdge> children = entry->children(); |
3312 bool has_new_edges = false; | 3350 bool has_new_edges = false; |
3313 for (int i = 0; i < children.length(); ++i) { | 3351 for (int i = 0; i < children.length(); ++i) { |
3314 if (children[i].type() == HeapGraphEdge::kShortcut) continue; | 3352 if (entry != root && !IsRetainingEdge(&children[i])) continue; |
3315 HeapEntry* child = children[i].to(); | 3353 HeapEntry* child = children[i].to(); |
3316 if (!child->painted()) { | 3354 if (!child->painted()) { |
3317 nodes_to_visit.Add(child); | 3355 nodes_to_visit.Add(child); |
3318 child->paint(); | 3356 child->paint(); |
3319 has_new_edges = true; | 3357 has_new_edges = true; |
3320 } | 3358 } |
3321 } | 3359 } |
3322 if (!has_new_edges) { | 3360 if (!has_new_edges) { |
3323 entry->set_ordered_index(current_entry); | 3361 entry->set_ordered_index(current_entry); |
3324 (*entries)[current_entry++] = entry; | 3362 (*entries)[current_entry++] = entry; |
(...skipping 14 matching lines...) Expand all Loading... | |
3339 } | 3377 } |
3340 | 3378 |
3341 | 3379 |
3342 // The algorithm is based on the article: | 3380 // The algorithm is based on the article: |
3343 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" | 3381 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" |
3344 // Softw. Pract. Exper. 4 (2001), pp. 1-10. | 3382 // Softw. Pract. Exper. 4 (2001), pp. 1-10. |
3345 bool HeapSnapshotGenerator::BuildDominatorTree( | 3383 bool HeapSnapshotGenerator::BuildDominatorTree( |
3346 const Vector<HeapEntry*>& entries, | 3384 const Vector<HeapEntry*>& entries, |
3347 Vector<int>* dominators) { | 3385 Vector<int>* dominators) { |
3348 if (entries.length() == 0) return true; | 3386 if (entries.length() == 0) return true; |
3387 HeapEntry* root = snapshot_->root(); | |
3349 const int entries_length = entries.length(), root_index = entries_length - 1; | 3388 const int entries_length = entries.length(), root_index = entries_length - 1; |
3350 static const int kNoDominator = -1; | 3389 static const int kNoDominator = -1; |
3351 for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; | 3390 for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; |
3352 (*dominators)[root_index] = root_index; | 3391 (*dominators)[root_index] = root_index; |
3353 | 3392 |
3354 // The affected array is used to mark entries which dominators | 3393 // The affected array is used to mark entries which dominators |
3355 // have to be racalculated because of changes in their retainers. | 3394 // have to be racalculated because of changes in their retainers. |
3356 ScopedVector<bool> affected(entries_length); | 3395 ScopedVector<bool> affected(entries_length); |
3357 for (int i = 0; i < affected.length(); ++i) affected[i] = false; | 3396 for (int i = 0; i < affected.length(); ++i) affected[i] = false; |
3358 // Mark the root direct children as affected. | 3397 // Mark the root direct children as affected. |
3359 Vector<HeapGraphEdge> children = entries[root_index]->children(); | 3398 Vector<HeapGraphEdge> children = entries[root_index]->children(); |
3360 for (int i = 0; i < children.length(); ++i) { | 3399 for (int i = 0; i < children.length(); ++i) { |
3361 affected[children[i].to()->ordered_index()] = true; | 3400 affected[children[i].to()->ordered_index()] = true; |
3362 } | 3401 } |
3363 | 3402 |
3364 bool changed = true; | 3403 bool changed = true; |
3365 while (changed) { | 3404 while (changed) { |
3366 changed = false; | 3405 changed = false; |
3367 if (!ProgressReport(true)) return false; | 3406 if (!ProgressReport(true)) return false; |
3368 for (int i = root_index - 1; i >= 0; --i) { | 3407 for (int i = root_index - 1; i >= 0; --i) { |
3369 if (!affected[i]) continue; | 3408 if (!affected[i]) continue; |
3370 affected[i] = false; | 3409 affected[i] = false; |
3371 // If dominator of the entry has already been set to root, | 3410 // If dominator of the entry has already been set to root, |
3372 // then it can't propagate any further. | 3411 // then it can't propagate any further. |
3373 if ((*dominators)[i] == root_index) continue; | 3412 if ((*dominators)[i] == root_index) continue; |
3374 int new_idom_index = kNoDominator; | 3413 int new_idom_index = kNoDominator; |
3375 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); | 3414 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
3376 for (int j = 0; j < rets.length(); ++j) { | 3415 for (int j = 0; j < rets.length(); ++j) { |
3377 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; | 3416 if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; |
3378 int ret_index = rets[j]->From()->ordered_index(); | 3417 int ret_index = rets[j]->from()->ordered_index(); |
3379 if (dominators->at(ret_index) != kNoDominator) { | 3418 if (dominators->at(ret_index) != kNoDominator) { |
3380 new_idom_index = new_idom_index == kNoDominator | 3419 new_idom_index = new_idom_index == kNoDominator |
3381 ? ret_index | 3420 ? ret_index |
3382 : Intersect(ret_index, new_idom_index, *dominators); | 3421 : Intersect(ret_index, new_idom_index, *dominators); |
3383 // If idom has already reached the root, it doesn't make sense | 3422 // If idom has already reached the root, it doesn't make sense |
3384 // to check other retainers. | 3423 // to check other retainers. |
3385 if (new_idom_index == root_index) break; | 3424 if (new_idom_index == root_index) break; |
3386 } | 3425 } |
3387 } | 3426 } |
3388 if (new_idom_index != kNoDominator | 3427 if (new_idom_index != kNoDominator |
3389 && dominators->at(i) != new_idom_index) { | 3428 && dominators->at(i) != new_idom_index) { |
3390 (*dominators)[i] = new_idom_index; | 3429 (*dominators)[i] = new_idom_index; |
3391 changed = true; | 3430 changed = true; |
3392 Vector<HeapGraphEdge> children = entries[i]->children(); | 3431 Vector<HeapGraphEdge> children = entries[i]->children(); |
3393 for (int j = 0; j < children.length(); ++j) { | 3432 for (int j = 0; j < children.length(); ++j) { |
3394 affected[children[j].to()->ordered_index()] = true; | 3433 affected[children[j].to()->ordered_index()] = true; |
3395 } | 3434 } |
3396 } | 3435 } |
3397 } | 3436 } |
3398 } | 3437 } |
3399 return true; | 3438 return true; |
3400 } | 3439 } |
3401 | 3440 |
3402 | 3441 |
3403 bool HeapSnapshotGenerator::SetEntriesDominators() { | 3442 bool HeapSnapshotGenerator::SetEntriesDominators() { |
3404 // This array is used for maintaining reverse postorder of nodes. | 3443 MarkWindowReachableObjects(); |
3444 // This array is used for maintaining postorder of nodes. | |
3405 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); | 3445 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
3406 FillReversePostorderIndexes(&ordered_entries); | 3446 FillPostorderIndexes(&ordered_entries); |
3407 ScopedVector<int> dominators(ordered_entries.length()); | 3447 ScopedVector<int> dominators(ordered_entries.length()); |
3408 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; | 3448 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
3409 for (int i = 0; i < ordered_entries.length(); ++i) { | 3449 for (int i = 0; i < ordered_entries.length(); ++i) { |
3410 ASSERT(dominators[i] >= 0); | 3450 ASSERT(dominators[i] >= 0); |
3411 ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); | 3451 ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); |
3412 } | 3452 } |
3413 return true; | 3453 return true; |
3414 } | 3454 } |
3415 | 3455 |
3416 | 3456 |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3887 | 3927 |
3888 | 3928 |
3889 void HeapSnapshotJSONSerializer::SortHashMap( | 3929 void HeapSnapshotJSONSerializer::SortHashMap( |
3890 HashMap* map, List<HashMap::Entry*>* sorted_entries) { | 3930 HashMap* map, List<HashMap::Entry*>* sorted_entries) { |
3891 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) | 3931 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) |
3892 sorted_entries->Add(p); | 3932 sorted_entries->Add(p); |
3893 sorted_entries->Sort(SortUsingEntryValue); | 3933 sorted_entries->Sort(SortUsingEntryValue); |
3894 } | 3934 } |
3895 | 3935 |
3896 } } // namespace v8::internal | 3936 } } // namespace v8::internal |
OLD | NEW |