blob: d56d874705da50fa7320ab01dd5f0cfe808b09eb [file] [log] [blame]
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002// 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
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
fschneider@chromium.org086aac62010-03-17 13:18:24 +000032#include "hashmap.h"
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000033#include "../include/v8-profiler.h"
fschneider@chromium.org086aac62010-03-17 13:18:24 +000034
35namespace v8 {
36namespace internal {
37
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000038class TokenEnumerator {
39 public:
40 TokenEnumerator();
41 ~TokenEnumerator();
42 int GetTokenId(Object* token);
43
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000044 static const int kNoSecurityToken = -1;
45 static const int kInheritsSecurityToken = -2;
46
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000047 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;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000056
57 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000058};
59
60
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000061// 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
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000068 const char* GetCopy(const char* src);
69 const char* GetFormatted(const char* format, ...);
70 const char* GetVFormatted(const char* format, va_list args);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000071 const char* GetName(String* name);
vegorov@chromium.org42841962010-10-18 11:18:59 +000072 const char* GetName(int index);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000073 inline const char* GetFunctionName(String* name);
74 inline const char* GetFunctionName(const char* name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +000075 size_t GetUsedMemorySize() const;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000076
77 private:
danno@chromium.orgc612e022011-11-10 11:38:15 +000078 static const int kMaxNameSize = 1024;
79
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000080 INLINE(static bool StringsMatch(void* key1, void* key2)) {
81 return strcmp(reinterpret_cast<char*>(key1),
82 reinterpret_cast<char*>(key2)) == 0;
83 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000084 const char* AddOrDisposeString(char* str, uint32_t hash);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000085
ricow@chromium.org4980dff2010-07-19 08:33:45 +000086 // Mapping of strings by String::Hash to const char* strings.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000087 HashMap names_;
88
89 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
90};
91
92
fschneider@chromium.org086aac62010-03-17 13:18:24 +000093class CodeEntry {
94 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000095 // CodeEntry doesn't own name strings, just references them.
lrn@chromium.org25156de2010-04-06 13:10:27 +000096 INLINE(CodeEntry(Logger::LogEventsAndTags tag,
97 const char* name_prefix,
98 const char* name,
99 const char* resource_name,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000100 int line_number,
101 int security_token_id));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000102
ager@chromium.org357bf652010-04-12 11:30:10 +0000103 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000104 INLINE(const char* name_prefix() const) { return name_prefix_; }
105 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
106 INLINE(const char* name() const) { return name_; }
107 INLINE(const char* resource_name() const) { return resource_name_; }
108 INLINE(int line_number() const) { return line_number_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000109 INLINE(int shared_id() const) { return shared_id_; }
110 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000111 INLINE(int security_token_id() const) { return security_token_id_; }
ager@chromium.org357bf652010-04-12 11:30:10 +0000112
113 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000114
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000115 void CopyData(const CodeEntry& source);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000116 uint32_t GetCallUid() const;
117 bool IsSameAs(CodeEntry* entry) const;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119 static const char* const kEmptyNamePrefix;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000120
121 private:
122 Logger::LogEventsAndTags tag_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000123 const char* name_prefix_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000124 const char* name_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000125 const char* resource_name_;
126 int line_number_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000127 int shared_id_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000128 int security_token_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000129
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000130 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000131};
132
133
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000134class ProfileTree;
135
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000136class ProfileNode {
137 public:
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000138 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000139
140 ProfileNode* FindChild(CodeEntry* entry);
141 ProfileNode* FindOrAddChild(CodeEntry* entry);
142 INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000143 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000144 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
145
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000146 INLINE(CodeEntry* entry() const) { return entry_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000147 INLINE(unsigned self_ticks() const) { return self_ticks_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000148 INLINE(unsigned total_ticks() const) { return total_ticks_; }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000149 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000150 double GetSelfMillis() const;
151 double GetTotalMillis() const;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000152
153 void Print(int indent);
154
155 private:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000156 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000157 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
158 reinterpret_cast<CodeEntry*>(entry2));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000159 }
160
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000161 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000162 return entry->GetCallUid();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000163 }
164
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000165 ProfileTree* tree_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000166 CodeEntry* entry_;
167 unsigned total_ticks_;
168 unsigned self_ticks_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000169 // Mapping from CodeEntry* to ProfileNode*
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000170 HashMap children_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000171 List<ProfileNode*> children_list_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000172
173 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
174};
175
176
lrn@chromium.org25156de2010-04-06 13:10:27 +0000177class ProfileTree {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000178 public:
ager@chromium.org357bf652010-04-12 11:30:10 +0000179 ProfileTree();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000180 ~ProfileTree();
181
182 void AddPathFromEnd(const Vector<CodeEntry*>& path);
183 void AddPathFromStart(const Vector<CodeEntry*>& path);
184 void CalculateTotalTicks();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000185 void FilteredClone(ProfileTree* src, int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000186
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000187 double TicksToMillis(unsigned ticks) const {
188 return ticks * ms_to_ticks_scale_;
189 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000190 ProfileNode* root() const { return root_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000191 void SetTickRatePerMs(double ticks_per_ms);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000192
193 void ShortPrint();
194 void Print() {
195 root_->Print(0);
196 }
197
198 private:
199 template <typename Callback>
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000200 void TraverseDepthFirst(Callback* callback);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000201
ager@chromium.org357bf652010-04-12 11:30:10 +0000202 CodeEntry root_entry_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000203 ProfileNode* root_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000204 double ms_to_ticks_scale_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000205
206 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
207};
208
209
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000210class CpuProfile {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000211 public:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000212 CpuProfile(const char* title, unsigned uid)
213 : title_(title), uid_(uid) { }
214
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000215 // Add pc -> ... -> main() call path to the profile.
216 void AddPath(const Vector<CodeEntry*>& path);
217 void CalculateTotalTicks();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000218 void SetActualSamplingRate(double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000219 CpuProfile* FilteredClone(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000220
lrn@chromium.org25156de2010-04-06 13:10:27 +0000221 INLINE(const char* title() const) { return title_; }
222 INLINE(unsigned uid() const) { return uid_; }
223 INLINE(const ProfileTree* top_down() const) { return &top_down_; }
224 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000225
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000226 void UpdateTicksScale();
227
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000228 void ShortPrint();
229 void Print();
230
231 private:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000232 const char* title_;
233 unsigned uid_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000234 ProfileTree top_down_;
235 ProfileTree bottom_up_;
236
237 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
238};
239
240
lrn@chromium.org25156de2010-04-06 13:10:27 +0000241class CodeMap {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000242 public:
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000243 CodeMap() : next_shared_id_(1) { }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000244 void AddCode(Address addr, CodeEntry* entry, unsigned size);
245 void MoveCode(Address from, Address to);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000246 CodeEntry* FindEntry(Address addr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000247 int GetSharedId(Address addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000248
lrn@chromium.org25156de2010-04-06 13:10:27 +0000249 void Print();
250
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000251 private:
252 struct CodeEntryInfo {
253 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
254 : entry(an_entry), size(a_size) { }
255 CodeEntry* entry;
256 unsigned size;
257 };
258
259 struct CodeTreeConfig {
260 typedef Address Key;
261 typedef CodeEntryInfo Value;
262 static const Key kNoKey;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000263 static const Value NoValue() { return CodeEntryInfo(NULL, 0); }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000264 static int Compare(const Key& a, const Key& b) {
265 return a < b ? -1 : (a > b ? 1 : 0);
266 }
267 };
268 typedef SplayTree<CodeTreeConfig> CodeTree;
269
lrn@chromium.org25156de2010-04-06 13:10:27 +0000270 class CodeTreePrinter {
271 public:
272 void Call(const Address& key, const CodeEntryInfo& value);
273 };
274
lrn@chromium.org34e60782011-09-15 07:25:40 +0000275 void DeleteAllCoveredCode(Address start, Address end);
276
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000277 // Fake CodeEntry pointer to distinguish shared function entries.
278 static CodeEntry* const kSharedFunctionCodeEntry;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000279
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000280 CodeTree tree_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000281 int next_shared_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000282
283 DISALLOW_COPY_AND_ASSIGN(CodeMap);
284};
285
286
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000287class CpuProfilesCollection {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000288 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000289 CpuProfilesCollection();
290 ~CpuProfilesCollection();
291
lrn@chromium.org25156de2010-04-06 13:10:27 +0000292 bool StartProfiling(const char* title, unsigned uid);
293 bool StartProfiling(String* title, unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000294 CpuProfile* StopProfiling(int security_token_id,
295 const char* title,
296 double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000297 List<CpuProfile*>* Profiles(int security_token_id);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000298 const char* GetName(String* name) {
299 return function_and_resource_names_.GetName(name);
300 }
vegorov@chromium.org42841962010-10-18 11:18:59 +0000301 const char* GetName(int args_count) {
302 return function_and_resource_names_.GetName(args_count);
303 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000304 CpuProfile* GetProfile(int security_token_id, unsigned uid);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000305 bool IsLastProfile(const char* title);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000306 void RemoveProfile(CpuProfile* profile);
307 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000308
309 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
310 String* name, String* resource_name, int line_number);
311 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000312 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
313 const char* name_prefix, String* name);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000314 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000315 CodeEntry* NewCodeEntry(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000316
lrn@chromium.org25156de2010-04-06 13:10:27 +0000317 // Called from profile generator thread.
318 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000319
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000320 // Limits the number of profiles that can be simultaneously collected.
321 static const int kMaxSimultaneousProfiles = 100;
322
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000323 private:
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000324 const char* GetFunctionName(String* name) {
325 return function_and_resource_names_.GetFunctionName(name);
326 }
327 const char* GetFunctionName(const char* name) {
328 return function_and_resource_names_.GetFunctionName(name);
329 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 int GetProfileIndex(unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000331 List<CpuProfile*>* GetProfilesList(int security_token_id);
332 int TokenToIndex(int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000333
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000334 INLINE(static bool UidsMatch(void* key1, void* key2)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000335 return key1 == key2;
336 }
337
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000338 StringsStorage function_and_resource_names_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000339 List<CodeEntry*> code_entries_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000340 List<List<CpuProfile*>* > profiles_by_token_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000341 // Mapping from profiles' uids to indexes in the second nested list
342 // of profiles_by_token_.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000343 HashMap profiles_uids_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 List<CpuProfile*> detached_profiles_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000345
346 // Accessed by VM thread and profile generator thread.
347 List<CpuProfile*> current_profiles_;
348 Semaphore* current_profiles_semaphore_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000349
350 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
351};
352
353
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000354class SampleRateCalculator {
355 public:
356 SampleRateCalculator()
357 : result_(Logger::kSamplingIntervalMs * kResultScale),
358 ticks_per_ms_(Logger::kSamplingIntervalMs),
359 measurements_count_(0),
360 wall_time_query_countdown_(1) {
361 }
362
363 double ticks_per_ms() {
364 return result_ / static_cast<double>(kResultScale);
365 }
366 void Tick();
367 void UpdateMeasurements(double current_time);
368
369 // Instead of querying current wall time each tick,
370 // we use this constant to control query intervals.
371 static const unsigned kWallTimeQueryIntervalMs = 100;
372
373 private:
374 // As the result needs to be accessed from a different thread, we
375 // use type that guarantees atomic writes to memory. There should
376 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
377 // order should provide enough precision while keeping away from a
378 // potential overflow.
379 static const int kResultScale = 100000;
380
381 AtomicWord result_;
382 // All other fields are accessed only from the sampler thread.
383 double ticks_per_ms_;
384 unsigned measurements_count_;
385 unsigned wall_time_query_countdown_;
386 double last_wall_time_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000387
388 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000389};
390
391
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000392class ProfileGenerator {
393 public:
394 explicit ProfileGenerator(CpuProfilesCollection* profiles);
395
396 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
397 String* name,
398 String* resource_name,
399 int line_number)) {
400 return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
401 }
402
403 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
404 const char* name)) {
405 return profiles_->NewCodeEntry(tag, name);
406 }
407
408 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000409 const char* name_prefix,
410 String* name)) {
411 return profiles_->NewCodeEntry(tag, name_prefix, name);
412 }
413
414 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000415 int args_count)) {
416 return profiles_->NewCodeEntry(tag, args_count);
417 }
418
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000419 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
420 return profiles_->NewCodeEntry(security_token_id);
421 }
422
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000423 void RecordTickSample(const TickSample& sample);
424
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000425 INLINE(CodeMap* code_map()) { return &code_map_; }
426
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000427 INLINE(void Tick()) { sample_rate_calc_.Tick(); }
428 INLINE(double actual_sampling_rate()) {
429 return sample_rate_calc_.ticks_per_ms();
430 }
431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 static const char* const kAnonymousFunctionName;
433 static const char* const kProgramEntryName;
434 static const char* const kGarbageCollectorEntryName;
ager@chromium.org357bf652010-04-12 11:30:10 +0000435
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000436 private:
ager@chromium.org357bf652010-04-12 11:30:10 +0000437 INLINE(CodeEntry* EntryForVMState(StateTag tag));
438
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000439 CpuProfilesCollection* profiles_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000440 CodeMap code_map_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000441 CodeEntry* program_entry_;
442 CodeEntry* gc_entry_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000443 SampleRateCalculator sample_rate_calc_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000444
445 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
446};
447
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000448
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000449class HeapEntry;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000450class HeapSnapshot;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000451
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000452class HeapGraphEdge BASE_EMBEDDED {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000453 public:
454 enum Type {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000455 kContextVariable = v8::HeapGraphEdge::kContextVariable,
456 kElement = v8::HeapGraphEdge::kElement,
457 kProperty = v8::HeapGraphEdge::kProperty,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000458 kInternal = v8::HeapGraphEdge::kInternal,
459 kHidden = v8::HeapGraphEdge::kHidden,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000460 kShortcut = v8::HeapGraphEdge::kShortcut,
461 kWeak = v8::HeapGraphEdge::kWeak
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000462 };
463
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000464 HeapGraphEdge() { }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000465 HeapGraphEdge(Type type, const char* name, int from, int to);
466 HeapGraphEdge(Type type, int index, int from, int to);
467 void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000468
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000469 Type type() const { return static_cast<Type>(type_); }
470 int index() const {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000471 ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000472 return index_;
473 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000474 const char* name() const {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000475 ASSERT(type_ == kContextVariable
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000476 || type_ == kProperty
477 || type_ == kInternal
478 || type_ == kShortcut);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000479 return name_;
480 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000481 INLINE(HeapEntry* from() const);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000482 HeapEntry* to() const { return to_entry_; }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000483
484 private:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000485 INLINE(HeapSnapshot* snapshot() const);
486
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000487 unsigned type_ : 3;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000488 int from_index_ : 29;
489 union {
490 // During entries population |to_index_| is used for storing the index,
491 // afterwards it is replaced with a pointer to the entry.
492 int to_index_;
493 HeapEntry* to_entry_;
494 };
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000495 union {
496 int index_;
497 const char* name_;
498 };
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000499};
500
501
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000502// HeapEntry instances represent an entity from the heap (or a special
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000503// virtual node, e.g. root).
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000504class HeapEntry BASE_EMBEDDED {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000505 public:
506 enum Type {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000507 kHidden = v8::HeapGraphNode::kHidden,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000508 kArray = v8::HeapGraphNode::kArray,
509 kString = v8::HeapGraphNode::kString,
510 kObject = v8::HeapGraphNode::kObject,
511 kCode = v8::HeapGraphNode::kCode,
vegorov@chromium.org42841962010-10-18 11:18:59 +0000512 kClosure = v8::HeapGraphNode::kClosure,
513 kRegExp = v8::HeapGraphNode::kRegExp,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000514 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000515 kNative = v8::HeapGraphNode::kNative,
516 kSynthetic = v8::HeapGraphNode::kSynthetic
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000517 };
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000518 static const int kNoEntry;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000519
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000520 HeapEntry() { }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000521 HeapEntry(HeapSnapshot* snapshot,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000522 Type type,
523 const char* name,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000524 SnapshotObjectId id,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000525 int self_size);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000526
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000527 HeapSnapshot* snapshot() { return snapshot_; }
528 Type type() { return static_cast<Type>(type_); }
529 const char* name() { return name_; }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000530 void set_name(const char* name) { name_ = name; }
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000531 inline SnapshotObjectId id() { return id_; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000532 int self_size() { return self_size_; }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000533 INLINE(int index() const);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000534 int children_count() const { return children_count_; }
535 INLINE(int set_children_index(int index));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000536 void add_child(HeapGraphEdge* edge) {
537 children_arr()[children_count_++] = edge;
538 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000539 Vector<HeapGraphEdge*> children() {
540 return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000541
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000542 void SetIndexedReference(
543 HeapGraphEdge::Type type, int index, HeapEntry* entry);
544 void SetNamedReference(
545 HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000546
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000547 void Print(
548 const char* prefix, const char* edge_name, int max_depth, int indent);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000549
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000550 Handle<HeapObject> GetHeapObject();
551
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000552 private:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000553 INLINE(HeapGraphEdge** children_arr());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000554 const char* TypeAsString();
555
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000556 unsigned type_: 4;
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000557 int children_count_: 28;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000558 int children_index_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000559 int self_size_;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000560 SnapshotObjectId id_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000561 HeapSnapshot* snapshot_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000562 const char* name_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000563};
564
565
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000566class HeapSnapshotsCollection;
567
568// HeapSnapshot represents a single heap snapshot. It is stored in
569// HeapSnapshotsCollection, which is also a factory for
570// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
571// to be able to return them even if they were collected.
572// HeapSnapshotGenerator fills in a HeapSnapshot.
573class HeapSnapshot {
574 public:
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000575 enum Type {
ager@chromium.org04921a82011-06-27 13:21:41 +0000576 kFull = v8::HeapSnapshot::kFull
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000577 };
578
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000579 HeapSnapshot(HeapSnapshotsCollection* collection,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000580 Type type,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000581 const char* title,
582 unsigned uid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 void Delete();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000584
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000585 HeapSnapshotsCollection* collection() { return collection_; }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000586 Type type() { return type_; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000587 const char* title() { return title_; }
588 unsigned uid() { return uid_; }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000589 size_t RawSnapshotSize() const;
590 HeapEntry* root() { return &entries_[root_index_]; }
591 HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
592 HeapEntry* natives_root() { return &entries_[natives_root_index_]; }
593 HeapEntry* gc_subroot(int index) {
594 return &entries_[gc_subroot_indexes_[index]];
595 }
596 List<HeapEntry>& entries() { return entries_; }
597 List<HeapGraphEdge>& edges() { return edges_; }
598 List<HeapGraphEdge*>& children() { return children_; }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000599 void RememberLastJSObjectId();
600 SnapshotObjectId max_snapshot_js_object_id() const {
601 return max_snapshot_js_object_id_;
602 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000603
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000604 HeapEntry* AddEntry(HeapEntry::Type type,
605 const char* name,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000606 SnapshotObjectId id,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000607 int size);
608 HeapEntry* AddRootEntry();
609 HeapEntry* AddGcRootsEntry();
610 HeapEntry* AddGcSubrootEntry(int tag);
611 HeapEntry* AddNativesRootEntry();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000612 HeapEntry* GetEntryById(SnapshotObjectId id);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000613 List<HeapEntry*>* GetSortedEntriesList();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000614 void FillChildren();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000615
616 void Print(int max_depth);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000617 void PrintEntriesSize();
618
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000619 private:
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000620 HeapSnapshotsCollection* collection_;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000621 Type type_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000622 const char* title_;
623 unsigned uid_;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000624 int root_index_;
625 int gc_roots_index_;
626 int natives_root_index_;
627 int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
628 List<HeapEntry> entries_;
629 List<HeapGraphEdge> edges_;
630 List<HeapGraphEdge*> children_;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000631 List<HeapEntry*> sorted_entries_;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000632 SnapshotObjectId max_snapshot_js_object_id_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000633
634 friend class HeapSnapshotTester;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000635
636 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
637};
638
639
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000640class HeapObjectsMap {
641 public:
642 HeapObjectsMap();
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000643
644 void SnapshotGenerationFinished();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000645 SnapshotObjectId FindEntry(Address addr);
646 SnapshotObjectId FindOrAddEntry(Address addr, unsigned int size);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000647 void MoveObject(Address from, Address to);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000648 SnapshotObjectId last_assigned_id() const {
649 return next_id_ - kObjectIdStep;
650 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000651
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000652 void StopHeapObjectsTracking();
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000653 SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000654 size_t GetUsedMemorySize() const;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000655
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000656 static SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
657 static inline SnapshotObjectId GetNthGcSubrootId(int delta);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000658
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000659 static const int kObjectIdStep = 2;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000660 static const SnapshotObjectId kInternalRootObjectId;
661 static const SnapshotObjectId kGcRootsObjectId;
662 static const SnapshotObjectId kNativesRootObjectId;
663 static const SnapshotObjectId kGcRootsFirstSubrootId;
664 static const SnapshotObjectId kFirstAvailableObjectId;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000665
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000666 private:
667 struct EntryInfo {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000668 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
669 : id(id), addr(addr), size(size), accessed(true) { }
670 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed)
671 : id(id), addr(addr), size(size), accessed(accessed) { }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000672 SnapshotObjectId id;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000673 Address addr;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000674 unsigned int size;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000675 bool accessed;
676 };
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000677 struct TimeInterval {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000678 explicit TimeInterval(SnapshotObjectId id) : id(id), size(0), count(0) { }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000679 SnapshotObjectId id;
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +0000680 uint32_t size;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000681 uint32_t count;
682 };
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000683
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000684 void UpdateHeapObjectsMap();
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000685 void RemoveDeadEntries();
686
687 static bool AddressesMatch(void* key1, void* key2) {
688 return key1 == key2;
689 }
690
691 static uint32_t AddressHash(Address addr) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000692 return ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000693 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)),
694 v8::internal::kZeroHashSeed);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000695 }
696
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000697 SnapshotObjectId next_id_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000698 HashMap entries_map_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000699 List<EntryInfo> entries_;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000700 List<TimeInterval> time_intervals_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000701
702 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
703};
704
705
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000706class HeapSnapshotsCollection {
707 public:
708 HeapSnapshotsCollection();
709 ~HeapSnapshotsCollection();
710
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000711 bool is_tracking_objects() { return is_tracking_objects_; }
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000712 SnapshotObjectId PushHeapObjectsStats(OutputStream* stream) {
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000713 return ids_.PushHeapObjectsStats(stream);
714 }
715 void StartHeapObjectsTracking() { is_tracking_objects_ = true; }
716 void StopHeapObjectsTracking() { ids_.StopHeapObjectsTracking(); }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000717
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000718 HeapSnapshot* NewSnapshot(
719 HeapSnapshot::Type type, const char* name, unsigned uid);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000720 void SnapshotGenerationFinished(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000721 List<HeapSnapshot*>* snapshots() { return &snapshots_; }
722 HeapSnapshot* GetSnapshot(unsigned uid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000723 void RemoveSnapshot(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000724
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000725 StringsStorage* names() { return &names_; }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000726 TokenEnumerator* token_enumerator() { return token_enumerator_; }
727
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000728 SnapshotObjectId FindObjectId(Address object_addr) {
729 return ids_.FindEntry(object_addr);
730 }
731 SnapshotObjectId GetObjectId(Address object_addr, int object_size) {
732 return ids_.FindOrAddEntry(object_addr, object_size);
733 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000734 Handle<HeapObject> FindHeapObjectById(SnapshotObjectId id);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000735 void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000736 SnapshotObjectId last_assigned_id() const {
737 return ids_.last_assigned_id();
738 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000739 size_t GetUsedMemorySize() const;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000740
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000741 private:
742 INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
743 return key1 == key2;
744 }
745
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000746 bool is_tracking_objects_; // Whether tracking object moves is needed.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000747 List<HeapSnapshot*> snapshots_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000748 // Mapping from snapshots' uids to HeapSnapshot* pointers.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000749 HashMap snapshots_uids_;
750 StringsStorage names_;
751 TokenEnumerator* token_enumerator_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000752 // Mapping from HeapObject addresses to objects' uids.
753 HeapObjectsMap ids_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000754
755 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
756};
757
758
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000759// A typedef for referencing anything that can be snapshotted living
760// in any kind of heap memory.
761typedef void* HeapThing;
762
763
764// An interface that creates HeapEntries by HeapThings.
765class HeapEntriesAllocator {
766 public:
767 virtual ~HeapEntriesAllocator() { }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000768 virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000769};
770
771
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000772// The HeapEntriesMap instance is used to track a mapping between
773// real heap objects and their representations in heap snapshots.
774class HeapEntriesMap {
775 public:
776 HeapEntriesMap();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000777
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000778 int Map(HeapThing thing);
779 void Pair(HeapThing thing, int entry);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000780
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000781 private:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000782 static uint32_t Hash(HeapThing thing) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000783 return ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000784 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
785 v8::internal::kZeroHashSeed);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000786 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000787 static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
788 return key1 == key2;
789 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000790
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000791 HashMap entries_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000792
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000793 friend class HeapObjectsSet;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000794
795 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
796};
797
798
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000799class HeapObjectsSet {
800 public:
801 HeapObjectsSet();
802 void Clear();
803 bool Contains(Object* object);
804 void Insert(Object* obj);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000805 const char* GetTag(Object* obj);
806 void SetTag(Object* obj, const char* tag);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000807 bool is_empty() const { return entries_.occupancy() == 0; }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000808
809 private:
810 HashMap entries_;
811
812 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
813};
814
815
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000816// An interface used to populate a snapshot with nodes and edges.
817class SnapshotFillerInterface {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000818 public:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000819 virtual ~SnapshotFillerInterface() { }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000820 virtual HeapEntry* AddEntry(HeapThing ptr,
821 HeapEntriesAllocator* allocator) = 0;
822 virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
823 virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
824 HeapEntriesAllocator* allocator) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000825 virtual void SetIndexedReference(HeapGraphEdge::Type type,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000826 int parent_entry,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000827 int index,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000828 HeapEntry* child_entry) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000829 virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000830 int parent_entry,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000831 HeapEntry* child_entry) = 0;
832 virtual void SetNamedReference(HeapGraphEdge::Type type,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000833 int parent_entry,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000834 const char* reference_name,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000835 HeapEntry* child_entry) = 0;
836 virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000837 int parent_entry,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000838 HeapEntry* child_entry) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000839};
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000840
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000841
842class SnapshottingProgressReportingInterface {
843 public:
844 virtual ~SnapshottingProgressReportingInterface() { }
845 virtual void ProgressStep() = 0;
846 virtual bool ProgressReport(bool force) = 0;
847};
848
849
850// An implementation of V8 heap graph extractor.
851class V8HeapExplorer : public HeapEntriesAllocator {
852 public:
853 V8HeapExplorer(HeapSnapshot* snapshot,
854 SnapshottingProgressReportingInterface* progress);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000855 virtual ~V8HeapExplorer();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000856 virtual HeapEntry* AllocateEntry(HeapThing ptr);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000857 void AddRootEntries(SnapshotFillerInterface* filler);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000858 int EstimateObjectsCount(HeapIterator* iterator);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000859 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000860 void TagGlobalObjects();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000861
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000862 static String* GetConstructorName(JSObject* object);
863
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000864 static HeapObject* const kInternalRootObject;
865
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000866 private:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000867 HeapEntry* AddEntry(HeapObject* object);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000868 HeapEntry* AddEntry(HeapObject* object,
869 HeapEntry::Type type,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000870 const char* name);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871 const char* GetSystemEntryName(HeapObject* object);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000872
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000873 void ExtractReferences(HeapObject* obj);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000874 void ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000875 void ExtractJSObjectReferences(int entry, JSObject* js_obj);
876 void ExtractStringReferences(int entry, String* obj);
877 void ExtractContextReferences(int entry, Context* context);
878 void ExtractMapReferences(int entry, Map* map);
879 void ExtractSharedFunctionInfoReferences(int entry,
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000880 SharedFunctionInfo* shared);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000881 void ExtractScriptReferences(int entry, Script* script);
882 void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
883 void ExtractCodeReferences(int entry, Code* code);
884 void ExtractJSGlobalPropertyCellReferences(int entry,
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000885 JSGlobalPropertyCell* cell);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000886 void ExtractClosureReferences(JSObject* js_obj, int entry);
887 void ExtractPropertyReferences(JSObject* js_obj, int entry);
888 void ExtractElementReferences(JSObject* js_obj, int entry);
889 void ExtractInternalReferences(JSObject* js_obj, int entry);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000890 bool IsEssentialObject(Object* object);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000891 void SetClosureReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000892 int parent,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000893 String* reference_name,
894 Object* child);
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000895 void SetNativeBindReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000896 int parent,
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000897 const char* reference_name,
898 Object* child);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000899 void SetElementReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000900 int parent,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000901 int index,
902 Object* child);
903 void SetInternalReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000904 int parent,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000905 const char* reference_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 Object* child,
907 int field_offset = -1);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000908 void SetInternalReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000909 int parent,
vegorov@chromium.org42841962010-10-18 11:18:59 +0000910 int index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 Object* child,
912 int field_offset = -1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000913 void SetHiddenReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000914 int parent,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000915 int index,
916 Object* child);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000917 void SetWeakReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000918 int parent,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000919 int index,
920 Object* child_obj,
921 int field_offset);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000922 void SetPropertyReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000923 int parent,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000924 String* reference_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 Object* child,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000926 const char* name_format_string = NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 int field_offset = -1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000928 void SetPropertyShortcutReference(HeapObject* parent_obj,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000929 int parent,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000930 String* reference_name,
931 Object* child);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000932 void SetUserGlobalReference(Object* user_global);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000933 void SetRootGcRootsReference();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000934 void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
935 void SetGcSubrootReference(
936 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000937 const char* GetStrongGcSubrootName(Object* object);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000938 void TagObject(Object* obj, const char* tag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000939
940 HeapEntry* GetEntry(Object* obj);
941
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000942 static inline HeapObject* GetNthGcSubrootObject(int delta);
943 static inline int GetGcSubrootOrder(HeapObject* subroot);
944
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000945 Heap* heap_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000946 HeapSnapshot* snapshot_;
947 HeapSnapshotsCollection* collection_;
948 SnapshottingProgressReportingInterface* progress_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000949 SnapshotFillerInterface* filler_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000950 HeapObjectsSet objects_tags_;
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000951 HeapObjectsSet strong_gc_subroot_names_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000952
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000953 static HeapObject* const kGcRootsObject;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000954 static HeapObject* const kFirstGcSubrootObject;
955 static HeapObject* const kLastGcSubrootObject;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000956
957 friend class IndexedReferencesExtractor;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000958 friend class GcSubrootsEnumerator;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000959 friend class RootsReferencesExtractor;
960
961 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
962};
963
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000964
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000965class NativeGroupRetainedObjectInfo;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000966
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000967
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000968// An implementation of retained native objects extractor.
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000969class NativeObjectsExplorer {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000970 public:
971 NativeObjectsExplorer(HeapSnapshot* snapshot,
972 SnapshottingProgressReportingInterface* progress);
973 virtual ~NativeObjectsExplorer();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000974 void AddRootEntries(SnapshotFillerInterface* filler);
975 int EstimateObjectsCount();
976 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
977
978 private:
979 void FillRetainedObjects();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000980 void FillImplicitReferences();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000981 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
982 void SetNativeRootReference(v8::RetainedObjectInfo* info);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000983 void SetRootNativeRootsReference();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000984 void SetWrapperNativeReferences(HeapObject* wrapper,
985 v8::RetainedObjectInfo* info);
986 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
987
988 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000989 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
990 v8::internal::kZeroHashSeed);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000991 }
992 static bool RetainedInfosMatch(void* key1, void* key2) {
993 return key1 == key2 ||
994 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
995 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
996 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000997 INLINE(static bool StringsMatch(void* key1, void* key2)) {
998 return strcmp(reinterpret_cast<char*>(key1),
999 reinterpret_cast<char*>(key2)) == 0;
1000 }
1001
1002 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001003
1004 HeapSnapshot* snapshot_;
1005 HeapSnapshotsCollection* collection_;
1006 SnapshottingProgressReportingInterface* progress_;
1007 bool embedder_queried_;
1008 HeapObjectsSet in_groups_;
1009 // RetainedObjectInfo* -> List<HeapObject*>*
1010 HashMap objects_by_info_;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001011 HashMap native_groups_;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001012 HeapEntriesAllocator* synthetic_entries_allocator_;
1013 HeapEntriesAllocator* native_entries_allocator_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001014 // Used during references extraction.
1015 SnapshotFillerInterface* filler_;
1016
1017 static HeapThing const kNativesRootObject;
1018
1019 friend class GlobalHandlesExtractor;
1020
1021 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
1022};
1023
1024
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001025class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
1026 public:
1027 HeapSnapshotGenerator(HeapSnapshot* snapshot,
1028 v8::ActivityControl* control);
1029 bool GenerateSnapshot();
1030
1031 private:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001032 bool FillReferences();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001033 void ProgressStep();
1034 bool ProgressReport(bool force = false);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001035 void SetProgressTotal(int iterations_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001036
1037 HeapSnapshot* snapshot_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001038 v8::ActivityControl* control_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001039 V8HeapExplorer v8_heap_explorer_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001040 NativeObjectsExplorer dom_explorer_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001041 // Mapping from HeapThing pointers to HeapEntry* pointers.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001042 HeapEntriesMap entries_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001043 // Used during snapshot generation.
1044 int progress_counter_;
1045 int progress_total_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001046
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001047 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
1048};
1049
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001050class OutputStreamWriter;
1051
1052class HeapSnapshotJSONSerializer {
1053 public:
1054 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
1055 : snapshot_(snapshot),
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001056 strings_(ObjectsMatch),
1057 next_node_id_(1),
1058 next_string_id_(1),
1059 writer_(NULL) {
1060 }
1061 void Serialize(v8::OutputStream* stream);
1062
1063 private:
1064 INLINE(static bool ObjectsMatch(void* key1, void* key2)) {
1065 return key1 == key2;
1066 }
1067
1068 INLINE(static uint32_t ObjectHash(const void* key)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001069 return ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001070 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)),
1071 v8::internal::kZeroHashSeed);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001072 }
1073
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001074 HeapSnapshot* CreateFakeSnapshot();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001075 int GetStringId(const char* s);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001076 int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001077 void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001078 void SerializeEdges();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001079 void SerializeImpl();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001080 void SerializeNode(HeapEntry* entry);
1081 void SerializeNodes();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001082 void SerializeSnapshot();
1083 void SerializeString(const unsigned char* s);
1084 void SerializeStrings();
1085 void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
1086
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001087 static const int kEdgeFieldsCount;
1088 static const int kNodeFieldsCount;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001089
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001090 HeapSnapshot* snapshot_;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001091 HashMap strings_;
1092 int next_node_id_;
1093 int next_string_id_;
1094 OutputStreamWriter* writer_;
1095
1096 friend class HeapSnapshotJSONSerializerEnumerator;
1097 friend class HeapSnapshotJSONSerializerIterator;
1098
1099 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
1100};
1101
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001102} } // namespace v8::internal
1103
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001104#endif // V8_PROFILE_GENERATOR_H_