blob: d9a1319b87bc9f9f5480b2106afa8242e54e981f [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// 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
Ben Murdoch3ef787d2012-04-12 10:51:47 +010038typedef uint32_t SnapshotObjectId;
39
Leon Clarkef7060e22010-06-03 12:02:55 +010040class TokenEnumerator {
41 public:
42 TokenEnumerator();
43 ~TokenEnumerator();
44 int GetTokenId(Object* token);
45
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010046 static const int kNoSecurityToken = -1;
47 static const int kInheritsSecurityToken = -2;
48
Leon Clarkef7060e22010-06-03 12:02:55 +010049 private:
50 static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
51 void* parameter);
52 void TokenRemoved(Object** token_location);
53
54 List<Object**> token_locations_;
55 List<bool> token_removed_;
56
57 friend class TokenEnumeratorTester;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010058
59 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator);
60};
61
62
63// Provides a storage of strings allocated in C++ heap, to hold them
64// forever, even if they disappear from JS heap or external storage.
65class StringsStorage {
66 public:
67 StringsStorage();
68 ~StringsStorage();
69
Steve Block44f0eee2011-05-26 01:26:41 +010070 const char* GetCopy(const char* src);
71 const char* GetFormatted(const char* format, ...);
72 const char* GetVFormatted(const char* format, va_list args);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010073 const char* GetName(String* name);
Ben Murdochf87a2032010-10-22 12:50:53 +010074 const char* GetName(int index);
Steve Block791712a2010-08-27 10:21:07 +010075 inline const char* GetFunctionName(String* name);
76 inline const char* GetFunctionName(const char* name);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010077
78 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010079 static const int kMaxNameSize = 1024;
80
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010081 INLINE(static bool StringsMatch(void* key1, void* key2)) {
82 return strcmp(reinterpret_cast<char*>(key1),
83 reinterpret_cast<char*>(key2)) == 0;
84 }
Steve Block44f0eee2011-05-26 01:26:41 +010085 const char* AddOrDisposeString(char* str, uint32_t hash);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010086
Ben Murdoch3bec4d22010-07-22 14:51:16 +010087 // Mapping of strings by String::Hash to const char* strings.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010088 HashMap names_;
89
90 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
Leon Clarkef7060e22010-06-03 12:02:55 +010091};
92
93
Steve Block6ded16b2010-05-10 14:33:55 +010094class CodeEntry {
95 public:
96 // CodeEntry doesn't own name strings, just references them.
97 INLINE(CodeEntry(Logger::LogEventsAndTags tag,
98 const char* name_prefix,
99 const char* name,
100 const char* resource_name,
Leon Clarkef7060e22010-06-03 12:02:55 +0100101 int line_number,
102 int security_token_id));
Steve Block6ded16b2010-05-10 14:33:55 +0100103
104 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
105 INLINE(const char* name_prefix() const) { return name_prefix_; }
106 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
107 INLINE(const char* name() const) { return name_; }
108 INLINE(const char* resource_name() const) { return resource_name_; }
109 INLINE(int line_number() const) { return line_number_; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100110 INLINE(int shared_id() const) { return shared_id_; }
111 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
Leon Clarkef7060e22010-06-03 12:02:55 +0100112 INLINE(int security_token_id() const) { return security_token_id_; }
Steve Block6ded16b2010-05-10 14:33:55 +0100113
114 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
115
Leon Clarkef7060e22010-06-03 12:02:55 +0100116 void CopyData(const CodeEntry& source);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100117 uint32_t GetCallUid() const;
118 bool IsSameAs(CodeEntry* entry) const;
Leon Clarkef7060e22010-06-03 12:02:55 +0100119
Steve Block44f0eee2011-05-26 01:26:41 +0100120 static const char* const kEmptyNamePrefix;
Steve Block6ded16b2010-05-10 14:33:55 +0100121
122 private:
Steve Block6ded16b2010-05-10 14:33:55 +0100123 Logger::LogEventsAndTags tag_;
124 const char* name_prefix_;
125 const char* name_;
126 const char* resource_name_;
127 int line_number_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100128 int shared_id_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100129 int security_token_id_;
Steve Block6ded16b2010-05-10 14:33:55 +0100130
Steve Block6ded16b2010-05-10 14:33:55 +0100131 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
132};
133
134
135class ProfileTree;
136
137class ProfileNode {
138 public:
139 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
140
141 ProfileNode* FindChild(CodeEntry* entry);
142 ProfileNode* FindOrAddChild(CodeEntry* entry);
143 INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
Leon Clarkef7060e22010-06-03 12:02:55 +0100144 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
Steve Block6ded16b2010-05-10 14:33:55 +0100145 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
146
147 INLINE(CodeEntry* entry() const) { return entry_; }
148 INLINE(unsigned self_ticks() const) { return self_ticks_; }
149 INLINE(unsigned total_ticks() const) { return total_ticks_; }
150 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
151 double GetSelfMillis() const;
152 double GetTotalMillis() const;
153
154 void Print(int indent);
155
156 private:
157 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100158 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
159 reinterpret_cast<CodeEntry*>(entry2));
Steve Block6ded16b2010-05-10 14:33:55 +0100160 }
161
162 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100163 return entry->GetCallUid();
Steve Block6ded16b2010-05-10 14:33:55 +0100164 }
165
166 ProfileTree* tree_;
167 CodeEntry* entry_;
168 unsigned total_ticks_;
169 unsigned self_ticks_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100170 // Mapping from CodeEntry* to ProfileNode*
Steve Block6ded16b2010-05-10 14:33:55 +0100171 HashMap children_;
172 List<ProfileNode*> children_list_;
173
174 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
175};
176
177
178class ProfileTree {
179 public:
180 ProfileTree();
181 ~ProfileTree();
182
183 void AddPathFromEnd(const Vector<CodeEntry*>& path);
184 void AddPathFromStart(const Vector<CodeEntry*>& path);
185 void CalculateTotalTicks();
Leon Clarkef7060e22010-06-03 12:02:55 +0100186 void FilteredClone(ProfileTree* src, int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100187
188 double TicksToMillis(unsigned ticks) const {
189 return ticks * ms_to_ticks_scale_;
190 }
191 ProfileNode* root() const { return root_; }
192 void SetTickRatePerMs(double ticks_per_ms);
193
194 void ShortPrint();
195 void Print() {
196 root_->Print(0);
197 }
198
199 private:
200 template <typename Callback>
Leon Clarkef7060e22010-06-03 12:02:55 +0100201 void TraverseDepthFirst(Callback* callback);
Steve Block6ded16b2010-05-10 14:33:55 +0100202
203 CodeEntry root_entry_;
204 ProfileNode* root_;
205 double ms_to_ticks_scale_;
206
207 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
208};
209
210
211class CpuProfile {
212 public:
213 CpuProfile(const char* title, unsigned uid)
214 : title_(title), uid_(uid) { }
215
216 // Add pc -> ... -> main() call path to the profile.
217 void AddPath(const Vector<CodeEntry*>& path);
218 void CalculateTotalTicks();
219 void SetActualSamplingRate(double actual_sampling_rate);
Leon Clarkef7060e22010-06-03 12:02:55 +0100220 CpuProfile* FilteredClone(int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100221
222 INLINE(const char* title() const) { return title_; }
223 INLINE(unsigned uid() const) { return uid_; }
224 INLINE(const ProfileTree* top_down() const) { return &top_down_; }
225 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
226
227 void UpdateTicksScale();
228
229 void ShortPrint();
230 void Print();
231
232 private:
233 const char* title_;
234 unsigned uid_;
235 ProfileTree top_down_;
236 ProfileTree bottom_up_;
237
238 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
239};
240
241
242class CodeMap {
243 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100244 CodeMap() : next_shared_id_(1) { }
Ben Murdoch589d6972011-11-30 16:04:58 +0000245 void AddCode(Address addr, CodeEntry* entry, unsigned size);
246 void MoveCode(Address from, Address to);
Steve Block6ded16b2010-05-10 14:33:55 +0100247 CodeEntry* FindEntry(Address addr);
Steve Block44f0eee2011-05-26 01:26:41 +0100248 int GetSharedId(Address addr);
Steve Block6ded16b2010-05-10 14:33:55 +0100249
250 void Print();
251
252 private:
253 struct CodeEntryInfo {
254 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
255 : entry(an_entry), size(a_size) { }
256 CodeEntry* entry;
257 unsigned size;
258 };
259
260 struct CodeTreeConfig {
261 typedef Address Key;
262 typedef CodeEntryInfo Value;
263 static const Key kNoKey;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100264 static const Value NoValue() { return CodeEntryInfo(NULL, 0); }
Steve Block6ded16b2010-05-10 14:33:55 +0100265 static int Compare(const Key& a, const Key& b) {
266 return a < b ? -1 : (a > b ? 1 : 0);
267 }
268 };
269 typedef SplayTree<CodeTreeConfig> CodeTree;
270
271 class CodeTreePrinter {
272 public:
273 void Call(const Address& key, const CodeEntryInfo& value);
274 };
275
Ben Murdoch589d6972011-11-30 16:04:58 +0000276 void DeleteAllCoveredCode(Address start, Address end);
277
Steve Block44f0eee2011-05-26 01:26:41 +0100278 // Fake CodeEntry pointer to distinguish shared function entries.
279 static CodeEntry* const kSharedFunctionCodeEntry;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100280
Steve Block6ded16b2010-05-10 14:33:55 +0100281 CodeTree tree_;
Steve Block44f0eee2011-05-26 01:26:41 +0100282 int next_shared_id_;
Steve Block6ded16b2010-05-10 14:33:55 +0100283
284 DISALLOW_COPY_AND_ASSIGN(CodeMap);
285};
286
287
288class CpuProfilesCollection {
289 public:
290 CpuProfilesCollection();
291 ~CpuProfilesCollection();
292
293 bool StartProfiling(const char* title, unsigned uid);
294 bool StartProfiling(String* title, unsigned uid);
Leon Clarkef7060e22010-06-03 12:02:55 +0100295 CpuProfile* StopProfiling(int security_token_id,
296 const char* title,
297 double actual_sampling_rate);
Leon Clarkef7060e22010-06-03 12:02:55 +0100298 List<CpuProfile*>* Profiles(int security_token_id);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100299 const char* GetName(String* name) {
300 return function_and_resource_names_.GetName(name);
301 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100302 const char* GetName(int args_count) {
303 return function_and_resource_names_.GetName(args_count);
304 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100305 CpuProfile* GetProfile(int security_token_id, unsigned uid);
Iain Merrick75681382010-08-19 15:07:18 +0100306 bool IsLastProfile(const char* title);
Steve Block44f0eee2011-05-26 01:26:41 +0100307 void RemoveProfile(CpuProfile* profile);
308 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
Steve Block6ded16b2010-05-10 14:33:55 +0100309
310 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
311 String* name, String* resource_name, int line_number);
312 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
313 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
314 const char* name_prefix, String* name);
315 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100316 CodeEntry* NewCodeEntry(int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100317
318 // Called from profile generator thread.
319 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
320
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100321 // Limits the number of profiles that can be simultaneously collected.
322 static const int kMaxSimultaneousProfiles = 100;
323
Steve Block6ded16b2010-05-10 14:33:55 +0100324 private:
Steve Block791712a2010-08-27 10:21:07 +0100325 const char* GetFunctionName(String* name) {
326 return function_and_resource_names_.GetFunctionName(name);
327 }
328 const char* GetFunctionName(const char* name) {
329 return function_and_resource_names_.GetFunctionName(name);
330 }
Steve Block44f0eee2011-05-26 01:26:41 +0100331 int GetProfileIndex(unsigned uid);
Leon Clarkef7060e22010-06-03 12:02:55 +0100332 List<CpuProfile*>* GetProfilesList(int security_token_id);
333 int TokenToIndex(int security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100334
Leon Clarkef7060e22010-06-03 12:02:55 +0100335 INLINE(static bool UidsMatch(void* key1, void* key2)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100336 return key1 == key2;
337 }
338
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100339 StringsStorage function_and_resource_names_;
Steve Block6ded16b2010-05-10 14:33:55 +0100340 List<CodeEntry*> code_entries_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100341 List<List<CpuProfile*>* > profiles_by_token_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100342 // Mapping from profiles' uids to indexes in the second nested list
343 // of profiles_by_token_.
Steve Block6ded16b2010-05-10 14:33:55 +0100344 HashMap profiles_uids_;
Steve Block44f0eee2011-05-26 01:26:41 +0100345 List<CpuProfile*> detached_profiles_;
Steve Block6ded16b2010-05-10 14:33:55 +0100346
347 // Accessed by VM thread and profile generator thread.
348 List<CpuProfile*> current_profiles_;
349 Semaphore* current_profiles_semaphore_;
350
351 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
352};
353
354
355class SampleRateCalculator {
356 public:
357 SampleRateCalculator()
358 : result_(Logger::kSamplingIntervalMs * kResultScale),
359 ticks_per_ms_(Logger::kSamplingIntervalMs),
360 measurements_count_(0),
361 wall_time_query_countdown_(1) {
362 }
363
364 double ticks_per_ms() {
365 return result_ / static_cast<double>(kResultScale);
366 }
367 void Tick();
368 void UpdateMeasurements(double current_time);
369
370 // Instead of querying current wall time each tick,
371 // we use this constant to control query intervals.
372 static const unsigned kWallTimeQueryIntervalMs = 100;
373
374 private:
375 // As the result needs to be accessed from a different thread, we
376 // use type that guarantees atomic writes to memory. There should
377 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
378 // order should provide enough precision while keeping away from a
379 // potential overflow.
380 static const int kResultScale = 100000;
381
382 AtomicWord result_;
383 // All other fields are accessed only from the sampler thread.
384 double ticks_per_ms_;
385 unsigned measurements_count_;
386 unsigned wall_time_query_countdown_;
387 double last_wall_time_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100388
389 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator);
Steve Block6ded16b2010-05-10 14:33:55 +0100390};
391
392
393class ProfileGenerator {
394 public:
395 explicit ProfileGenerator(CpuProfilesCollection* profiles);
396
397 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
398 String* name,
399 String* resource_name,
400 int line_number)) {
401 return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
402 }
403
404 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
405 const char* name)) {
406 return profiles_->NewCodeEntry(tag, name);
407 }
408
409 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
410 const char* name_prefix,
411 String* name)) {
412 return profiles_->NewCodeEntry(tag, name_prefix, name);
413 }
414
415 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
416 int args_count)) {
417 return profiles_->NewCodeEntry(tag, args_count);
418 }
419
Leon Clarkef7060e22010-06-03 12:02:55 +0100420 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
421 return profiles_->NewCodeEntry(security_token_id);
422 }
423
Steve Block6ded16b2010-05-10 14:33:55 +0100424 void RecordTickSample(const TickSample& sample);
425
426 INLINE(CodeMap* code_map()) { return &code_map_; }
427
428 INLINE(void Tick()) { sample_rate_calc_.Tick(); }
429 INLINE(double actual_sampling_rate()) {
430 return sample_rate_calc_.ticks_per_ms();
431 }
432
Steve Block44f0eee2011-05-26 01:26:41 +0100433 static const char* const kAnonymousFunctionName;
434 static const char* const kProgramEntryName;
435 static const char* const kGarbageCollectorEntryName;
Steve Block6ded16b2010-05-10 14:33:55 +0100436
437 private:
438 INLINE(CodeEntry* EntryForVMState(StateTag tag));
439
440 CpuProfilesCollection* profiles_;
441 CodeMap code_map_;
442 CodeEntry* program_entry_;
443 CodeEntry* gc_entry_;
444 SampleRateCalculator sample_rate_calc_;
445
446 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
447};
448
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100449
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100450class HeapEntry;
451
Iain Merrick75681382010-08-19 15:07:18 +0100452class HeapGraphEdge BASE_EMBEDDED {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100453 public:
454 enum Type {
Iain Merrick75681382010-08-19 15:07:18 +0100455 kContextVariable = v8::HeapGraphEdge::kContextVariable,
456 kElement = v8::HeapGraphEdge::kElement,
457 kProperty = v8::HeapGraphEdge::kProperty,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800458 kInternal = v8::HeapGraphEdge::kInternal,
459 kHidden = v8::HeapGraphEdge::kHidden,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100460 kShortcut = v8::HeapGraphEdge::kShortcut,
461 kWeak = v8::HeapGraphEdge::kWeak
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100462 };
463
Iain Merrick75681382010-08-19 15:07:18 +0100464 HeapGraphEdge() { }
465 void Init(int child_index, Type type, const char* name, HeapEntry* to);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800466 void Init(int child_index, Type type, int index, HeapEntry* to);
Iain Merrick75681382010-08-19 15:07:18 +0100467 void Init(int child_index, int index, HeapEntry* to);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100468
Iain Merrick75681382010-08-19 15:07:18 +0100469 Type type() { return static_cast<Type>(type_); }
470 int index() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100471 ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100472 return index_;
473 }
Iain Merrick75681382010-08-19 15:07:18 +0100474 const char* name() {
475 ASSERT(type_ == kContextVariable
476 || type_ == kProperty
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800477 || type_ == kInternal
478 || type_ == kShortcut);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100479 return name_;
480 }
Iain Merrick75681382010-08-19 15:07:18 +0100481 HeapEntry* to() { return to_; }
482
483 HeapEntry* From();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100484
485 private:
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800486 int child_index_ : 29;
487 unsigned type_ : 3;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100488 union {
489 int index_;
490 const char* name_;
491 };
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100492 HeapEntry* to_;
493
494 DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge);
495};
496
497
Iain Merrick75681382010-08-19 15:07:18 +0100498class HeapSnapshot;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100499
Iain Merrick75681382010-08-19 15:07:18 +0100500// HeapEntry instances represent an entity from the heap (or a special
501// virtual node, e.g. root). To make heap snapshots more compact,
502// HeapEntries has a special memory layout (no Vectors or Lists used):
503//
504// +-----------------+
505// HeapEntry
506// +-----------------+
507// HeapGraphEdge |
508// ... } children_count
509// HeapGraphEdge |
510// +-----------------+
511// HeapGraphEdge* |
512// ... } retainers_count
513// HeapGraphEdge* |
514// +-----------------+
515//
516// In a HeapSnapshot, all entries are hand-allocated in a continuous array
517// of raw bytes.
518//
519class HeapEntry BASE_EMBEDDED {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100520 public:
521 enum Type {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800522 kHidden = v8::HeapGraphNode::kHidden,
Iain Merrick75681382010-08-19 15:07:18 +0100523 kArray = v8::HeapGraphNode::kArray,
524 kString = v8::HeapGraphNode::kString,
525 kObject = v8::HeapGraphNode::kObject,
526 kCode = v8::HeapGraphNode::kCode,
Ben Murdochf87a2032010-10-22 12:50:53 +0100527 kClosure = v8::HeapGraphNode::kClosure,
528 kRegExp = v8::HeapGraphNode::kRegExp,
Steve Block44f0eee2011-05-26 01:26:41 +0100529 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100530 kNative = v8::HeapGraphNode::kNative,
531 kSynthetic = v8::HeapGraphNode::kSynthetic
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100532 };
533
Iain Merrick75681382010-08-19 15:07:18 +0100534 HeapEntry() { }
Iain Merrick75681382010-08-19 15:07:18 +0100535 void Init(HeapSnapshot* snapshot,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100536 Type type,
537 const char* name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100538 SnapshotObjectId id,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100539 int self_size,
Iain Merrick75681382010-08-19 15:07:18 +0100540 int children_count,
541 int retainers_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100542
Iain Merrick75681382010-08-19 15:07:18 +0100543 HeapSnapshot* snapshot() { return snapshot_; }
544 Type type() { return static_cast<Type>(type_); }
545 const char* name() { return name_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100546 void set_name(const char* name) { name_ = name; }
547 inline SnapshotObjectId id() { return id_; }
Iain Merrick75681382010-08-19 15:07:18 +0100548 int self_size() { return self_size_; }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800549 int retained_size() { return retained_size_; }
550 void add_retained_size(int size) { retained_size_ += size; }
551 void set_retained_size(int value) { retained_size_ = value; }
552 int ordered_index() { return ordered_index_; }
553 void set_ordered_index(int value) { ordered_index_ = value; }
Iain Merrick75681382010-08-19 15:07:18 +0100554
555 Vector<HeapGraphEdge> children() {
556 return Vector<HeapGraphEdge>(children_arr(), children_count_); }
557 Vector<HeapGraphEdge*> retainers() {
558 return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800559 HeapEntry* dominator() { return dominator_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100560 void set_dominator(HeapEntry* entry) {
561 ASSERT(entry != NULL);
562 dominator_ = entry;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000563 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100564 void clear_paint() { painted_ = false; }
565 bool painted() { return painted_; }
566 void paint() { painted_ = true; }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100567
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800568 void SetIndexedReference(HeapGraphEdge::Type type,
569 int child_index,
570 int index,
571 HeapEntry* entry,
572 int retainer_index);
Iain Merrick75681382010-08-19 15:07:18 +0100573 void SetNamedReference(HeapGraphEdge::Type type,
574 int child_index,
575 const char* name,
576 HeapEntry* entry,
577 int retainer_index);
578 void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
579
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100580 size_t EntrySize() {
581 return EntriesSize(1, children_count_, retainers_count_);
582 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100583
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100584 void Print(
585 const char* prefix, const char* edge_name, int max_depth, int indent);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100586
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000587 Handle<HeapObject> GetHeapObject();
588
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100589 static size_t EntriesSize(int entries_count,
590 int children_count,
591 int retainers_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100592
Iain Merrick75681382010-08-19 15:07:18 +0100593 private:
594 HeapGraphEdge* children_arr() {
595 return reinterpret_cast<HeapGraphEdge*>(this + 1);
596 }
597 HeapGraphEdge** retainers_arr() {
598 return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
599 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100600 const char* TypeAsString();
601
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100602 unsigned painted_: 1;
Steve Block44f0eee2011-05-26 01:26:41 +0100603 unsigned type_: 4;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100604 int children_count_: 27;
Iain Merrick75681382010-08-19 15:07:18 +0100605 int retainers_count_;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800606 int self_size_;
607 union {
608 int ordered_index_; // Used during dominator tree building.
609 int retained_size_; // At that moment, there is no retained size yet.
610 };
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100611 SnapshotObjectId id_;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800612 HeapEntry* dominator_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100613 HeapSnapshot* snapshot_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100614 const char* name_;
Iain Merrick75681382010-08-19 15:07:18 +0100615
Iain Merrick75681382010-08-19 15:07:18 +0100616 DISALLOW_COPY_AND_ASSIGN(HeapEntry);
617};
618
619
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100620class HeapSnapshotsCollection;
621
622// HeapSnapshot represents a single heap snapshot. It is stored in
623// HeapSnapshotsCollection, which is also a factory for
624// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
625// to be able to return them even if they were collected.
626// HeapSnapshotGenerator fills in a HeapSnapshot.
627class HeapSnapshot {
628 public:
Steve Block791712a2010-08-27 10:21:07 +0100629 enum Type {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000630 kFull = v8::HeapSnapshot::kFull
Steve Block791712a2010-08-27 10:21:07 +0100631 };
632
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100633 HeapSnapshot(HeapSnapshotsCollection* collection,
Steve Block791712a2010-08-27 10:21:07 +0100634 Type type,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100635 const char* title,
636 unsigned uid);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100637 ~HeapSnapshot();
Steve Block44f0eee2011-05-26 01:26:41 +0100638 void Delete();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100639
Iain Merrick75681382010-08-19 15:07:18 +0100640 HeapSnapshotsCollection* collection() { return collection_; }
Steve Block791712a2010-08-27 10:21:07 +0100641 Type type() { return type_; }
Iain Merrick75681382010-08-19 15:07:18 +0100642 const char* title() { return title_; }
643 unsigned uid() { return uid_; }
Ben Murdochf87a2032010-10-22 12:50:53 +0100644 HeapEntry* root() { return root_entry_; }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800645 HeapEntry* gc_roots() { return gc_roots_entry_; }
Steve Block44f0eee2011-05-26 01:26:41 +0100646 HeapEntry* natives_root() { return natives_root_entry_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100647 HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100648 List<HeapEntry*>* entries() { return &entries_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100649 size_t raw_entries_size() { return raw_entries_size_; }
Iain Merrick75681382010-08-19 15:07:18 +0100650
651 void AllocateEntries(
652 int entries_count, int children_count, int retainers_count);
Steve Block791712a2010-08-27 10:21:07 +0100653 HeapEntry* AddEntry(HeapEntry::Type type,
654 const char* name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100655 SnapshotObjectId id,
Steve Block791712a2010-08-27 10:21:07 +0100656 int size,
657 int children_count,
658 int retainers_count);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100659 HeapEntry* AddRootEntry(int children_count);
660 HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100661 HeapEntry* AddGcSubrootEntry(int tag,
662 int children_count,
663 int retainers_count);
Steve Block44f0eee2011-05-26 01:26:41 +0100664 HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
Iain Merrick75681382010-08-19 15:07:18 +0100665 void ClearPaint();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100666 HeapEntry* GetEntryById(SnapshotObjectId id);
Iain Merrick75681382010-08-19 15:07:18 +0100667 List<HeapEntry*>* GetSortedEntriesList();
668 template<class Visitor>
669 void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800670 void SetDominatorsToSelf();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100671
672 void Print(int max_depth);
Iain Merrick75681382010-08-19 15:07:18 +0100673 void PrintEntriesSize();
674
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100675 private:
Iain Merrick75681382010-08-19 15:07:18 +0100676 HeapEntry* GetNextEntryToInit();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100677
678 HeapSnapshotsCollection* collection_;
Steve Block791712a2010-08-27 10:21:07 +0100679 Type type_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100680 const char* title_;
681 unsigned uid_;
Ben Murdochf87a2032010-10-22 12:50:53 +0100682 HeapEntry* root_entry_;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800683 HeapEntry* gc_roots_entry_;
Steve Block44f0eee2011-05-26 01:26:41 +0100684 HeapEntry* natives_root_entry_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100685 HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
Iain Merrick75681382010-08-19 15:07:18 +0100686 char* raw_entries_;
687 List<HeapEntry*> entries_;
688 bool entries_sorted_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100689 size_t raw_entries_size_;
Iain Merrick75681382010-08-19 15:07:18 +0100690
691 friend class HeapSnapshotTester;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100692
693 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
694};
695
696
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100697class HeapObjectsMap {
698 public:
699 HeapObjectsMap();
700 ~HeapObjectsMap();
701
702 void SnapshotGenerationFinished();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100703 SnapshotObjectId FindObject(Address addr);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100704 void MoveObject(Address from, Address to);
705
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100706 static SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
707 static inline SnapshotObjectId GetNthGcSubrootId(int delta);
Steve Block44f0eee2011-05-26 01:26:41 +0100708
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100709 static const int kObjectIdStep = 2;
710 static const SnapshotObjectId kInternalRootObjectId;
711 static const SnapshotObjectId kGcRootsObjectId;
712 static const SnapshotObjectId kNativesRootObjectId;
713 static const SnapshotObjectId kGcRootsFirstSubrootId;
714 static const SnapshotObjectId kFirstAvailableObjectId;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800715
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100716 private:
717 struct EntryInfo {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100718 explicit EntryInfo(SnapshotObjectId id) : id(id), accessed(true) { }
719 EntryInfo(SnapshotObjectId id, bool accessed)
720 : id(id),
721 accessed(accessed) { }
722 SnapshotObjectId id;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100723 bool accessed;
724 };
725
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100726 void AddEntry(Address addr, SnapshotObjectId id);
727 SnapshotObjectId FindEntry(Address addr);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100728 void RemoveDeadEntries();
729
730 static bool AddressesMatch(void* key1, void* key2) {
731 return key1 == key2;
732 }
733
734 static uint32_t AddressHash(Address addr) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100735 return ComputeIntegerHash(
Ben Murdochc7cc0282012-03-05 14:35:55 +0000736 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)),
737 v8::internal::kZeroHashSeed);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100738 }
739
740 bool initial_fill_mode_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100741 SnapshotObjectId next_id_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100742 HashMap entries_map_;
743 List<EntryInfo>* entries_;
744
745 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
746};
747
748
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100749class HeapSnapshotsCollection {
750 public:
751 HeapSnapshotsCollection();
752 ~HeapSnapshotsCollection();
753
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100754 bool is_tracking_objects() { return is_tracking_objects_; }
755
Steve Block791712a2010-08-27 10:21:07 +0100756 HeapSnapshot* NewSnapshot(
757 HeapSnapshot::Type type, const char* name, unsigned uid);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100758 void SnapshotGenerationFinished(HeapSnapshot* snapshot);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100759 List<HeapSnapshot*>* snapshots() { return &snapshots_; }
760 HeapSnapshot* GetSnapshot(unsigned uid);
Steve Block44f0eee2011-05-26 01:26:41 +0100761 void RemoveSnapshot(HeapSnapshot* snapshot);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100762
Steve Block44f0eee2011-05-26 01:26:41 +0100763 StringsStorage* names() { return &names_; }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100764 TokenEnumerator* token_enumerator() { return token_enumerator_; }
765
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100766 SnapshotObjectId GetObjectId(Address addr) { return ids_.FindObject(addr); }
767 Handle<HeapObject> FindHeapObjectById(SnapshotObjectId id);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100768 void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
769
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100770 private:
771 INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
772 return key1 == key2;
773 }
774
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100775 bool is_tracking_objects_; // Whether tracking object moves is needed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100776 List<HeapSnapshot*> snapshots_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100777 // Mapping from snapshots' uids to HeapSnapshot* pointers.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100778 HashMap snapshots_uids_;
779 StringsStorage names_;
780 TokenEnumerator* token_enumerator_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100781 // Mapping from HeapObject addresses to objects' uids.
782 HeapObjectsMap ids_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100783
784 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
785};
786
787
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100788// A typedef for referencing anything that can be snapshotted living
789// in any kind of heap memory.
790typedef void* HeapThing;
791
792
793// An interface that creates HeapEntries by HeapThings.
794class HeapEntriesAllocator {
795 public:
796 virtual ~HeapEntriesAllocator() { }
797 virtual HeapEntry* AllocateEntry(
798 HeapThing ptr, int children_count, int retainers_count) = 0;
799};
800
801
Iain Merrick75681382010-08-19 15:07:18 +0100802// The HeapEntriesMap instance is used to track a mapping between
803// real heap objects and their representations in heap snapshots.
804class HeapEntriesMap {
805 public:
806 HeapEntriesMap();
807 ~HeapEntriesMap();
808
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100809 void AllocateEntries();
810 HeapEntry* Map(HeapThing thing);
811 void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
812 void CountReference(HeapThing from, HeapThing to,
Iain Merrick75681382010-08-19 15:07:18 +0100813 int* prev_children_count = NULL,
814 int* prev_retainers_count = NULL);
Iain Merrick75681382010-08-19 15:07:18 +0100815
816 int entries_count() { return entries_count_; }
817 int total_children_count() { return total_children_count_; }
818 int total_retainers_count() { return total_retainers_count_; }
819
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100820 static HeapEntry* const kHeapEntryPlaceholder;
Steve Block791712a2010-08-27 10:21:07 +0100821
Iain Merrick75681382010-08-19 15:07:18 +0100822 private:
823 struct EntryInfo {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100824 EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
825 : entry(entry),
826 allocator(allocator),
827 children_count(0),
828 retainers_count(0) {
829 }
Iain Merrick75681382010-08-19 15:07:18 +0100830 HeapEntry* entry;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100831 HeapEntriesAllocator* allocator;
Iain Merrick75681382010-08-19 15:07:18 +0100832 int children_count;
833 int retainers_count;
834 };
835
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100836 static uint32_t Hash(HeapThing thing) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100837 return ComputeIntegerHash(
Ben Murdochc7cc0282012-03-05 14:35:55 +0000838 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
839 v8::internal::kZeroHashSeed);
Iain Merrick75681382010-08-19 15:07:18 +0100840 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100841 static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
842 return key1 == key2;
843 }
Iain Merrick75681382010-08-19 15:07:18 +0100844
Iain Merrick75681382010-08-19 15:07:18 +0100845 HashMap entries_;
846 int entries_count_;
847 int total_children_count_;
848 int total_retainers_count_;
849
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800850 friend class HeapObjectsSet;
Iain Merrick75681382010-08-19 15:07:18 +0100851
852 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
853};
854
855
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800856class HeapObjectsSet {
857 public:
858 HeapObjectsSet();
859 void Clear();
860 bool Contains(Object* object);
861 void Insert(Object* obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000862 const char* GetTag(Object* obj);
863 void SetTag(Object* obj, const char* tag);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800864
865 private:
866 HashMap entries_;
867
868 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
869};
870
871
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100872// An interface used to populate a snapshot with nodes and edges.
873class SnapshotFillerInterface {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100874 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100875 virtual ~SnapshotFillerInterface() { }
Steve Block44f0eee2011-05-26 01:26:41 +0100876 virtual HeapEntry* AddEntry(HeapThing ptr,
877 HeapEntriesAllocator* allocator) = 0;
878 virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
879 virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
880 HeapEntriesAllocator* allocator) = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100881 virtual void SetIndexedReference(HeapGraphEdge::Type type,
882 HeapThing parent_ptr,
Iain Merrick75681382010-08-19 15:07:18 +0100883 HeapEntry* parent_entry,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100884 int index,
885 HeapThing child_ptr,
Iain Merrick75681382010-08-19 15:07:18 +0100886 HeapEntry* child_entry) = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100887 virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
888 HeapThing parent_ptr,
889 HeapEntry* parent_entry,
890 HeapThing child_ptr,
891 HeapEntry* child_entry) = 0;
892 virtual void SetNamedReference(HeapGraphEdge::Type type,
893 HeapThing parent_ptr,
894 HeapEntry* parent_entry,
895 const char* reference_name,
896 HeapThing child_ptr,
897 HeapEntry* child_entry) = 0;
898 virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
899 HeapThing parent_ptr,
900 HeapEntry* parent_entry,
901 HeapThing child_ptr,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800902 HeapEntry* child_entry) = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100903};
Iain Merrick75681382010-08-19 15:07:18 +0100904
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100905
906class SnapshottingProgressReportingInterface {
907 public:
908 virtual ~SnapshottingProgressReportingInterface() { }
909 virtual void ProgressStep() = 0;
910 virtual bool ProgressReport(bool force) = 0;
911};
912
913
914// An implementation of V8 heap graph extractor.
915class V8HeapExplorer : public HeapEntriesAllocator {
916 public:
917 V8HeapExplorer(HeapSnapshot* snapshot,
918 SnapshottingProgressReportingInterface* progress);
Steve Block44f0eee2011-05-26 01:26:41 +0100919 virtual ~V8HeapExplorer();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100920 virtual HeapEntry* AllocateEntry(
921 HeapThing ptr, int children_count, int retainers_count);
922 void AddRootEntries(SnapshotFillerInterface* filler);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100923 int EstimateObjectsCount(HeapIterator* iterator);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100924 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100925 bool IterateAndSetObjectNames(SnapshotFillerInterface* filler);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000926 void TagGlobalObjects();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100927
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000928 static String* GetConstructorName(JSObject* object);
929
Steve Block44f0eee2011-05-26 01:26:41 +0100930 static HeapObject* const kInternalRootObject;
931
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100932 private:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100933 HeapEntry* AddEntry(
934 HeapObject* object, int children_count, int retainers_count);
935 HeapEntry* AddEntry(HeapObject* object,
936 HeapEntry::Type type,
937 const char* name,
938 int children_count,
939 int retainers_count);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100940 const char* GetSystemEntryName(HeapObject* object);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100941 void ExtractReferences(HeapObject* obj);
942 void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
943 void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
944 void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
Ben Murdochf87a2032010-10-22 12:50:53 +0100945 void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
Iain Merrick75681382010-08-19 15:07:18 +0100946 void SetClosureReference(HeapObject* parent_obj,
947 HeapEntry* parent,
948 String* reference_name,
949 Object* child);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100950 void SetNativeBindReference(HeapObject* parent_obj,
951 HeapEntry* parent,
952 const char* reference_name,
953 Object* child);
Iain Merrick75681382010-08-19 15:07:18 +0100954 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);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100972 void SetWeakReference(HeapObject* parent_obj,
973 HeapEntry* parent_entry,
974 int index,
975 Object* child_obj,
976 int field_offset);
Iain Merrick75681382010-08-19 15:07:18 +0100977 void SetPropertyReference(HeapObject* parent_obj,
978 HeapEntry* parent,
979 String* reference_name,
Steve Block44f0eee2011-05-26 01:26:41 +0100980 Object* child,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100981 const char* name_format_string = NULL,
Steve Block44f0eee2011-05-26 01:26:41 +0100982 int field_offset = -1);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800983 void SetPropertyShortcutReference(HeapObject* parent_obj,
984 HeapEntry* parent,
985 String* reference_name,
986 Object* child);
987 void SetRootShortcutReference(Object* child);
988 void SetRootGcRootsReference();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100989 void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
990 void SetGcSubrootReference(
991 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
992 void SetObjectName(HeapObject* object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000993 void TagObject(Object* obj, const char* tag);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100994
995 HeapEntry* GetEntry(Object* obj);
996
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100997 static inline HeapObject* GetNthGcSubrootObject(int delta);
998 static inline int GetGcSubrootOrder(HeapObject* subroot);
999
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001000 Heap* heap_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001001 HeapSnapshot* snapshot_;
1002 HeapSnapshotsCollection* collection_;
1003 SnapshottingProgressReportingInterface* progress_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001004 SnapshotFillerInterface* filler_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001005 HeapObjectsSet objects_tags_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001006
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001007 static HeapObject* const kGcRootsObject;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001008 static HeapObject* const kFirstGcSubrootObject;
1009 static HeapObject* const kLastGcSubrootObject;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001010
1011 friend class IndexedReferencesExtractor;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001012 friend class GcSubrootsEnumerator;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001013 friend class RootsReferencesExtractor;
1014
1015 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
1016};
1017
1018
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001019class NativeGroupRetainedObjectInfo;
1020
1021
Steve Block44f0eee2011-05-26 01:26:41 +01001022// An implementation of retained native objects extractor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001023class NativeObjectsExplorer {
Steve Block44f0eee2011-05-26 01:26:41 +01001024 public:
1025 NativeObjectsExplorer(HeapSnapshot* snapshot,
1026 SnapshottingProgressReportingInterface* progress);
1027 virtual ~NativeObjectsExplorer();
Steve Block44f0eee2011-05-26 01:26:41 +01001028 void AddRootEntries(SnapshotFillerInterface* filler);
1029 int EstimateObjectsCount();
1030 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
1031
1032 private:
1033 void FillRetainedObjects();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001034 void FillImplicitReferences();
Steve Block44f0eee2011-05-26 01:26:41 +01001035 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
1036 void SetNativeRootReference(v8::RetainedObjectInfo* info);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001037 void SetRootNativeRootsReference();
Steve Block44f0eee2011-05-26 01:26:41 +01001038 void SetWrapperNativeReferences(HeapObject* wrapper,
1039 v8::RetainedObjectInfo* info);
1040 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
1041
1042 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001043 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
1044 v8::internal::kZeroHashSeed);
Steve Block44f0eee2011-05-26 01:26:41 +01001045 }
1046 static bool RetainedInfosMatch(void* key1, void* key2) {
1047 return key1 == key2 ||
1048 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
1049 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
1050 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001051 INLINE(static bool StringsMatch(void* key1, void* key2)) {
1052 return strcmp(reinterpret_cast<char*>(key1),
1053 reinterpret_cast<char*>(key2)) == 0;
1054 }
1055
1056 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
Steve Block44f0eee2011-05-26 01:26:41 +01001057
1058 HeapSnapshot* snapshot_;
1059 HeapSnapshotsCollection* collection_;
1060 SnapshottingProgressReportingInterface* progress_;
1061 bool embedder_queried_;
1062 HeapObjectsSet in_groups_;
1063 // RetainedObjectInfo* -> List<HeapObject*>*
1064 HashMap objects_by_info_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001065 HashMap native_groups_;
1066 HeapEntriesAllocator* synthetic_entries_allocator_;
1067 HeapEntriesAllocator* native_entries_allocator_;
Steve Block44f0eee2011-05-26 01:26:41 +01001068 // Used during references extraction.
1069 SnapshotFillerInterface* filler_;
1070
1071 static HeapThing const kNativesRootObject;
1072
1073 friend class GlobalHandlesExtractor;
1074
1075 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
1076};
1077
1078
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001079class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
1080 public:
1081 HeapSnapshotGenerator(HeapSnapshot* snapshot,
1082 v8::ActivityControl* control);
1083 bool GenerateSnapshot();
1084
1085 private:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001086 bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001087 Vector<int>* dominators);
1088 bool CalculateRetainedSizes();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001089 bool CountEntriesAndReferences();
1090 bool FillReferences();
1091 void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
1092 void ProgressStep();
1093 bool ProgressReport(bool force = false);
1094 bool SetEntriesDominators();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001095 void SetProgressTotal(int iterations_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001096
1097 HeapSnapshot* snapshot_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001098 v8::ActivityControl* control_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001099 V8HeapExplorer v8_heap_explorer_;
Steve Block44f0eee2011-05-26 01:26:41 +01001100 NativeObjectsExplorer dom_explorer_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001101 // Mapping from HeapThing pointers to HeapEntry* pointers.
Iain Merrick75681382010-08-19 15:07:18 +01001102 HeapEntriesMap entries_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001103 // Used during snapshot generation.
1104 int progress_counter_;
1105 int progress_total_;
Iain Merrick75681382010-08-19 15:07:18 +01001106
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001107 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
1108};
1109
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001110class OutputStreamWriter;
1111
1112class HeapSnapshotJSONSerializer {
1113 public:
1114 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
1115 : snapshot_(snapshot),
1116 nodes_(ObjectsMatch),
1117 strings_(ObjectsMatch),
1118 next_node_id_(1),
1119 next_string_id_(1),
1120 writer_(NULL) {
1121 }
1122 void Serialize(v8::OutputStream* stream);
1123
1124 private:
1125 INLINE(static bool ObjectsMatch(void* key1, void* key2)) {
1126 return key1 == key2;
1127 }
1128
1129 INLINE(static uint32_t ObjectHash(const void* key)) {
1130 return ComputeIntegerHash(
Ben Murdochc7cc0282012-03-05 14:35:55 +00001131 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)),
1132 v8::internal::kZeroHashSeed);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001133 }
1134
1135 void EnumerateNodes();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001136 HeapSnapshot* CreateFakeSnapshot();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001137 int GetNodeId(HeapEntry* entry);
1138 int GetStringId(const char* s);
1139 void SerializeEdge(HeapGraphEdge* edge);
1140 void SerializeImpl();
1141 void SerializeNode(HeapEntry* entry);
1142 void SerializeNodes();
1143 void SerializeSnapshot();
1144 void SerializeString(const unsigned char* s);
1145 void SerializeStrings();
1146 void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
1147
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001148 static const int kMaxSerializableSnapshotRawSize;
1149
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001150 HeapSnapshot* snapshot_;
1151 HashMap nodes_;
1152 HashMap strings_;
1153 int next_node_id_;
1154 int next_string_id_;
1155 OutputStreamWriter* writer_;
1156
1157 friend class HeapSnapshotJSONSerializerEnumerator;
1158 friend class HeapSnapshotJSONSerializerIterator;
1159
1160 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
1161};
1162
Steve Block6ded16b2010-05-10 14:33:55 +01001163} } // namespace v8::internal
1164
Steve Block6ded16b2010-05-10 14:33:55 +01001165#endif // V8_PROFILE_GENERATOR_H_