| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #ifndef V8_PROFILE_GENERATOR_H_ | 28 #ifndef V8_HEAP_SNAPSHOT_GENERATOR_H_ |
| 29 #define V8_PROFILE_GENERATOR_H_ | 29 #define V8_HEAP_SNAPSHOT_GENERATOR_H_ |
| 30 | |
| 31 #include "allocation.h" | |
| 32 #include "hashmap.h" | |
| 33 #include "../include/v8-profiler.h" | |
| 34 | 30 |
| 35 namespace v8 { | 31 namespace v8 { |
| 36 namespace internal { | 32 namespace internal { |
| 37 | 33 |
| 38 class TokenEnumerator { | |
| 39 public: | |
| 40 TokenEnumerator(); | |
| 41 ~TokenEnumerator(); | |
| 42 int GetTokenId(Object* token); | |
| 43 | |
| 44 static const int kNoSecurityToken = -1; | |
| 45 static const int kInheritsSecurityToken = -2; | |
| 46 | |
| 47 private: | |
| 48 static void TokenRemovedCallback(v8::Isolate* isolate, | |
| 49 v8::Persistent<v8::Value> handle, | |
| 50 void* parameter); | |
| 51 void TokenRemoved(Object** token_location); | |
| 52 | |
| 53 List<Object**> token_locations_; | |
| 54 List<bool> token_removed_; | |
| 55 | |
| 56 friend class TokenEnumeratorTester; | |
| 57 | |
| 58 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator); | |
| 59 }; | |
| 60 | |
| 61 | |
| 62 // Provides a storage of strings allocated in C++ heap, to hold them | |
| 63 // forever, even if they disappear from JS heap or external storage. | |
| 64 class StringsStorage { | |
| 65 public: | |
| 66 StringsStorage(); | |
| 67 ~StringsStorage(); | |
| 68 | |
| 69 const char* GetCopy(const char* src); | |
| 70 const char* GetFormatted(const char* format, ...); | |
| 71 const char* GetVFormatted(const char* format, va_list args); | |
| 72 const char* GetName(String* name); | |
| 73 const char* GetName(int index); | |
| 74 inline const char* GetFunctionName(String* name); | |
| 75 inline const char* GetFunctionName(const char* name); | |
| 76 size_t GetUsedMemorySize() const; | |
| 77 | |
| 78 private: | |
| 79 static const int kMaxNameSize = 1024; | |
| 80 | |
| 81 INLINE(static bool StringsMatch(void* key1, void* key2)) { | |
| 82 return strcmp(reinterpret_cast<char*>(key1), | |
| 83 reinterpret_cast<char*>(key2)) == 0; | |
| 84 } | |
| 85 const char* AddOrDisposeString(char* str, uint32_t hash); | |
| 86 | |
| 87 // Mapping of strings by String::Hash to const char* strings. | |
| 88 HashMap names_; | |
| 89 | |
| 90 DISALLOW_COPY_AND_ASSIGN(StringsStorage); | |
| 91 }; | |
| 92 | |
| 93 | |
| 94 class CodeEntry { | |
| 95 public: | |
| 96 // CodeEntry doesn't own name strings, just references them. | |
| 97 INLINE(CodeEntry(Logger::LogEventsAndTags tag, | |
| 98 const char* name_prefix, | |
| 99 const char* name, | |
| 100 const char* resource_name, | |
| 101 int line_number, | |
| 102 int security_token_id)); | |
| 103 | |
| 104 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); } | |
| 105 INLINE(const char* name_prefix() const) { return name_prefix_; } | |
| 106 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; } | |
| 107 INLINE(const char* name() const) { return name_; } | |
| 108 INLINE(const char* resource_name() const) { return resource_name_; } | |
| 109 INLINE(int line_number() const) { return line_number_; } | |
| 110 INLINE(int shared_id() const) { return shared_id_; } | |
| 111 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; } | |
| 112 INLINE(int security_token_id() const) { return security_token_id_; } | |
| 113 | |
| 114 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag)); | |
| 115 | |
| 116 void CopyData(const CodeEntry& source); | |
| 117 uint32_t GetCallUid() const; | |
| 118 bool IsSameAs(CodeEntry* entry) const; | |
| 119 | |
| 120 static const char* const kEmptyNamePrefix; | |
| 121 | |
| 122 private: | |
| 123 Logger::LogEventsAndTags tag_; | |
| 124 const char* name_prefix_; | |
| 125 const char* name_; | |
| 126 const char* resource_name_; | |
| 127 int line_number_; | |
| 128 int shared_id_; | |
| 129 int security_token_id_; | |
| 130 | |
| 131 DISALLOW_COPY_AND_ASSIGN(CodeEntry); | |
| 132 }; | |
| 133 | |
| 134 | |
| 135 class ProfileTree; | |
| 136 | |
| 137 class ProfileNode { | |
| 138 public: | |
| 139 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry)); | |
| 140 | |
| 141 ProfileNode* FindChild(CodeEntry* entry); | |
| 142 ProfileNode* FindOrAddChild(CodeEntry* entry); | |
| 143 INLINE(void IncrementSelfTicks()) { ++self_ticks_; } | |
| 144 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; } | |
| 145 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; } | |
| 146 | |
| 147 INLINE(CodeEntry* entry() const) { return entry_; } | |
| 148 INLINE(unsigned self_ticks() const) { return self_ticks_; } | |
| 149 INLINE(unsigned total_ticks() const) { return total_ticks_; } | |
| 150 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; } | |
| 151 double GetSelfMillis() const; | |
| 152 double GetTotalMillis() const; | |
| 153 | |
| 154 void Print(int indent); | |
| 155 | |
| 156 private: | |
| 157 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) { | |
| 158 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs( | |
| 159 reinterpret_cast<CodeEntry*>(entry2)); | |
| 160 } | |
| 161 | |
| 162 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) { | |
| 163 return entry->GetCallUid(); | |
| 164 } | |
| 165 | |
| 166 ProfileTree* tree_; | |
| 167 CodeEntry* entry_; | |
| 168 unsigned total_ticks_; | |
| 169 unsigned self_ticks_; | |
| 170 // Mapping from CodeEntry* to ProfileNode* | |
| 171 HashMap children_; | |
| 172 List<ProfileNode*> children_list_; | |
| 173 | |
| 174 DISALLOW_COPY_AND_ASSIGN(ProfileNode); | |
| 175 }; | |
| 176 | |
| 177 | |
| 178 class ProfileTree { | |
| 179 public: | |
| 180 ProfileTree(); | |
| 181 ~ProfileTree(); | |
| 182 | |
| 183 void AddPathFromEnd(const Vector<CodeEntry*>& path); | |
| 184 void AddPathFromStart(const Vector<CodeEntry*>& path); | |
| 185 void CalculateTotalTicks(); | |
| 186 void FilteredClone(ProfileTree* src, int security_token_id); | |
| 187 | |
| 188 double TicksToMillis(unsigned ticks) const { | |
| 189 return ticks * ms_to_ticks_scale_; | |
| 190 } | |
| 191 ProfileNode* root() const { return root_; } | |
| 192 void SetTickRatePerMs(double ticks_per_ms); | |
| 193 | |
| 194 void ShortPrint(); | |
| 195 void Print() { | |
| 196 root_->Print(0); | |
| 197 } | |
| 198 | |
| 199 private: | |
| 200 template <typename Callback> | |
| 201 void TraverseDepthFirst(Callback* callback); | |
| 202 | |
| 203 CodeEntry root_entry_; | |
| 204 ProfileNode* root_; | |
| 205 double ms_to_ticks_scale_; | |
| 206 | |
| 207 DISALLOW_COPY_AND_ASSIGN(ProfileTree); | |
| 208 }; | |
| 209 | |
| 210 | |
| 211 class CpuProfile { | |
| 212 public: | |
| 213 CpuProfile(const char* title, unsigned uid) | |
| 214 : title_(title), uid_(uid) { } | |
| 215 | |
| 216 // Add pc -> ... -> main() call path to the profile. | |
| 217 void AddPath(const Vector<CodeEntry*>& path); | |
| 218 void CalculateTotalTicks(); | |
| 219 void SetActualSamplingRate(double actual_sampling_rate); | |
| 220 CpuProfile* FilteredClone(int security_token_id); | |
| 221 | |
| 222 INLINE(const char* title() const) { return title_; } | |
| 223 INLINE(unsigned uid() const) { return uid_; } | |
| 224 INLINE(const ProfileTree* top_down() const) { return &top_down_; } | |
| 225 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; } | |
| 226 | |
| 227 void UpdateTicksScale(); | |
| 228 | |
| 229 void ShortPrint(); | |
| 230 void Print(); | |
| 231 | |
| 232 private: | |
| 233 const char* title_; | |
| 234 unsigned uid_; | |
| 235 ProfileTree top_down_; | |
| 236 ProfileTree bottom_up_; | |
| 237 | |
| 238 DISALLOW_COPY_AND_ASSIGN(CpuProfile); | |
| 239 }; | |
| 240 | |
| 241 | |
| 242 class CodeMap { | |
| 243 public: | |
| 244 CodeMap() : next_shared_id_(1) { } | |
| 245 void AddCode(Address addr, CodeEntry* entry, unsigned size); | |
| 246 void MoveCode(Address from, Address to); | |
| 247 CodeEntry* FindEntry(Address addr); | |
| 248 int GetSharedId(Address addr); | |
| 249 | |
| 250 void Print(); | |
| 251 | |
| 252 private: | |
| 253 struct CodeEntryInfo { | |
| 254 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) | |
| 255 : entry(an_entry), size(a_size) { } | |
| 256 CodeEntry* entry; | |
| 257 unsigned size; | |
| 258 }; | |
| 259 | |
| 260 struct CodeTreeConfig { | |
| 261 typedef Address Key; | |
| 262 typedef CodeEntryInfo Value; | |
| 263 static const Key kNoKey; | |
| 264 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } | |
| 265 static int Compare(const Key& a, const Key& b) { | |
| 266 return a < b ? -1 : (a > b ? 1 : 0); | |
| 267 } | |
| 268 }; | |
| 269 typedef SplayTree<CodeTreeConfig> CodeTree; | |
| 270 | |
| 271 class CodeTreePrinter { | |
| 272 public: | |
| 273 void Call(const Address& key, const CodeEntryInfo& value); | |
| 274 }; | |
| 275 | |
| 276 void DeleteAllCoveredCode(Address start, Address end); | |
| 277 | |
| 278 // Fake CodeEntry pointer to distinguish shared function entries. | |
| 279 static CodeEntry* const kSharedFunctionCodeEntry; | |
| 280 | |
| 281 CodeTree tree_; | |
| 282 int next_shared_id_; | |
| 283 | |
| 284 DISALLOW_COPY_AND_ASSIGN(CodeMap); | |
| 285 }; | |
| 286 | |
| 287 | |
| 288 class CpuProfilesCollection { | |
| 289 public: | |
| 290 CpuProfilesCollection(); | |
| 291 ~CpuProfilesCollection(); | |
| 292 | |
| 293 bool StartProfiling(const char* title, unsigned uid); | |
| 294 bool StartProfiling(String* title, unsigned uid); | |
| 295 CpuProfile* StopProfiling(int security_token_id, | |
| 296 const char* title, | |
| 297 double actual_sampling_rate); | |
| 298 List<CpuProfile*>* Profiles(int security_token_id); | |
| 299 const char* GetName(String* name) { | |
| 300 return function_and_resource_names_.GetName(name); | |
| 301 } | |
| 302 const char* GetName(int args_count) { | |
| 303 return function_and_resource_names_.GetName(args_count); | |
| 304 } | |
| 305 CpuProfile* GetProfile(int security_token_id, unsigned uid); | |
| 306 bool IsLastProfile(const char* title); | |
| 307 void RemoveProfile(CpuProfile* profile); | |
| 308 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; } | |
| 309 | |
| 310 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
| 311 String* name, String* resource_name, int line_number); | |
| 312 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name); | |
| 313 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
| 314 const char* name_prefix, String* name); | |
| 315 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count); | |
| 316 CodeEntry* NewCodeEntry(int security_token_id); | |
| 317 | |
| 318 // Called from profile generator thread. | |
| 319 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path); | |
| 320 | |
| 321 // Limits the number of profiles that can be simultaneously collected. | |
| 322 static const int kMaxSimultaneousProfiles = 100; | |
| 323 | |
| 324 private: | |
| 325 const char* GetFunctionName(String* name) { | |
| 326 return function_and_resource_names_.GetFunctionName(name); | |
| 327 } | |
| 328 const char* GetFunctionName(const char* name) { | |
| 329 return function_and_resource_names_.GetFunctionName(name); | |
| 330 } | |
| 331 int GetProfileIndex(unsigned uid); | |
| 332 List<CpuProfile*>* GetProfilesList(int security_token_id); | |
| 333 int TokenToIndex(int security_token_id); | |
| 334 | |
| 335 INLINE(static bool UidsMatch(void* key1, void* key2)) { | |
| 336 return key1 == key2; | |
| 337 } | |
| 338 | |
| 339 StringsStorage function_and_resource_names_; | |
| 340 List<CodeEntry*> code_entries_; | |
| 341 List<List<CpuProfile*>* > profiles_by_token_; | |
| 342 // Mapping from profiles' uids to indexes in the second nested list | |
| 343 // of profiles_by_token_. | |
| 344 HashMap profiles_uids_; | |
| 345 List<CpuProfile*> detached_profiles_; | |
| 346 | |
| 347 // Accessed by VM thread and profile generator thread. | |
| 348 List<CpuProfile*> current_profiles_; | |
| 349 Semaphore* current_profiles_semaphore_; | |
| 350 | |
| 351 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); | |
| 352 }; | |
| 353 | |
| 354 | |
| 355 class SampleRateCalculator { | |
| 356 public: | |
| 357 SampleRateCalculator() | |
| 358 : result_(Logger::kSamplingIntervalMs * kResultScale), | |
| 359 ticks_per_ms_(Logger::kSamplingIntervalMs), | |
| 360 measurements_count_(0), | |
| 361 wall_time_query_countdown_(1) { | |
| 362 } | |
| 363 | |
| 364 double ticks_per_ms() { | |
| 365 return result_ / static_cast<double>(kResultScale); | |
| 366 } | |
| 367 void Tick(); | |
| 368 void UpdateMeasurements(double current_time); | |
| 369 | |
| 370 // Instead of querying current wall time each tick, | |
| 371 // we use this constant to control query intervals. | |
| 372 static const unsigned kWallTimeQueryIntervalMs = 100; | |
| 373 | |
| 374 private: | |
| 375 // As the result needs to be accessed from a different thread, we | |
| 376 // use type that guarantees atomic writes to memory. There should | |
| 377 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5 | |
| 378 // order should provide enough precision while keeping away from a | |
| 379 // potential overflow. | |
| 380 static const int kResultScale = 100000; | |
| 381 | |
| 382 AtomicWord result_; | |
| 383 // All other fields are accessed only from the sampler thread. | |
| 384 double ticks_per_ms_; | |
| 385 unsigned measurements_count_; | |
| 386 unsigned wall_time_query_countdown_; | |
| 387 double last_wall_time_; | |
| 388 | |
| 389 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator); | |
| 390 }; | |
| 391 | |
| 392 | |
| 393 class ProfileGenerator { | |
| 394 public: | |
| 395 explicit ProfileGenerator(CpuProfilesCollection* profiles); | |
| 396 | |
| 397 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
| 398 String* name, | |
| 399 String* resource_name, | |
| 400 int line_number)) { | |
| 401 return profiles_->NewCodeEntry(tag, name, resource_name, line_number); | |
| 402 } | |
| 403 | |
| 404 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
| 405 const char* name)) { | |
| 406 return profiles_->NewCodeEntry(tag, name); | |
| 407 } | |
| 408 | |
| 409 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
| 410 const char* name_prefix, | |
| 411 String* name)) { | |
| 412 return profiles_->NewCodeEntry(tag, name_prefix, name); | |
| 413 } | |
| 414 | |
| 415 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
| 416 int args_count)) { | |
| 417 return profiles_->NewCodeEntry(tag, args_count); | |
| 418 } | |
| 419 | |
| 420 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) { | |
| 421 return profiles_->NewCodeEntry(security_token_id); | |
| 422 } | |
| 423 | |
| 424 void RecordTickSample(const TickSample& sample); | |
| 425 | |
| 426 INLINE(CodeMap* code_map()) { return &code_map_; } | |
| 427 | |
| 428 INLINE(void Tick()) { sample_rate_calc_.Tick(); } | |
| 429 INLINE(double actual_sampling_rate()) { | |
| 430 return sample_rate_calc_.ticks_per_ms(); | |
| 431 } | |
| 432 | |
| 433 static const char* const kAnonymousFunctionName; | |
| 434 static const char* const kProgramEntryName; | |
| 435 static const char* const kGarbageCollectorEntryName; | |
| 436 | |
| 437 private: | |
| 438 INLINE(CodeEntry* EntryForVMState(StateTag tag)); | |
| 439 | |
| 440 CpuProfilesCollection* profiles_; | |
| 441 CodeMap code_map_; | |
| 442 CodeEntry* program_entry_; | |
| 443 CodeEntry* gc_entry_; | |
| 444 SampleRateCalculator sample_rate_calc_; | |
| 445 | |
| 446 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); | |
| 447 }; | |
| 448 | |
| 449 | |
| 450 class HeapEntry; | 34 class HeapEntry; |
| 451 class HeapSnapshot; | 35 class HeapSnapshot; |
| 452 | 36 |
| 453 class HeapGraphEdge BASE_EMBEDDED { | 37 class HeapGraphEdge BASE_EMBEDDED { |
| 454 public: | 38 public: |
| 455 enum Type { | 39 enum Type { |
| 456 kContextVariable = v8::HeapGraphEdge::kContextVariable, | 40 kContextVariable = v8::HeapGraphEdge::kContextVariable, |
| 457 kElement = v8::HeapGraphEdge::kElement, | 41 kElement = v8::HeapGraphEdge::kElement, |
| 458 kProperty = v8::HeapGraphEdge::kProperty, | 42 kProperty = v8::HeapGraphEdge::kProperty, |
| 459 kInternal = v8::HeapGraphEdge::kInternal, | 43 kInternal = v8::HeapGraphEdge::kInternal, |
| (...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1099 int next_node_id_; | 683 int next_node_id_; |
| 1100 int next_string_id_; | 684 int next_string_id_; |
| 1101 OutputStreamWriter* writer_; | 685 OutputStreamWriter* writer_; |
| 1102 | 686 |
| 1103 friend class HeapSnapshotJSONSerializerEnumerator; | 687 friend class HeapSnapshotJSONSerializerEnumerator; |
| 1104 friend class HeapSnapshotJSONSerializerIterator; | 688 friend class HeapSnapshotJSONSerializerIterator; |
| 1105 | 689 |
| 1106 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer); | 690 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer); |
| 1107 }; | 691 }; |
| 1108 | 692 |
| 693 |
| 1109 } } // namespace v8::internal | 694 } } // namespace v8::internal |
| 1110 | 695 |
| 1111 #endif // V8_PROFILE_GENERATOR_H_ | 696 #endif // V8_HEAP_SNAPSHOT_GENERATOR_H_ |
| 697 |
| OLD | NEW |