Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Side by Side Diff: src/profile-generator.cc

Issue 10086006: External references should not affect dominance relation. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressing comments. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698