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 children_count_ = children_count; | 974 children_count_ = children_count; |
979 retainers_count_ = retainers_count; | 975 retainers_count_ = retainers_count; |
980 dominator_ = NULL; | 976 dominator_ = NULL; |
981 id_ = id; | 977 id_ = id; |
982 } | 978 } |
983 | 979 |
984 | 980 |
(...skipping 1166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2151 break; | 2147 break; |
2152 } | 2148 } |
2153 } | 2149 } |
2154 } else { | 2150 } else { |
2155 StringDictionary* dictionary = js_obj->property_dictionary(); | 2151 StringDictionary* dictionary = js_obj->property_dictionary(); |
2156 int length = dictionary->Capacity(); | 2152 int length = dictionary->Capacity(); |
2157 for (int i = 0; i < length; ++i) { | 2153 for (int i = 0; i < length; ++i) { |
2158 Object* k = dictionary->KeyAt(i); | 2154 Object* k = dictionary->KeyAt(i); |
2159 if (dictionary->IsKey(k)) { | 2155 if (dictionary->IsKey(k)) { |
2160 Object* target = dictionary->ValueAt(i); | 2156 Object* target = dictionary->ValueAt(i); |
2161 SetPropertyReference( | |
2162 js_obj, entry, String::cast(k), target); | |
2163 // We assume that global objects can only have slow properties. | 2157 // We assume that global objects can only have slow properties. |
2164 if (target->IsJSGlobalPropertyCell()) { | 2158 Object* value = target->IsJSGlobalPropertyCell() |
2165 SetPropertyShortcutReference(js_obj, | 2159 ? JSGlobalPropertyCell::cast(target)->value() |
2166 entry, | 2160 : target; |
2167 String::cast(k), | 2161 if (String::cast(k)->length() > 0) { |
2168 JSGlobalPropertyCell::cast( | 2162 SetPropertyReference(js_obj, entry, String::cast(k), value); |
2169 target)->value()); | 2163 } else { |
| 2164 TagObject(value, "(hidden properties)"); |
| 2165 SetInternalReference(js_obj, entry, "hidden_properties", value); |
2170 } | 2166 } |
2171 } | 2167 } |
2172 } | 2168 } |
2173 } | 2169 } |
2174 } | 2170 } |
2175 | 2171 |
2176 | 2172 |
2177 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, | 2173 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
2178 HeapEntry* entry) { | 2174 HeapEntry* entry) { |
2179 if (js_obj->HasFastElements()) { | 2175 if (js_obj->HasFastElements()) { |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2610 isolate->factory()->NewStringFromAscii(CStrVector("document")); | 2606 isolate->factory()->NewStringFromAscii(CStrVector("document")); |
2611 Handle<String> url_string = | 2607 Handle<String> url_string = |
2612 isolate->factory()->NewStringFromAscii(CStrVector("URL")); | 2608 isolate->factory()->NewStringFromAscii(CStrVector("URL")); |
2613 const char** urls = NewArray<const char*>(enumerator.count()); | 2609 const char** urls = NewArray<const char*>(enumerator.count()); |
2614 for (int i = 0, l = enumerator.count(); i < l; ++i) { | 2610 for (int i = 0, l = enumerator.count(); i < l; ++i) { |
2615 urls[i] = NULL; | 2611 urls[i] = NULL; |
2616 HandleScope scope; | 2612 HandleScope scope; |
2617 Handle<JSGlobalObject> global_obj = enumerator.at(i); | 2613 Handle<JSGlobalObject> global_obj = enumerator.at(i); |
2618 Object* obj_document; | 2614 Object* obj_document; |
2619 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && | 2615 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && |
2620 obj_document->IsJSObject()) { | 2616 obj_document->IsJSObject()) { |
2621 JSObject* document = JSObject::cast(obj_document); | 2617 JSObject* document = JSObject::cast(obj_document); |
2622 Object* obj_url; | 2618 Object* obj_url; |
2623 if (document->GetProperty(*url_string)->ToObject(&obj_url) && | 2619 if (document->GetProperty(*url_string)->ToObject(&obj_url) && |
2624 obj_url->IsString()) { | 2620 obj_url->IsString()) { |
2625 urls[i] = collection_->names()->GetName(String::cast(obj_url)); | 2621 urls[i] = collection_->names()->GetName(String::cast(obj_url)); |
2626 } | 2622 } |
2627 } | 2623 } |
2628 } | 2624 } |
2629 | 2625 |
2630 AssertNoAllocation no_allocation; | 2626 AssertNoAllocation no_allocation; |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3164 // in turn may relocate objects in property maps thus changing the heap | 3160 // in turn may relocate objects in property maps thus changing the heap |
3165 // layout and affecting retainer counts. This is not acceptable because | 3161 // layout and affecting retainer counts. This is not acceptable because |
3166 // number of retainers must not change between count and fill passes. | 3162 // number of retainers must not change between count and fill passes. |
3167 // To avoid this there's a separate postpass that set object names. | 3163 // To avoid this there's a separate postpass that set object names. |
3168 return v8_heap_explorer_.IterateAndExtractReferences(&filler) | 3164 return v8_heap_explorer_.IterateAndExtractReferences(&filler) |
3169 && dom_explorer_.IterateAndExtractReferences(&filler) | 3165 && dom_explorer_.IterateAndExtractReferences(&filler) |
3170 && v8_heap_explorer_.IterateAndSetObjectNames(&filler); | 3166 && v8_heap_explorer_.IterateAndSetObjectNames(&filler); |
3171 } | 3167 } |
3172 | 3168 |
3173 | 3169 |
3174 void HeapSnapshotGenerator::FillReversePostorderIndexes( | 3170 void HeapSnapshotGenerator::MarkWindowReachableObjects() { |
| 3171 List<HeapEntry*> worklist; |
| 3172 |
| 3173 Vector<HeapGraphEdge> children = snapshot_->root()->children(); |
| 3174 for (int i = 0; i < children.length(); ++i) { |
| 3175 if (children[i].type() == HeapGraphEdge::kShortcut) { |
| 3176 worklist.Add(children[i].to()); |
| 3177 } |
| 3178 } |
| 3179 |
| 3180 while (!worklist.is_empty()) { |
| 3181 HeapEntry* entry = worklist.RemoveLast(); |
| 3182 if (entry->reachable_from_window()) continue; |
| 3183 entry->set_reachable_from_window(); |
| 3184 Vector<HeapGraphEdge> children = entry->children(); |
| 3185 for (int i = 0; i < children.length(); ++i) { |
| 3186 HeapEntry* child = children[i].to(); |
| 3187 if (!child->reachable_from_window()) { |
| 3188 worklist.Add(child); |
| 3189 } |
| 3190 } |
| 3191 } |
| 3192 } |
| 3193 |
| 3194 |
| 3195 static bool IsRetainingEdge(HeapGraphEdge* edge) { |
| 3196 if (edge->type() == HeapGraphEdge::kShortcut) return false; |
| 3197 // The edge is not retaining if it goes from system domain |
| 3198 // (i.e. an object not reachable from window) to the user domain |
| 3199 // (i.e. a reachable object). |
| 3200 return edge->from()->reachable_from_window() |
| 3201 || !edge->to()->reachable_from_window(); |
| 3202 } |
| 3203 |
| 3204 |
| 3205 void HeapSnapshotGenerator::FillPostorderIndexes( |
3175 Vector<HeapEntry*>* entries) { | 3206 Vector<HeapEntry*>* entries) { |
3176 snapshot_->ClearPaint(); | 3207 snapshot_->ClearPaint(); |
3177 int current_entry = 0; | 3208 int current_entry = 0; |
3178 List<HeapEntry*> nodes_to_visit; | 3209 List<HeapEntry*> nodes_to_visit; |
3179 nodes_to_visit.Add(snapshot_->root()); | 3210 HeapEntry* root = snapshot_->root(); |
| 3211 nodes_to_visit.Add(root); |
3180 snapshot_->root()->paint(); | 3212 snapshot_->root()->paint(); |
3181 while (!nodes_to_visit.is_empty()) { | 3213 while (!nodes_to_visit.is_empty()) { |
3182 HeapEntry* entry = nodes_to_visit.last(); | 3214 HeapEntry* entry = nodes_to_visit.last(); |
3183 Vector<HeapGraphEdge> children = entry->children(); | 3215 Vector<HeapGraphEdge> children = entry->children(); |
3184 bool has_new_edges = false; | 3216 bool has_new_edges = false; |
3185 for (int i = 0; i < children.length(); ++i) { | 3217 for (int i = 0; i < children.length(); ++i) { |
3186 if (children[i].type() == HeapGraphEdge::kShortcut) continue; | 3218 if (entry != root && !IsRetainingEdge(&children[i])) continue; |
3187 HeapEntry* child = children[i].to(); | 3219 HeapEntry* child = children[i].to(); |
3188 if (!child->painted()) { | 3220 if (!child->painted()) { |
3189 nodes_to_visit.Add(child); | 3221 nodes_to_visit.Add(child); |
3190 child->paint(); | 3222 child->paint(); |
3191 has_new_edges = true; | 3223 has_new_edges = true; |
3192 } | 3224 } |
3193 } | 3225 } |
3194 if (!has_new_edges) { | 3226 if (!has_new_edges) { |
3195 entry->set_ordered_index(current_entry); | 3227 entry->set_ordered_index(current_entry); |
3196 (*entries)[current_entry++] = entry; | 3228 (*entries)[current_entry++] = entry; |
(...skipping 14 matching lines...) Expand all Loading... |
3211 } | 3243 } |
3212 | 3244 |
3213 | 3245 |
3214 // The algorithm is based on the article: | 3246 // The algorithm is based on the article: |
3215 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" | 3247 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" |
3216 // Softw. Pract. Exper. 4 (2001), pp. 1-10. | 3248 // Softw. Pract. Exper. 4 (2001), pp. 1-10. |
3217 bool HeapSnapshotGenerator::BuildDominatorTree( | 3249 bool HeapSnapshotGenerator::BuildDominatorTree( |
3218 const Vector<HeapEntry*>& entries, | 3250 const Vector<HeapEntry*>& entries, |
3219 Vector<int>* dominators) { | 3251 Vector<int>* dominators) { |
3220 if (entries.length() == 0) return true; | 3252 if (entries.length() == 0) return true; |
| 3253 HeapEntry* root = snapshot_->root(); |
3221 const int entries_length = entries.length(), root_index = entries_length - 1; | 3254 const int entries_length = entries.length(), root_index = entries_length - 1; |
3222 static const int kNoDominator = -1; | 3255 static const int kNoDominator = -1; |
3223 for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; | 3256 for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; |
3224 (*dominators)[root_index] = root_index; | 3257 (*dominators)[root_index] = root_index; |
3225 | 3258 |
3226 // The affected array is used to mark entries which dominators | 3259 // The affected array is used to mark entries which dominators |
3227 // have to be racalculated because of changes in their retainers. | 3260 // have to be racalculated because of changes in their retainers. |
3228 ScopedVector<bool> affected(entries_length); | 3261 ScopedVector<bool> affected(entries_length); |
3229 for (int i = 0; i < affected.length(); ++i) affected[i] = false; | 3262 for (int i = 0; i < affected.length(); ++i) affected[i] = false; |
3230 // Mark the root direct children as affected. | 3263 // Mark the root direct children as affected. |
3231 Vector<HeapGraphEdge> children = entries[root_index]->children(); | 3264 Vector<HeapGraphEdge> children = entries[root_index]->children(); |
3232 for (int i = 0; i < children.length(); ++i) { | 3265 for (int i = 0; i < children.length(); ++i) { |
3233 affected[children[i].to()->ordered_index()] = true; | 3266 affected[children[i].to()->ordered_index()] = true; |
3234 } | 3267 } |
3235 | 3268 |
3236 bool changed = true; | 3269 bool changed = true; |
3237 while (changed) { | 3270 while (changed) { |
3238 changed = false; | 3271 changed = false; |
3239 if (!ProgressReport(true)) return false; | 3272 if (!ProgressReport(true)) return false; |
3240 for (int i = root_index - 1; i >= 0; --i) { | 3273 for (int i = root_index - 1; i >= 0; --i) { |
3241 if (!affected[i]) continue; | 3274 if (!affected[i]) continue; |
3242 affected[i] = false; | 3275 affected[i] = false; |
3243 // If dominator of the entry has already been set to root, | 3276 // If dominator of the entry has already been set to root, |
3244 // then it can't propagate any further. | 3277 // then it can't propagate any further. |
3245 if ((*dominators)[i] == root_index) continue; | 3278 if ((*dominators)[i] == root_index) continue; |
3246 int new_idom_index = kNoDominator; | 3279 int new_idom_index = kNoDominator; |
3247 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); | 3280 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
3248 for (int j = 0; j < rets.length(); ++j) { | 3281 for (int j = 0; j < rets.length(); ++j) { |
3249 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; | 3282 if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; |
3250 int ret_index = rets[j]->From()->ordered_index(); | 3283 int ret_index = rets[j]->from()->ordered_index(); |
3251 if (dominators->at(ret_index) != kNoDominator) { | 3284 if (dominators->at(ret_index) != kNoDominator) { |
3252 new_idom_index = new_idom_index == kNoDominator | 3285 new_idom_index = new_idom_index == kNoDominator |
3253 ? ret_index | 3286 ? ret_index |
3254 : Intersect(ret_index, new_idom_index, *dominators); | 3287 : Intersect(ret_index, new_idom_index, *dominators); |
3255 // If idom has already reached the root, it doesn't make sense | 3288 // If idom has already reached the root, it doesn't make sense |
3256 // to check other retainers. | 3289 // to check other retainers. |
3257 if (new_idom_index == root_index) break; | 3290 if (new_idom_index == root_index) break; |
3258 } | 3291 } |
3259 } | 3292 } |
3260 if (new_idom_index != kNoDominator | 3293 if (new_idom_index != kNoDominator |
3261 && dominators->at(i) != new_idom_index) { | 3294 && dominators->at(i) != new_idom_index) { |
3262 (*dominators)[i] = new_idom_index; | 3295 (*dominators)[i] = new_idom_index; |
3263 changed = true; | 3296 changed = true; |
3264 Vector<HeapGraphEdge> children = entries[i]->children(); | 3297 Vector<HeapGraphEdge> children = entries[i]->children(); |
3265 for (int j = 0; j < children.length(); ++j) { | 3298 for (int j = 0; j < children.length(); ++j) { |
3266 affected[children[j].to()->ordered_index()] = true; | 3299 affected[children[j].to()->ordered_index()] = true; |
3267 } | 3300 } |
3268 } | 3301 } |
3269 } | 3302 } |
3270 } | 3303 } |
3271 return true; | 3304 return true; |
3272 } | 3305 } |
3273 | 3306 |
3274 | 3307 |
3275 bool HeapSnapshotGenerator::SetEntriesDominators() { | 3308 bool HeapSnapshotGenerator::SetEntriesDominators() { |
3276 // This array is used for maintaining reverse postorder of nodes. | 3309 MarkWindowReachableObjects(); |
| 3310 // This array is used for maintaining postorder of nodes. |
3277 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); | 3311 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
3278 FillReversePostorderIndexes(&ordered_entries); | 3312 FillPostorderIndexes(&ordered_entries); |
3279 ScopedVector<int> dominators(ordered_entries.length()); | 3313 ScopedVector<int> dominators(ordered_entries.length()); |
3280 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; | 3314 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
3281 for (int i = 0; i < ordered_entries.length(); ++i) { | 3315 for (int i = 0; i < ordered_entries.length(); ++i) { |
3282 ASSERT(dominators[i] >= 0); | 3316 ASSERT(dominators[i] >= 0); |
3283 ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); | 3317 ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); |
3284 } | 3318 } |
3285 return true; | 3319 return true; |
3286 } | 3320 } |
3287 | 3321 |
3288 | 3322 |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3763 | 3797 |
3764 | 3798 |
3765 void HeapSnapshotJSONSerializer::SortHashMap( | 3799 void HeapSnapshotJSONSerializer::SortHashMap( |
3766 HashMap* map, List<HashMap::Entry*>* sorted_entries) { | 3800 HashMap* map, List<HashMap::Entry*>* sorted_entries) { |
3767 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) | 3801 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) |
3768 sorted_entries->Add(p); | 3802 sorted_entries->Add(p); |
3769 sorted_entries->Sort(SortUsingEntryValue); | 3803 sorted_entries->Sort(SortUsingEntryValue); |
3770 } | 3804 } |
3771 | 3805 |
3772 } } // namespace v8::internal | 3806 } } // namespace v8::internal |
OLD | NEW |