blob: b88d4659d013cd17104d40b7aaf0f0fab96d943e [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);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000075
76 private:
danno@chromium.orgc612e022011-11-10 11:38:15 +000077 static const int kMaxNameSize = 1024;
78
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000079 INLINE(static bool StringsMatch(void* key1, void* key2)) {
80 return strcmp(reinterpret_cast<char*>(key1),
81 reinterpret_cast<char*>(key2)) == 0;
82 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000083 const char* AddOrDisposeString(char* str, uint32_t hash);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000084
ricow@chromium.org4980dff2010-07-19 08:33:45 +000085 // Mapping of strings by String::Hash to const char* strings.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000086 HashMap names_;
87
88 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
89};
90
91
fschneider@chromium.org086aac62010-03-17 13:18:24 +000092class CodeEntry {
93 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000094 // CodeEntry doesn't own name strings, just references them.
lrn@chromium.org25156de2010-04-06 13:10:27 +000095 INLINE(CodeEntry(Logger::LogEventsAndTags tag,
96 const char* name_prefix,
97 const char* name,
98 const char* resource_name,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000099 int line_number,
100 int security_token_id));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000101
ager@chromium.org357bf652010-04-12 11:30:10 +0000102 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000103 INLINE(const char* name_prefix() const) { return name_prefix_; }
104 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
105 INLINE(const char* name() const) { return name_; }
106 INLINE(const char* resource_name() const) { return resource_name_; }
107 INLINE(int line_number() const) { return line_number_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000108 INLINE(int shared_id() const) { return shared_id_; }
109 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000110 INLINE(int security_token_id() const) { return security_token_id_; }
ager@chromium.org357bf652010-04-12 11:30:10 +0000111
112 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000113
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000114 void CopyData(const CodeEntry& source);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000115 uint32_t GetCallUid() const;
116 bool IsSameAs(CodeEntry* entry) const;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000118 static const char* const kEmptyNamePrefix;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000119
120 private:
121 Logger::LogEventsAndTags tag_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000122 const char* name_prefix_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000123 const char* name_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000124 const char* resource_name_;
125 int line_number_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000126 int shared_id_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000127 int security_token_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000128
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000129 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000130};
131
132
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000133class ProfileTree;
134
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000135class ProfileNode {
136 public:
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000137 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000138
139 ProfileNode* FindChild(CodeEntry* entry);
140 ProfileNode* FindOrAddChild(CodeEntry* entry);
141 INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000142 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000143 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
144
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000145 INLINE(CodeEntry* entry() const) { return entry_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000146 INLINE(unsigned self_ticks() const) { return self_ticks_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000147 INLINE(unsigned total_ticks() const) { return total_ticks_; }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000148 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000149 double GetSelfMillis() const;
150 double GetTotalMillis() const;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000151
152 void Print(int indent);
153
154 private:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000155 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000156 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
157 reinterpret_cast<CodeEntry*>(entry2));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000158 }
159
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000160 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000161 return entry->GetCallUid();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000162 }
163
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000164 ProfileTree* tree_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000165 CodeEntry* entry_;
166 unsigned total_ticks_;
167 unsigned self_ticks_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000168 // Mapping from CodeEntry* to ProfileNode*
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000169 HashMap children_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000170 List<ProfileNode*> children_list_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000171
172 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
173};
174
175
lrn@chromium.org25156de2010-04-06 13:10:27 +0000176class ProfileTree {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000177 public:
ager@chromium.org357bf652010-04-12 11:30:10 +0000178 ProfileTree();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000179 ~ProfileTree();
180
181 void AddPathFromEnd(const Vector<CodeEntry*>& path);
182 void AddPathFromStart(const Vector<CodeEntry*>& path);
183 void CalculateTotalTicks();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000184 void FilteredClone(ProfileTree* src, int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000185
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000186 double TicksToMillis(unsigned ticks) const {
187 return ticks * ms_to_ticks_scale_;
188 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000189 ProfileNode* root() const { return root_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000190 void SetTickRatePerMs(double ticks_per_ms);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000191
192 void ShortPrint();
193 void Print() {
194 root_->Print(0);
195 }
196
197 private:
198 template <typename Callback>
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000199 void TraverseDepthFirst(Callback* callback);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000200
ager@chromium.org357bf652010-04-12 11:30:10 +0000201 CodeEntry root_entry_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000202 ProfileNode* root_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000203 double ms_to_ticks_scale_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000204
205 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
206};
207
208
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000209class CpuProfile {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000210 public:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000211 CpuProfile(const char* title, unsigned uid)
212 : title_(title), uid_(uid) { }
213
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000214 // Add pc -> ... -> main() call path to the profile.
215 void AddPath(const Vector<CodeEntry*>& path);
216 void CalculateTotalTicks();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000217 void SetActualSamplingRate(double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000218 CpuProfile* FilteredClone(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000219
lrn@chromium.org25156de2010-04-06 13:10:27 +0000220 INLINE(const char* title() const) { return title_; }
221 INLINE(unsigned uid() const) { return uid_; }
222 INLINE(const ProfileTree* top_down() const) { return &top_down_; }
223 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000224
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000225 void UpdateTicksScale();
226
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000227 void ShortPrint();
228 void Print();
229
230 private:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000231 const char* title_;
232 unsigned uid_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000233 ProfileTree top_down_;
234 ProfileTree bottom_up_;
235
236 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
237};
238
239
lrn@chromium.org25156de2010-04-06 13:10:27 +0000240class CodeMap {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000241 public:
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000242 CodeMap() : next_shared_id_(1) { }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000243 void AddCode(Address addr, CodeEntry* entry, unsigned size);
244 void MoveCode(Address from, Address to);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000245 CodeEntry* FindEntry(Address addr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000246 int GetSharedId(Address addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000247
lrn@chromium.org25156de2010-04-06 13:10:27 +0000248 void Print();
249
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000250 private:
251 struct CodeEntryInfo {
252 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
253 : entry(an_entry), size(a_size) { }
254 CodeEntry* entry;
255 unsigned size;
256 };
257
258 struct CodeTreeConfig {
259 typedef Address Key;
260 typedef CodeEntryInfo Value;
261 static const Key kNoKey;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000262 static const Value NoValue() { return CodeEntryInfo(NULL, 0); }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000263 static int Compare(const Key& a, const Key& b) {
264 return a < b ? -1 : (a > b ? 1 : 0);
265 }
266 };
267 typedef SplayTree<CodeTreeConfig> CodeTree;
268
lrn@chromium.org25156de2010-04-06 13:10:27 +0000269 class CodeTreePrinter {
270 public:
271 void Call(const Address& key, const CodeEntryInfo& value);
272 };
273
lrn@chromium.org34e60782011-09-15 07:25:40 +0000274 void DeleteAllCoveredCode(Address start, Address end);
275
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000276 // Fake CodeEntry pointer to distinguish shared function entries.
277 static CodeEntry* const kSharedFunctionCodeEntry;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000278
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000279 CodeTree tree_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000280 int next_shared_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000281
282 DISALLOW_COPY_AND_ASSIGN(CodeMap);
283};
284
285
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000286class CpuProfilesCollection {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000287 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000288 CpuProfilesCollection();
289 ~CpuProfilesCollection();
290
lrn@chromium.org25156de2010-04-06 13:10:27 +0000291 bool StartProfiling(const char* title, unsigned uid);
292 bool StartProfiling(String* title, unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000293 CpuProfile* StopProfiling(int security_token_id,
294 const char* title,
295 double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000296 List<CpuProfile*>* Profiles(int security_token_id);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000297 const char* GetName(String* name) {
298 return function_and_resource_names_.GetName(name);
299 }
vegorov@chromium.org42841962010-10-18 11:18:59 +0000300 const char* GetName(int args_count) {
301 return function_and_resource_names_.GetName(args_count);
302 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000303 CpuProfile* GetProfile(int security_token_id, unsigned uid);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000304 bool IsLastProfile(const char* title);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 void RemoveProfile(CpuProfile* profile);
306 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000307
308 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
309 String* name, String* resource_name, int line_number);
310 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000311 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
312 const char* name_prefix, String* name);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000313 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000314 CodeEntry* NewCodeEntry(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000315
lrn@chromium.org25156de2010-04-06 13:10:27 +0000316 // Called from profile generator thread.
317 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000318
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000319 // Limits the number of profiles that can be simultaneously collected.
320 static const int kMaxSimultaneousProfiles = 100;
321
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000322 private:
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000323 const char* GetFunctionName(String* name) {
324 return function_and_resource_names_.GetFunctionName(name);
325 }
326 const char* GetFunctionName(const char* name) {
327 return function_and_resource_names_.GetFunctionName(name);
328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 int GetProfileIndex(unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000330 List<CpuProfile*>* GetProfilesList(int security_token_id);
331 int TokenToIndex(int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000332
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000333 INLINE(static bool UidsMatch(void* key1, void* key2)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000334 return key1 == key2;
335 }
336
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000337 StringsStorage function_and_resource_names_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000338 List<CodeEntry*> code_entries_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000339 List<List<CpuProfile*>* > profiles_by_token_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000340 // Mapping from profiles' uids to indexes in the second nested list
341 // of profiles_by_token_.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000342 HashMap profiles_uids_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000343 List<CpuProfile*> detached_profiles_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000344
345 // Accessed by VM thread and profile generator thread.
346 List<CpuProfile*> current_profiles_;
347 Semaphore* current_profiles_semaphore_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000348
349 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
350};
351
352
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000353class SampleRateCalculator {
354 public:
355 SampleRateCalculator()
356 : result_(Logger::kSamplingIntervalMs * kResultScale),
357 ticks_per_ms_(Logger::kSamplingIntervalMs),
358 measurements_count_(0),
359 wall_time_query_countdown_(1) {
360 }
361
362 double ticks_per_ms() {
363 return result_ / static_cast<double>(kResultScale);
364 }
365 void Tick();
366 void UpdateMeasurements(double current_time);
367
368 // Instead of querying current wall time each tick,
369 // we use this constant to control query intervals.
370 static const unsigned kWallTimeQueryIntervalMs = 100;
371
372 private:
373 // As the result needs to be accessed from a different thread, we
374 // use type that guarantees atomic writes to memory. There should
375 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
376 // order should provide enough precision while keeping away from a
377 // potential overflow.
378 static const int kResultScale = 100000;
379
380 AtomicWord result_;
381 // All other fields are accessed only from the sampler thread.
382 double ticks_per_ms_;
383 unsigned measurements_count_;
384 unsigned wall_time_query_countdown_;
385 double last_wall_time_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000386
387 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000388};
389
390
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000391class ProfileGenerator {
392 public:
393 explicit ProfileGenerator(CpuProfilesCollection* profiles);
394
395 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
396 String* name,
397 String* resource_name,
398 int line_number)) {
399 return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
400 }
401
402 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
403 const char* name)) {
404 return profiles_->NewCodeEntry(tag, name);
405 }
406
407 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000408 const char* name_prefix,
409 String* name)) {
410 return profiles_->NewCodeEntry(tag, name_prefix, name);
411 }
412
413 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000414 int args_count)) {
415 return profiles_->NewCodeEntry(tag, args_count);
416 }
417
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000418 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
419 return profiles_->NewCodeEntry(security_token_id);
420 }
421
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000422 void RecordTickSample(const TickSample& sample);
423
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000424 INLINE(CodeMap* code_map()) { return &code_map_; }
425
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000426 INLINE(void Tick()) { sample_rate_calc_.Tick(); }
427 INLINE(double actual_sampling_rate()) {
428 return sample_rate_calc_.ticks_per_ms();
429 }
430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 static const char* const kAnonymousFunctionName;
432 static const char* const kProgramEntryName;
433 static const char* const kGarbageCollectorEntryName;
ager@chromium.org357bf652010-04-12 11:30:10 +0000434
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000435 private:
ager@chromium.org357bf652010-04-12 11:30:10 +0000436 INLINE(CodeEntry* EntryForVMState(StateTag tag));
437
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000438 CpuProfilesCollection* profiles_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000439 CodeMap code_map_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000440 CodeEntry* program_entry_;
441 CodeEntry* gc_entry_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000442 SampleRateCalculator sample_rate_calc_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000443
444 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
445};
446
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000447
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000448class HeapEntry;
449
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000450class HeapGraphEdge BASE_EMBEDDED {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000451 public:
452 enum Type {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000453 kContextVariable = v8::HeapGraphEdge::kContextVariable,
454 kElement = v8::HeapGraphEdge::kElement,
455 kProperty = v8::HeapGraphEdge::kProperty,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000456 kInternal = v8::HeapGraphEdge::kInternal,
457 kHidden = v8::HeapGraphEdge::kHidden,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000458 kShortcut = v8::HeapGraphEdge::kShortcut,
459 kWeak = v8::HeapGraphEdge::kWeak
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000460 };
461
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000462 HeapGraphEdge() { }
463 void Init(int child_index, Type type, const char* name, HeapEntry* to);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000464 void Init(int child_index, Type type, int index, HeapEntry* to);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000465 void Init(int child_index, int index, HeapEntry* to);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000466
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000467 Type type() { return static_cast<Type>(type_); }
468 int index() {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000469 ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000470 return index_;
471 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000472 const char* name() {
473 ASSERT(type_ == kContextVariable
474 || type_ == kProperty
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000475 || type_ == kInternal
476 || type_ == kShortcut);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000477 return name_;
478 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000479 HeapEntry* to() { return to_; }
480
481 HeapEntry* From();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000482
483 private:
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000484 int child_index_ : 29;
485 unsigned type_ : 3;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000486 union {
487 int index_;
488 const char* name_;
489 };
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000490 HeapEntry* to_;
491
492 DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge);
493};
494
495
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000496class HeapSnapshot;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000497
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000498// HeapEntry instances represent an entity from the heap (or a special
499// virtual node, e.g. root). To make heap snapshots more compact,
500// HeapEntries has a special memory layout (no Vectors or Lists used):
501//
502// +-----------------+
503// HeapEntry
504// +-----------------+
505// HeapGraphEdge |
506// ... } children_count
507// HeapGraphEdge |
508// +-----------------+
509// HeapGraphEdge* |
510// ... } retainers_count
511// HeapGraphEdge* |
512// +-----------------+
513//
514// In a HeapSnapshot, all entries are hand-allocated in a continuous array
515// of raw bytes.
516//
517class HeapEntry BASE_EMBEDDED {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000518 public:
519 enum Type {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000520 kHidden = v8::HeapGraphNode::kHidden,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000521 kArray = v8::HeapGraphNode::kArray,
522 kString = v8::HeapGraphNode::kString,
523 kObject = v8::HeapGraphNode::kObject,
524 kCode = v8::HeapGraphNode::kCode,
vegorov@chromium.org42841962010-10-18 11:18:59 +0000525 kClosure = v8::HeapGraphNode::kClosure,
526 kRegExp = v8::HeapGraphNode::kRegExp,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000527 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
528 kNative = v8::HeapGraphNode::kNative
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000529 };
530
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000531 HeapEntry() { }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000532 void Init(HeapSnapshot* snapshot,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000533 Type type,
534 const char* name,
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000535 uint64_t id,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000536 int self_size,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000537 int children_count,
538 int retainers_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000539
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000540 HeapSnapshot* snapshot() { return snapshot_; }
541 Type type() { return static_cast<Type>(type_); }
542 const char* name() { return name_; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000543 inline uint64_t id();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000544 int self_size() { return self_size_; }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000545 int retained_size() { return retained_size_; }
546 void add_retained_size(int size) { retained_size_ += size; }
547 void set_retained_size(int value) { retained_size_ = value; }
548 int ordered_index() { return ordered_index_; }
549 void set_ordered_index(int value) { ordered_index_ = value; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000550
551 Vector<HeapGraphEdge> children() {
552 return Vector<HeapGraphEdge>(children_arr(), children_count_); }
553 Vector<HeapGraphEdge*> retainers() {
554 return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000555 HeapEntry* dominator() { return dominator_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000556 void set_dominator(HeapEntry* entry) {
557 ASSERT(entry != NULL);
558 dominator_ = entry;
559 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000560
561 void clear_paint() { painted_ = kUnpainted; }
562 bool painted_reachable() { return painted_ == kPainted; }
563 void paint_reachable() {
564 ASSERT(painted_ == kUnpainted);
565 painted_ = kPainted;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000566 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000567 bool not_painted_reachable_from_others() {
568 return painted_ != kPaintedReachableFromOthers;
569 }
570 void paint_reachable_from_others() {
571 painted_ = kPaintedReachableFromOthers;
572 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000573 template<class Visitor>
574 void ApplyAndPaintAllReachable(Visitor* visitor);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000575 void PaintAllReachable();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000576
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000577 void SetIndexedReference(HeapGraphEdge::Type type,
578 int child_index,
579 int index,
580 HeapEntry* entry,
581 int retainer_index);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000582 void SetNamedReference(HeapGraphEdge::Type type,
583 int child_index,
584 const char* name,
585 HeapEntry* entry,
586 int retainer_index);
587 void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
588
589 int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000590 int RetainedSize(bool exact);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000591
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000592 void Print(
593 const char* prefix, const char* edge_name, int max_depth, int indent);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000594
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000595 Handle<HeapObject> GetHeapObject();
596
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000597 static int EntriesSize(int entries_count,
598 int children_count,
599 int retainers_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000600
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000601 private:
602 HeapGraphEdge* children_arr() {
603 return reinterpret_cast<HeapGraphEdge*>(this + 1);
604 }
605 HeapGraphEdge** retainers_arr() {
606 return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
607 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000608 void CalculateExactRetainedSize();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000609 const char* TypeAsString();
610
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000611 unsigned painted_: 2;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000612 unsigned type_: 4;
613 int children_count_: 26;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000614 int retainers_count_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000615 int self_size_;
616 union {
617 int ordered_index_; // Used during dominator tree building.
618 int retained_size_; // At that moment, there is no retained size yet.
619 };
620 HeapEntry* dominator_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000621 HeapSnapshot* snapshot_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000622 struct Id {
623 uint32_t id1_;
624 uint32_t id2_;
625 } id_; // This is to avoid extra padding of 64-bit value.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000626 const char* name_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000627
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000628 // Paints used for exact retained sizes calculation.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000629 static const unsigned kUnpainted = 0;
630 static const unsigned kPainted = 1;
631 static const unsigned kPaintedReachableFromOthers = 2;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000632
633 static const int kExactRetainedSizeTag = 1;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000634
635 DISALLOW_COPY_AND_ASSIGN(HeapEntry);
636};
637
638
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000639class HeapSnapshotsCollection;
640
641// HeapSnapshot represents a single heap snapshot. It is stored in
642// HeapSnapshotsCollection, which is also a factory for
643// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
644// to be able to return them even if they were collected.
645// HeapSnapshotGenerator fills in a HeapSnapshot.
646class HeapSnapshot {
647 public:
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000648 enum Type {
ager@chromium.org04921a82011-06-27 13:21:41 +0000649 kFull = v8::HeapSnapshot::kFull
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000650 };
651
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000652 HeapSnapshot(HeapSnapshotsCollection* collection,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000653 Type type,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000654 const char* title,
655 unsigned uid);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000656 ~HeapSnapshot();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 void Delete();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000658
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000659 HeapSnapshotsCollection* collection() { return collection_; }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000660 Type type() { return type_; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000661 const char* title() { return title_; }
662 unsigned uid() { return uid_; }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000663 HeapEntry* root() { return root_entry_; }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000664 HeapEntry* gc_roots() { return gc_roots_entry_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000665 HeapEntry* natives_root() { return natives_root_entry_; }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000666 HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000667 List<HeapEntry*>* entries() { return &entries_; }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000668 int raw_entries_size() { return raw_entries_size_; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000669
670 void AllocateEntries(
671 int entries_count, int children_count, int retainers_count);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000672 HeapEntry* AddEntry(HeapEntry::Type type,
673 const char* name,
674 uint64_t id,
675 int size,
676 int children_count,
677 int retainers_count);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000678 HeapEntry* AddRootEntry(int children_count);
679 HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000680 HeapEntry* AddGcSubrootEntry(int tag,
681 int children_count,
682 int retainers_count);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000683 HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000684 void ClearPaint();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000685 HeapEntry* GetEntryById(uint64_t id);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000686 List<HeapEntry*>* GetSortedEntriesList();
687 template<class Visitor>
688 void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000689 void SetDominatorsToSelf();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000690
691 void Print(int max_depth);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000692 void PrintEntriesSize();
693
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000694 private:
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000695 HeapEntry* GetNextEntryToInit();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000696
697 HeapSnapshotsCollection* collection_;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000698 Type type_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000699 const char* title_;
700 unsigned uid_;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000701 HeapEntry* root_entry_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000702 HeapEntry* gc_roots_entry_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000703 HeapEntry* natives_root_entry_;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000704 HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000705 char* raw_entries_;
706 List<HeapEntry*> entries_;
707 bool entries_sorted_;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000708 int raw_entries_size_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000709
710 friend class HeapSnapshotTester;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000711
712 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
713};
714
715
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000716class HeapObjectsMap {
717 public:
718 HeapObjectsMap();
719 ~HeapObjectsMap();
720
721 void SnapshotGenerationFinished();
722 uint64_t FindObject(Address addr);
723 void MoveObject(Address from, Address to);
724
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000725 static uint64_t GenerateId(v8::RetainedObjectInfo* info);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000726 static inline uint64_t GetNthGcSubrootId(int delta);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000727
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000728 static const int kObjectIdStep = 2;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000729 static const uint64_t kInternalRootObjectId;
730 static const uint64_t kGcRootsObjectId;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000731 static const uint64_t kNativesRootObjectId;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000732 static const uint64_t kGcRootsFirstSubrootId;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000733 static const uint64_t kFirstAvailableObjectId;
734
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000735 private:
736 struct EntryInfo {
737 explicit EntryInfo(uint64_t id) : id(id), accessed(true) { }
738 EntryInfo(uint64_t id, bool accessed) : id(id), accessed(accessed) { }
739 uint64_t id;
740 bool accessed;
741 };
742
743 void AddEntry(Address addr, uint64_t id);
744 uint64_t FindEntry(Address addr);
745 void RemoveDeadEntries();
746
747 static bool AddressesMatch(void* key1, void* key2) {
748 return key1 == key2;
749 }
750
751 static uint32_t AddressHash(Address addr) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000752 return ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000753 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)),
754 v8::internal::kZeroHashSeed);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000755 }
756
757 bool initial_fill_mode_;
758 uint64_t next_id_;
759 HashMap entries_map_;
760 List<EntryInfo>* entries_;
761
762 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
763};
764
765
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000766class HeapSnapshotsCollection {
767 public:
768 HeapSnapshotsCollection();
769 ~HeapSnapshotsCollection();
770
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000771 bool is_tracking_objects() { return is_tracking_objects_; }
772
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000773 HeapSnapshot* NewSnapshot(
774 HeapSnapshot::Type type, const char* name, unsigned uid);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000775 void SnapshotGenerationFinished(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000776 List<HeapSnapshot*>* snapshots() { return &snapshots_; }
777 HeapSnapshot* GetSnapshot(unsigned uid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000778 void RemoveSnapshot(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000779
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000780 StringsStorage* names() { return &names_; }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000781 TokenEnumerator* token_enumerator() { return token_enumerator_; }
782
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000783 uint64_t GetObjectId(Address addr) { return ids_.FindObject(addr); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000784 Handle<HeapObject> FindHeapObjectById(uint64_t id);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000785 void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
786
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000787 private:
788 INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
789 return key1 == key2;
790 }
791
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000792 bool is_tracking_objects_; // Whether tracking object moves is needed.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000793 List<HeapSnapshot*> snapshots_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000794 // Mapping from snapshots' uids to HeapSnapshot* pointers.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000795 HashMap snapshots_uids_;
796 StringsStorage names_;
797 TokenEnumerator* token_enumerator_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000798 // Mapping from HeapObject addresses to objects' uids.
799 HeapObjectsMap ids_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000800
801 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
802};
803
804
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000805// A typedef for referencing anything that can be snapshotted living
806// in any kind of heap memory.
807typedef void* HeapThing;
808
809
810// An interface that creates HeapEntries by HeapThings.
811class HeapEntriesAllocator {
812 public:
813 virtual ~HeapEntriesAllocator() { }
814 virtual HeapEntry* AllocateEntry(
815 HeapThing ptr, int children_count, int retainers_count) = 0;
816};
817
818
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000819// The HeapEntriesMap instance is used to track a mapping between
820// real heap objects and their representations in heap snapshots.
821class HeapEntriesMap {
822 public:
823 HeapEntriesMap();
824 ~HeapEntriesMap();
825
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000826 void AllocateEntries();
827 HeapEntry* Map(HeapThing thing);
828 void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
829 void CountReference(HeapThing from, HeapThing to,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000830 int* prev_children_count = NULL,
831 int* prev_retainers_count = NULL);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000832
833 int entries_count() { return entries_count_; }
834 int total_children_count() { return total_children_count_; }
835 int total_retainers_count() { return total_retainers_count_; }
836
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000837 static HeapEntry* const kHeapEntryPlaceholder;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000838
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000839 private:
840 struct EntryInfo {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000841 EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
842 : entry(entry),
843 allocator(allocator),
844 children_count(0),
845 retainers_count(0) {
846 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000847 HeapEntry* entry;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 HeapEntriesAllocator* allocator;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000849 int children_count;
850 int retainers_count;
851 };
852
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000853 static uint32_t Hash(HeapThing thing) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000854 return ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000855 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
856 v8::internal::kZeroHashSeed);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000857 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000858 static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
859 return key1 == key2;
860 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000861
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000862 HashMap entries_;
863 int entries_count_;
864 int total_children_count_;
865 int total_retainers_count_;
866
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000867 friend class HeapObjectsSet;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000868
869 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
870};
871
872
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000873class HeapObjectsSet {
874 public:
875 HeapObjectsSet();
876 void Clear();
877 bool Contains(Object* object);
878 void Insert(Object* obj);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000879 const char* GetTag(Object* obj);
880 void SetTag(Object* obj, const char* tag);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000881
882 private:
883 HashMap entries_;
884
885 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
886};
887
888
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889// An interface used to populate a snapshot with nodes and edges.
890class SnapshotFillerInterface {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000891 public:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000892 virtual ~SnapshotFillerInterface() { }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000893 virtual HeapEntry* AddEntry(HeapThing ptr,
894 HeapEntriesAllocator* allocator) = 0;
895 virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
896 virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
897 HeapEntriesAllocator* allocator) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000898 virtual void SetIndexedReference(HeapGraphEdge::Type type,
899 HeapThing parent_ptr,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000900 HeapEntry* parent_entry,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000901 int index,
902 HeapThing child_ptr,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000903 HeapEntry* child_entry) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000904 virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
905 HeapThing parent_ptr,
906 HeapEntry* parent_entry,
907 HeapThing child_ptr,
908 HeapEntry* child_entry) = 0;
909 virtual void SetNamedReference(HeapGraphEdge::Type type,
910 HeapThing parent_ptr,
911 HeapEntry* parent_entry,
912 const char* reference_name,
913 HeapThing child_ptr,
914 HeapEntry* child_entry) = 0;
915 virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
916 HeapThing parent_ptr,
917 HeapEntry* parent_entry,
918 HeapThing child_ptr,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000919 HeapEntry* child_entry) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000920};
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000921
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000922
923class SnapshottingProgressReportingInterface {
924 public:
925 virtual ~SnapshottingProgressReportingInterface() { }
926 virtual void ProgressStep() = 0;
927 virtual bool ProgressReport(bool force) = 0;
928};
929
930
931// An implementation of V8 heap graph extractor.
932class V8HeapExplorer : public HeapEntriesAllocator {
933 public:
934 V8HeapExplorer(HeapSnapshot* snapshot,
935 SnapshottingProgressReportingInterface* progress);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000936 virtual ~V8HeapExplorer();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000937 virtual HeapEntry* AllocateEntry(
938 HeapThing ptr, int children_count, int retainers_count);
939 void AddRootEntries(SnapshotFillerInterface* filler);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000940 int EstimateObjectsCount(HeapIterator* iterator);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000941 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000942 void TagGlobalObjects();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000943
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000944 static String* GetConstructorName(JSObject* object);
945
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000946 static HeapObject* const kInternalRootObject;
947
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000948 private:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000949 HeapEntry* AddEntry(
950 HeapObject* object, int children_count, int retainers_count);
951 HeapEntry* AddEntry(HeapObject* object,
952 HeapEntry::Type type,
953 const char* name,
954 int children_count,
955 int retainers_count);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000956 const char* GetSystemEntryName(HeapObject* object);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000957 void ExtractReferences(HeapObject* obj);
958 void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
959 void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
960 void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000961 void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000962 void SetClosureReference(HeapObject* parent_obj,
963 HeapEntry* parent,
964 String* reference_name,
965 Object* child);
966 void SetElementReference(HeapObject* parent_obj,
967 HeapEntry* parent,
968 int index,
969 Object* child);
970 void SetInternalReference(HeapObject* parent_obj,
971 HeapEntry* parent,
972 const char* reference_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000973 Object* child,
974 int field_offset = -1);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000975 void SetInternalReference(HeapObject* parent_obj,
976 HeapEntry* parent,
977 int index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 Object* child,
979 int field_offset = -1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000980 void SetHiddenReference(HeapObject* parent_obj,
981 HeapEntry* parent,
982 int index,
983 Object* child);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000984 void SetWeakReference(HeapObject* parent_obj,
985 HeapEntry* parent_entry,
986 int index,
987 Object* child_obj,
988 int field_offset);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000989 void SetPropertyReference(HeapObject* parent_obj,
990 HeapEntry* parent,
991 String* reference_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 Object* child,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000993 const char* name_format_string = NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 int field_offset = -1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000995 void SetPropertyShortcutReference(HeapObject* parent_obj,
996 HeapEntry* parent,
997 String* reference_name,
998 Object* child);
999 void SetRootShortcutReference(Object* child);
1000 void SetRootGcRootsReference();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001001 void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
1002 void SetGcSubrootReference(
1003 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001004 void TagObject(Object* obj, const char* tag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001005
1006 HeapEntry* GetEntry(Object* obj);
1007
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001008 static inline HeapObject* GetNthGcSubrootObject(int delta);
1009 static inline int GetGcSubrootOrder(HeapObject* subroot);
1010
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001011 Heap* heap_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001012 HeapSnapshot* snapshot_;
1013 HeapSnapshotsCollection* collection_;
1014 SnapshottingProgressReportingInterface* progress_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001015 SnapshotFillerInterface* filler_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001016 HeapObjectsSet objects_tags_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001017
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001018 static HeapObject* const kGcRootsObject;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001019 static HeapObject* const kFirstGcSubrootObject;
1020 static HeapObject* const kLastGcSubrootObject;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001021
1022 friend class IndexedReferencesExtractor;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001023 friend class GcSubrootsEnumerator;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001024 friend class RootsReferencesExtractor;
1025
1026 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
1027};
1028
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001029class NativeGroupRetainedObjectInfo;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001030
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001031// An implementation of retained native objects extractor.
1032class NativeObjectsExplorer : public HeapEntriesAllocator {
1033 public:
1034 NativeObjectsExplorer(HeapSnapshot* snapshot,
1035 SnapshottingProgressReportingInterface* progress);
1036 virtual ~NativeObjectsExplorer();
1037 virtual HeapEntry* AllocateEntry(
1038 HeapThing ptr, int children_count, int retainers_count);
1039 void AddRootEntries(SnapshotFillerInterface* filler);
1040 int EstimateObjectsCount();
1041 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
1042
1043 private:
1044 void FillRetainedObjects();
rossberg@chromium.org994edf62012-02-06 10:12:55 +00001045 void FillImplicitReferences();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001046 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
1047 void SetNativeRootReference(v8::RetainedObjectInfo* info);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001048 void SetRootNativeRootsReference();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001049 void SetWrapperNativeReferences(HeapObject* wrapper,
1050 v8::RetainedObjectInfo* info);
1051 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
1052
1053 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
1055 v8::internal::kZeroHashSeed);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001056 }
1057 static bool RetainedInfosMatch(void* key1, void* key2) {
1058 return key1 == key2 ||
1059 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
1060 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
1061 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001062 INLINE(static bool StringsMatch(void* key1, void* key2)) {
1063 return strcmp(reinterpret_cast<char*>(key1),
1064 reinterpret_cast<char*>(key2)) == 0;
1065 }
1066
1067 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001068
1069 HeapSnapshot* snapshot_;
1070 HeapSnapshotsCollection* collection_;
1071 SnapshottingProgressReportingInterface* progress_;
1072 bool embedder_queried_;
1073 HeapObjectsSet in_groups_;
1074 // RetainedObjectInfo* -> List<HeapObject*>*
1075 HashMap objects_by_info_;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001076 HashMap native_groups_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001077 // Used during references extraction.
1078 SnapshotFillerInterface* filler_;
1079
1080 static HeapThing const kNativesRootObject;
1081
1082 friend class GlobalHandlesExtractor;
1083
1084 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
1085};
1086
1087
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
1089 public:
1090 HeapSnapshotGenerator(HeapSnapshot* snapshot,
1091 v8::ActivityControl* control);
1092 bool GenerateSnapshot();
1093
1094 private:
1095 bool ApproximateRetainedSizes();
1096 bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
1097 Vector<HeapEntry*>* dominators);
1098 bool CountEntriesAndReferences();
1099 bool FillReferences();
1100 void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
1101 void ProgressStep();
1102 bool ProgressReport(bool force = false);
1103 bool SetEntriesDominators();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001104 void SetProgressTotal(int iterations_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001105
1106 HeapSnapshot* snapshot_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001107 v8::ActivityControl* control_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001108 V8HeapExplorer v8_heap_explorer_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001109 NativeObjectsExplorer dom_explorer_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001110 // Mapping from HeapThing pointers to HeapEntry* pointers.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001111 HeapEntriesMap entries_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001112 // Used during snapshot generation.
1113 int progress_counter_;
1114 int progress_total_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001115
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001116 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
1117};
1118
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001119class OutputStreamWriter;
1120
1121class HeapSnapshotJSONSerializer {
1122 public:
1123 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
1124 : snapshot_(snapshot),
1125 nodes_(ObjectsMatch),
1126 strings_(ObjectsMatch),
1127 next_node_id_(1),
1128 next_string_id_(1),
1129 writer_(NULL) {
1130 }
1131 void Serialize(v8::OutputStream* stream);
1132
1133 private:
1134 INLINE(static bool ObjectsMatch(void* key1, void* key2)) {
1135 return key1 == key2;
1136 }
1137
1138 INLINE(static uint32_t ObjectHash(const void* key)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001139 return ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001140 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)),
1141 v8::internal::kZeroHashSeed);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001142 }
1143
1144 void EnumerateNodes();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001145 HeapSnapshot* CreateFakeSnapshot();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001146 int GetNodeId(HeapEntry* entry);
1147 int GetStringId(const char* s);
1148 void SerializeEdge(HeapGraphEdge* edge);
1149 void SerializeImpl();
1150 void SerializeNode(HeapEntry* entry);
1151 void SerializeNodes();
1152 void SerializeSnapshot();
1153 void SerializeString(const unsigned char* s);
1154 void SerializeStrings();
1155 void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
1156
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001157 static const int kMaxSerializableSnapshotRawSize;
1158
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001159 HeapSnapshot* snapshot_;
1160 HashMap nodes_;
1161 HashMap strings_;
1162 int next_node_id_;
1163 int next_string_id_;
1164 OutputStreamWriter* writer_;
1165
1166 friend class HeapSnapshotJSONSerializerEnumerator;
1167 friend class HeapSnapshotJSONSerializerIterator;
1168
1169 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
1170};
1171
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001172} } // namespace v8::internal
1173
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001174#endif // V8_PROFILE_GENERATOR_H_