blob: 44be3db78c9b3938a54215b83b6b936b724d7429 [file] [log] [blame]
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Block6ded16b2010-05-10 14:33:55 +01002// 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#ifndef V8_PROFILE_GENERATOR_H_
29#define V8_PROFILE_GENERATOR_H_
30
Ben Murdoch257744e2011-11-30 15:57:28 +000031#include "allocation.h"
Steve Block6ded16b2010-05-10 14:33:55 +010032#include "hashmap.h"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010033#include "../include/v8-profiler.h"
Steve Block6ded16b2010-05-10 14:33:55 +010034
35namespace v8 {
36namespace internal {
37
Leon Clarkef7060e22010-06-03 12:02:55 +010038class TokenEnumerator {
39 public:
40 TokenEnumerator();
41 ~TokenEnumerator();
42 int GetTokenId(Object* token);
43
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010044 static const int kNoSecurityToken = -1;
45 static const int kInheritsSecurityToken = -2;
46
Leon Clarkef7060e22010-06-03 12:02:55 +010047 private:
48 static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
49 void* parameter);
50 void TokenRemoved(Object** token_location);
51
52 List<Object**> token_locations_;
53 List<bool> token_removed_;
54
55 friend class TokenEnumeratorTester;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010056
57 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator);
58};
59
60
61// Provides a storage of strings allocated in C++ heap, to hold them
62// forever, even if they disappear from JS heap or external storage.
63class StringsStorage {
64 public:
65 StringsStorage();
66 ~StringsStorage();
67
Steve Block44f0eee2011-05-26 01:26:41 +010068 const char* GetCopy(const char* src);
69 const char* GetFormatted(const char* format, ...);
70 const char* GetVFormatted(const char* format, va_list args);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010071 const char* GetName(String* name);
Ben Murdochf87a2032010-10-22 12:50:53 +010072 const char* GetName(int index);
Steve Block791712a2010-08-27 10:21:07 +010073 inline const char* GetFunctionName(String* name);
74 inline const char* GetFunctionName(const char* name);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010075
76 private:
Ben Murdoch592a9fc2012-03-05 11:04:45 +000077 static const int kMaxNameSize = 1024;
78
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010079 INLINE(static bool StringsMatch(void* key1, void* key2)) {
80 return strcmp(reinterpret_cast<char*>(key1),
81 reinterpret_cast<char*>(key2)) == 0;
82 }
Steve Block44f0eee2011-05-26 01:26:41 +010083 const char* AddOrDisposeString(char* str, uint32_t hash);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010084
Ben Murdoch3bec4d22010-07-22 14:51:16 +010085 // Mapping of strings by String::Hash to const char* strings.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010086 HashMap names_;
87
88 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
Leon Clarkef7060e22010-06-03 12:02:55 +010089};
90
91
Steve Block6ded16b2010-05-10 14:33:55 +010092class CodeEntry {
93 public:
94 // CodeEntry doesn't own name strings, just references them.
95 INLINE(CodeEntry(Logger::LogEventsAndTags tag,
96 const char* name_prefix,
97 const char* name,
98 const char* resource_name,
Leon Clarkef7060e22010-06-03 12:02:55 +010099 int line_number,
100 int security_token_id));
Steve Block6ded16b2010-05-10 14:33:55 +0100101
102 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
103 INLINE(const char* name_prefix() const) { return name_prefix_; }
104 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
105 INLINE(const char* name() const) { return name_; }
106 INLINE(const char* resource_name() const) { return resource_name_; }
107 INLINE(int line_number() const) { return line_number_; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100108 INLINE(int shared_id() const) { return shared_id_; }
109 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
Leon Clarkef7060e22010-06-03 12:02:55 +0100110 INLINE(int security_token_id() const) { return security_token_id_; }
Steve Block6ded16b2010-05-10 14:33:55 +0100111
112 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
113
Leon Clarkef7060e22010-06-03 12:02:55 +0100114 void CopyData(const CodeEntry& source);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100115 uint32_t GetCallUid() const;
116 bool IsSameAs(CodeEntry* entry) const;
Leon Clarkef7060e22010-06-03 12:02:55 +0100117
Steve Block44f0eee2011-05-26 01:26:41 +0100118 static const char* const kEmptyNamePrefix;
Steve Block6ded16b2010-05-10 14:33:55 +0100119
120 private:
Steve Block6ded16b2010-05-10 14:33:55 +0100121 Logger::LogEventsAndTags tag_;
122 const char* name_prefix_;
123 const char* name_;
124 const char* resource_name_;
125 int line_number_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100126 int shared_id_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100127 int security_token_id_;
Steve Block6ded16b2010-05-10 14:33:55 +0100128
Steve Block6ded16b2010-05-10 14:33:55 +0100129 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
130};
131
132
133class ProfileTree;
134
135class ProfileNode {
136 public:
137 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
138
139 ProfileNode* FindChild(CodeEntry* entry);
140 ProfileNode* FindOrAddChild(CodeEntry* entry);
141 INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
Leon Clarkef7060e22010-06-03 12:02:55 +0100142 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
Steve Block6ded16b2010-05-10 14:33:55 +0100143 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
144
145 INLINE(CodeEntry* entry() const) { return entry_; }
146 INLINE(unsigned self_ticks() const) { return self_ticks_; }
147 INLINE(unsigned total_ticks() const) { return total_ticks_; }
148 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
149 double GetSelfMillis() const;
150 double GetTotalMillis() const;
151
152 void Print(int indent);
153
154 private:
155 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100156 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
157 reinterpret_cast<CodeEntry*>(entry2));
Steve Block6ded16b2010-05-10 14:33:55 +0100158 }
159
160 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100161 return entry->GetCallUid();
Steve Block6ded16b2010-05-10 14:33:55 +0100162 }
163
164 ProfileTree* tree_;
165 CodeEntry* entry_;
166 unsigned total_ticks_;
167 unsigned self_ticks_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100168 // Mapping from CodeEntry* to ProfileNode*
Steve Block6ded16b2010-05-10 14:33:55 +0100169 HashMap children_;
170 List<ProfileNode*> children_list_;
171
172 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
173};
174
175
176class ProfileTree {
177 public:
178 ProfileTree();
179 ~ProfileTree();
180
181 void AddPathFromEnd(const Vector<CodeEntry*>& path);
182 void AddPathFromStart(const Vector<CodeEntry*>& path);
183 void CalculateTotalTicks();
Leon Clarkef7060e22010-06-03 12:02:55 +0100184 void FilteredClone(ProfileTree* src, int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100185
186 double TicksToMillis(unsigned ticks) const {
187 return ticks * ms_to_ticks_scale_;
188 }
189 ProfileNode* root() const { return root_; }
190 void SetTickRatePerMs(double ticks_per_ms);
191
192 void ShortPrint();
193 void Print() {
194 root_->Print(0);
195 }
196
197 private:
198 template <typename Callback>
Leon Clarkef7060e22010-06-03 12:02:55 +0100199 void TraverseDepthFirst(Callback* callback);
Steve Block6ded16b2010-05-10 14:33:55 +0100200
201 CodeEntry root_entry_;
202 ProfileNode* root_;
203 double ms_to_ticks_scale_;
204
205 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
206};
207
208
209class CpuProfile {
210 public:
211 CpuProfile(const char* title, unsigned uid)
212 : title_(title), uid_(uid) { }
213
214 // Add pc -> ... -> main() call path to the profile.
215 void AddPath(const Vector<CodeEntry*>& path);
216 void CalculateTotalTicks();
217 void SetActualSamplingRate(double actual_sampling_rate);
Leon Clarkef7060e22010-06-03 12:02:55 +0100218 CpuProfile* FilteredClone(int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100219
220 INLINE(const char* title() const) { return title_; }
221 INLINE(unsigned uid() const) { return uid_; }
222 INLINE(const ProfileTree* top_down() const) { return &top_down_; }
223 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
224
225 void UpdateTicksScale();
226
227 void ShortPrint();
228 void Print();
229
230 private:
231 const char* title_;
232 unsigned uid_;
233 ProfileTree top_down_;
234 ProfileTree bottom_up_;
235
236 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
237};
238
239
240class CodeMap {
241 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100242 CodeMap() : next_shared_id_(1) { }
Ben Murdoch589d6972011-11-30 16:04:58 +0000243 void AddCode(Address addr, CodeEntry* entry, unsigned size);
244 void MoveCode(Address from, Address to);
Steve Block6ded16b2010-05-10 14:33:55 +0100245 CodeEntry* FindEntry(Address addr);
Steve Block44f0eee2011-05-26 01:26:41 +0100246 int GetSharedId(Address addr);
Steve Block6ded16b2010-05-10 14:33:55 +0100247
248 void Print();
249
250 private:
251 struct CodeEntryInfo {
252 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
253 : entry(an_entry), size(a_size) { }
254 CodeEntry* entry;
255 unsigned size;
256 };
257
258 struct CodeTreeConfig {
259 typedef Address Key;
260 typedef CodeEntryInfo Value;
261 static const Key kNoKey;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000262 static const Value NoValue() { return CodeEntryInfo(NULL, 0); }
Steve Block6ded16b2010-05-10 14:33:55 +0100263 static int Compare(const Key& a, const Key& b) {
264 return a < b ? -1 : (a > b ? 1 : 0);
265 }
266 };
267 typedef SplayTree<CodeTreeConfig> CodeTree;
268
269 class CodeTreePrinter {
270 public:
271 void Call(const Address& key, const CodeEntryInfo& value);
272 };
273
Ben Murdoch589d6972011-11-30 16:04:58 +0000274 void DeleteAllCoveredCode(Address start, Address end);
275
Steve Block44f0eee2011-05-26 01:26:41 +0100276 // Fake CodeEntry pointer to distinguish shared function entries.
277 static CodeEntry* const kSharedFunctionCodeEntry;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100278
Steve Block6ded16b2010-05-10 14:33:55 +0100279 CodeTree tree_;
Steve Block44f0eee2011-05-26 01:26:41 +0100280 int next_shared_id_;
Steve Block6ded16b2010-05-10 14:33:55 +0100281
282 DISALLOW_COPY_AND_ASSIGN(CodeMap);
283};
284
285
286class CpuProfilesCollection {
287 public:
288 CpuProfilesCollection();
289 ~CpuProfilesCollection();
290
291 bool StartProfiling(const char* title, unsigned uid);
292 bool StartProfiling(String* title, unsigned uid);
Leon Clarkef7060e22010-06-03 12:02:55 +0100293 CpuProfile* StopProfiling(int security_token_id,
294 const char* title,
295 double actual_sampling_rate);
Leon Clarkef7060e22010-06-03 12:02:55 +0100296 List<CpuProfile*>* Profiles(int security_token_id);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100297 const char* GetName(String* name) {
298 return function_and_resource_names_.GetName(name);
299 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100300 const char* GetName(int args_count) {
301 return function_and_resource_names_.GetName(args_count);
302 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100303 CpuProfile* GetProfile(int security_token_id, unsigned uid);
Iain Merrick75681382010-08-19 15:07:18 +0100304 bool IsLastProfile(const char* title);
Steve Block44f0eee2011-05-26 01:26:41 +0100305 void RemoveProfile(CpuProfile* profile);
306 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +0100307
308 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
309 String* name, String* resource_name, int line_number);
310 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
311 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
312 const char* name_prefix, String* name);
313 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100314 CodeEntry* NewCodeEntry(int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100315
316 // Called from profile generator thread.
317 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
318
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100319 // Limits the number of profiles that can be simultaneously collected.
320 static const int kMaxSimultaneousProfiles = 100;
321
Steve Block6ded16b2010-05-10 14:33:55 +0100322 private:
Steve Block791712a2010-08-27 10:21:07 +0100323 const char* GetFunctionName(String* name) {
324 return function_and_resource_names_.GetFunctionName(name);
325 }
326 const char* GetFunctionName(const char* name) {
327 return function_and_resource_names_.GetFunctionName(name);
328 }
Steve Block44f0eee2011-05-26 01:26:41 +0100329 int GetProfileIndex(unsigned uid);
Leon Clarkef7060e22010-06-03 12:02:55 +0100330 List<CpuProfile*>* GetProfilesList(int security_token_id);
331 int TokenToIndex(int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100332
Leon Clarkef7060e22010-06-03 12:02:55 +0100333 INLINE(static bool UidsMatch(void* key1, void* key2)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100334 return key1 == key2;
335 }
336
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100337 StringsStorage function_and_resource_names_;
Steve Block6ded16b2010-05-10 14:33:55 +0100338 List<CodeEntry*> code_entries_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100339 List<List<CpuProfile*>* > profiles_by_token_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100340 // Mapping from profiles' uids to indexes in the second nested list
341 // of profiles_by_token_.
Steve Block6ded16b2010-05-10 14:33:55 +0100342 HashMap profiles_uids_;
Steve Block44f0eee2011-05-26 01:26:41 +0100343 List<CpuProfile*> detached_profiles_;
Steve Block6ded16b2010-05-10 14:33:55 +0100344
345 // Accessed by VM thread and profile generator thread.
346 List<CpuProfile*> current_profiles_;
347 Semaphore* current_profiles_semaphore_;
348
349 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
350};
351
352
353class SampleRateCalculator {
354 public:
355 SampleRateCalculator()
356 : result_(Logger::kSamplingIntervalMs * kResultScale),
357 ticks_per_ms_(Logger::kSamplingIntervalMs),
358 measurements_count_(0),
359 wall_time_query_countdown_(1) {
360 }
361
362 double ticks_per_ms() {
363 return result_ / static_cast<double>(kResultScale);
364 }
365 void Tick();
366 void UpdateMeasurements(double current_time);
367
368 // Instead of querying current wall time each tick,
369 // we use this constant to control query intervals.
370 static const unsigned kWallTimeQueryIntervalMs = 100;
371
372 private:
373 // As the result needs to be accessed from a different thread, we
374 // use type that guarantees atomic writes to memory. There should
375 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
376 // order should provide enough precision while keeping away from a
377 // potential overflow.
378 static const int kResultScale = 100000;
379
380 AtomicWord result_;
381 // All other fields are accessed only from the sampler thread.
382 double ticks_per_ms_;
383 unsigned measurements_count_;
384 unsigned wall_time_query_countdown_;
385 double last_wall_time_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100386
387 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator);
Steve Block6ded16b2010-05-10 14:33:55 +0100388};
389
390
391class ProfileGenerator {
392 public:
393 explicit ProfileGenerator(CpuProfilesCollection* profiles);
394
395 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
396 String* name,
397 String* resource_name,
398 int line_number)) {
399 return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
400 }
401
402 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
403 const char* name)) {
404 return profiles_->NewCodeEntry(tag, name);
405 }
406
407 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
408 const char* name_prefix,
409 String* name)) {
410 return profiles_->NewCodeEntry(tag, name_prefix, name);
411 }
412
413 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
414 int args_count)) {
415 return profiles_->NewCodeEntry(tag, args_count);
416 }
417
Leon Clarkef7060e22010-06-03 12:02:55 +0100418 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
419 return profiles_->NewCodeEntry(security_token_id);
420 }
421
Steve Block6ded16b2010-05-10 14:33:55 +0100422 void RecordTickSample(const TickSample& sample);
423
424 INLINE(CodeMap* code_map()) { return &code_map_; }
425
426 INLINE(void Tick()) { sample_rate_calc_.Tick(); }
427 INLINE(double actual_sampling_rate()) {
428 return sample_rate_calc_.ticks_per_ms();
429 }
430
Steve Block44f0eee2011-05-26 01:26:41 +0100431 static const char* const kAnonymousFunctionName;
432 static const char* const kProgramEntryName;
433 static const char* const kGarbageCollectorEntryName;
Steve Block6ded16b2010-05-10 14:33:55 +0100434
435 private:
436 INLINE(CodeEntry* EntryForVMState(StateTag tag));
437
438 CpuProfilesCollection* profiles_;
439 CodeMap code_map_;
440 CodeEntry* program_entry_;
441 CodeEntry* gc_entry_;
442 SampleRateCalculator sample_rate_calc_;
443
444 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
445};
446
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100447
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100448class HeapEntry;
449
Iain Merrick75681382010-08-19 15:07:18 +0100450class HeapGraphEdge BASE_EMBEDDED {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100451 public:
452 enum Type {
Iain Merrick75681382010-08-19 15:07:18 +0100453 kContextVariable = v8::HeapGraphEdge::kContextVariable,
454 kElement = v8::HeapGraphEdge::kElement,
455 kProperty = v8::HeapGraphEdge::kProperty,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800456 kInternal = v8::HeapGraphEdge::kInternal,
457 kHidden = v8::HeapGraphEdge::kHidden,
458 kShortcut = v8::HeapGraphEdge::kShortcut
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100459 };
460
Iain Merrick75681382010-08-19 15:07:18 +0100461 HeapGraphEdge() { }
462 void Init(int child_index, Type type, const char* name, HeapEntry* to);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800463 void Init(int child_index, Type type, int index, HeapEntry* to);
Iain Merrick75681382010-08-19 15:07:18 +0100464 void Init(int child_index, int index, HeapEntry* to);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100465
Iain Merrick75681382010-08-19 15:07:18 +0100466 Type type() { return static_cast<Type>(type_); }
467 int index() {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800468 ASSERT(type_ == kElement || type_ == kHidden);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100469 return index_;
470 }
Iain Merrick75681382010-08-19 15:07:18 +0100471 const char* name() {
472 ASSERT(type_ == kContextVariable
473 || type_ == kProperty
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800474 || type_ == kInternal
475 || type_ == kShortcut);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100476 return name_;
477 }
Iain Merrick75681382010-08-19 15:07:18 +0100478 HeapEntry* to() { return to_; }
479
480 HeapEntry* From();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100481
482 private:
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800483 int child_index_ : 29;
484 unsigned type_ : 3;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100485 union {
486 int index_;
487 const char* name_;
488 };
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100489 HeapEntry* to_;
490
491 DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge);
492};
493
494
Iain Merrick75681382010-08-19 15:07:18 +0100495class HeapSnapshot;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100496
Iain Merrick75681382010-08-19 15:07:18 +0100497// HeapEntry instances represent an entity from the heap (or a special
498// virtual node, e.g. root). To make heap snapshots more compact,
499// HeapEntries has a special memory layout (no Vectors or Lists used):
500//
501// +-----------------+
502// HeapEntry
503// +-----------------+
504// HeapGraphEdge |
505// ... } children_count
506// HeapGraphEdge |
507// +-----------------+
508// HeapGraphEdge* |
509// ... } retainers_count
510// HeapGraphEdge* |
511// +-----------------+
512//
513// In a HeapSnapshot, all entries are hand-allocated in a continuous array
514// of raw bytes.
515//
516class HeapEntry BASE_EMBEDDED {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100517 public:
518 enum Type {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800519 kHidden = v8::HeapGraphNode::kHidden,
Iain Merrick75681382010-08-19 15:07:18 +0100520 kArray = v8::HeapGraphNode::kArray,
521 kString = v8::HeapGraphNode::kString,
522 kObject = v8::HeapGraphNode::kObject,
523 kCode = v8::HeapGraphNode::kCode,
Ben Murdochf87a2032010-10-22 12:50:53 +0100524 kClosure = v8::HeapGraphNode::kClosure,
525 kRegExp = v8::HeapGraphNode::kRegExp,
Steve Block44f0eee2011-05-26 01:26:41 +0100526 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
527 kNative = v8::HeapGraphNode::kNative
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100528 };
529
Iain Merrick75681382010-08-19 15:07:18 +0100530 HeapEntry() { }
Iain Merrick75681382010-08-19 15:07:18 +0100531 void Init(HeapSnapshot* snapshot,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100532 Type type,
533 const char* name,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100534 uint64_t id,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100535 int self_size,
Iain Merrick75681382010-08-19 15:07:18 +0100536 int children_count,
537 int retainers_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100538
Iain Merrick75681382010-08-19 15:07:18 +0100539 HeapSnapshot* snapshot() { return snapshot_; }
540 Type type() { return static_cast<Type>(type_); }
541 const char* name() { return name_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100542 inline uint64_t id();
Iain Merrick75681382010-08-19 15:07:18 +0100543 int self_size() { return self_size_; }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800544 int retained_size() { return retained_size_; }
545 void add_retained_size(int size) { retained_size_ += size; }
546 void set_retained_size(int value) { retained_size_ = value; }
547 int ordered_index() { return ordered_index_; }
548 void set_ordered_index(int value) { ordered_index_ = value; }
Iain Merrick75681382010-08-19 15:07:18 +0100549
550 Vector<HeapGraphEdge> children() {
551 return Vector<HeapGraphEdge>(children_arr(), children_count_); }
552 Vector<HeapGraphEdge*> retainers() {
553 return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800554 HeapEntry* dominator() { return dominator_; }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000555 void set_dominator(HeapEntry* entry) {
556 ASSERT(entry != NULL);
557 dominator_ = entry;
558 }
Iain Merrick75681382010-08-19 15:07:18 +0100559
560 void clear_paint() { painted_ = kUnpainted; }
561 bool painted_reachable() { return painted_ == kPainted; }
562 void paint_reachable() {
563 ASSERT(painted_ == kUnpainted);
564 painted_ = kPainted;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100565 }
Iain Merrick75681382010-08-19 15:07:18 +0100566 bool not_painted_reachable_from_others() {
567 return painted_ != kPaintedReachableFromOthers;
568 }
569 void paint_reachable_from_others() {
570 painted_ = kPaintedReachableFromOthers;
571 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100572 template<class Visitor>
573 void ApplyAndPaintAllReachable(Visitor* visitor);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100574 void PaintAllReachable();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100575
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800576 void SetIndexedReference(HeapGraphEdge::Type type,
577 int child_index,
578 int index,
579 HeapEntry* entry,
580 int retainer_index);
Iain Merrick75681382010-08-19 15:07:18 +0100581 void SetNamedReference(HeapGraphEdge::Type type,
582 int child_index,
583 const char* name,
584 HeapEntry* entry,
585 int retainer_index);
586 void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
587
588 int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800589 int RetainedSize(bool exact);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100590
591 void Print(int max_depth, int indent);
592
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000593 Handle<HeapObject> GetHeapObject();
594
Iain Merrick75681382010-08-19 15:07:18 +0100595 static int EntriesSize(int entries_count,
596 int children_count,
597 int retainers_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100598
Iain Merrick75681382010-08-19 15:07:18 +0100599 private:
600 HeapGraphEdge* children_arr() {
601 return reinterpret_cast<HeapGraphEdge*>(this + 1);
602 }
603 HeapGraphEdge** retainers_arr() {
604 return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
605 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800606 void CalculateExactRetainedSize();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100607 const char* TypeAsString();
608
Iain Merrick75681382010-08-19 15:07:18 +0100609 unsigned painted_: 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100610 unsigned type_: 4;
611 int children_count_: 26;
Iain Merrick75681382010-08-19 15:07:18 +0100612 int retainers_count_;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800613 int self_size_;
614 union {
615 int ordered_index_; // Used during dominator tree building.
616 int retained_size_; // At that moment, there is no retained size yet.
617 };
618 HeapEntry* dominator_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100619 HeapSnapshot* snapshot_;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800620 struct Id {
621 uint32_t id1_;
622 uint32_t id2_;
623 } id_; // This is to avoid extra padding of 64-bit value.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100624 const char* name_;
Iain Merrick75681382010-08-19 15:07:18 +0100625
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800626 // Paints used for exact retained sizes calculation.
Iain Merrick75681382010-08-19 15:07:18 +0100627 static const unsigned kUnpainted = 0;
628 static const unsigned kPainted = 1;
629 static const unsigned kPaintedReachableFromOthers = 2;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800630
631 static const int kExactRetainedSizeTag = 1;
Iain Merrick75681382010-08-19 15:07:18 +0100632
633 DISALLOW_COPY_AND_ASSIGN(HeapEntry);
634};
635
636
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100637class HeapSnapshotsCollection;
638
639// HeapSnapshot represents a single heap snapshot. It is stored in
640// HeapSnapshotsCollection, which is also a factory for
641// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
642// to be able to return them even if they were collected.
643// HeapSnapshotGenerator fills in a HeapSnapshot.
644class HeapSnapshot {
645 public:
Steve Block791712a2010-08-27 10:21:07 +0100646 enum Type {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000647 kFull = v8::HeapSnapshot::kFull
Steve Block791712a2010-08-27 10:21:07 +0100648 };
649
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100650 HeapSnapshot(HeapSnapshotsCollection* collection,
Steve Block791712a2010-08-27 10:21:07 +0100651 Type type,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100652 const char* title,
653 unsigned uid);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100654 ~HeapSnapshot();
Steve Block44f0eee2011-05-26 01:26:41 +0100655 void Delete();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100656
Iain Merrick75681382010-08-19 15:07:18 +0100657 HeapSnapshotsCollection* collection() { return collection_; }
Steve Block791712a2010-08-27 10:21:07 +0100658 Type type() { return type_; }
Iain Merrick75681382010-08-19 15:07:18 +0100659 const char* title() { return title_; }
660 unsigned uid() { return uid_; }
Ben Murdochf87a2032010-10-22 12:50:53 +0100661 HeapEntry* root() { return root_entry_; }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800662 HeapEntry* gc_roots() { return gc_roots_entry_; }
Steve Block44f0eee2011-05-26 01:26:41 +0100663 HeapEntry* natives_root() { return natives_root_entry_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100664 List<HeapEntry*>* entries() { return &entries_; }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000665 int raw_entries_size() { return raw_entries_size_; }
Iain Merrick75681382010-08-19 15:07:18 +0100666
667 void AllocateEntries(
668 int entries_count, int children_count, int retainers_count);
Steve Block791712a2010-08-27 10:21:07 +0100669 HeapEntry* AddEntry(HeapEntry::Type type,
670 const char* name,
671 uint64_t id,
672 int size,
673 int children_count,
674 int retainers_count);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100675 HeapEntry* AddRootEntry(int children_count);
676 HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
Steve Block44f0eee2011-05-26 01:26:41 +0100677 HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
Iain Merrick75681382010-08-19 15:07:18 +0100678 void ClearPaint();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100679 HeapEntry* GetEntryById(uint64_t id);
Iain Merrick75681382010-08-19 15:07:18 +0100680 List<HeapEntry*>* GetSortedEntriesList();
681 template<class Visitor>
682 void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800683 void SetDominatorsToSelf();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100684
685 void Print(int max_depth);
Iain Merrick75681382010-08-19 15:07:18 +0100686 void PrintEntriesSize();
687
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100688 private:
Iain Merrick75681382010-08-19 15:07:18 +0100689 HeapEntry* GetNextEntryToInit();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100690
691 HeapSnapshotsCollection* collection_;
Steve Block791712a2010-08-27 10:21:07 +0100692 Type type_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100693 const char* title_;
694 unsigned uid_;
Ben Murdochf87a2032010-10-22 12:50:53 +0100695 HeapEntry* root_entry_;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800696 HeapEntry* gc_roots_entry_;
Steve Block44f0eee2011-05-26 01:26:41 +0100697 HeapEntry* natives_root_entry_;
Iain Merrick75681382010-08-19 15:07:18 +0100698 char* raw_entries_;
699 List<HeapEntry*> entries_;
700 bool entries_sorted_;
Steve Block791712a2010-08-27 10:21:07 +0100701 int raw_entries_size_;
Iain Merrick75681382010-08-19 15:07:18 +0100702
703 friend class HeapSnapshotTester;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100704
705 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
706};
707
708
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100709class HeapObjectsMap {
710 public:
711 HeapObjectsMap();
712 ~HeapObjectsMap();
713
714 void SnapshotGenerationFinished();
715 uint64_t FindObject(Address addr);
716 void MoveObject(Address from, Address to);
717
Steve Block44f0eee2011-05-26 01:26:41 +0100718 static uint64_t GenerateId(v8::RetainedObjectInfo* info);
719
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800720 static const uint64_t kInternalRootObjectId;
721 static const uint64_t kGcRootsObjectId;
Steve Block44f0eee2011-05-26 01:26:41 +0100722 static const uint64_t kNativesRootObjectId;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800723 static const uint64_t kFirstAvailableObjectId;
724
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100725 private:
726 struct EntryInfo {
727 explicit EntryInfo(uint64_t id) : id(id), accessed(true) { }
728 EntryInfo(uint64_t id, bool accessed) : id(id), accessed(accessed) { }
729 uint64_t id;
730 bool accessed;
731 };
732
733 void AddEntry(Address addr, uint64_t id);
734 uint64_t FindEntry(Address addr);
735 void RemoveDeadEntries();
736
737 static bool AddressesMatch(void* key1, void* key2) {
738 return key1 == key2;
739 }
740
741 static uint32_t AddressHash(Address addr) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100742 return ComputeIntegerHash(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000743 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100744 }
745
746 bool initial_fill_mode_;
747 uint64_t next_id_;
748 HashMap entries_map_;
749 List<EntryInfo>* entries_;
750
751 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
752};
753
754
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100755class HeapSnapshotsCollection {
756 public:
757 HeapSnapshotsCollection();
758 ~HeapSnapshotsCollection();
759
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100760 bool is_tracking_objects() { return is_tracking_objects_; }
761
Steve Block791712a2010-08-27 10:21:07 +0100762 HeapSnapshot* NewSnapshot(
763 HeapSnapshot::Type type, const char* name, unsigned uid);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100764 void SnapshotGenerationFinished(HeapSnapshot* snapshot);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100765 List<HeapSnapshot*>* snapshots() { return &snapshots_; }
766 HeapSnapshot* GetSnapshot(unsigned uid);
Steve Block44f0eee2011-05-26 01:26:41 +0100767 void RemoveSnapshot(HeapSnapshot* snapshot);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100768
Steve Block44f0eee2011-05-26 01:26:41 +0100769 StringsStorage* names() { return &names_; }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100770 TokenEnumerator* token_enumerator() { return token_enumerator_; }
771
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100772 uint64_t GetObjectId(Address addr) { return ids_.FindObject(addr); }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000773 Handle<HeapObject> FindHeapObjectById(uint64_t id);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100774 void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
775
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100776 private:
777 INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
778 return key1 == key2;
779 }
780
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100781 bool is_tracking_objects_; // Whether tracking object moves is needed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100782 List<HeapSnapshot*> snapshots_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100783 // Mapping from snapshots' uids to HeapSnapshot* pointers.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100784 HashMap snapshots_uids_;
785 StringsStorage names_;
786 TokenEnumerator* token_enumerator_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100787 // Mapping from HeapObject addresses to objects' uids.
788 HeapObjectsMap ids_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100789
790 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
791};
792
793
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100794// A typedef for referencing anything that can be snapshotted living
795// in any kind of heap memory.
796typedef void* HeapThing;
797
798
799// An interface that creates HeapEntries by HeapThings.
800class HeapEntriesAllocator {
801 public:
802 virtual ~HeapEntriesAllocator() { }
803 virtual HeapEntry* AllocateEntry(
804 HeapThing ptr, int children_count, int retainers_count) = 0;
805};
806
807
Iain Merrick75681382010-08-19 15:07:18 +0100808// The HeapEntriesMap instance is used to track a mapping between
809// real heap objects and their representations in heap snapshots.
810class HeapEntriesMap {
811 public:
812 HeapEntriesMap();
813 ~HeapEntriesMap();
814
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100815 void AllocateEntries();
816 HeapEntry* Map(HeapThing thing);
817 void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
818 void CountReference(HeapThing from, HeapThing to,
Iain Merrick75681382010-08-19 15:07:18 +0100819 int* prev_children_count = NULL,
820 int* prev_retainers_count = NULL);
Iain Merrick75681382010-08-19 15:07:18 +0100821
822 int entries_count() { return entries_count_; }
823 int total_children_count() { return total_children_count_; }
824 int total_retainers_count() { return total_retainers_count_; }
825
Steve Block791712a2010-08-27 10:21:07 +0100826 static HeapEntry *const kHeapEntryPlaceholder;
827
Iain Merrick75681382010-08-19 15:07:18 +0100828 private:
829 struct EntryInfo {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100830 EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
831 : entry(entry),
832 allocator(allocator),
833 children_count(0),
834 retainers_count(0) {
835 }
Iain Merrick75681382010-08-19 15:07:18 +0100836 HeapEntry* entry;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100837 HeapEntriesAllocator* allocator;
Iain Merrick75681382010-08-19 15:07:18 +0100838 int children_count;
839 int retainers_count;
840 };
841
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100842 static uint32_t Hash(HeapThing thing) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100843 return ComputeIntegerHash(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000844 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)));
Iain Merrick75681382010-08-19 15:07:18 +0100845 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100846 static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
847 return key1 == key2;
848 }
Iain Merrick75681382010-08-19 15:07:18 +0100849
Iain Merrick75681382010-08-19 15:07:18 +0100850 HashMap entries_;
851 int entries_count_;
852 int total_children_count_;
853 int total_retainers_count_;
854
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800855 friend class HeapObjectsSet;
Iain Merrick75681382010-08-19 15:07:18 +0100856
857 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
858};
859
860
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800861class HeapObjectsSet {
862 public:
863 HeapObjectsSet();
864 void Clear();
865 bool Contains(Object* object);
866 void Insert(Object* obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000867 const char* GetTag(Object* obj);
868 void SetTag(Object* obj, const char* tag);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800869
870 private:
871 HashMap entries_;
872
873 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
874};
875
876
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100877// An interface used to populate a snapshot with nodes and edges.
878class SnapshotFillerInterface {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100879 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100880 virtual ~SnapshotFillerInterface() { }
Steve Block44f0eee2011-05-26 01:26:41 +0100881 virtual HeapEntry* AddEntry(HeapThing ptr,
882 HeapEntriesAllocator* allocator) = 0;
883 virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
884 virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
885 HeapEntriesAllocator* allocator) = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100886 virtual void SetIndexedReference(HeapGraphEdge::Type type,
887 HeapThing parent_ptr,
Iain Merrick75681382010-08-19 15:07:18 +0100888 HeapEntry* parent_entry,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100889 int index,
890 HeapThing child_ptr,
Iain Merrick75681382010-08-19 15:07:18 +0100891 HeapEntry* child_entry) = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100892 virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
893 HeapThing parent_ptr,
894 HeapEntry* parent_entry,
895 HeapThing child_ptr,
896 HeapEntry* child_entry) = 0;
897 virtual void SetNamedReference(HeapGraphEdge::Type type,
898 HeapThing parent_ptr,
899 HeapEntry* parent_entry,
900 const char* reference_name,
901 HeapThing child_ptr,
902 HeapEntry* child_entry) = 0;
903 virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
904 HeapThing parent_ptr,
905 HeapEntry* parent_entry,
906 HeapThing child_ptr,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800907 HeapEntry* child_entry) = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100908};
Iain Merrick75681382010-08-19 15:07:18 +0100909
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100910
911class SnapshottingProgressReportingInterface {
912 public:
913 virtual ~SnapshottingProgressReportingInterface() { }
914 virtual void ProgressStep() = 0;
915 virtual bool ProgressReport(bool force) = 0;
916};
917
918
919// An implementation of V8 heap graph extractor.
920class V8HeapExplorer : public HeapEntriesAllocator {
921 public:
922 V8HeapExplorer(HeapSnapshot* snapshot,
923 SnapshottingProgressReportingInterface* progress);
Steve Block44f0eee2011-05-26 01:26:41 +0100924 virtual ~V8HeapExplorer();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100925 virtual HeapEntry* AllocateEntry(
926 HeapThing ptr, int children_count, int retainers_count);
927 void AddRootEntries(SnapshotFillerInterface* filler);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000928 int EstimateObjectsCount(HeapIterator* iterator);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100929 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000930 void TagGlobalObjects();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100931
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000932 static String* GetConstructorName(JSObject* object);
933
Steve Block44f0eee2011-05-26 01:26:41 +0100934 static HeapObject* const kInternalRootObject;
935
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100936 private:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100937 HeapEntry* AddEntry(
938 HeapObject* object, int children_count, int retainers_count);
939 HeapEntry* AddEntry(HeapObject* object,
940 HeapEntry::Type type,
941 const char* name,
942 int children_count,
943 int retainers_count);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100944 const char* GetSystemEntryName(HeapObject* object);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100945 void ExtractReferences(HeapObject* obj);
946 void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
947 void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
948 void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
Ben Murdochf87a2032010-10-22 12:50:53 +0100949 void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
Iain Merrick75681382010-08-19 15:07:18 +0100950 void SetClosureReference(HeapObject* parent_obj,
951 HeapEntry* parent,
952 String* reference_name,
953 Object* child);
954 void SetElementReference(HeapObject* parent_obj,
955 HeapEntry* parent,
956 int index,
957 Object* child);
958 void SetInternalReference(HeapObject* parent_obj,
959 HeapEntry* parent,
960 const char* reference_name,
Steve Block44f0eee2011-05-26 01:26:41 +0100961 Object* child,
962 int field_offset = -1);
Ben Murdochf87a2032010-10-22 12:50:53 +0100963 void SetInternalReference(HeapObject* parent_obj,
964 HeapEntry* parent,
965 int index,
Steve Block44f0eee2011-05-26 01:26:41 +0100966 Object* child,
967 int field_offset = -1);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800968 void SetHiddenReference(HeapObject* parent_obj,
969 HeapEntry* parent,
970 int index,
971 Object* child);
Iain Merrick75681382010-08-19 15:07:18 +0100972 void SetPropertyReference(HeapObject* parent_obj,
973 HeapEntry* parent,
974 String* reference_name,
Steve Block44f0eee2011-05-26 01:26:41 +0100975 Object* child,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000976 const char* name_format_string = NULL,
Steve Block44f0eee2011-05-26 01:26:41 +0100977 int field_offset = -1);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800978 void SetPropertyShortcutReference(HeapObject* parent_obj,
979 HeapEntry* parent,
980 String* reference_name,
981 Object* child);
982 void SetRootShortcutReference(Object* child);
983 void SetRootGcRootsReference();
984 void SetGcRootsReference(Object* child);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000985 void TagObject(Object* obj, const char* tag);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100986
987 HeapEntry* GetEntry(Object* obj);
988
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000989 Heap* heap_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100990 HeapSnapshot* snapshot_;
991 HeapSnapshotsCollection* collection_;
992 SnapshottingProgressReportingInterface* progress_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100993 SnapshotFillerInterface* filler_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000994 HeapObjectsSet objects_tags_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100995
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100996 static HeapObject* const kGcRootsObject;
997
998 friend class IndexedReferencesExtractor;
999 friend class RootsReferencesExtractor;
1000
1001 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
1002};
1003
1004
Steve Block44f0eee2011-05-26 01:26:41 +01001005// An implementation of retained native objects extractor.
1006class NativeObjectsExplorer : public HeapEntriesAllocator {
1007 public:
1008 NativeObjectsExplorer(HeapSnapshot* snapshot,
1009 SnapshottingProgressReportingInterface* progress);
1010 virtual ~NativeObjectsExplorer();
1011 virtual HeapEntry* AllocateEntry(
1012 HeapThing ptr, int children_count, int retainers_count);
1013 void AddRootEntries(SnapshotFillerInterface* filler);
1014 int EstimateObjectsCount();
1015 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
1016
1017 private:
1018 void FillRetainedObjects();
1019 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
1020 void SetNativeRootReference(v8::RetainedObjectInfo* info);
1021 void SetRootNativesRootReference();
1022 void SetWrapperNativeReferences(HeapObject* wrapper,
1023 v8::RetainedObjectInfo* info);
1024 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
1025
1026 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001027 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()));
Steve Block44f0eee2011-05-26 01:26:41 +01001028 }
1029 static bool RetainedInfosMatch(void* key1, void* key2) {
1030 return key1 == key2 ||
1031 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
1032 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
1033 }
1034
1035 HeapSnapshot* snapshot_;
1036 HeapSnapshotsCollection* collection_;
1037 SnapshottingProgressReportingInterface* progress_;
1038 bool embedder_queried_;
1039 HeapObjectsSet in_groups_;
1040 // RetainedObjectInfo* -> List<HeapObject*>*
1041 HashMap objects_by_info_;
1042 // Used during references extraction.
1043 SnapshotFillerInterface* filler_;
1044
1045 static HeapThing const kNativesRootObject;
1046
1047 friend class GlobalHandlesExtractor;
1048
1049 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
1050};
1051
1052
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001053class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
1054 public:
1055 HeapSnapshotGenerator(HeapSnapshot* snapshot,
1056 v8::ActivityControl* control);
1057 bool GenerateSnapshot();
1058
1059 private:
1060 bool ApproximateRetainedSizes();
1061 bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
1062 Vector<HeapEntry*>* dominators);
1063 bool CountEntriesAndReferences();
1064 bool FillReferences();
1065 void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
1066 void ProgressStep();
1067 bool ProgressReport(bool force = false);
1068 bool SetEntriesDominators();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001069 void SetProgressTotal(int iterations_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001070
1071 HeapSnapshot* snapshot_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001072 v8::ActivityControl* control_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001073 V8HeapExplorer v8_heap_explorer_;
Steve Block44f0eee2011-05-26 01:26:41 +01001074 NativeObjectsExplorer dom_explorer_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001075 // Mapping from HeapThing pointers to HeapEntry* pointers.
Iain Merrick75681382010-08-19 15:07:18 +01001076 HeapEntriesMap entries_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001077 // Used during snapshot generation.
1078 int progress_counter_;
1079 int progress_total_;
Iain Merrick75681382010-08-19 15:07:18 +01001080
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001081 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
1082};
1083
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001084class OutputStreamWriter;
1085
1086class HeapSnapshotJSONSerializer {
1087 public:
1088 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
1089 : snapshot_(snapshot),
1090 nodes_(ObjectsMatch),
1091 strings_(ObjectsMatch),
1092 next_node_id_(1),
1093 next_string_id_(1),
1094 writer_(NULL) {
1095 }
1096 void Serialize(v8::OutputStream* stream);
1097
1098 private:
1099 INLINE(static bool ObjectsMatch(void* key1, void* key2)) {
1100 return key1 == key2;
1101 }
1102
1103 INLINE(static uint32_t ObjectHash(const void* key)) {
1104 return ComputeIntegerHash(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001105 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001106 }
1107
1108 void EnumerateNodes();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001109 HeapSnapshot* CreateFakeSnapshot();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001110 int GetNodeId(HeapEntry* entry);
1111 int GetStringId(const char* s);
1112 void SerializeEdge(HeapGraphEdge* edge);
1113 void SerializeImpl();
1114 void SerializeNode(HeapEntry* entry);
1115 void SerializeNodes();
1116 void SerializeSnapshot();
1117 void SerializeString(const unsigned char* s);
1118 void SerializeStrings();
1119 void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
1120
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001121 static const int kMaxSerializableSnapshotRawSize;
1122
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001123 HeapSnapshot* snapshot_;
1124 HashMap nodes_;
1125 HashMap strings_;
1126 int next_node_id_;
1127 int next_string_id_;
1128 OutputStreamWriter* writer_;
1129
1130 friend class HeapSnapshotJSONSerializerEnumerator;
1131 friend class HeapSnapshotJSONSerializerIterator;
1132
1133 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
1134};
1135
Steve Block6ded16b2010-05-10 14:33:55 +01001136} } // namespace v8::internal
1137
Steve Block6ded16b2010-05-10 14:33:55 +01001138#endif // V8_PROFILE_GENERATOR_H_