| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 // A helper class for recording back references. | 65 // A helper class for recording back references. |
| 66 class ReferencesExtractor : public ObjectVisitor { | 66 class ReferencesExtractor : public ObjectVisitor { |
| 67 public: | 67 public: |
| 68 ReferencesExtractor( | 68 ReferencesExtractor( |
| 69 const JSObjectsCluster& cluster, RetainerHeapProfile* profile) | 69 const JSObjectsCluster& cluster, RetainerHeapProfile* profile) |
| 70 : cluster_(cluster), | 70 : cluster_(cluster), |
| 71 profile_(profile), | 71 profile_(profile), |
| 72 insideArray_(false) { | 72 inside_array_(false) { |
| 73 } | 73 } |
| 74 | 74 |
| 75 void VisitPointer(Object** o) { | 75 void VisitPointer(Object** o) { |
| 76 if ((*o)->IsJSObject() || (*o)->IsString()) { | 76 if ((*o)->IsJSObject() || (*o)->IsString()) { |
| 77 profile_->StoreReference(cluster_, *o); | 77 profile_->StoreReference(cluster_, *o); |
| 78 } else if ((*o)->IsFixedArray() && !insideArray_) { | 78 } else if ((*o)->IsFixedArray() && !inside_array_) { |
| 79 // Traverse one level deep for data members that are fixed arrays. | 79 // Traverse one level deep for data members that are fixed arrays. |
| 80 // This covers the case of 'elements' and 'properties' of JSObject, | 80 // This covers the case of 'elements' and 'properties' of JSObject, |
| 81 // and function contexts. | 81 // and function contexts. |
| 82 insideArray_ = true; | 82 inside_array_ = true; |
| 83 FixedArray::cast(*o)->Iterate(this); | 83 FixedArray::cast(*o)->Iterate(this); |
| 84 insideArray_ = false; | 84 inside_array_ = false; |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 | 87 |
| 88 void VisitPointers(Object** start, Object** end) { | 88 void VisitPointers(Object** start, Object** end) { |
| 89 for (Object** p = start; p < end; p++) VisitPointer(p); | 89 for (Object** p = start; p < end; p++) VisitPointer(p); |
| 90 } | 90 } |
| 91 | 91 |
| 92 private: | 92 private: |
| 93 const JSObjectsCluster& cluster_; | 93 const JSObjectsCluster& cluster_; |
| 94 RetainerHeapProfile* profile_; | 94 RetainerHeapProfile* profile_; |
| 95 bool insideArray_; | 95 bool inside_array_; |
| 96 }; | 96 }; |
| 97 | 97 |
| 98 | 98 |
| 99 // A printer interface implementation for the Retainers profile. | 99 // A printer interface implementation for the Retainers profile. |
| 100 class RetainersPrinter : public RetainerHeapProfile::Printer { | 100 class RetainersPrinter : public RetainerHeapProfile::Printer { |
| 101 public: | 101 public: |
| 102 void PrintRetainers(const StringStream& retainers) { | 102 void PrintRetainers(const StringStream& retainers) { |
| 103 LOG(HeapSampleJSRetainersEvent(*(retainers.ToCString()))); | 103 LOG(HeapSampleJSRetainersEvent(*(retainers.ToCString()))); |
| 104 } | 104 } |
| 105 }; | 105 }; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 for (int i = 0; i < a.refs.length(); ++i) { | 219 for (int i = 0; i < a.refs.length(); ++i) { |
| 220 int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]); | 220 int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]); |
| 221 if (cmp != 0) return cmp; | 221 if (cmp != 0) return cmp; |
| 222 } | 222 } |
| 223 return 0; | 223 return 0; |
| 224 } | 224 } |
| 225 | 225 |
| 226 | 226 |
| 227 ClustersCoarser::ClustersCoarser() | 227 ClustersCoarser::ClustersCoarser() |
| 228 : zscope_(DELETE_ON_EXIT), | 228 : zscope_(DELETE_ON_EXIT), |
| 229 simList_(ClustersCoarser::kInitialSimilarityListCapacity), | 229 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity), |
| 230 currentPair_(NULL) { | 230 current_pair_(NULL) { |
| 231 } | 231 } |
| 232 | 232 |
| 233 | 233 |
| 234 void ClustersCoarser::Call( | 234 void ClustersCoarser::Call( |
| 235 const JSObjectsCluster& cluster, JSObjectsClusterTree* tree) { | 235 const JSObjectsCluster& cluster, JSObjectsClusterTree* tree) { |
| 236 if (tree != NULL) { | 236 if (tree != NULL) { |
| 237 // First level of retainer graph. | 237 // First level of retainer graph. |
| 238 if (!cluster.can_be_coarsed()) return; | 238 if (!cluster.can_be_coarsed()) return; |
| 239 ClusterBackRefs pair(cluster); | 239 ClusterBackRefs pair(cluster); |
| 240 ASSERT(currentPair_ == NULL); | 240 ASSERT(current_pair_ == NULL); |
| 241 currentPair_ = &pair; | 241 current_pair_ = &pair; |
| 242 currentSet_ = new JSObjectsClusterTree(); | 242 current_set_ = new JSObjectsClusterTree(); |
| 243 tree->ForEach(this); | 243 tree->ForEach(this); |
| 244 simList_.Add(pair); | 244 sim_list_.Add(pair); |
| 245 currentPair_ = NULL; | 245 current_pair_ = NULL; |
| 246 currentSet_ = NULL; | 246 current_set_ = NULL; |
| 247 } else { | 247 } else { |
| 248 // Second level of retainer graph. | 248 // Second level of retainer graph. |
| 249 ASSERT(currentPair_ != NULL); | 249 ASSERT(current_pair_ != NULL); |
| 250 ASSERT(currentSet_ != NULL); | 250 ASSERT(current_set_ != NULL); |
| 251 JSObjectsCluster eq = GetCoarseEquivalent(cluster); | 251 JSObjectsCluster eq = GetCoarseEquivalent(cluster); |
| 252 JSObjectsClusterTree::Locator loc; | 252 JSObjectsClusterTree::Locator loc; |
| 253 if (!eq.is_null()) { | 253 if (!eq.is_null()) { |
| 254 if (currentSet_->Find(eq, &loc)) return; | 254 if (current_set_->Find(eq, &loc)) return; |
| 255 currentPair_->refs.Add(eq); | 255 current_pair_->refs.Add(eq); |
| 256 currentSet_->Insert(eq, &loc); | 256 current_set_->Insert(eq, &loc); |
| 257 } else { | 257 } else { |
| 258 currentPair_->refs.Add(cluster); | 258 current_pair_->refs.Add(cluster); |
| 259 } | 259 } |
| 260 } | 260 } |
| 261 } | 261 } |
| 262 | 262 |
| 263 | 263 |
| 264 void ClustersCoarser::Process(JSObjectsClusterTree* tree) { | 264 void ClustersCoarser::Process(JSObjectsClusterTree* tree) { |
| 265 int last_eq_clusters = -1; | 265 int last_eq_clusters = -1; |
| 266 for (int i = 0; i < kMaxPassesCount; ++i) { | 266 for (int i = 0; i < kMaxPassesCount; ++i) { |
| 267 simList_.Clear(); | 267 sim_list_.Clear(); |
| 268 const int curr_eq_clusters = DoProcess(tree); | 268 const int curr_eq_clusters = DoProcess(tree); |
| 269 // If no new cluster equivalents discovered, abort processing. | 269 // If no new cluster equivalents discovered, abort processing. |
| 270 if (last_eq_clusters == curr_eq_clusters) break; | 270 if (last_eq_clusters == curr_eq_clusters) break; |
| 271 last_eq_clusters = curr_eq_clusters; | 271 last_eq_clusters = curr_eq_clusters; |
| 272 } | 272 } |
| 273 } | 273 } |
| 274 | 274 |
| 275 | 275 |
| 276 int ClustersCoarser::DoProcess(JSObjectsClusterTree* tree) { | 276 int ClustersCoarser::DoProcess(JSObjectsClusterTree* tree) { |
| 277 tree->ForEach(this); | 277 tree->ForEach(this); |
| 278 // To sort similarity list properly, references list of a cluster is | 278 // To sort similarity list properly, references list of a cluster is |
| 279 // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would | 279 // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would |
| 280 // be considered equivalent. But we don't sort them explicitly | 280 // be considered equivalent. But we don't sort them explicitly |
| 281 // because we know that they come from a splay tree traversal, so | 281 // because we know that they come from a splay tree traversal, so |
| 282 // they are already sorted. | 282 // they are already sorted. |
| 283 simList_.Sort(ClusterBackRefsCmp); | 283 sim_list_.Sort(ClusterBackRefsCmp); |
| 284 return FillEqualityTree(); | 284 return FillEqualityTree(); |
| 285 } | 285 } |
| 286 | 286 |
| 287 | 287 |
| 288 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent( | 288 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent( |
| 289 const JSObjectsCluster& cluster) { | 289 const JSObjectsCluster& cluster) { |
| 290 if (!cluster.can_be_coarsed()) return JSObjectsCluster(); | 290 if (!cluster.can_be_coarsed()) return JSObjectsCluster(); |
| 291 EqualityTree::Locator loc; | 291 EqualityTree::Locator loc; |
| 292 return eqTree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster(); | 292 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster(); |
| 293 } | 293 } |
| 294 | 294 |
| 295 | 295 |
| 296 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) { | 296 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) { |
| 297 // Return true for coarsible clusters that have a non-identical equivalent. | 297 // Return true for coarsible clusters that have a non-identical equivalent. |
| 298 return cluster.can_be_coarsed() && | 298 return cluster.can_be_coarsed() && |
| 299 JSObjectsCluster::Compare(cluster, GetCoarseEquivalent(cluster)) != 0; | 299 JSObjectsCluster::Compare(cluster, GetCoarseEquivalent(cluster)) != 0; |
| 300 } | 300 } |
| 301 | 301 |
| 302 | 302 |
| 303 int ClustersCoarser::FillEqualityTree() { | 303 int ClustersCoarser::FillEqualityTree() { |
| 304 int eqClustersCount = 0; | 304 int eq_clusters_count = 0; |
| 305 int eqTo = 0; | 305 int eq_to = 0; |
| 306 bool firstAdded = false; | 306 bool first_added = false; |
| 307 for (int i = 1; i < simList_.length(); ++i) { | 307 for (int i = 1; i < sim_list_.length(); ++i) { |
| 308 if (ClusterBackRefs::Compare(simList_[i], simList_[eqTo]) == 0) { | 308 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) { |
| 309 EqualityTree::Locator loc; | 309 EqualityTree::Locator loc; |
| 310 if (!firstAdded) { | 310 if (!first_added) { |
| 311 // Add self-equivalence, if we have more than one item in this | 311 // Add self-equivalence, if we have more than one item in this |
| 312 // equivalence class. | 312 // equivalence class. |
| 313 eqTree_.Insert(simList_[eqTo].cluster, &loc); | 313 eq_tree_.Insert(sim_list_[eq_to].cluster, &loc); |
| 314 loc.set_value(simList_[eqTo].cluster); | 314 loc.set_value(sim_list_[eq_to].cluster); |
| 315 firstAdded = true; | 315 first_added = true; |
| 316 } | 316 } |
| 317 eqTree_.Insert(simList_[i].cluster, &loc); | 317 eq_tree_.Insert(sim_list_[i].cluster, &loc); |
| 318 loc.set_value(simList_[eqTo].cluster); | 318 loc.set_value(sim_list_[eq_to].cluster); |
| 319 ++eqClustersCount; | 319 ++eq_clusters_count; |
| 320 } else { | 320 } else { |
| 321 eqTo = i; | 321 eq_to = i; |
| 322 firstAdded = false; | 322 first_added = false; |
| 323 } | 323 } |
| 324 } | 324 } |
| 325 return eqClustersCount; | 325 return eq_clusters_count; |
| 326 } | 326 } |
| 327 | 327 |
| 328 | 328 |
| 329 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey; | 329 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey; |
| 330 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue; | 330 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue; |
| 331 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey; | 331 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey; |
| 332 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue = | 332 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue = |
| 333 NULL; | 333 NULL; |
| 334 | 334 |
| 335 | 335 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 366 | 366 |
| 367 | 367 |
| 368 void RetainerHeapProfile::StoreReference( | 368 void RetainerHeapProfile::StoreReference( |
| 369 const JSObjectsCluster& cluster, | 369 const JSObjectsCluster& cluster, |
| 370 Object* ref) { | 370 Object* ref) { |
| 371 JSObjectsCluster ref_cluster = Clusterize(ref); | 371 JSObjectsCluster ref_cluster = Clusterize(ref); |
| 372 JSObjectsClusterTree::Locator ref_loc; | 372 JSObjectsClusterTree::Locator ref_loc; |
| 373 if (retainers_tree_.Insert(ref_cluster, &ref_loc)) { | 373 if (retainers_tree_.Insert(ref_cluster, &ref_loc)) { |
| 374 ref_loc.set_value(new JSObjectsClusterTree()); | 374 ref_loc.set_value(new JSObjectsClusterTree()); |
| 375 } | 375 } |
| 376 JSObjectsClusterTree* referencedBy = ref_loc.value(); | 376 JSObjectsClusterTree* referenced_by = ref_loc.value(); |
| 377 JSObjectsClusterTree::Locator obj_loc; | 377 JSObjectsClusterTree::Locator obj_loc; |
| 378 referencedBy->Insert(cluster, &obj_loc); | 378 referenced_by->Insert(cluster, &obj_loc); |
| 379 } | 379 } |
| 380 | 380 |
| 381 | 381 |
| 382 void RetainerHeapProfile::CollectStats(HeapObject* obj) { | 382 void RetainerHeapProfile::CollectStats(HeapObject* obj) { |
| 383 if (obj->IsJSObject()) { | 383 if (obj->IsJSObject()) { |
| 384 const JSObjectsCluster cluster = Clusterize(JSObject::cast(obj)); | 384 const JSObjectsCluster cluster = Clusterize(JSObject::cast(obj)); |
| 385 ReferencesExtractor extractor(cluster, this); | 385 ReferencesExtractor extractor(cluster, this); |
| 386 obj->Iterate(&extractor); | 386 obj->Iterate(&extractor); |
| 387 } else if (obj->IsJSGlobalPropertyCell()) { | 387 } else if (obj->IsJSGlobalPropertyCell()) { |
| 388 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY); | 388 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 js_retainer_profile.PrintStats(); | 510 js_retainer_profile.PrintStats(); |
| 511 | 511 |
| 512 LOG(HeapSampleEndEvent("Heap", "allocated")); | 512 LOG(HeapSampleEndEvent("Heap", "allocated")); |
| 513 } | 513 } |
| 514 | 514 |
| 515 | 515 |
| 516 #endif // ENABLE_LOGGING_AND_PROFILING | 516 #endif // ENABLE_LOGGING_AND_PROFILING |
| 517 | 517 |
| 518 | 518 |
| 519 } } // namespace v8::internal | 519 } } // namespace v8::internal |
| OLD | NEW |