blob: bfd378dda831e352f3c0957c8f390d8f91115cf2 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "heap-profiler.h"
Steve Block3ce2e202009-11-05 08:53:23 +000031#include "frames-inl.h"
32#include "global-handles.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "string-stream.h"
34
35namespace v8 {
36namespace internal {
37
38
39#ifdef ENABLE_LOGGING_AND_PROFILING
40namespace {
41
42// Clusterizer is a set of helper functions for converting
43// object references into clusters.
44class Clusterizer : public AllStatic {
45 public:
46 static JSObjectsCluster Clusterize(HeapObject* obj) {
47 return Clusterize(obj, true);
48 }
49 static void InsertIntoTree(JSObjectsClusterTree* tree,
50 HeapObject* obj, bool fine_grain);
51 static void InsertReferenceIntoTree(JSObjectsClusterTree* tree,
52 const JSObjectsCluster& cluster) {
53 InsertIntoTree(tree, cluster, 0);
54 }
55
56 private:
57 static JSObjectsCluster Clusterize(HeapObject* obj, bool fine_grain);
58 static int CalculateNetworkSize(JSObject* obj);
59 static int GetObjectSize(HeapObject* obj) {
60 return obj->IsJSObject() ?
61 CalculateNetworkSize(JSObject::cast(obj)) : obj->Size();
62 }
63 static void InsertIntoTree(JSObjectsClusterTree* tree,
64 const JSObjectsCluster& cluster, int size);
65};
66
67
68JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
69 if (obj->IsJSObject()) {
70 JSObject* js_obj = JSObject::cast(obj);
71 String* constructor = JSObject::cast(js_obj)->constructor_name();
72 // Differentiate Object and Array instances.
73 if (fine_grain && (constructor == Heap::Object_symbol() ||
74 constructor == Heap::Array_symbol())) {
75 return JSObjectsCluster(constructor, obj);
76 } else {
77 return JSObjectsCluster(constructor);
78 }
79 } else if (obj->IsString()) {
80 return JSObjectsCluster(Heap::String_symbol());
81 }
82 return JSObjectsCluster();
83}
84
85
86void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
87 HeapObject* obj, bool fine_grain) {
88 JSObjectsCluster cluster = Clusterize(obj, fine_grain);
89 if (cluster.is_null()) return;
90 InsertIntoTree(tree, cluster, GetObjectSize(obj));
91}
92
93
94void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
95 const JSObjectsCluster& cluster, int size) {
96 JSObjectsClusterTree::Locator loc;
97 tree->Insert(cluster, &loc);
98 NumberAndSizeInfo number_and_size = loc.value();
99 number_and_size.increment_number(1);
100 number_and_size.increment_bytes(size);
101 loc.set_value(number_and_size);
102}
103
104
105int Clusterizer::CalculateNetworkSize(JSObject* obj) {
106 int size = obj->Size();
107 // If 'properties' and 'elements' are non-empty (thus, non-shared),
108 // take their size into account.
109 if (FixedArray::cast(obj->properties())->length() != 0) {
110 size += obj->properties()->Size();
111 }
112 if (FixedArray::cast(obj->elements())->length() != 0) {
113 size += obj->elements()->Size();
114 }
115 return size;
116}
117
118
119// A helper class for recording back references.
120class ReferencesExtractor : public ObjectVisitor {
121 public:
122 ReferencesExtractor(const JSObjectsCluster& cluster,
123 RetainerHeapProfile* profile)
124 : cluster_(cluster),
125 profile_(profile),
126 inside_array_(false) {
127 }
128
129 void VisitPointer(Object** o) {
130 if ((*o)->IsJSObject() || (*o)->IsString()) {
131 profile_->StoreReference(cluster_, HeapObject::cast(*o));
132 } else if ((*o)->IsFixedArray() && !inside_array_) {
133 // Traverse one level deep for data members that are fixed arrays.
134 // This covers the case of 'elements' and 'properties' of JSObject,
135 // and function contexts.
136 inside_array_ = true;
137 FixedArray::cast(*o)->Iterate(this);
138 inside_array_ = false;
139 }
140 }
141
142 void VisitPointers(Object** start, Object** end) {
143 for (Object** p = start; p < end; p++) VisitPointer(p);
144 }
145
146 private:
147 const JSObjectsCluster& cluster_;
148 RetainerHeapProfile* profile_;
149 bool inside_array_;
150};
151
152
153// A printer interface implementation for the Retainers profile.
154class RetainersPrinter : public RetainerHeapProfile::Printer {
155 public:
156 void PrintRetainers(const JSObjectsCluster& cluster,
157 const StringStream& retainers) {
158 HeapStringAllocator allocator;
159 StringStream stream(&allocator);
160 cluster.Print(&stream);
161 LOG(HeapSampleJSRetainersEvent(
162 *(stream.ToCString()), *(retainers.ToCString())));
163 }
164};
165
166
167// Visitor for printing a cluster tree.
168class ClusterTreePrinter BASE_EMBEDDED {
169 public:
170 explicit ClusterTreePrinter(StringStream* stream) : stream_(stream) {}
171 void Call(const JSObjectsCluster& cluster,
172 const NumberAndSizeInfo& number_and_size) {
173 Print(stream_, cluster, number_and_size);
174 }
175 static void Print(StringStream* stream,
176 const JSObjectsCluster& cluster,
177 const NumberAndSizeInfo& number_and_size);
178
179 private:
180 StringStream* stream_;
181};
182
183
184void ClusterTreePrinter::Print(StringStream* stream,
185 const JSObjectsCluster& cluster,
186 const NumberAndSizeInfo& number_and_size) {
187 stream->Put(',');
188 cluster.Print(stream);
189 stream->Add(";%d", number_and_size.number());
190}
191
192
193// Visitor for printing a retainer tree.
194class SimpleRetainerTreePrinter BASE_EMBEDDED {
195 public:
196 explicit SimpleRetainerTreePrinter(RetainerHeapProfile::Printer* printer)
197 : printer_(printer) {}
198 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
199
200 private:
201 RetainerHeapProfile::Printer* printer_;
202};
203
204
205void SimpleRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
206 JSObjectsClusterTree* tree) {
207 HeapStringAllocator allocator;
208 StringStream stream(&allocator);
209 ClusterTreePrinter retainers_printer(&stream);
210 tree->ForEach(&retainers_printer);
211 printer_->PrintRetainers(cluster, stream);
212}
213
214
215// Visitor for aggregating references count of equivalent clusters.
216class RetainersAggregator BASE_EMBEDDED {
217 public:
218 RetainersAggregator(ClustersCoarser* coarser, JSObjectsClusterTree* dest_tree)
219 : coarser_(coarser), dest_tree_(dest_tree) {}
220 void Call(const JSObjectsCluster& cluster,
221 const NumberAndSizeInfo& number_and_size);
222
223 private:
224 ClustersCoarser* coarser_;
225 JSObjectsClusterTree* dest_tree_;
226};
227
228
229void RetainersAggregator::Call(const JSObjectsCluster& cluster,
230 const NumberAndSizeInfo& number_and_size) {
231 JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
232 if (eq.is_null()) eq = cluster;
233 JSObjectsClusterTree::Locator loc;
234 dest_tree_->Insert(eq, &loc);
235 NumberAndSizeInfo aggregated_number = loc.value();
236 aggregated_number.increment_number(number_and_size.number());
237 loc.set_value(aggregated_number);
238}
239
240
241// Visitor for printing retainers tree. Aggregates equivalent retainer clusters.
242class AggregatingRetainerTreePrinter BASE_EMBEDDED {
243 public:
244 AggregatingRetainerTreePrinter(ClustersCoarser* coarser,
245 RetainerHeapProfile::Printer* printer)
246 : coarser_(coarser), printer_(printer) {}
247 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
248
249 private:
250 ClustersCoarser* coarser_;
251 RetainerHeapProfile::Printer* printer_;
252};
253
254
255void AggregatingRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
256 JSObjectsClusterTree* tree) {
257 if (!coarser_->GetCoarseEquivalent(cluster).is_null()) return;
258 JSObjectsClusterTree dest_tree_;
259 RetainersAggregator retainers_aggregator(coarser_, &dest_tree_);
260 tree->ForEach(&retainers_aggregator);
261 HeapStringAllocator allocator;
262 StringStream stream(&allocator);
263 ClusterTreePrinter retainers_printer(&stream);
264 dest_tree_.ForEach(&retainers_printer);
265 printer_->PrintRetainers(cluster, stream);
266}
267
268
269// A helper class for building a retainers tree, that aggregates
270// all equivalent clusters.
271class RetainerTreeAggregator BASE_EMBEDDED {
272 public:
273 explicit RetainerTreeAggregator(ClustersCoarser* coarser)
274 : coarser_(coarser) {}
275 void Process(JSObjectsRetainerTree* input_tree) {
276 input_tree->ForEach(this);
277 }
278 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
279 JSObjectsRetainerTree& output_tree() { return output_tree_; }
280
281 private:
282 ClustersCoarser* coarser_;
283 JSObjectsRetainerTree output_tree_;
284};
285
286
287void RetainerTreeAggregator::Call(const JSObjectsCluster& cluster,
288 JSObjectsClusterTree* tree) {
289 JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
290 if (eq.is_null()) return;
291 JSObjectsRetainerTree::Locator loc;
292 if (output_tree_.Insert(eq, &loc)) {
293 loc.set_value(new JSObjectsClusterTree());
294 }
295 RetainersAggregator retainers_aggregator(coarser_, loc.value());
296 tree->ForEach(&retainers_aggregator);
297}
298
299} // namespace
300
301
302const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey;
303const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue;
304
305
306ConstructorHeapProfile::ConstructorHeapProfile()
307 : zscope_(DELETE_ON_EXIT) {
308}
309
310
311void ConstructorHeapProfile::Call(const JSObjectsCluster& cluster,
312 const NumberAndSizeInfo& number_and_size) {
313 HeapStringAllocator allocator;
314 StringStream stream(&allocator);
315 cluster.Print(&stream);
316 LOG(HeapSampleJSConstructorEvent(*(stream.ToCString()),
317 number_and_size.number(),
318 number_and_size.bytes()));
319}
320
321
322void ConstructorHeapProfile::CollectStats(HeapObject* obj) {
323 Clusterizer::InsertIntoTree(&js_objects_info_tree_, obj, false);
324}
325
326
327void ConstructorHeapProfile::PrintStats() {
328 js_objects_info_tree_.ForEach(this);
329}
330
331
Steve Block3ce2e202009-11-05 08:53:23 +0000332static const char* GetConstructorName(const char* name) {
333 return name[0] != '\0' ? name : "(anonymous)";
334}
335
336
Steve Blocka7e24c12009-10-30 11:49:00 +0000337void JSObjectsCluster::Print(StringStream* accumulator) const {
338 ASSERT(!is_null());
339 if (constructor_ == FromSpecialCase(ROOTS)) {
340 accumulator->Add("(roots)");
341 } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
342 accumulator->Add("(global property)");
343 } else if (constructor_ == FromSpecialCase(SELF)) {
344 accumulator->Add("(self)");
345 } else {
346 SmartPointer<char> s_name(
347 constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
Steve Block3ce2e202009-11-05 08:53:23 +0000348 accumulator->Add("%s", GetConstructorName(*s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000349 if (instance_ != NULL) {
350 accumulator->Add(":%p", static_cast<void*>(instance_));
351 }
352 }
353}
354
355
356void JSObjectsCluster::DebugPrint(StringStream* accumulator) const {
357 if (!is_null()) {
358 Print(accumulator);
359 } else {
360 accumulator->Add("(null cluster)");
361 }
362}
363
364
365inline ClustersCoarser::ClusterBackRefs::ClusterBackRefs(
366 const JSObjectsCluster& cluster_)
367 : cluster(cluster_), refs(kInitialBackrefsListCapacity) {
368}
369
370
371inline ClustersCoarser::ClusterBackRefs::ClusterBackRefs(
372 const ClustersCoarser::ClusterBackRefs& src)
373 : cluster(src.cluster), refs(src.refs.capacity()) {
374 refs.AddAll(src.refs);
375}
376
377
378inline ClustersCoarser::ClusterBackRefs&
379 ClustersCoarser::ClusterBackRefs::operator=(
380 const ClustersCoarser::ClusterBackRefs& src) {
381 if (this == &src) return *this;
382 cluster = src.cluster;
383 refs.Clear();
384 refs.AddAll(src.refs);
385 return *this;
386}
387
388
389inline int ClustersCoarser::ClusterBackRefs::Compare(
390 const ClustersCoarser::ClusterBackRefs& a,
391 const ClustersCoarser::ClusterBackRefs& b) {
392 int cmp = JSObjectsCluster::CompareConstructors(a.cluster, b.cluster);
393 if (cmp != 0) return cmp;
394 if (a.refs.length() < b.refs.length()) return -1;
395 if (a.refs.length() > b.refs.length()) return 1;
396 for (int i = 0; i < a.refs.length(); ++i) {
397 int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]);
398 if (cmp != 0) return cmp;
399 }
400 return 0;
401}
402
403
404ClustersCoarser::ClustersCoarser()
405 : zscope_(DELETE_ON_EXIT),
406 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
407 current_pair_(NULL),
408 current_set_(NULL),
409 self_(NULL) {
410}
411
412
413void ClustersCoarser::Call(const JSObjectsCluster& cluster,
414 JSObjectsClusterTree* tree) {
415 if (!cluster.can_be_coarsed()) return;
416 ClusterBackRefs pair(cluster);
417 ASSERT(current_pair_ == NULL);
418 current_pair_ = &pair;
419 current_set_ = new JSObjectsRetainerTree();
420 self_ = &cluster;
421 tree->ForEach(this);
422 sim_list_.Add(pair);
423 current_pair_ = NULL;
424 current_set_ = NULL;
425 self_ = NULL;
426}
427
428
429void ClustersCoarser::Call(const JSObjectsCluster& cluster,
430 const NumberAndSizeInfo& number_and_size) {
431 ASSERT(current_pair_ != NULL);
432 ASSERT(current_set_ != NULL);
433 ASSERT(self_ != NULL);
434 JSObjectsRetainerTree::Locator loc;
435 if (JSObjectsCluster::Compare(*self_, cluster) == 0) {
436 current_pair_->refs.Add(JSObjectsCluster(JSObjectsCluster::SELF));
437 return;
438 }
439 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
440 if (!eq.is_null()) {
441 if (current_set_->Find(eq, &loc)) return;
442 current_pair_->refs.Add(eq);
443 current_set_->Insert(eq, &loc);
444 } else {
445 current_pair_->refs.Add(cluster);
446 }
447}
448
449
450void ClustersCoarser::Process(JSObjectsRetainerTree* tree) {
451 int last_eq_clusters = -1;
452 for (int i = 0; i < kMaxPassesCount; ++i) {
453 sim_list_.Clear();
454 const int curr_eq_clusters = DoProcess(tree);
455 // If no new cluster equivalents discovered, abort processing.
456 if (last_eq_clusters == curr_eq_clusters) break;
457 last_eq_clusters = curr_eq_clusters;
458 }
459}
460
461
462int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) {
463 tree->ForEach(this);
464 sim_list_.Iterate(ClusterBackRefs::SortRefsIterator);
465 sim_list_.Sort(ClusterBackRefsCmp);
466 return FillEqualityTree();
467}
468
469
470JSObjectsCluster ClustersCoarser::GetCoarseEquivalent(
471 const JSObjectsCluster& cluster) {
472 if (!cluster.can_be_coarsed()) return JSObjectsCluster();
473 EqualityTree::Locator loc;
474 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster();
475}
476
477
478bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) {
479 // Return true for coarsible clusters that have a non-identical equivalent.
480 if (!cluster.can_be_coarsed()) return false;
481 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
482 return !eq.is_null() && JSObjectsCluster::Compare(cluster, eq) != 0;
483}
484
485
486int ClustersCoarser::FillEqualityTree() {
487 int eq_clusters_count = 0;
488 int eq_to = 0;
489 bool first_added = false;
490 for (int i = 1; i < sim_list_.length(); ++i) {
491 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) {
492 EqualityTree::Locator loc;
493 if (!first_added) {
494 // Add self-equivalence, if we have more than one item in this
495 // equivalence class.
496 eq_tree_.Insert(sim_list_[eq_to].cluster, &loc);
497 loc.set_value(sim_list_[eq_to].cluster);
498 first_added = true;
499 }
500 eq_tree_.Insert(sim_list_[i].cluster, &loc);
501 loc.set_value(sim_list_[eq_to].cluster);
502 ++eq_clusters_count;
503 } else {
504 eq_to = i;
505 first_added = false;
506 }
507 }
508 return eq_clusters_count;
509}
510
511
512const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey;
513const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue;
514const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey;
515const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue =
516 NULL;
517
518
519RetainerHeapProfile::RetainerHeapProfile()
520 : zscope_(DELETE_ON_EXIT) {
521 JSObjectsCluster roots(JSObjectsCluster::ROOTS);
522 ReferencesExtractor extractor(roots, this);
523 Heap::IterateRoots(&extractor);
524}
525
526
527void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
528 HeapObject* ref) {
529 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
530 JSObjectsRetainerTree::Locator ref_loc;
531 if (retainers_tree_.Insert(ref_cluster, &ref_loc)) {
532 ref_loc.set_value(new JSObjectsClusterTree());
533 }
534 JSObjectsClusterTree* referenced_by = ref_loc.value();
535 Clusterizer::InsertReferenceIntoTree(referenced_by, cluster);
536}
537
538
539void RetainerHeapProfile::CollectStats(HeapObject* obj) {
540 if (obj->IsJSObject()) {
541 const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
542 ReferencesExtractor extractor(cluster, this);
543 obj->Iterate(&extractor);
544 } else if (obj->IsJSGlobalPropertyCell()) {
545 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY);
546 ReferencesExtractor extractor(global_prop, this);
547 obj->Iterate(&extractor);
548 }
549}
550
551
552void RetainerHeapProfile::DebugPrintStats(
553 RetainerHeapProfile::Printer* printer) {
554 coarser_.Process(&retainers_tree_);
555 // Print clusters that have no equivalents, aggregating their retainers.
556 AggregatingRetainerTreePrinter agg_printer(&coarser_, printer);
557 retainers_tree_.ForEach(&agg_printer);
558 // Now aggregate clusters that have equivalents...
559 RetainerTreeAggregator aggregator(&coarser_);
560 aggregator.Process(&retainers_tree_);
561 // ...and print them.
562 SimpleRetainerTreePrinter s_printer(printer);
563 aggregator.output_tree().ForEach(&s_printer);
564}
565
566
567void RetainerHeapProfile::PrintStats() {
568 RetainersPrinter printer;
569 DebugPrintStats(&printer);
570}
571
572
573//
574// HeapProfiler class implementation.
575//
576void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
577 InstanceType type = obj->map()->instance_type();
578 ASSERT(0 <= type && type <= LAST_TYPE);
Steve Block3ce2e202009-11-05 08:53:23 +0000579 if (!FreeListNode::IsFreeListNode(obj)) {
580 info[type].increment_number(1);
581 info[type].increment_bytes(obj->Size());
582 }
583}
584
585
586static void StackWeakReferenceCallback(Persistent<Value> object,
587 void* trace) {
588 DeleteArray(static_cast<Address*>(trace));
589 object.Dispose();
590}
591
592
593static void PrintProducerStackTrace(Object* obj, void* trace) {
594 if (!obj->IsJSObject()) return;
595 String* constructor = JSObject::cast(obj)->constructor_name();
596 SmartPointer<char> s_name(
597 constructor->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
598 LOG(HeapSampleJSProducerEvent(GetConstructorName(*s_name),
599 reinterpret_cast<Address*>(trace)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000600}
601
602
603void HeapProfiler::WriteSample() {
604 LOG(HeapSampleBeginEvent("Heap", "allocated"));
605 LOG(HeapSampleStats(
Steve Block3ce2e202009-11-05 08:53:23 +0000606 "Heap", "allocated", Heap::CommittedMemory(), Heap::SizeOfObjects()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000607
608 HistogramInfo info[LAST_TYPE+1];
609#define DEF_TYPE_NAME(name) info[name].set_name(#name);
610 INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
611#undef DEF_TYPE_NAME
612
613 ConstructorHeapProfile js_cons_profile;
614 RetainerHeapProfile js_retainer_profile;
615 HeapIterator iterator;
616 while (iterator.has_next()) {
617 HeapObject* obj = iterator.next();
618 CollectStats(obj, info);
619 js_cons_profile.CollectStats(obj);
620 js_retainer_profile.CollectStats(obj);
621 }
622
623 // Lump all the string types together.
624 int string_number = 0;
625 int string_bytes = 0;
626#define INCREMENT_SIZE(type, size, name, camel_name) \
627 string_number += info[type].number(); \
628 string_bytes += info[type].bytes();
629 STRING_TYPE_LIST(INCREMENT_SIZE)
630#undef INCREMENT_SIZE
631 if (string_bytes > 0) {
632 LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
633 }
634
635 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
636 if (info[i].bytes() > 0) {
637 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
638 info[i].bytes()));
639 }
640 }
641
642 js_cons_profile.PrintStats();
643 js_retainer_profile.PrintStats();
644
Steve Block3ce2e202009-11-05 08:53:23 +0000645 GlobalHandles::IterateWeakRoots(PrintProducerStackTrace,
646 StackWeakReferenceCallback);
647
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 LOG(HeapSampleEndEvent("Heap", "allocated"));
649}
650
651
Steve Block3ce2e202009-11-05 08:53:23 +0000652bool ProducerHeapProfile::can_log_ = false;
653
654void ProducerHeapProfile::Setup() {
655 can_log_ = true;
656}
657
658void ProducerHeapProfile::RecordJSObjectAllocation(Object* obj) {
659 if (!can_log_ || !FLAG_log_producers) return;
660 int framesCount = 0;
661 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
662 ++framesCount;
663 }
664 if (framesCount == 0) return;
665 ++framesCount; // Reserve place for the terminator item.
666 Vector<Address> stack(NewArray<Address>(framesCount), framesCount);
667 int i = 0;
668 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
669 stack[i++] = it.frame()->pc();
670 }
671 stack[i] = NULL;
672 Handle<Object> handle = GlobalHandles::Create(obj);
673 GlobalHandles::MakeWeak(handle.location(),
674 static_cast<void*>(stack.start()),
675 StackWeakReferenceCallback);
676}
677
678
Steve Blocka7e24c12009-10-30 11:49:00 +0000679#endif // ENABLE_LOGGING_AND_PROFILING
680
681
682} } // namespace v8::internal