Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // 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 #ifdef ENABLE_LOGGING_AND_PROFILING
     29 
     30 #include "v8.h"
     31 #include "global-handles.h"
     32 #include "heap-profiler.h"
     33 #include "scopeinfo.h"
     34 #include "unicode.h"
     35 #include "zone-inl.h"
     36 
     37 #include "profile-generator-inl.h"
     38 
     39 namespace v8 {
     40 namespace internal {
     41 
     42 
     43 TokenEnumerator::TokenEnumerator()
     44     : token_locations_(4),
     45       token_removed_(4) {
     46 }
     47 
     48 
     49 TokenEnumerator::~TokenEnumerator() {
     50   Isolate* isolate = Isolate::Current();
     51   for (int i = 0; i < token_locations_.length(); ++i) {
     52     if (!token_removed_[i]) {
     53       isolate->global_handles()->ClearWeakness(token_locations_[i]);
     54       isolate->global_handles()->Destroy(token_locations_[i]);
     55     }
     56   }
     57 }
     58 
     59 
     60 int TokenEnumerator::GetTokenId(Object* token) {
     61   Isolate* isolate = Isolate::Current();
     62   if (token == NULL) return TokenEnumerator::kNoSecurityToken;
     63   for (int i = 0; i < token_locations_.length(); ++i) {
     64     if (*token_locations_[i] == token && !token_removed_[i]) return i;
     65   }
     66   Handle<Object> handle = isolate->global_handles()->Create(token);
     67   // handle.location() points to a memory cell holding a pointer
     68   // to a token object in the V8's heap.
     69   isolate->global_handles()->MakeWeak(handle.location(), this,
     70                                       TokenRemovedCallback);
     71   token_locations_.Add(handle.location());
     72   token_removed_.Add(false);
     73   return token_locations_.length() - 1;
     74 }
     75 
     76 
     77 void TokenEnumerator::TokenRemovedCallback(v8::Persistent<v8::Value> handle,
     78                                            void* parameter) {
     79   reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved(
     80       Utils::OpenHandle(*handle).location());
     81   handle.Dispose();
     82 }
     83 
     84 
     85 void TokenEnumerator::TokenRemoved(Object** token_location) {
     86   for (int i = 0; i < token_locations_.length(); ++i) {
     87     if (token_locations_[i] == token_location && !token_removed_[i]) {
     88       token_removed_[i] = true;
     89       return;
     90     }
     91   }
     92 }
     93 
     94 
     95 StringsStorage::StringsStorage()
     96     : names_(StringsMatch) {
     97 }
     98 
     99 
    100 StringsStorage::~StringsStorage() {
    101   for (HashMap::Entry* p = names_.Start();
    102        p != NULL;
    103        p = names_.Next(p)) {
    104     DeleteArray(reinterpret_cast<const char*>(p->value));
    105   }
    106 }
    107 
    108 
    109 const char* StringsStorage::GetCopy(const char* src) {
    110   int len = static_cast<int>(strlen(src));
    111   Vector<char> dst = Vector<char>::New(len + 1);
    112   OS::StrNCpy(dst, src, len);
    113   dst[len] = '\0';
    114   uint32_t hash = HashSequentialString(dst.start(), len);
    115   return AddOrDisposeString(dst.start(), hash);
    116 }
    117 
    118 
    119 const char* StringsStorage::GetFormatted(const char* format, ...) {
    120   va_list args;
    121   va_start(args, format);
    122   const char* result = GetVFormatted(format, args);
    123   va_end(args);
    124   return result;
    125 }
    126 
    127 
    128 const char* StringsStorage::AddOrDisposeString(char* str, uint32_t hash) {
    129   HashMap::Entry* cache_entry = names_.Lookup(str, hash, true);
    130   if (cache_entry->value == NULL) {
    131     // New entry added.
    132     cache_entry->value = str;
    133   } else {
    134     DeleteArray(str);
    135   }
    136   return reinterpret_cast<const char*>(cache_entry->value);
    137 }
    138 
    139 
    140 const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
    141   Vector<char> str = Vector<char>::New(1024);
    142   int len = OS::VSNPrintF(str, format, args);
    143   if (len == -1) {
    144     DeleteArray(str.start());
    145     return format;
    146   }
    147   uint32_t hash = HashSequentialString(str.start(), len);
    148   return AddOrDisposeString(str.start(), hash);
    149 }
    150 
    151 
    152 const char* StringsStorage::GetName(String* name) {
    153   if (name->IsString()) {
    154     return AddOrDisposeString(
    155         name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(),
    156         name->Hash());
    157   }
    158   return "";
    159 }
    160 
    161 
    162 const char* StringsStorage::GetName(int index) {
    163   return GetFormatted("%d", index);
    164 }
    165 
    166 
    167 const char* const CodeEntry::kEmptyNamePrefix = "";
    168 
    169 
    170 void CodeEntry::CopyData(const CodeEntry& source) {
    171   tag_ = source.tag_;
    172   name_prefix_ = source.name_prefix_;
    173   name_ = source.name_;
    174   resource_name_ = source.resource_name_;
    175   line_number_ = source.line_number_;
    176 }
    177 
    178 
    179 uint32_t CodeEntry::GetCallUid() const {
    180   uint32_t hash = ComputeIntegerHash(tag_);
    181   if (shared_id_ != 0) {
    182     hash ^= ComputeIntegerHash(
    183         static_cast<uint32_t>(shared_id_));
    184   } else {
    185     hash ^= ComputeIntegerHash(
    186         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
    187     hash ^= ComputeIntegerHash(
    188         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
    189     hash ^= ComputeIntegerHash(
    190         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
    191     hash ^= ComputeIntegerHash(line_number_);
    192   }
    193   return hash;
    194 }
    195 
    196 
    197 bool CodeEntry::IsSameAs(CodeEntry* entry) const {
    198   return this == entry
    199       || (tag_ == entry->tag_
    200           && shared_id_ == entry->shared_id_
    201           && (shared_id_ != 0
    202               || (name_prefix_ == entry->name_prefix_
    203                   && name_ == entry->name_
    204                   && resource_name_ == entry->resource_name_
    205                   && line_number_ == entry->line_number_)));
    206 }
    207 
    208 
    209 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
    210   HashMap::Entry* map_entry =
    211       children_.Lookup(entry, CodeEntryHash(entry), false);
    212   return map_entry != NULL ?
    213       reinterpret_cast<ProfileNode*>(map_entry->value) : NULL;
    214 }
    215 
    216 
    217 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
    218   HashMap::Entry* map_entry =
    219       children_.Lookup(entry, CodeEntryHash(entry), true);
    220   if (map_entry->value == NULL) {
    221     // New node added.
    222     ProfileNode* new_node = new ProfileNode(tree_, entry);
    223     map_entry->value = new_node;
    224     children_list_.Add(new_node);
    225   }
    226   return reinterpret_cast<ProfileNode*>(map_entry->value);
    227 }
    228 
    229 
    230 double ProfileNode::GetSelfMillis() const {
    231   return tree_->TicksToMillis(self_ticks_);
    232 }
    233 
    234 
    235 double ProfileNode::GetTotalMillis() const {
    236   return tree_->TicksToMillis(total_ticks_);
    237 }
    238 
    239 
    240 void ProfileNode::Print(int indent) {
    241   OS::Print("%5u %5u %*c %s%s [%d]",
    242             total_ticks_, self_ticks_,
    243             indent, ' ',
    244             entry_->name_prefix(),
    245             entry_->name(),
    246             entry_->security_token_id());
    247   if (entry_->resource_name()[0] != '\0')
    248     OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
    249   OS::Print("\n");
    250   for (HashMap::Entry* p = children_.Start();
    251        p != NULL;
    252        p = children_.Next(p)) {
    253     reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2);
    254   }
    255 }
    256 
    257 
    258 class DeleteNodesCallback {
    259  public:
    260   void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
    261 
    262   void AfterAllChildrenTraversed(ProfileNode* node) {
    263     delete node;
    264   }
    265 
    266   void AfterChildTraversed(ProfileNode*, ProfileNode*) { }
    267 };
    268 
    269 
    270 ProfileTree::ProfileTree()
    271     : root_entry_(Logger::FUNCTION_TAG,
    272                   "",
    273                   "(root)",
    274                   "",
    275                   0,
    276                   TokenEnumerator::kNoSecurityToken),
    277       root_(new ProfileNode(this, &root_entry_)) {
    278 }
    279 
    280 
    281 ProfileTree::~ProfileTree() {
    282   DeleteNodesCallback cb;
    283   TraverseDepthFirst(&cb);
    284 }
    285 
    286 
    287 void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) {
    288   ProfileNode* node = root_;
    289   for (CodeEntry** entry = path.start() + path.length() - 1;
    290        entry != path.start() - 1;
    291        --entry) {
    292     if (*entry != NULL) {
    293       node = node->FindOrAddChild(*entry);
    294     }
    295   }
    296   node->IncrementSelfTicks();
    297 }
    298 
    299 
    300 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) {
    301   ProfileNode* node = root_;
    302   for (CodeEntry** entry = path.start();
    303        entry != path.start() + path.length();
    304        ++entry) {
    305     if (*entry != NULL) {
    306       node = node->FindOrAddChild(*entry);
    307     }
    308   }
    309   node->IncrementSelfTicks();
    310 }
    311 
    312 
    313 struct NodesPair {
    314   NodesPair(ProfileNode* src, ProfileNode* dst)
    315       : src(src), dst(dst) { }
    316   ProfileNode* src;
    317   ProfileNode* dst;
    318 };
    319 
    320 
    321 class FilteredCloneCallback {
    322  public:
    323   FilteredCloneCallback(ProfileNode* dst_root, int security_token_id)
    324       : stack_(10),
    325         security_token_id_(security_token_id) {
    326     stack_.Add(NodesPair(NULL, dst_root));
    327   }
    328 
    329   void BeforeTraversingChild(ProfileNode* parent, ProfileNode* child) {
    330     if (IsTokenAcceptable(child->entry()->security_token_id(),
    331                           parent->entry()->security_token_id())) {
    332       ProfileNode* clone = stack_.last().dst->FindOrAddChild(child->entry());
    333       clone->IncreaseSelfTicks(child->self_ticks());
    334       stack_.Add(NodesPair(child, clone));
    335     } else {
    336       // Attribute ticks to parent node.
    337       stack_.last().dst->IncreaseSelfTicks(child->self_ticks());
    338     }
    339   }
    340 
    341   void AfterAllChildrenTraversed(ProfileNode* parent) { }
    342 
    343   void AfterChildTraversed(ProfileNode*, ProfileNode* child) {
    344     if (stack_.last().src == child) {
    345       stack_.RemoveLast();
    346     }
    347   }
    348 
    349  private:
    350   bool IsTokenAcceptable(int token, int parent_token) {
    351     if (token == TokenEnumerator::kNoSecurityToken
    352         || token == security_token_id_) return true;
    353     if (token == TokenEnumerator::kInheritsSecurityToken) {
    354       ASSERT(parent_token != TokenEnumerator::kInheritsSecurityToken);
    355       return parent_token == TokenEnumerator::kNoSecurityToken
    356           || parent_token == security_token_id_;
    357     }
    358     return false;
    359   }
    360 
    361   List<NodesPair> stack_;
    362   int security_token_id_;
    363 };
    364 
    365 void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) {
    366   ms_to_ticks_scale_ = src->ms_to_ticks_scale_;
    367   FilteredCloneCallback cb(root_, security_token_id);
    368   src->TraverseDepthFirst(&cb);
    369   CalculateTotalTicks();
    370 }
    371 
    372 
    373 void ProfileTree::SetTickRatePerMs(double ticks_per_ms) {
    374   ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0;
    375 }
    376 
    377 
    378 class Position {
    379  public:
    380   explicit Position(ProfileNode* node)
    381       : node(node), child_idx_(0) { }
    382   INLINE(ProfileNode* current_child()) {
    383     return node->children()->at(child_idx_);
    384   }
    385   INLINE(bool has_current_child()) {
    386     return child_idx_ < node->children()->length();
    387   }
    388   INLINE(void next_child()) { ++child_idx_; }
    389 
    390   ProfileNode* node;
    391  private:
    392   int child_idx_;
    393 };
    394 
    395 
    396 // Non-recursive implementation of a depth-first post-order tree traversal.
    397 template <typename Callback>
    398 void ProfileTree::TraverseDepthFirst(Callback* callback) {
    399   List<Position> stack(10);
    400   stack.Add(Position(root_));
    401   while (stack.length() > 0) {
    402     Position& current = stack.last();
    403     if (current.has_current_child()) {
    404       callback->BeforeTraversingChild(current.node, current.current_child());
    405       stack.Add(Position(current.current_child()));
    406     } else {
    407       callback->AfterAllChildrenTraversed(current.node);
    408       if (stack.length() > 1) {
    409         Position& parent = stack[stack.length() - 2];
    410         callback->AfterChildTraversed(parent.node, current.node);
    411         parent.next_child();
    412       }
    413       // Remove child from the stack.
    414       stack.RemoveLast();
    415     }
    416   }
    417 }
    418 
    419 
    420 class CalculateTotalTicksCallback {
    421  public:
    422   void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
    423 
    424   void AfterAllChildrenTraversed(ProfileNode* node) {
    425     node->IncreaseTotalTicks(node->self_ticks());
    426   }
    427 
    428   void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) {
    429     parent->IncreaseTotalTicks(child->total_ticks());
    430   }
    431 };
    432 
    433 
    434 void ProfileTree::CalculateTotalTicks() {
    435   CalculateTotalTicksCallback cb;
    436   TraverseDepthFirst(&cb);
    437 }
    438 
    439 
    440 void ProfileTree::ShortPrint() {
    441   OS::Print("root: %u %u %.2fms %.2fms\n",
    442             root_->total_ticks(), root_->self_ticks(),
    443             root_->GetTotalMillis(), root_->GetSelfMillis());
    444 }
    445 
    446 
    447 void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
    448   top_down_.AddPathFromEnd(path);
    449   bottom_up_.AddPathFromStart(path);
    450 }
    451 
    452 
    453 void CpuProfile::CalculateTotalTicks() {
    454   top_down_.CalculateTotalTicks();
    455   bottom_up_.CalculateTotalTicks();
    456 }
    457 
    458 
    459 void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) {
    460   top_down_.SetTickRatePerMs(actual_sampling_rate);
    461   bottom_up_.SetTickRatePerMs(actual_sampling_rate);
    462 }
    463 
    464 
    465 CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
    466   ASSERT(security_token_id != TokenEnumerator::kNoSecurityToken);
    467   CpuProfile* clone = new CpuProfile(title_, uid_);
    468   clone->top_down_.FilteredClone(&top_down_, security_token_id);
    469   clone->bottom_up_.FilteredClone(&bottom_up_, security_token_id);
    470   return clone;
    471 }
    472 
    473 
    474 void CpuProfile::ShortPrint() {
    475   OS::Print("top down ");
    476   top_down_.ShortPrint();
    477   OS::Print("bottom up ");
    478   bottom_up_.ShortPrint();
    479 }
    480 
    481 
    482 void CpuProfile::Print() {
    483   OS::Print("[Top down]:\n");
    484   top_down_.Print();
    485   OS::Print("[Bottom up]:\n");
    486   bottom_up_.Print();
    487 }
    488 
    489 
    490 CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL;
    491 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
    492 const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
    493     CodeMap::CodeEntryInfo(NULL, 0);
    494 
    495 
    496 CodeEntry* CodeMap::FindEntry(Address addr) {
    497   CodeTree::Locator locator;
    498   if (tree_.FindGreatestLessThan(addr, &locator)) {
    499     // locator.key() <= addr. Need to check that addr is within entry.
    500     const CodeEntryInfo& entry = locator.value();
    501     if (addr < (locator.key() + entry.size))
    502       return entry.entry;
    503   }
    504   return NULL;
    505 }
    506 
    507 
    508 int CodeMap::GetSharedId(Address addr) {
    509   CodeTree::Locator locator;
    510   // For shared function entries, 'size' field is used to store their IDs.
    511   if (tree_.Find(addr, &locator)) {
    512     const CodeEntryInfo& entry = locator.value();
    513     ASSERT(entry.entry == kSharedFunctionCodeEntry);
    514     return entry.size;
    515   } else {
    516     tree_.Insert(addr, &locator);
    517     int id = next_shared_id_++;
    518     locator.set_value(CodeEntryInfo(kSharedFunctionCodeEntry, id));
    519     return id;
    520   }
    521 }
    522 
    523 
    524 void CodeMap::CodeTreePrinter::Call(
    525     const Address& key, const CodeMap::CodeEntryInfo& value) {
    526   OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
    527 }
    528 
    529 
    530 void CodeMap::Print() {
    531   CodeTreePrinter printer;
    532   tree_.ForEach(&printer);
    533 }
    534 
    535 
    536 CpuProfilesCollection::CpuProfilesCollection()
    537     : profiles_uids_(UidsMatch),
    538       current_profiles_semaphore_(OS::CreateSemaphore(1)) {
    539   // Create list of unabridged profiles.
    540   profiles_by_token_.Add(new List<CpuProfile*>());
    541 }
    542 
    543 
    544 static void DeleteCodeEntry(CodeEntry** entry_ptr) {
    545   delete *entry_ptr;
    546 }
    547 
    548 static void DeleteCpuProfile(CpuProfile** profile_ptr) {
    549   delete *profile_ptr;
    550 }
    551 
    552 static void DeleteProfilesList(List<CpuProfile*>** list_ptr) {
    553   if (*list_ptr != NULL) {
    554     (*list_ptr)->Iterate(DeleteCpuProfile);
    555     delete *list_ptr;
    556   }
    557 }
    558 
    559 CpuProfilesCollection::~CpuProfilesCollection() {
    560   delete current_profiles_semaphore_;
    561   current_profiles_.Iterate(DeleteCpuProfile);
    562   detached_profiles_.Iterate(DeleteCpuProfile);
    563   profiles_by_token_.Iterate(DeleteProfilesList);
    564   code_entries_.Iterate(DeleteCodeEntry);
    565 }
    566 
    567 
    568 bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid) {
    569   ASSERT(uid > 0);
    570   current_profiles_semaphore_->Wait();
    571   if (current_profiles_.length() >= kMaxSimultaneousProfiles) {
    572     current_profiles_semaphore_->Signal();
    573     return false;
    574   }
    575   for (int i = 0; i < current_profiles_.length(); ++i) {
    576     if (strcmp(current_profiles_[i]->title(), title) == 0) {
    577       // Ignore attempts to start profile with the same title.
    578       current_profiles_semaphore_->Signal();
    579       return false;
    580     }
    581   }
    582   current_profiles_.Add(new CpuProfile(title, uid));
    583   current_profiles_semaphore_->Signal();
    584   return true;
    585 }
    586 
    587 
    588 bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) {
    589   return StartProfiling(GetName(title), uid);
    590 }
    591 
    592 
    593 CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
    594                                                  const char* title,
    595                                                  double actual_sampling_rate) {
    596   const int title_len = StrLength(title);
    597   CpuProfile* profile = NULL;
    598   current_profiles_semaphore_->Wait();
    599   for (int i = current_profiles_.length() - 1; i >= 0; --i) {
    600     if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) {
    601       profile = current_profiles_.Remove(i);
    602       break;
    603     }
    604   }
    605   current_profiles_semaphore_->Signal();
    606 
    607   if (profile != NULL) {
    608     profile->CalculateTotalTicks();
    609     profile->SetActualSamplingRate(actual_sampling_rate);
    610     List<CpuProfile*>* unabridged_list =
    611         profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
    612     unabridged_list->Add(profile);
    613     HashMap::Entry* entry =
    614         profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()),
    615                               static_cast<uint32_t>(profile->uid()),
    616                               true);
    617     ASSERT(entry->value == NULL);
    618     entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1);
    619     return GetProfile(security_token_id, profile->uid());
    620   }
    621   return NULL;
    622 }
    623 
    624 
    625 CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
    626                                               unsigned uid) {
    627   int index = GetProfileIndex(uid);
    628   if (index < 0) return NULL;
    629   List<CpuProfile*>* unabridged_list =
    630       profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
    631   if (security_token_id == TokenEnumerator::kNoSecurityToken) {
    632     return unabridged_list->at(index);
    633   }
    634   List<CpuProfile*>* list = GetProfilesList(security_token_id);
    635   if (list->at(index) == NULL) {
    636     (*list)[index] =
    637         unabridged_list->at(index)->FilteredClone(security_token_id);
    638   }
    639   return list->at(index);
    640 }
    641 
    642 
    643 int CpuProfilesCollection::GetProfileIndex(unsigned uid) {
    644   HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
    645                                                 static_cast<uint32_t>(uid),
    646                                                 false);
    647   return entry != NULL ?
    648       static_cast<int>(reinterpret_cast<intptr_t>(entry->value)) : -1;
    649 }
    650 
    651 
    652 bool CpuProfilesCollection::IsLastProfile(const char* title) {
    653   // Called from VM thread, and only it can mutate the list,
    654   // so no locking is needed here.
    655   if (current_profiles_.length() != 1) return false;
    656   return StrLength(title) == 0
    657       || strcmp(current_profiles_[0]->title(), title) == 0;
    658 }
    659 
    660 
    661 void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
    662   // Called from VM thread for a completed profile.
    663   unsigned uid = profile->uid();
    664   int index = GetProfileIndex(uid);
    665   if (index < 0) {
    666     detached_profiles_.RemoveElement(profile);
    667     return;
    668   }
    669   profiles_uids_.Remove(reinterpret_cast<void*>(uid),
    670                         static_cast<uint32_t>(uid));
    671   // Decrement all indexes above the deleted one.
    672   for (HashMap::Entry* p = profiles_uids_.Start();
    673        p != NULL;
    674        p = profiles_uids_.Next(p)) {
    675     intptr_t p_index = reinterpret_cast<intptr_t>(p->value);
    676     if (p_index > index) {
    677       p->value = reinterpret_cast<void*>(p_index - 1);
    678     }
    679   }
    680   for (int i = 0; i < profiles_by_token_.length(); ++i) {
    681     List<CpuProfile*>* list = profiles_by_token_[i];
    682     if (list != NULL && index < list->length()) {
    683       // Move all filtered clones into detached_profiles_,
    684       // so we can know that they are still in use.
    685       CpuProfile* cloned_profile = list->Remove(index);
    686       if (cloned_profile != NULL && cloned_profile != profile) {
    687         detached_profiles_.Add(cloned_profile);
    688       }
    689     }
    690   }
    691 }
    692 
    693 
    694 int CpuProfilesCollection::TokenToIndex(int security_token_id) {
    695   ASSERT(TokenEnumerator::kNoSecurityToken == -1);
    696   return security_token_id + 1;  // kNoSecurityToken -> 0, 0 -> 1, ...
    697 }
    698 
    699 
    700 List<CpuProfile*>* CpuProfilesCollection::GetProfilesList(
    701     int security_token_id) {
    702   const int index = TokenToIndex(security_token_id);
    703   const int lists_to_add = index - profiles_by_token_.length() + 1;
    704   if (lists_to_add > 0) profiles_by_token_.AddBlock(NULL, lists_to_add);
    705   List<CpuProfile*>* unabridged_list =
    706       profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
    707   const int current_count = unabridged_list->length();
    708   if (profiles_by_token_[index] == NULL) {
    709     profiles_by_token_[index] = new List<CpuProfile*>(current_count);
    710   }
    711   List<CpuProfile*>* list = profiles_by_token_[index];
    712   const int profiles_to_add = current_count - list->length();
    713   if (profiles_to_add > 0) list->AddBlock(NULL, profiles_to_add);
    714   return list;
    715 }
    716 
    717 
    718 List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
    719   List<CpuProfile*>* unabridged_list =
    720       profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
    721   if (security_token_id == TokenEnumerator::kNoSecurityToken) {
    722     return unabridged_list;
    723   }
    724   List<CpuProfile*>* list = GetProfilesList(security_token_id);
    725   const int current_count = unabridged_list->length();
    726   for (int i = 0; i < current_count; ++i) {
    727     if (list->at(i) == NULL) {
    728       (*list)[i] = unabridged_list->at(i)->FilteredClone(security_token_id);
    729     }
    730   }
    731   return list;
    732 }
    733 
    734 
    735 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
    736                                                String* name,
    737                                                String* resource_name,
    738                                                int line_number) {
    739   CodeEntry* entry = new CodeEntry(tag,
    740                                    CodeEntry::kEmptyNamePrefix,
    741                                    GetFunctionName(name),
    742                                    GetName(resource_name),
    743                                    line_number,
    744                                    TokenEnumerator::kNoSecurityToken);
    745   code_entries_.Add(entry);
    746   return entry;
    747 }
    748 
    749 
    750 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
    751                                                const char* name) {
    752   CodeEntry* entry = new CodeEntry(tag,
    753                                    CodeEntry::kEmptyNamePrefix,
    754                                    GetFunctionName(name),
    755                                    "",
    756                                    v8::CpuProfileNode::kNoLineNumberInfo,
    757                                    TokenEnumerator::kNoSecurityToken);
    758   code_entries_.Add(entry);
    759   return entry;
    760 }
    761 
    762 
    763 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
    764                                                const char* name_prefix,
    765                                                String* name) {
    766   CodeEntry* entry = new CodeEntry(tag,
    767                                    name_prefix,
    768                                    GetName(name),
    769                                    "",
    770                                    v8::CpuProfileNode::kNoLineNumberInfo,
    771                                    TokenEnumerator::kInheritsSecurityToken);
    772   code_entries_.Add(entry);
    773   return entry;
    774 }
    775 
    776 
    777 CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
    778                                                int args_count) {
    779   CodeEntry* entry = new CodeEntry(tag,
    780                                    "args_count: ",
    781                                    GetName(args_count),
    782                                    "",
    783                                    v8::CpuProfileNode::kNoLineNumberInfo,
    784                                    TokenEnumerator::kInheritsSecurityToken);
    785   code_entries_.Add(entry);
    786   return entry;
    787 }
    788 
    789 
    790 void CpuProfilesCollection::AddPathToCurrentProfiles(
    791     const Vector<CodeEntry*>& path) {
    792   // As starting / stopping profiles is rare relatively to this
    793   // method, we don't bother minimizing the duration of lock holding,
    794   // e.g. copying contents of the list to a local vector.
    795   current_profiles_semaphore_->Wait();
    796   for (int i = 0; i < current_profiles_.length(); ++i) {
    797     current_profiles_[i]->AddPath(path);
    798   }
    799   current_profiles_semaphore_->Signal();
    800 }
    801 
    802 
    803 void SampleRateCalculator::Tick() {
    804   if (--wall_time_query_countdown_ == 0)
    805     UpdateMeasurements(OS::TimeCurrentMillis());
    806 }
    807 
    808 
    809 void SampleRateCalculator::UpdateMeasurements(double current_time) {
    810   if (measurements_count_++ != 0) {
    811     const double measured_ticks_per_ms =
    812         (kWallTimeQueryIntervalMs * ticks_per_ms_) /
    813         (current_time - last_wall_time_);
    814     // Update the average value.
    815     ticks_per_ms_ +=
    816         (measured_ticks_per_ms - ticks_per_ms_) / measurements_count_;
    817     // Update the externally accessible result.
    818     result_ = static_cast<AtomicWord>(ticks_per_ms_ * kResultScale);
    819   }
    820   last_wall_time_ = current_time;
    821   wall_time_query_countdown_ =
    822       static_cast<unsigned>(kWallTimeQueryIntervalMs * ticks_per_ms_);
    823 }
    824 
    825 
    826 const char* const ProfileGenerator::kAnonymousFunctionName =
    827     "(anonymous function)";
    828 const char* const ProfileGenerator::kProgramEntryName =
    829     "(program)";
    830 const char* const ProfileGenerator::kGarbageCollectorEntryName =
    831     "(garbage collector)";
    832 
    833 
    834 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
    835     : profiles_(profiles),
    836       program_entry_(
    837           profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)),
    838       gc_entry_(
    839           profiles->NewCodeEntry(Logger::BUILTIN_TAG,
    840                                  kGarbageCollectorEntryName)) {
    841 }
    842 
    843 
    844 void ProfileGenerator::RecordTickSample(const TickSample& sample) {
    845   // Allocate space for stack frames + pc + function + vm-state.
    846   ScopedVector<CodeEntry*> entries(sample.frames_count + 3);
    847   // As actual number of decoded code entries may vary, initialize
    848   // entries vector with NULL values.
    849   CodeEntry** entry = entries.start();
    850   memset(entry, 0, entries.length() * sizeof(*entry));
    851   if (sample.pc != NULL) {
    852     *entry++ = code_map_.FindEntry(sample.pc);
    853 
    854     if (sample.has_external_callback) {
    855       // Don't use PC when in external callback code, as it can point
    856       // inside callback's code, and we will erroneously report
    857       // that a callback calls itself.
    858       *(entries.start()) = NULL;
    859       *entry++ = code_map_.FindEntry(sample.external_callback);
    860     } else if (sample.tos != NULL) {
    861       // Find out, if top of stack was pointing inside a JS function
    862       // meaning that we have encountered a frameless invocation.
    863       *entry = code_map_.FindEntry(sample.tos);
    864       if (*entry != NULL && !(*entry)->is_js_function()) {
    865         *entry = NULL;
    866       }
    867       entry++;
    868     }
    869 
    870     for (const Address *stack_pos = sample.stack,
    871            *stack_end = stack_pos + sample.frames_count;
    872          stack_pos != stack_end;
    873          ++stack_pos) {
    874       *entry++ = code_map_.FindEntry(*stack_pos);
    875     }
    876   }
    877 
    878   if (FLAG_prof_browser_mode) {
    879     bool no_symbolized_entries = true;
    880     for (CodeEntry** e = entries.start(); e != entry; ++e) {
    881       if (*e != NULL) {
    882         no_symbolized_entries = false;
    883         break;
    884       }
    885     }
    886     // If no frames were symbolized, put the VM state entry in.
    887     if (no_symbolized_entries) {
    888       *entry++ = EntryForVMState(sample.state);
    889     }
    890   }
    891 
    892   profiles_->AddPathToCurrentProfiles(entries);
    893 }
    894 
    895 
    896 void HeapGraphEdge::Init(
    897     int child_index, Type type, const char* name, HeapEntry* to) {
    898   ASSERT(type == kContextVariable
    899          || type == kProperty
    900          || type == kInternal
    901          || type == kShortcut);
    902   child_index_ = child_index;
    903   type_ = type;
    904   name_ = name;
    905   to_ = to;
    906 }
    907 
    908 
    909 void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) {
    910   ASSERT(type == kElement || type == kHidden);
    911   child_index_ = child_index;
    912   type_ = type;
    913   index_ = index;
    914   to_ = to;
    915 }
    916 
    917 
    918 void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
    919   Init(child_index, kElement, index, to);
    920 }
    921 
    922 
    923 HeapEntry* HeapGraphEdge::From() {
    924   return reinterpret_cast<HeapEntry*>(this - child_index_) - 1;
    925 }
    926 
    927 
    928 void HeapEntry::Init(HeapSnapshot* snapshot,
    929                      Type type,
    930                      const char* name,
    931                      uint64_t id,
    932                      int self_size,
    933                      int children_count,
    934                      int retainers_count) {
    935   snapshot_ = snapshot;
    936   type_ = type;
    937   painted_ = kUnpainted;
    938   name_ = name;
    939   self_size_ = self_size;
    940   retained_size_ = 0;
    941   children_count_ = children_count;
    942   retainers_count_ = retainers_count;
    943   dominator_ = NULL;
    944 
    945   union {
    946     uint64_t set_id;
    947     Id stored_id;
    948   } id_adaptor = {id};
    949   id_ = id_adaptor.stored_id;
    950 }
    951 
    952 
    953 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
    954                                   int child_index,
    955                                   const char* name,
    956                                   HeapEntry* entry,
    957                                   int retainer_index) {
    958   children_arr()[child_index].Init(child_index, type, name, entry);
    959   entry->retainers_arr()[retainer_index] = children_arr() + child_index;
    960 }
    961 
    962 
    963 void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
    964                                     int child_index,
    965                                     int index,
    966                                     HeapEntry* entry,
    967                                     int retainer_index) {
    968   children_arr()[child_index].Init(child_index, type, index, entry);
    969   entry->retainers_arr()[retainer_index] = children_arr() + child_index;
    970 }
    971 
    972 
    973 void HeapEntry::SetUnidirElementReference(
    974     int child_index, int index, HeapEntry* entry) {
    975   children_arr()[child_index].Init(child_index, index, entry);
    976 }
    977 
    978 
    979 int HeapEntry::RetainedSize(bool exact) {
    980   if (exact && (retained_size_ & kExactRetainedSizeTag) == 0) {
    981     CalculateExactRetainedSize();
    982   }
    983   return retained_size_ & (~kExactRetainedSizeTag);
    984 }
    985 
    986 
    987 template<class Visitor>
    988 void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) {
    989   List<HeapEntry*> list(10);
    990   list.Add(this);
    991   this->paint_reachable();
    992   visitor->Apply(this);
    993   while (!list.is_empty()) {
    994     HeapEntry* entry = list.RemoveLast();
    995     Vector<HeapGraphEdge> children = entry->children();
    996     for (int i = 0; i < children.length(); ++i) {
    997       if (children[i].type() == HeapGraphEdge::kShortcut) continue;
    998       HeapEntry* child = children[i].to();
    999       if (!child->painted_reachable()) {
   1000         list.Add(child);
   1001         child->paint_reachable();
   1002         visitor->Apply(child);
   1003       }
   1004     }
   1005   }
   1006 }
   1007 
   1008 
   1009 class NullClass {
   1010  public:
   1011   void Apply(HeapEntry* entry) { }
   1012 };
   1013 
   1014 void HeapEntry::PaintAllReachable() {
   1015   NullClass null;
   1016   ApplyAndPaintAllReachable(&null);
   1017 }
   1018 
   1019 
   1020 void HeapEntry::Print(int max_depth, int indent) {
   1021   OS::Print("%6d %6d [%llu] ", self_size(), RetainedSize(false), id());
   1022   if (type() != kString) {
   1023     OS::Print("%s %.40s\n", TypeAsString(), name_);
   1024   } else {
   1025     OS::Print("\"");
   1026     const char* c = name_;
   1027     while (*c && (c - name_) <= 40) {
   1028       if (*c != '\n')
   1029         OS::Print("%c", *c);
   1030       else
   1031         OS::Print("\\n");
   1032       ++c;
   1033     }
   1034     OS::Print("\"\n");
   1035   }
   1036   if (--max_depth == 0) return;
   1037   Vector<HeapGraphEdge> ch = children();
   1038   for (int i = 0; i < ch.length(); ++i) {
   1039     HeapGraphEdge& edge = ch[i];
   1040     switch (edge.type()) {
   1041       case HeapGraphEdge::kContextVariable:
   1042         OS::Print("  %*c #%s: ", indent, ' ', edge.name());
   1043         break;
   1044       case HeapGraphEdge::kElement:
   1045         OS::Print("  %*c %d: ", indent, ' ', edge.index());
   1046         break;
   1047       case HeapGraphEdge::kInternal:
   1048         OS::Print("  %*c $%s: ", indent, ' ', edge.name());
   1049         break;
   1050       case HeapGraphEdge::kProperty:
   1051         OS::Print("  %*c %s: ", indent, ' ', edge.name());
   1052         break;
   1053       case HeapGraphEdge::kHidden:
   1054         OS::Print("  %*c $%d: ", indent, ' ', edge.index());
   1055         break;
   1056       case HeapGraphEdge::kShortcut:
   1057         OS::Print("  %*c ^%s: ", indent, ' ', edge.name());
   1058         break;
   1059       default:
   1060         OS::Print("!!! unknown edge type: %d ", edge.type());
   1061     }
   1062     edge.to()->Print(max_depth, indent + 2);
   1063   }
   1064 }
   1065 
   1066 
   1067 const char* HeapEntry::TypeAsString() {
   1068   switch (type()) {
   1069     case kHidden: return "/hidden/";
   1070     case kObject: return "/object/";
   1071     case kClosure: return "/closure/";
   1072     case kString: return "/string/";
   1073     case kCode: return "/code/";
   1074     case kArray: return "/array/";
   1075     case kRegExp: return "/regexp/";
   1076     case kHeapNumber: return "/number/";
   1077     case kNative: return "/native/";
   1078     default: return "???";
   1079   }
   1080 }
   1081 
   1082 
   1083 int HeapEntry::EntriesSize(int entries_count,
   1084                            int children_count,
   1085                            int retainers_count) {
   1086   return sizeof(HeapEntry) * entries_count         // NOLINT
   1087       + sizeof(HeapGraphEdge) * children_count     // NOLINT
   1088       + sizeof(HeapGraphEdge*) * retainers_count;  // NOLINT
   1089 }
   1090 
   1091 
   1092 class RetainedSizeCalculator {
   1093  public:
   1094   RetainedSizeCalculator()
   1095       : retained_size_(0) {
   1096   }
   1097 
   1098   int reained_size() const { return retained_size_; }
   1099 
   1100   void Apply(HeapEntry** entry_ptr) {
   1101     if ((*entry_ptr)->painted_reachable()) {
   1102       retained_size_ += (*entry_ptr)->self_size();
   1103     }
   1104   }
   1105 
   1106  private:
   1107   int retained_size_;
   1108 };
   1109 
   1110 void HeapEntry::CalculateExactRetainedSize() {
   1111   // To calculate retained size, first we paint all reachable nodes in
   1112   // one color, then we paint (or re-paint) all nodes reachable from
   1113   // other nodes with a different color. Then we sum up self sizes of
   1114   // nodes painted with the first color.
   1115   snapshot()->ClearPaint();
   1116   PaintAllReachable();
   1117 
   1118   List<HeapEntry*> list(10);
   1119   HeapEntry* root = snapshot()->root();
   1120   if (this != root) {
   1121     list.Add(root);
   1122     root->paint_reachable_from_others();
   1123   }
   1124   while (!list.is_empty()) {
   1125     HeapEntry* curr = list.RemoveLast();
   1126     Vector<HeapGraphEdge> children = curr->children();
   1127     for (int i = 0; i < children.length(); ++i) {
   1128       if (children[i].type() == HeapGraphEdge::kShortcut) continue;
   1129       HeapEntry* child = children[i].to();
   1130       if (child != this && child->not_painted_reachable_from_others()) {
   1131         list.Add(child);
   1132         child->paint_reachable_from_others();
   1133       }
   1134     }
   1135   }
   1136 
   1137   RetainedSizeCalculator ret_size_calc;
   1138   snapshot()->IterateEntries(&ret_size_calc);
   1139   retained_size_ = ret_size_calc.reained_size();
   1140   ASSERT((retained_size_ & kExactRetainedSizeTag) == 0);
   1141   retained_size_ |= kExactRetainedSizeTag;
   1142 }
   1143 
   1144 
   1145 // It is very important to keep objects that form a heap snapshot
   1146 // as small as possible.
   1147 namespace {  // Avoid littering the global namespace.
   1148 
   1149 template <size_t ptr_size> struct SnapshotSizeConstants;
   1150 
   1151 template <> struct SnapshotSizeConstants<4> {
   1152   static const int kExpectedHeapGraphEdgeSize = 12;
   1153   static const int kExpectedHeapEntrySize = 36;
   1154 };
   1155 
   1156 template <> struct SnapshotSizeConstants<8> {
   1157   static const int kExpectedHeapGraphEdgeSize = 24;
   1158   static const int kExpectedHeapEntrySize = 48;
   1159 };
   1160 
   1161 }  // namespace
   1162 
   1163 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
   1164                            HeapSnapshot::Type type,
   1165                            const char* title,
   1166                            unsigned uid)
   1167     : collection_(collection),
   1168       type_(type),
   1169       title_(title),
   1170       uid_(uid),
   1171       root_entry_(NULL),
   1172       gc_roots_entry_(NULL),
   1173       natives_root_entry_(NULL),
   1174       raw_entries_(NULL),
   1175       entries_sorted_(false) {
   1176   STATIC_ASSERT(
   1177       sizeof(HeapGraphEdge) ==
   1178       SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize);  // NOLINT
   1179   STATIC_ASSERT(
   1180       sizeof(HeapEntry) ==
   1181       SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize);  // NOLINT
   1182 }
   1183 
   1184 HeapSnapshot::~HeapSnapshot() {
   1185   DeleteArray(raw_entries_);
   1186 }
   1187 
   1188 
   1189 void HeapSnapshot::Delete() {
   1190   collection_->RemoveSnapshot(this);
   1191   delete this;
   1192 }
   1193 
   1194 
   1195 void HeapSnapshot::AllocateEntries(int entries_count,
   1196                                    int children_count,
   1197                                    int retainers_count) {
   1198   ASSERT(raw_entries_ == NULL);
   1199   raw_entries_ = NewArray<char>(
   1200       HeapEntry::EntriesSize(entries_count, children_count, retainers_count));
   1201 #ifdef DEBUG
   1202   raw_entries_size_ =
   1203       HeapEntry::EntriesSize(entries_count, children_count, retainers_count);
   1204 #endif
   1205 }
   1206 
   1207 
   1208 static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
   1209   (*entry_ptr)->clear_paint();
   1210 }
   1211 
   1212 void HeapSnapshot::ClearPaint() {
   1213   entries_.Iterate(HeapEntryClearPaint);
   1214 }
   1215 
   1216 
   1217 HeapEntry* HeapSnapshot::AddRootEntry(int children_count) {
   1218   ASSERT(root_entry_ == NULL);
   1219   return (root_entry_ = AddEntry(HeapEntry::kObject,
   1220                                  "",
   1221                                  HeapObjectsMap::kInternalRootObjectId,
   1222                                  0,
   1223                                  children_count,
   1224                                  0));
   1225 }
   1226 
   1227 
   1228 HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count,
   1229                                          int retainers_count) {
   1230   ASSERT(gc_roots_entry_ == NULL);
   1231   return (gc_roots_entry_ = AddEntry(HeapEntry::kObject,
   1232                                      "(GC roots)",
   1233                                      HeapObjectsMap::kGcRootsObjectId,
   1234                                      0,
   1235                                      children_count,
   1236                                      retainers_count));
   1237 }
   1238 
   1239 
   1240 HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count,
   1241                                                  int retainers_count) {
   1242   ASSERT(natives_root_entry_ == NULL);
   1243   return (natives_root_entry_ = AddEntry(
   1244       HeapEntry::kObject,
   1245       "(Native objects)",
   1246       HeapObjectsMap::kNativesRootObjectId,
   1247       0,
   1248       children_count,
   1249       retainers_count));
   1250 }
   1251 
   1252 
   1253 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
   1254                                   const char* name,
   1255                                   uint64_t id,
   1256                                   int size,
   1257                                   int children_count,
   1258                                   int retainers_count) {
   1259   HeapEntry* entry = GetNextEntryToInit();
   1260   entry->Init(this, type, name, id, size, children_count, retainers_count);
   1261   return entry;
   1262 }
   1263 
   1264 
   1265 void HeapSnapshot::SetDominatorsToSelf() {
   1266   for (int i = 0; i < entries_.length(); ++i) {
   1267     HeapEntry* entry = entries_[i];
   1268     if (entry->dominator() == NULL) entry->set_dominator(entry);
   1269   }
   1270 }
   1271 
   1272 
   1273 HeapEntry* HeapSnapshot::GetNextEntryToInit() {
   1274   if (entries_.length() > 0) {
   1275     HeapEntry* last_entry = entries_.last();
   1276     entries_.Add(reinterpret_cast<HeapEntry*>(
   1277         reinterpret_cast<char*>(last_entry) + last_entry->EntrySize()));
   1278   } else {
   1279     entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_));
   1280   }
   1281   ASSERT(reinterpret_cast<char*>(entries_.last()) <
   1282          (raw_entries_ + raw_entries_size_));
   1283   return entries_.last();
   1284 }
   1285 
   1286 
   1287 HeapEntry* HeapSnapshot::GetEntryById(uint64_t id) {
   1288   List<HeapEntry*>* entries_by_id = GetSortedEntriesList();
   1289 
   1290   // Perform a binary search by id.
   1291   int low = 0;
   1292   int high = entries_by_id->length() - 1;
   1293   while (low <= high) {
   1294     int mid =
   1295         (static_cast<unsigned int>(low) + static_cast<unsigned int>(high)) >> 1;
   1296     uint64_t mid_id = entries_by_id->at(mid)->id();
   1297     if (mid_id > id)
   1298       high = mid - 1;
   1299     else if (mid_id < id)
   1300       low = mid + 1;
   1301     else
   1302       return entries_by_id->at(mid);
   1303   }
   1304   return NULL;
   1305 }
   1306 
   1307 
   1308 template<class T>
   1309 static int SortByIds(const T* entry1_ptr,
   1310                      const T* entry2_ptr) {
   1311   if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0;
   1312   return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1;
   1313 }
   1314 
   1315 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
   1316   if (!entries_sorted_) {
   1317     entries_.Sort(SortByIds);
   1318     entries_sorted_ = true;
   1319   }
   1320   return &entries_;
   1321 }
   1322 
   1323 
   1324 void HeapSnapshot::Print(int max_depth) {
   1325   root()->Print(max_depth, 0);
   1326 }
   1327 
   1328 
   1329 // We split IDs on evens for embedder objects (see
   1330 // HeapObjectsMap::GenerateId) and odds for native objects.
   1331 const uint64_t HeapObjectsMap::kInternalRootObjectId = 1;
   1332 const uint64_t HeapObjectsMap::kGcRootsObjectId = 3;
   1333 const uint64_t HeapObjectsMap::kNativesRootObjectId = 5;
   1334 // Increase kFirstAvailableObjectId if new 'special' objects appear.
   1335 const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7;
   1336 
   1337 HeapObjectsMap::HeapObjectsMap()
   1338     : initial_fill_mode_(true),
   1339       next_id_(kFirstAvailableObjectId),
   1340       entries_map_(AddressesMatch),
   1341       entries_(new List<EntryInfo>()) { }
   1342 
   1343 
   1344 HeapObjectsMap::~HeapObjectsMap() {
   1345   delete entries_;
   1346 }
   1347 
   1348 
   1349 void HeapObjectsMap::SnapshotGenerationFinished() {
   1350     initial_fill_mode_ = false;
   1351     RemoveDeadEntries();
   1352 }
   1353 
   1354 
   1355 uint64_t HeapObjectsMap::FindObject(Address addr) {
   1356   if (!initial_fill_mode_) {
   1357     uint64_t existing = FindEntry(addr);
   1358     if (existing != 0) return existing;
   1359   }
   1360   uint64_t id = next_id_;
   1361   next_id_ += 2;
   1362   AddEntry(addr, id);
   1363   return id;
   1364 }
   1365 
   1366 
   1367 void HeapObjectsMap::MoveObject(Address from, Address to) {
   1368   if (from == to) return;
   1369   HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false);
   1370   if (entry != NULL) {
   1371     void* value = entry->value;
   1372     entries_map_.Remove(from, AddressHash(from));
   1373     entry = entries_map_.Lookup(to, AddressHash(to), true);
   1374     // We can have an entry at the new location, it is OK, as GC can overwrite
   1375     // dead objects with alive objects being moved.
   1376     entry->value = value;
   1377   }
   1378 }
   1379 
   1380 
   1381 void HeapObjectsMap::AddEntry(Address addr, uint64_t id) {
   1382   HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true);
   1383   ASSERT(entry->value == NULL);
   1384   entry->value = reinterpret_cast<void*>(entries_->length());
   1385   entries_->Add(EntryInfo(id));
   1386 }
   1387 
   1388 
   1389 uint64_t HeapObjectsMap::FindEntry(Address addr) {
   1390   HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false);
   1391   if (entry != NULL) {
   1392     int entry_index =
   1393         static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
   1394     EntryInfo& entry_info = entries_->at(entry_index);
   1395     entry_info.accessed = true;
   1396     return entry_info.id;
   1397   } else {
   1398     return 0;
   1399   }
   1400 }
   1401 
   1402 
   1403 void HeapObjectsMap::RemoveDeadEntries() {
   1404   List<EntryInfo>* new_entries = new List<EntryInfo>();
   1405   List<void*> dead_entries;
   1406   for (HashMap::Entry* entry = entries_map_.Start();
   1407        entry != NULL;
   1408        entry = entries_map_.Next(entry)) {
   1409     int entry_index =
   1410         static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
   1411     EntryInfo& entry_info = entries_->at(entry_index);
   1412     if (entry_info.accessed) {
   1413       entry->value = reinterpret_cast<void*>(new_entries->length());
   1414       new_entries->Add(EntryInfo(entry_info.id, false));
   1415     } else {
   1416       dead_entries.Add(entry->key);
   1417     }
   1418   }
   1419   for (int i = 0; i < dead_entries.length(); ++i) {
   1420     void* raw_entry = dead_entries[i];
   1421     entries_map_.Remove(
   1422         raw_entry, AddressHash(reinterpret_cast<Address>(raw_entry)));
   1423   }
   1424   delete entries_;
   1425   entries_ = new_entries;
   1426 }
   1427 
   1428 
   1429 uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
   1430   uint64_t id = static_cast<uint64_t>(info->GetHash());
   1431   const char* label = info->GetLabel();
   1432   id ^= HashSequentialString(label, static_cast<int>(strlen(label)));
   1433   intptr_t element_count = info->GetElementCount();
   1434   if (element_count != -1)
   1435     id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count));
   1436   return id << 1;
   1437 }
   1438 
   1439 
   1440 HeapSnapshotsCollection::HeapSnapshotsCollection()
   1441     : is_tracking_objects_(false),
   1442       snapshots_uids_(HeapSnapshotsMatch),
   1443       token_enumerator_(new TokenEnumerator()) {
   1444 }
   1445 
   1446 
   1447 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) {
   1448   delete *snapshot_ptr;
   1449 }
   1450 
   1451 
   1452 HeapSnapshotsCollection::~HeapSnapshotsCollection() {
   1453   delete token_enumerator_;
   1454   snapshots_.Iterate(DeleteHeapSnapshot);
   1455 }
   1456 
   1457 
   1458 HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(HeapSnapshot::Type type,
   1459                                                    const char* name,
   1460                                                    unsigned uid) {
   1461   is_tracking_objects_ = true;  // Start watching for heap objects moves.
   1462   return new HeapSnapshot(this, type, name, uid);
   1463 }
   1464 
   1465 
   1466 void HeapSnapshotsCollection::SnapshotGenerationFinished(
   1467     HeapSnapshot* snapshot) {
   1468   ids_.SnapshotGenerationFinished();
   1469   if (snapshot != NULL) {
   1470     snapshots_.Add(snapshot);
   1471     HashMap::Entry* entry =
   1472         snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()),
   1473                                static_cast<uint32_t>(snapshot->uid()),
   1474                                true);
   1475     ASSERT(entry->value == NULL);
   1476     entry->value = snapshot;
   1477   }
   1478 }
   1479 
   1480 
   1481 HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) {
   1482   HashMap::Entry* entry = snapshots_uids_.Lookup(reinterpret_cast<void*>(uid),
   1483                                                  static_cast<uint32_t>(uid),
   1484                                                  false);
   1485   return entry != NULL ? reinterpret_cast<HeapSnapshot*>(entry->value) : NULL;
   1486 }
   1487 
   1488 
   1489 void HeapSnapshotsCollection::RemoveSnapshot(HeapSnapshot* snapshot) {
   1490   snapshots_.RemoveElement(snapshot);
   1491   unsigned uid = snapshot->uid();
   1492   snapshots_uids_.Remove(reinterpret_cast<void*>(uid),
   1493                          static_cast<uint32_t>(uid));
   1494 }
   1495 
   1496 
   1497 HeapEntry *const HeapEntriesMap::kHeapEntryPlaceholder =
   1498     reinterpret_cast<HeapEntry*>(1);
   1499 
   1500 HeapEntriesMap::HeapEntriesMap()
   1501     : entries_(HeapThingsMatch),
   1502       entries_count_(0),
   1503       total_children_count_(0),
   1504       total_retainers_count_(0) {
   1505 }
   1506 
   1507 
   1508 HeapEntriesMap::~HeapEntriesMap() {
   1509   for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) {
   1510     delete reinterpret_cast<EntryInfo*>(p->value);
   1511   }
   1512 }
   1513 
   1514 
   1515 void HeapEntriesMap::AllocateEntries() {
   1516   for (HashMap::Entry* p = entries_.Start();
   1517        p != NULL;
   1518        p = entries_.Next(p)) {
   1519     EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
   1520     entry_info->entry = entry_info->allocator->AllocateEntry(
   1521         p->key,
   1522         entry_info->children_count,
   1523         entry_info->retainers_count);
   1524     ASSERT(entry_info->entry != NULL);
   1525     ASSERT(entry_info->entry != kHeapEntryPlaceholder);
   1526     entry_info->children_count = 0;
   1527     entry_info->retainers_count = 0;
   1528   }
   1529 }
   1530 
   1531 
   1532 HeapEntry* HeapEntriesMap::Map(HeapThing thing) {
   1533   HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false);
   1534   if (cache_entry != NULL) {
   1535     EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value);
   1536     return entry_info->entry;
   1537   } else {
   1538     return NULL;
   1539   }
   1540 }
   1541 
   1542 
   1543 void HeapEntriesMap::Pair(
   1544     HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) {
   1545   HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true);
   1546   ASSERT(cache_entry->value == NULL);
   1547   cache_entry->value = new EntryInfo(entry, allocator);
   1548   ++entries_count_;
   1549 }
   1550 
   1551 
   1552 void HeapEntriesMap::CountReference(HeapThing from, HeapThing to,
   1553                                     int* prev_children_count,
   1554                                     int* prev_retainers_count) {
   1555   HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false);
   1556   HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
   1557   ASSERT(from_cache_entry != NULL);
   1558   ASSERT(to_cache_entry != NULL);
   1559   EntryInfo* from_entry_info =
   1560       reinterpret_cast<EntryInfo*>(from_cache_entry->value);
   1561   EntryInfo* to_entry_info =
   1562       reinterpret_cast<EntryInfo*>(to_cache_entry->value);
   1563   if (prev_children_count)
   1564     *prev_children_count = from_entry_info->children_count;
   1565   if (prev_retainers_count)
   1566     *prev_retainers_count = to_entry_info->retainers_count;
   1567   ++from_entry_info->children_count;
   1568   ++to_entry_info->retainers_count;
   1569   ++total_children_count_;
   1570   ++total_retainers_count_;
   1571 }
   1572 
   1573 
   1574 HeapObjectsSet::HeapObjectsSet()
   1575     : entries_(HeapEntriesMap::HeapThingsMatch) {
   1576 }
   1577 
   1578 
   1579 void HeapObjectsSet::Clear() {
   1580   entries_.Clear();
   1581 }
   1582 
   1583 
   1584 bool HeapObjectsSet::Contains(Object* obj) {
   1585   if (!obj->IsHeapObject()) return false;
   1586   HeapObject* object = HeapObject::cast(obj);
   1587   HashMap::Entry* cache_entry =
   1588       entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
   1589   return cache_entry != NULL;
   1590 }
   1591 
   1592 
   1593 void HeapObjectsSet::Insert(Object* obj) {
   1594   if (!obj->IsHeapObject()) return;
   1595   HeapObject* object = HeapObject::cast(obj);
   1596   HashMap::Entry* cache_entry =
   1597       entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
   1598   if (cache_entry->value == NULL) {
   1599     cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder;
   1600   }
   1601 }
   1602 
   1603 
   1604 HeapObject *const V8HeapExplorer::kInternalRootObject =
   1605     reinterpret_cast<HeapObject*>(
   1606         static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId));
   1607 HeapObject *const V8HeapExplorer::kGcRootsObject =
   1608     reinterpret_cast<HeapObject*>(
   1609         static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId));
   1610 
   1611 
   1612 V8HeapExplorer::V8HeapExplorer(
   1613     HeapSnapshot* snapshot,
   1614     SnapshottingProgressReportingInterface* progress)
   1615     : snapshot_(snapshot),
   1616       collection_(snapshot_->collection()),
   1617       progress_(progress),
   1618       filler_(NULL) {
   1619 }
   1620 
   1621 
   1622 V8HeapExplorer::~V8HeapExplorer() {
   1623 }
   1624 
   1625 
   1626 HeapEntry* V8HeapExplorer::AllocateEntry(
   1627     HeapThing ptr, int children_count, int retainers_count) {
   1628   return AddEntry(
   1629       reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count);
   1630 }
   1631 
   1632 
   1633 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
   1634                                     int children_count,
   1635                                     int retainers_count) {
   1636   if (object == kInternalRootObject) {
   1637     ASSERT(retainers_count == 0);
   1638     return snapshot_->AddRootEntry(children_count);
   1639   } else if (object == kGcRootsObject) {
   1640     return snapshot_->AddGcRootsEntry(children_count, retainers_count);
   1641   } else if (object->IsJSFunction()) {
   1642     JSFunction* func = JSFunction::cast(object);
   1643     SharedFunctionInfo* shared = func->shared();
   1644     return AddEntry(object,
   1645                     HeapEntry::kClosure,
   1646                     collection_->names()->GetName(String::cast(shared->name())),
   1647                     children_count,
   1648                     retainers_count);
   1649   } else if (object->IsJSRegExp()) {
   1650     JSRegExp* re = JSRegExp::cast(object);
   1651     return AddEntry(object,
   1652                     HeapEntry::kRegExp,
   1653                     collection_->names()->GetName(re->Pattern()),
   1654                     children_count,
   1655                     retainers_count);
   1656   } else if (object->IsJSObject()) {
   1657     return AddEntry(object,
   1658                     HeapEntry::kObject,
   1659                     collection_->names()->GetName(
   1660                         GetConstructorNameForHeapProfile(
   1661                             JSObject::cast(object))),
   1662                     children_count,
   1663                     retainers_count);
   1664   } else if (object->IsString()) {
   1665     return AddEntry(object,
   1666                     HeapEntry::kString,
   1667                     collection_->names()->GetName(String::cast(object)),
   1668                     children_count,
   1669                     retainers_count);
   1670   } else if (object->IsCode()) {
   1671     return AddEntry(object,
   1672                     HeapEntry::kCode,
   1673                     "",
   1674                     children_count,
   1675                     retainers_count);
   1676   } else if (object->IsSharedFunctionInfo()) {
   1677     SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
   1678     return AddEntry(object,
   1679                     HeapEntry::kCode,
   1680                     collection_->names()->GetName(String::cast(shared->name())),
   1681                     children_count,
   1682                     retainers_count);
   1683   } else if (object->IsScript()) {
   1684     Script* script = Script::cast(object);
   1685     return AddEntry(object,
   1686                     HeapEntry::kCode,
   1687                     script->name()->IsString() ?
   1688                         collection_->names()->GetName(
   1689                             String::cast(script->name()))
   1690                         : "",
   1691                     children_count,
   1692                     retainers_count);
   1693   } else if (object->IsFixedArray() || object->IsByteArray()) {
   1694     return AddEntry(object,
   1695                     HeapEntry::kArray,
   1696                     "",
   1697                     children_count,
   1698                     retainers_count);
   1699   } else if (object->IsHeapNumber()) {
   1700     return AddEntry(object,
   1701                     HeapEntry::kHeapNumber,
   1702                     "number",
   1703                     children_count,
   1704                     retainers_count);
   1705   }
   1706   return AddEntry(object,
   1707                   HeapEntry::kHidden,
   1708                   GetSystemEntryName(object),
   1709                   children_count,
   1710                   retainers_count);
   1711 }
   1712 
   1713 
   1714 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
   1715                                     HeapEntry::Type type,
   1716                                     const char* name,
   1717                                     int children_count,
   1718                                     int retainers_count) {
   1719   return snapshot_->AddEntry(type,
   1720                              name,
   1721                              collection_->GetObjectId(object->address()),
   1722                              object->Size(),
   1723                              children_count,
   1724                              retainers_count);
   1725 }
   1726 
   1727 
   1728 void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
   1729   filler->AddEntry(kInternalRootObject, this);
   1730   filler->AddEntry(kGcRootsObject, this);
   1731 }
   1732 
   1733 
   1734 const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) {
   1735   switch (object->map()->instance_type()) {
   1736     case MAP_TYPE: return "system / Map";
   1737     case JS_GLOBAL_PROPERTY_CELL_TYPE: return "system / JSGlobalPropertyCell";
   1738     case PROXY_TYPE: return "system / Proxy";
   1739     case ODDBALL_TYPE: return "system / Oddball";
   1740 #define MAKE_STRUCT_CASE(NAME, Name, name) \
   1741     case NAME##_TYPE: return "system / "#Name;
   1742   STRUCT_LIST(MAKE_STRUCT_CASE)
   1743 #undef MAKE_STRUCT_CASE
   1744     default: return "system";
   1745   }
   1746 }
   1747 
   1748 
   1749 int V8HeapExplorer::EstimateObjectsCount() {
   1750   HeapIterator iterator(HeapIterator::kFilterUnreachable);
   1751   int objects_count = 0;
   1752   for (HeapObject* obj = iterator.next();
   1753        obj != NULL;
   1754        obj = iterator.next(), ++objects_count) {}
   1755   return objects_count;
   1756 }
   1757 
   1758 
   1759 class IndexedReferencesExtractor : public ObjectVisitor {
   1760  public:
   1761   IndexedReferencesExtractor(V8HeapExplorer* generator,
   1762                              HeapObject* parent_obj,
   1763                              HeapEntry* parent_entry)
   1764       : generator_(generator),
   1765         parent_obj_(parent_obj),
   1766         parent_(parent_entry),
   1767         next_index_(1) {
   1768   }
   1769   void VisitPointers(Object** start, Object** end) {
   1770     for (Object** p = start; p < end; p++) {
   1771       if (CheckVisitedAndUnmark(p)) continue;
   1772       generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
   1773     }
   1774   }
   1775   static void MarkVisitedField(HeapObject* obj, int offset) {
   1776     if (offset < 0) return;
   1777     Address field = obj->address() + offset;
   1778     ASSERT(!Memory::Object_at(field)->IsFailure());
   1779     ASSERT(Memory::Object_at(field)->IsHeapObject());
   1780     *field |= kFailureTag;
   1781   }
   1782  private:
   1783   bool CheckVisitedAndUnmark(Object** field) {
   1784     if ((*field)->IsFailure()) {
   1785       intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
   1786       *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
   1787       ASSERT((*field)->IsHeapObject());
   1788       return true;
   1789     }
   1790     return false;
   1791   }
   1792   V8HeapExplorer* generator_;
   1793   HeapObject* parent_obj_;
   1794   HeapEntry* parent_;
   1795   int next_index_;
   1796 };
   1797 
   1798 
   1799 void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
   1800   HeapEntry* entry = GetEntry(obj);
   1801   if (entry == NULL) return;  // No interest in this object.
   1802 
   1803   if (obj->IsJSGlobalProxy()) {
   1804     // We need to reference JS global objects from snapshot's root.
   1805     // We use JSGlobalProxy because this is what embedder (e.g. browser)
   1806     // uses for the global object.
   1807     JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
   1808     SetRootShortcutReference(proxy->map()->prototype());
   1809     SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
   1810     IndexedReferencesExtractor refs_extractor(this, obj, entry);
   1811     obj->Iterate(&refs_extractor);
   1812   } else if (obj->IsJSObject()) {
   1813     JSObject* js_obj = JSObject::cast(obj);
   1814     ExtractClosureReferences(js_obj, entry);
   1815     ExtractPropertyReferences(js_obj, entry);
   1816     ExtractElementReferences(js_obj, entry);
   1817     ExtractInternalReferences(js_obj, entry);
   1818     SetPropertyReference(
   1819         obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype());
   1820     if (obj->IsJSFunction()) {
   1821       JSFunction* js_fun = JSFunction::cast(js_obj);
   1822       Object* proto_or_map = js_fun->prototype_or_initial_map();
   1823       if (!proto_or_map->IsTheHole()) {
   1824         if (!proto_or_map->IsMap()) {
   1825           SetPropertyReference(
   1826               obj, entry,
   1827               HEAP->prototype_symbol(), proto_or_map,
   1828               JSFunction::kPrototypeOrInitialMapOffset);
   1829         } else {
   1830           SetPropertyReference(
   1831               obj, entry,
   1832               HEAP->prototype_symbol(), js_fun->prototype());
   1833         }
   1834       }
   1835       SetInternalReference(js_fun, entry,
   1836                            "shared", js_fun->shared(),
   1837                            JSFunction::kSharedFunctionInfoOffset);
   1838       SetInternalReference(js_fun, entry,
   1839                            "context", js_fun->unchecked_context(),
   1840                            JSFunction::kContextOffset);
   1841       SetInternalReference(js_fun, entry,
   1842                            "literals", js_fun->literals(),
   1843                            JSFunction::kLiteralsOffset);
   1844     }
   1845     SetInternalReference(obj, entry,
   1846                          "properties", js_obj->properties(),
   1847                          JSObject::kPropertiesOffset);
   1848     SetInternalReference(obj, entry,
   1849                          "elements", js_obj->elements(),
   1850                          JSObject::kElementsOffset);
   1851     SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
   1852     IndexedReferencesExtractor refs_extractor(this, obj, entry);
   1853     obj->Iterate(&refs_extractor);
   1854   } else if (obj->IsString()) {
   1855     if (obj->IsConsString()) {
   1856       ConsString* cs = ConsString::cast(obj);
   1857       SetInternalReference(obj, entry, 1, cs->first());
   1858       SetInternalReference(obj, entry, 2, cs->second());
   1859     }
   1860   } else if (obj->IsMap()) {
   1861     Map* map = Map::cast(obj);
   1862     SetInternalReference(obj, entry,
   1863                          "prototype", map->prototype(), Map::kPrototypeOffset);
   1864     SetInternalReference(obj, entry,
   1865                          "constructor", map->constructor(),
   1866                          Map::kConstructorOffset);
   1867     SetInternalReference(obj, entry,
   1868                          "descriptors", map->instance_descriptors(),
   1869                          Map::kInstanceDescriptorsOffset);
   1870     SetInternalReference(obj, entry,
   1871                          "code_cache", map->code_cache(),
   1872                          Map::kCodeCacheOffset);
   1873     SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
   1874     IndexedReferencesExtractor refs_extractor(this, obj, entry);
   1875     obj->Iterate(&refs_extractor);
   1876   } else if (obj->IsSharedFunctionInfo()) {
   1877     SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
   1878     SetInternalReference(obj, entry,
   1879                          "name", shared->name(),
   1880                          SharedFunctionInfo::kNameOffset);
   1881     SetInternalReference(obj, entry,
   1882                          "code", shared->unchecked_code(),
   1883                          SharedFunctionInfo::kCodeOffset);
   1884     SetInternalReference(obj, entry,
   1885                          "instance_class_name", shared->instance_class_name(),
   1886                          SharedFunctionInfo::kInstanceClassNameOffset);
   1887     SetInternalReference(obj, entry,
   1888                          "script", shared->script(),
   1889                          SharedFunctionInfo::kScriptOffset);
   1890     SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
   1891     IndexedReferencesExtractor refs_extractor(this, obj, entry);
   1892     obj->Iterate(&refs_extractor);
   1893   } else {
   1894     SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
   1895     IndexedReferencesExtractor refs_extractor(this, obj, entry);
   1896     obj->Iterate(&refs_extractor);
   1897   }
   1898 }
   1899 
   1900 
   1901 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
   1902                                               HeapEntry* entry) {
   1903   if (js_obj->IsJSFunction()) {
   1904     HandleScope hs;
   1905     JSFunction* func = JSFunction::cast(js_obj);
   1906     Context* context = func->context();
   1907     ZoneScope zscope(DELETE_ON_EXIT);
   1908     SerializedScopeInfo* serialized_scope_info =
   1909         context->closure()->shared()->scope_info();
   1910     ScopeInfo<ZoneListAllocationPolicy> zone_scope_info(serialized_scope_info);
   1911     int locals_number = zone_scope_info.NumberOfLocals();
   1912     for (int i = 0; i < locals_number; ++i) {
   1913       String* local_name = *zone_scope_info.LocalName(i);
   1914       int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL);
   1915       if (idx >= 0 && idx < context->length()) {
   1916         SetClosureReference(js_obj, entry, local_name, context->get(idx));
   1917       }
   1918     }
   1919   }
   1920 }
   1921 
   1922 
   1923 void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
   1924                                                HeapEntry* entry) {
   1925   if (js_obj->HasFastProperties()) {
   1926     DescriptorArray* descs = js_obj->map()->instance_descriptors();
   1927     for (int i = 0; i < descs->number_of_descriptors(); i++) {
   1928       switch (descs->GetType(i)) {
   1929         case FIELD: {
   1930           int index = descs->GetFieldIndex(i);
   1931           if (index < js_obj->map()->inobject_properties()) {
   1932             SetPropertyReference(
   1933                 js_obj, entry,
   1934                 descs->GetKey(i), js_obj->InObjectPropertyAt(index),
   1935                 js_obj->GetInObjectPropertyOffset(index));
   1936           } else {
   1937             SetPropertyReference(
   1938                 js_obj, entry,
   1939                 descs->GetKey(i), js_obj->FastPropertyAt(index));
   1940           }
   1941           break;
   1942         }
   1943         case CONSTANT_FUNCTION:
   1944           SetPropertyReference(
   1945               js_obj, entry,
   1946               descs->GetKey(i), descs->GetConstantFunction(i));
   1947           break;
   1948         default: ;
   1949       }
   1950     }
   1951   } else {
   1952     StringDictionary* dictionary = js_obj->property_dictionary();
   1953     int length = dictionary->Capacity();
   1954     for (int i = 0; i < length; ++i) {
   1955       Object* k = dictionary->KeyAt(i);
   1956       if (dictionary->IsKey(k)) {
   1957         Object* target = dictionary->ValueAt(i);
   1958         SetPropertyReference(
   1959             js_obj, entry, String::cast(k), target);
   1960         // We assume that global objects can only have slow properties.
   1961         if (target->IsJSGlobalPropertyCell()) {
   1962           SetPropertyShortcutReference(js_obj,
   1963                                        entry,
   1964                                        String::cast(k),
   1965                                        JSGlobalPropertyCell::cast(
   1966                                            target)->value());
   1967         }
   1968       }
   1969     }
   1970   }
   1971 }
   1972 
   1973 
   1974 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
   1975                                               HeapEntry* entry) {
   1976   if (js_obj->HasFastElements()) {
   1977     FixedArray* elements = FixedArray::cast(js_obj->elements());
   1978     int length = js_obj->IsJSArray() ?
   1979         Smi::cast(JSArray::cast(js_obj)->length())->value() :
   1980         elements->length();
   1981     for (int i = 0; i < length; ++i) {
   1982       if (!elements->get(i)->IsTheHole()) {
   1983         SetElementReference(js_obj, entry, i, elements->get(i));
   1984       }
   1985     }
   1986   } else if (js_obj->HasDictionaryElements()) {
   1987     NumberDictionary* dictionary = js_obj->element_dictionary();
   1988     int length = dictionary->Capacity();
   1989     for (int i = 0; i < length; ++i) {
   1990       Object* k = dictionary->KeyAt(i);
   1991       if (dictionary->IsKey(k)) {
   1992         ASSERT(k->IsNumber());
   1993         uint32_t index = static_cast<uint32_t>(k->Number());
   1994         SetElementReference(js_obj, entry, index, dictionary->ValueAt(i));
   1995       }
   1996     }
   1997   }
   1998 }
   1999 
   2000 
   2001 void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
   2002                                                HeapEntry* entry) {
   2003   int length = js_obj->GetInternalFieldCount();
   2004   for (int i = 0; i < length; ++i) {
   2005     Object* o = js_obj->GetInternalField(i);
   2006     SetInternalReference(
   2007         js_obj, entry, i, o, js_obj->GetInternalFieldOffset(i));
   2008   }
   2009 }
   2010 
   2011 
   2012 HeapEntry* V8HeapExplorer::GetEntry(Object* obj) {
   2013   if (!obj->IsHeapObject()) return NULL;
   2014   return filler_->FindOrAddEntry(obj, this);
   2015 }
   2016 
   2017 
   2018 class RootsReferencesExtractor : public ObjectVisitor {
   2019  public:
   2020   explicit RootsReferencesExtractor(V8HeapExplorer* explorer)
   2021       : explorer_(explorer) {
   2022   }
   2023   void VisitPointers(Object** start, Object** end) {
   2024     for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p);
   2025   }
   2026  private:
   2027   V8HeapExplorer* explorer_;
   2028 };
   2029 
   2030 
   2031 bool V8HeapExplorer::IterateAndExtractReferences(
   2032     SnapshotFillerInterface* filler) {
   2033   filler_ = filler;
   2034   HeapIterator iterator(HeapIterator::kFilterUnreachable);
   2035   bool interrupted = false;
   2036   // Heap iteration with filtering must be finished in any case.
   2037   for (HeapObject* obj = iterator.next();
   2038        obj != NULL;
   2039        obj = iterator.next(), progress_->ProgressStep()) {
   2040     if (!interrupted) {
   2041       ExtractReferences(obj);
   2042       if (!progress_->ProgressReport(false)) interrupted = true;
   2043     }
   2044   }
   2045   if (interrupted) {
   2046     filler_ = NULL;
   2047     return false;
   2048   }
   2049   SetRootGcRootsReference();
   2050   RootsReferencesExtractor extractor(this);
   2051   HEAP->IterateRoots(&extractor, VISIT_ALL);
   2052   filler_ = NULL;
   2053   return progress_->ProgressReport(false);
   2054 }
   2055 
   2056 
   2057 void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
   2058                                          HeapEntry* parent_entry,
   2059                                          String* reference_name,
   2060                                          Object* child_obj) {
   2061   HeapEntry* child_entry = GetEntry(child_obj);
   2062   if (child_entry != NULL) {
   2063     filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
   2064                                parent_obj,
   2065                                parent_entry,
   2066                                collection_->names()->GetName(reference_name),
   2067                                child_obj,
   2068                                child_entry);
   2069   }
   2070 }
   2071 
   2072 
   2073 void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
   2074                                          HeapEntry* parent_entry,
   2075                                          int index,
   2076                                          Object* child_obj) {
   2077   HeapEntry* child_entry = GetEntry(child_obj);
   2078   if (child_entry != NULL) {
   2079     filler_->SetIndexedReference(HeapGraphEdge::kElement,
   2080                                  parent_obj,
   2081                                  parent_entry,
   2082                                  index,
   2083                                  child_obj,
   2084                                  child_entry);
   2085   }
   2086 }
   2087 
   2088 
   2089 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
   2090                                           HeapEntry* parent_entry,
   2091                                           const char* reference_name,
   2092                                           Object* child_obj,
   2093                                           int field_offset) {
   2094   HeapEntry* child_entry = GetEntry(child_obj);
   2095   if (child_entry != NULL) {
   2096     filler_->SetNamedReference(HeapGraphEdge::kInternal,
   2097                                parent_obj,
   2098                                parent_entry,
   2099                                reference_name,
   2100                                child_obj,
   2101                                child_entry);
   2102     IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   2103   }
   2104 }
   2105 
   2106 
   2107 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
   2108                                           HeapEntry* parent_entry,
   2109                                           int index,
   2110                                           Object* child_obj,
   2111                                           int field_offset) {
   2112   HeapEntry* child_entry = GetEntry(child_obj);
   2113   if (child_entry != NULL) {
   2114     filler_->SetNamedReference(HeapGraphEdge::kInternal,
   2115                                parent_obj,
   2116                                parent_entry,
   2117                                collection_->names()->GetName(index),
   2118                                child_obj,
   2119                                child_entry);
   2120     IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   2121   }
   2122 }
   2123 
   2124 
   2125 void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
   2126                                         HeapEntry* parent_entry,
   2127                                         int index,
   2128                                         Object* child_obj) {
   2129   HeapEntry* child_entry = GetEntry(child_obj);
   2130   if (child_entry != NULL) {
   2131     filler_->SetIndexedReference(HeapGraphEdge::kHidden,
   2132                                  parent_obj,
   2133                                  parent_entry,
   2134                                  index,
   2135                                  child_obj,
   2136                                  child_entry);
   2137   }
   2138 }
   2139 
   2140 
   2141 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
   2142                                           HeapEntry* parent_entry,
   2143                                           String* reference_name,
   2144                                           Object* child_obj,
   2145                                           int field_offset) {
   2146   HeapEntry* child_entry = GetEntry(child_obj);
   2147   if (child_entry != NULL) {
   2148     HeapGraphEdge::Type type = reference_name->length() > 0 ?
   2149         HeapGraphEdge::kProperty : HeapGraphEdge::kInternal;
   2150     filler_->SetNamedReference(type,
   2151                                parent_obj,
   2152                                parent_entry,
   2153                                collection_->names()->GetName(reference_name),
   2154                                child_obj,
   2155                                child_entry);
   2156     IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   2157   }
   2158 }
   2159 
   2160 
   2161 void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
   2162                                                   HeapEntry* parent_entry,
   2163                                                   String* reference_name,
   2164                                                   Object* child_obj) {
   2165   HeapEntry* child_entry = GetEntry(child_obj);
   2166   if (child_entry != NULL) {
   2167     filler_->SetNamedReference(HeapGraphEdge::kShortcut,
   2168                                parent_obj,
   2169                                parent_entry,
   2170                                collection_->names()->GetName(reference_name),
   2171                                child_obj,
   2172                                child_entry);
   2173   }
   2174 }
   2175 
   2176 
   2177 void V8HeapExplorer::SetRootGcRootsReference() {
   2178   filler_->SetIndexedAutoIndexReference(
   2179       HeapGraphEdge::kElement,
   2180       kInternalRootObject, snapshot_->root(),
   2181       kGcRootsObject, snapshot_->gc_roots());
   2182 }
   2183 
   2184 
   2185 void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) {
   2186   HeapEntry* child_entry = GetEntry(child_obj);
   2187   ASSERT(child_entry != NULL);
   2188   filler_->SetNamedAutoIndexReference(
   2189       HeapGraphEdge::kShortcut,
   2190       kInternalRootObject, snapshot_->root(),
   2191       child_obj, child_entry);
   2192 }
   2193 
   2194 
   2195 void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
   2196   HeapEntry* child_entry = GetEntry(child_obj);
   2197   if (child_entry != NULL) {
   2198     filler_->SetIndexedAutoIndexReference(
   2199         HeapGraphEdge::kElement,
   2200         kGcRootsObject, snapshot_->gc_roots(),
   2201         child_obj, child_entry);
   2202   }
   2203 }
   2204 
   2205 
   2206 class GlobalHandlesExtractor : public ObjectVisitor {
   2207  public:
   2208   explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer)
   2209       : explorer_(explorer) {}
   2210   virtual ~GlobalHandlesExtractor() {}
   2211   virtual void VisitPointers(Object** start, Object** end) {
   2212     UNREACHABLE();
   2213   }
   2214   virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {
   2215     explorer_->VisitSubtreeWrapper(p, class_id);
   2216   }
   2217  private:
   2218   NativeObjectsExplorer* explorer_;
   2219 };
   2220 
   2221 HeapThing const NativeObjectsExplorer::kNativesRootObject =
   2222     reinterpret_cast<HeapThing>(
   2223         static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId));
   2224 
   2225 
   2226 NativeObjectsExplorer::NativeObjectsExplorer(
   2227     HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
   2228     : snapshot_(snapshot),
   2229       collection_(snapshot_->collection()),
   2230       progress_(progress),
   2231       embedder_queried_(false),
   2232       objects_by_info_(RetainedInfosMatch),
   2233       filler_(NULL) {
   2234 }
   2235 
   2236 
   2237 NativeObjectsExplorer::~NativeObjectsExplorer() {
   2238   for (HashMap::Entry* p = objects_by_info_.Start();
   2239        p != NULL;
   2240        p = objects_by_info_.Next(p)) {
   2241     v8::RetainedObjectInfo* info =
   2242         reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
   2243     info->Dispose();
   2244     List<HeapObject*>* objects =
   2245         reinterpret_cast<List<HeapObject*>* >(p->value);
   2246     delete objects;
   2247   }
   2248 }
   2249 
   2250 
   2251 HeapEntry* NativeObjectsExplorer::AllocateEntry(
   2252     HeapThing ptr, int children_count, int retainers_count) {
   2253   if (ptr == kNativesRootObject) {
   2254     return snapshot_->AddNativesRootEntry(children_count, retainers_count);
   2255   } else {
   2256     v8::RetainedObjectInfo* info =
   2257         reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
   2258     intptr_t elements = info->GetElementCount();
   2259     intptr_t size = info->GetSizeInBytes();
   2260     return snapshot_->AddEntry(
   2261         HeapEntry::kNative,
   2262         elements != -1 ?
   2263             collection_->names()->GetFormatted(
   2264                 "%s / %" V8_PTR_PREFIX "d entries",
   2265                 info->GetLabel(),
   2266                 info->GetElementCount()) :
   2267                 collection_->names()->GetCopy(info->GetLabel()),
   2268         HeapObjectsMap::GenerateId(info),
   2269         size != -1 ? static_cast<int>(size) : 0,
   2270         children_count,
   2271         retainers_count);
   2272   }
   2273 }
   2274 
   2275 
   2276 void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
   2277   if (EstimateObjectsCount() <= 0) return;
   2278   filler->AddEntry(kNativesRootObject, this);
   2279 }
   2280 
   2281 
   2282 int NativeObjectsExplorer::EstimateObjectsCount() {
   2283   FillRetainedObjects();
   2284   return objects_by_info_.occupancy();
   2285 }
   2286 
   2287 
   2288 void NativeObjectsExplorer::FillRetainedObjects() {
   2289   if (embedder_queried_) return;
   2290   Isolate* isolate = Isolate::Current();
   2291   // Record objects that are joined into ObjectGroups.
   2292   isolate->heap()->CallGlobalGCPrologueCallback();
   2293   List<ObjectGroup*>* groups = isolate->global_handles()->object_groups();
   2294   for (int i = 0; i < groups->length(); ++i) {
   2295     ObjectGroup* group = groups->at(i);
   2296     if (group->info_ == NULL) continue;
   2297     List<HeapObject*>* list = GetListMaybeDisposeInfo(group->info_);
   2298     for (size_t j = 0; j < group->length_; ++j) {
   2299       HeapObject* obj = HeapObject::cast(*group->objects_[j]);
   2300       list->Add(obj);
   2301       in_groups_.Insert(obj);
   2302     }
   2303     group->info_ = NULL;  // Acquire info object ownership.
   2304   }
   2305   isolate->global_handles()->RemoveObjectGroups();
   2306   isolate->heap()->CallGlobalGCEpilogueCallback();
   2307   // Record objects that are not in ObjectGroups, but have class ID.
   2308   GlobalHandlesExtractor extractor(this);
   2309   isolate->global_handles()->IterateAllRootsWithClassIds(&extractor);
   2310   embedder_queried_ = true;
   2311 }
   2312 
   2313 
   2314 List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo(
   2315     v8::RetainedObjectInfo* info) {
   2316   HashMap::Entry* entry =
   2317       objects_by_info_.Lookup(info, InfoHash(info), true);
   2318   if (entry->value != NULL) {
   2319     info->Dispose();
   2320   } else {
   2321     entry->value = new List<HeapObject*>(4);
   2322   }
   2323   return reinterpret_cast<List<HeapObject*>* >(entry->value);
   2324 }
   2325 
   2326 
   2327 bool NativeObjectsExplorer::IterateAndExtractReferences(
   2328     SnapshotFillerInterface* filler) {
   2329   if (EstimateObjectsCount() <= 0) return true;
   2330   filler_ = filler;
   2331   FillRetainedObjects();
   2332   for (HashMap::Entry* p = objects_by_info_.Start();
   2333        p != NULL;
   2334        p = objects_by_info_.Next(p)) {
   2335     v8::RetainedObjectInfo* info =
   2336         reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
   2337     SetNativeRootReference(info);
   2338     List<HeapObject*>* objects =
   2339         reinterpret_cast<List<HeapObject*>* >(p->value);
   2340     for (int i = 0; i < objects->length(); ++i) {
   2341       SetWrapperNativeReferences(objects->at(i), info);
   2342     }
   2343   }
   2344   SetRootNativesRootReference();
   2345   filler_ = NULL;
   2346   return true;
   2347 }
   2348 
   2349 
   2350 void NativeObjectsExplorer::SetNativeRootReference(
   2351     v8::RetainedObjectInfo* info) {
   2352   HeapEntry* child_entry = filler_->FindOrAddEntry(info, this);
   2353   ASSERT(child_entry != NULL);
   2354   filler_->SetIndexedAutoIndexReference(
   2355       HeapGraphEdge::kElement,
   2356       kNativesRootObject, snapshot_->natives_root(),
   2357       info, child_entry);
   2358 }
   2359 
   2360 
   2361 void NativeObjectsExplorer::SetWrapperNativeReferences(
   2362     HeapObject* wrapper, v8::RetainedObjectInfo* info) {
   2363   HeapEntry* wrapper_entry = filler_->FindEntry(wrapper);
   2364   ASSERT(wrapper_entry != NULL);
   2365   HeapEntry* info_entry = filler_->FindOrAddEntry(info, this);
   2366   ASSERT(info_entry != NULL);
   2367   filler_->SetNamedReference(HeapGraphEdge::kInternal,
   2368                              wrapper, wrapper_entry,
   2369                              "native",
   2370                              info, info_entry);
   2371   filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
   2372                                         info, info_entry,
   2373                                         wrapper, wrapper_entry);
   2374 }
   2375 
   2376 
   2377 void NativeObjectsExplorer::SetRootNativesRootReference() {
   2378   filler_->SetIndexedAutoIndexReference(
   2379       HeapGraphEdge::kElement,
   2380       V8HeapExplorer::kInternalRootObject, snapshot_->root(),
   2381       kNativesRootObject, snapshot_->natives_root());
   2382 }
   2383 
   2384 
   2385 void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
   2386   if (in_groups_.Contains(*p)) return;
   2387   Isolate* isolate = Isolate::Current();
   2388   v8::RetainedObjectInfo* info =
   2389       isolate->heap_profiler()->ExecuteWrapperClassCallback(class_id, p);
   2390   if (info == NULL) return;
   2391   GetListMaybeDisposeInfo(info)->Add(HeapObject::cast(*p));
   2392 }
   2393 
   2394 
   2395 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
   2396                                              v8::ActivityControl* control)
   2397     : snapshot_(snapshot),
   2398       control_(control),
   2399       v8_heap_explorer_(snapshot_, this),
   2400       dom_explorer_(snapshot_, this) {
   2401 }
   2402 
   2403 
   2404 class SnapshotCounter : public SnapshotFillerInterface {
   2405  public:
   2406   explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { }
   2407   HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
   2408     entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder);
   2409     return HeapEntriesMap::kHeapEntryPlaceholder;
   2410   }
   2411   HeapEntry* FindEntry(HeapThing ptr) {
   2412     return entries_->Map(ptr);
   2413   }
   2414   HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
   2415     HeapEntry* entry = FindEntry(ptr);
   2416     return entry != NULL ? entry : AddEntry(ptr, allocator);
   2417   }
   2418   void SetIndexedReference(HeapGraphEdge::Type,
   2419                            HeapThing parent_ptr,
   2420                            HeapEntry*,
   2421                            int,
   2422                            HeapThing child_ptr,
   2423                            HeapEntry*) {
   2424     entries_->CountReference(parent_ptr, child_ptr);
   2425   }
   2426   void SetIndexedAutoIndexReference(HeapGraphEdge::Type,
   2427                                     HeapThing parent_ptr,
   2428                                     HeapEntry*,
   2429                                     HeapThing child_ptr,
   2430                                     HeapEntry*) {
   2431     entries_->CountReference(parent_ptr, child_ptr);
   2432   }
   2433   void SetNamedReference(HeapGraphEdge::Type,
   2434                          HeapThing parent_ptr,
   2435                          HeapEntry*,
   2436                          const char*,
   2437                          HeapThing child_ptr,
   2438                          HeapEntry*) {
   2439     entries_->CountReference(parent_ptr, child_ptr);
   2440   }
   2441   void SetNamedAutoIndexReference(HeapGraphEdge::Type,
   2442                                   HeapThing parent_ptr,
   2443                                   HeapEntry*,
   2444                                   HeapThing child_ptr,
   2445                                   HeapEntry*) {
   2446     entries_->CountReference(parent_ptr, child_ptr);
   2447   }
   2448  private:
   2449   HeapEntriesMap* entries_;
   2450 };
   2451 
   2452 
   2453 class SnapshotFiller : public SnapshotFillerInterface {
   2454  public:
   2455   explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
   2456       : snapshot_(snapshot),
   2457         collection_(snapshot->collection()),
   2458         entries_(entries) { }
   2459   HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
   2460     UNREACHABLE();
   2461     return NULL;
   2462   }
   2463   HeapEntry* FindEntry(HeapThing ptr) {
   2464     return entries_->Map(ptr);
   2465   }
   2466   HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
   2467     HeapEntry* entry = FindEntry(ptr);
   2468     return entry != NULL ? entry : AddEntry(ptr, allocator);
   2469   }
   2470   void SetIndexedReference(HeapGraphEdge::Type type,
   2471                            HeapThing parent_ptr,
   2472                            HeapEntry* parent_entry,
   2473                            int index,
   2474                            HeapThing child_ptr,
   2475                            HeapEntry* child_entry) {
   2476     int child_index, retainer_index;
   2477     entries_->CountReference(
   2478         parent_ptr, child_ptr, &child_index, &retainer_index);
   2479     parent_entry->SetIndexedReference(
   2480         type, child_index, index, child_entry, retainer_index);
   2481   }
   2482   void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
   2483                                     HeapThing parent_ptr,
   2484                                     HeapEntry* parent_entry,
   2485                                     HeapThing child_ptr,
   2486                                     HeapEntry* child_entry) {
   2487     int child_index, retainer_index;
   2488     entries_->CountReference(
   2489         parent_ptr, child_ptr, &child_index, &retainer_index);
   2490     parent_entry->SetIndexedReference(
   2491         type, child_index, child_index + 1, child_entry, retainer_index);
   2492   }
   2493   void SetNamedReference(HeapGraphEdge::Type type,
   2494                          HeapThing parent_ptr,
   2495                          HeapEntry* parent_entry,
   2496                          const char* reference_name,
   2497                          HeapThing child_ptr,
   2498                          HeapEntry* child_entry) {
   2499     int child_index, retainer_index;
   2500     entries_->CountReference(
   2501         parent_ptr, child_ptr, &child_index, &retainer_index);
   2502     parent_entry->SetNamedReference(
   2503         type, child_index, reference_name, child_entry, retainer_index);
   2504   }
   2505   void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
   2506                                   HeapThing parent_ptr,
   2507                                   HeapEntry* parent_entry,
   2508                                   HeapThing child_ptr,
   2509                                   HeapEntry* child_entry) {
   2510     int child_index, retainer_index;
   2511     entries_->CountReference(
   2512         parent_ptr, child_ptr, &child_index, &retainer_index);
   2513     parent_entry->SetNamedReference(type,
   2514                               child_index,
   2515                               collection_->names()->GetName(child_index + 1),
   2516                               child_entry,
   2517                               retainer_index);
   2518   }
   2519  private:
   2520   HeapSnapshot* snapshot_;
   2521   HeapSnapshotsCollection* collection_;
   2522   HeapEntriesMap* entries_;
   2523 };
   2524 
   2525 
   2526 bool HeapSnapshotGenerator::GenerateSnapshot() {
   2527   AssertNoAllocation no_alloc;
   2528 
   2529   SetProgressTotal(4);  // 2 passes + dominators + sizes.
   2530 
   2531   // Pass 1. Iterate heap contents to count entries and references.
   2532   if (!CountEntriesAndReferences()) return false;
   2533 
   2534   // Allocate and fill entries in the snapshot, allocate references.
   2535   snapshot_->AllocateEntries(entries_.entries_count(),
   2536                              entries_.total_children_count(),
   2537                              entries_.total_retainers_count());
   2538   entries_.AllocateEntries();
   2539 
   2540   // Pass 2. Fill references.
   2541   if (!FillReferences()) return false;
   2542 
   2543   if (!SetEntriesDominators()) return false;
   2544   if (!ApproximateRetainedSizes()) return false;
   2545 
   2546   progress_counter_ = progress_total_;
   2547   if (!ProgressReport(true)) return false;
   2548   return true;
   2549 }
   2550 
   2551 
   2552 void HeapSnapshotGenerator::ProgressStep() {
   2553   ++progress_counter_;
   2554 }
   2555 
   2556 
   2557 bool HeapSnapshotGenerator::ProgressReport(bool force) {
   2558   const int kProgressReportGranularity = 10000;
   2559   if (control_ != NULL
   2560       && (force || progress_counter_ % kProgressReportGranularity == 0)) {
   2561       return
   2562           control_->ReportProgressValue(progress_counter_, progress_total_) ==
   2563           v8::ActivityControl::kContinue;
   2564   }
   2565   return true;
   2566 }
   2567 
   2568 
   2569 void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
   2570   if (control_ == NULL) return;
   2571   progress_total_ = (
   2572       v8_heap_explorer_.EstimateObjectsCount() +
   2573       dom_explorer_.EstimateObjectsCount()) * iterations_count;
   2574   progress_counter_ = 0;
   2575 }
   2576 
   2577 
   2578 bool HeapSnapshotGenerator::CountEntriesAndReferences() {
   2579   SnapshotCounter counter(&entries_);
   2580   v8_heap_explorer_.AddRootEntries(&counter);
   2581   dom_explorer_.AddRootEntries(&counter);
   2582   return
   2583       v8_heap_explorer_.IterateAndExtractReferences(&counter) &&
   2584       dom_explorer_.IterateAndExtractReferences(&counter);
   2585 }
   2586 
   2587 
   2588 bool HeapSnapshotGenerator::FillReferences() {
   2589   SnapshotFiller filler(snapshot_, &entries_);
   2590   return
   2591       v8_heap_explorer_.IterateAndExtractReferences(&filler) &&
   2592       dom_explorer_.IterateAndExtractReferences(&filler);
   2593 }
   2594 
   2595 
   2596 void HeapSnapshotGenerator::FillReversePostorderIndexes(
   2597     Vector<HeapEntry*>* entries) {
   2598   snapshot_->ClearPaint();
   2599   int current_entry = 0;
   2600   List<HeapEntry*> nodes_to_visit;
   2601   nodes_to_visit.Add(snapshot_->root());
   2602   snapshot_->root()->paint_reachable();
   2603   while (!nodes_to_visit.is_empty()) {
   2604     HeapEntry* entry = nodes_to_visit.last();
   2605     Vector<HeapGraphEdge> children = entry->children();
   2606     bool has_new_edges = false;
   2607     for (int i = 0; i < children.length(); ++i) {
   2608       if (children[i].type() == HeapGraphEdge::kShortcut) continue;
   2609       HeapEntry* child = children[i].to();
   2610       if (!child->painted_reachable()) {
   2611         nodes_to_visit.Add(child);
   2612         child->paint_reachable();
   2613         has_new_edges = true;
   2614       }
   2615     }
   2616     if (!has_new_edges) {
   2617       entry->set_ordered_index(current_entry);
   2618       (*entries)[current_entry++] = entry;
   2619       nodes_to_visit.RemoveLast();
   2620     }
   2621   }
   2622   entries->Truncate(current_entry);
   2623 }
   2624 
   2625 
   2626 static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) {
   2627   int finger1 = i1, finger2 = i2;
   2628   while (finger1 != finger2) {
   2629     while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index();
   2630     while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index();
   2631   }
   2632   return finger1;
   2633 }
   2634 
   2635 // The algorithm is based on the article:
   2636 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
   2637 // Softw. Pract. Exper. 4 (2001), pp. 1-10.
   2638 bool HeapSnapshotGenerator::BuildDominatorTree(
   2639     const Vector<HeapEntry*>& entries,
   2640     Vector<HeapEntry*>* dominators) {
   2641   if (entries.length() == 0) return true;
   2642   const int entries_length = entries.length(), root_index = entries_length - 1;
   2643   for (int i = 0; i < root_index; ++i) (*dominators)[i] = NULL;
   2644   (*dominators)[root_index] = entries[root_index];
   2645   int changed = 1;
   2646   const int base_progress_counter = progress_counter_;
   2647   while (changed != 0) {
   2648     changed = 0;
   2649     for (int i = root_index - 1; i >= 0; --i) {
   2650       HeapEntry* new_idom = NULL;
   2651       Vector<HeapGraphEdge*> rets = entries[i]->retainers();
   2652       int j = 0;
   2653       for (; j < rets.length(); ++j) {
   2654         if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
   2655         HeapEntry* ret = rets[j]->From();
   2656         if (dominators->at(ret->ordered_index()) != NULL) {
   2657           new_idom = ret;
   2658           break;
   2659         }
   2660       }
   2661       for (++j; j < rets.length(); ++j) {
   2662         if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
   2663         HeapEntry* ret = rets[j]->From();
   2664         if (dominators->at(ret->ordered_index()) != NULL) {
   2665           new_idom = entries[Intersect(ret->ordered_index(),
   2666                                        new_idom->ordered_index(),
   2667                                        *dominators)];
   2668         }
   2669       }
   2670       if (new_idom != NULL && dominators->at(i) != new_idom) {
   2671         (*dominators)[i] = new_idom;
   2672         ++changed;
   2673       }
   2674     }
   2675     int remaining = entries_length - changed;
   2676     if (remaining < 0) remaining = 0;
   2677     progress_counter_ = base_progress_counter + remaining;
   2678     if (!ProgressReport(true)) return false;
   2679   }
   2680   return true;
   2681 }
   2682 
   2683 
   2684 bool HeapSnapshotGenerator::SetEntriesDominators() {
   2685   // This array is used for maintaining reverse postorder of nodes.
   2686   ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length());
   2687   FillReversePostorderIndexes(&ordered_entries);
   2688   ScopedVector<HeapEntry*> dominators(ordered_entries.length());
   2689   if (!BuildDominatorTree(ordered_entries, &dominators)) return false;
   2690   for (int i = 0; i < ordered_entries.length(); ++i) {
   2691     ASSERT(dominators[i] != NULL);
   2692     ordered_entries[i]->set_dominator(dominators[i]);
   2693   }
   2694   return true;
   2695 }
   2696 
   2697 
   2698 bool HeapSnapshotGenerator::ApproximateRetainedSizes() {
   2699   // As for the dominators tree we only know parent nodes, not
   2700   // children, to sum up total sizes we "bubble" node's self size
   2701   // adding it to all of its parents.
   2702   for (int i = 0; i < snapshot_->entries()->length(); ++i) {
   2703     HeapEntry* entry = snapshot_->entries()->at(i);
   2704     entry->set_retained_size(entry->self_size());
   2705   }
   2706   for (int i = 0;
   2707        i < snapshot_->entries()->length();
   2708        ++i, ProgressStep()) {
   2709     HeapEntry* entry = snapshot_->entries()->at(i);
   2710     int entry_size = entry->self_size();
   2711     for (HeapEntry* dominator = entry->dominator();
   2712          dominator != entry;
   2713          entry = dominator, dominator = entry->dominator()) {
   2714       dominator->add_retained_size(entry_size);
   2715     }
   2716     if (!ProgressReport()) return false;
   2717   }
   2718   return true;
   2719 }
   2720 
   2721 
   2722 class OutputStreamWriter {
   2723  public:
   2724   explicit OutputStreamWriter(v8::OutputStream* stream)
   2725       : stream_(stream),
   2726         chunk_size_(stream->GetChunkSize()),
   2727         chunk_(chunk_size_),
   2728         chunk_pos_(0),
   2729         aborted_(false) {
   2730     ASSERT(chunk_size_ > 0);
   2731   }
   2732   bool aborted() { return aborted_; }
   2733   void AddCharacter(char c) {
   2734     ASSERT(c != '\0');
   2735     ASSERT(chunk_pos_ < chunk_size_);
   2736     chunk_[chunk_pos_++] = c;
   2737     MaybeWriteChunk();
   2738   }
   2739   void AddString(const char* s) {
   2740     AddSubstring(s, StrLength(s));
   2741   }
   2742   void AddSubstring(const char* s, int n) {
   2743     if (n <= 0) return;
   2744     ASSERT(static_cast<size_t>(n) <= strlen(s));
   2745     const char* s_end = s + n;
   2746     while (s < s_end) {
   2747       int s_chunk_size = Min(
   2748           chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
   2749       ASSERT(s_chunk_size > 0);
   2750       memcpy(chunk_.start() + chunk_pos_, s, s_chunk_size);
   2751       s += s_chunk_size;
   2752       chunk_pos_ += s_chunk_size;
   2753       MaybeWriteChunk();
   2754     }
   2755   }
   2756   void AddNumber(int n) { AddNumberImpl<int>(n, "%d"); }
   2757   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
   2758   void AddNumber(uint64_t n) { AddNumberImpl<uint64_t>(n, "%llu"); }
   2759   void Finalize() {
   2760     if (aborted_) return;
   2761     ASSERT(chunk_pos_ < chunk_size_);
   2762     if (chunk_pos_ != 0) {
   2763       WriteChunk();
   2764     }
   2765     stream_->EndOfStream();
   2766   }
   2767 
   2768  private:
   2769   template<typename T>
   2770   void AddNumberImpl(T n, const char* format) {
   2771     ScopedVector<char> buffer(32);
   2772     int result = OS::SNPrintF(buffer, format, n);
   2773     USE(result);
   2774     ASSERT(result != -1);
   2775     AddString(buffer.start());
   2776   }
   2777   void MaybeWriteChunk() {
   2778     ASSERT(chunk_pos_ <= chunk_size_);
   2779     if (chunk_pos_ == chunk_size_) {
   2780       WriteChunk();
   2781       chunk_pos_ = 0;
   2782     }
   2783   }
   2784   void WriteChunk() {
   2785     if (aborted_) return;
   2786     if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) ==
   2787         v8::OutputStream::kAbort) aborted_ = true;
   2788   }
   2789 
   2790   v8::OutputStream* stream_;
   2791   int chunk_size_;
   2792   ScopedVector<char> chunk_;
   2793   int chunk_pos_;
   2794   bool aborted_;
   2795 };
   2796 
   2797 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
   2798   ASSERT(writer_ == NULL);
   2799   writer_ = new OutputStreamWriter(stream);
   2800 
   2801   // Since nodes graph is cyclic, we need the first pass to enumerate
   2802   // them. Strings can be serialized in one pass.
   2803   EnumerateNodes();
   2804   SerializeImpl();
   2805 
   2806   delete writer_;
   2807   writer_ = NULL;
   2808 }
   2809 
   2810 
   2811 void HeapSnapshotJSONSerializer::SerializeImpl() {
   2812   writer_->AddCharacter('{');
   2813   writer_->AddString("\"snapshot\":{");
   2814   SerializeSnapshot();
   2815   if (writer_->aborted()) return;
   2816   writer_->AddString("},\n");
   2817   writer_->AddString("\"nodes\":[");
   2818   SerializeNodes();
   2819   if (writer_->aborted()) return;
   2820   writer_->AddString("],\n");
   2821   writer_->AddString("\"strings\":[");
   2822   SerializeStrings();
   2823   if (writer_->aborted()) return;
   2824   writer_->AddCharacter(']');
   2825   writer_->AddCharacter('}');
   2826   writer_->Finalize();
   2827 }
   2828 
   2829 
   2830 class HeapSnapshotJSONSerializerEnumerator {
   2831  public:
   2832   explicit HeapSnapshotJSONSerializerEnumerator(HeapSnapshotJSONSerializer* s)
   2833       : s_(s) {
   2834   }
   2835   void Apply(HeapEntry** entry) {
   2836     s_->GetNodeId(*entry);
   2837   }
   2838  private:
   2839   HeapSnapshotJSONSerializer* s_;
   2840 };
   2841 
   2842 void HeapSnapshotJSONSerializer::EnumerateNodes() {
   2843   GetNodeId(snapshot_->root());  // Make sure root gets the first id.
   2844   HeapSnapshotJSONSerializerEnumerator iter(this);
   2845   snapshot_->IterateEntries(&iter);
   2846 }
   2847 
   2848 
   2849 int HeapSnapshotJSONSerializer::GetNodeId(HeapEntry* entry) {
   2850   HashMap::Entry* cache_entry = nodes_.Lookup(entry, ObjectHash(entry), true);
   2851   if (cache_entry->value == NULL) {
   2852     cache_entry->value = reinterpret_cast<void*>(next_node_id_++);
   2853   }
   2854   return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
   2855 }
   2856 
   2857 
   2858 int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
   2859   HashMap::Entry* cache_entry = strings_.Lookup(
   2860       const_cast<char*>(s), ObjectHash(s), true);
   2861   if (cache_entry->value == NULL) {
   2862     cache_entry->value = reinterpret_cast<void*>(next_string_id_++);
   2863   }
   2864   return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
   2865 }
   2866 
   2867 
   2868 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) {
   2869   writer_->AddCharacter(',');
   2870   writer_->AddNumber(edge->type());
   2871   writer_->AddCharacter(',');
   2872   if (edge->type() == HeapGraphEdge::kElement
   2873       || edge->type() == HeapGraphEdge::kHidden) {
   2874     writer_->AddNumber(edge->index());
   2875   } else {
   2876     writer_->AddNumber(GetStringId(edge->name()));
   2877   }
   2878   writer_->AddCharacter(',');
   2879   writer_->AddNumber(GetNodeId(edge->to()));
   2880 }
   2881 
   2882 
   2883 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
   2884   writer_->AddCharacter('\n');
   2885   writer_->AddCharacter(',');
   2886   writer_->AddNumber(entry->type());
   2887   writer_->AddCharacter(',');
   2888   writer_->AddNumber(GetStringId(entry->name()));
   2889   writer_->AddCharacter(',');
   2890   writer_->AddNumber(entry->id());
   2891   writer_->AddCharacter(',');
   2892   writer_->AddNumber(entry->self_size());
   2893   writer_->AddCharacter(',');
   2894   writer_->AddNumber(entry->RetainedSize(false));
   2895   writer_->AddCharacter(',');
   2896   writer_->AddNumber(GetNodeId(entry->dominator()));
   2897   Vector<HeapGraphEdge> children = entry->children();
   2898   writer_->AddCharacter(',');
   2899   writer_->AddNumber(children.length());
   2900   for (int i = 0; i < children.length(); ++i) {
   2901     SerializeEdge(&children[i]);
   2902     if (writer_->aborted()) return;
   2903   }
   2904 }
   2905 
   2906 
   2907 void HeapSnapshotJSONSerializer::SerializeNodes() {
   2908   // The first (zero) item of nodes array is an object describing node
   2909   // serialization layout.  We use a set of macros to improve
   2910   // readability.
   2911 #define JSON_A(s) "["s"]"
   2912 #define JSON_O(s) "{"s"}"
   2913 #define JSON_S(s) "\""s"\""
   2914   writer_->AddString(JSON_O(
   2915     JSON_S("fields") ":" JSON_A(
   2916         JSON_S("type")
   2917         "," JSON_S("name")
   2918         "," JSON_S("id")
   2919         "," JSON_S("self_size")
   2920         "," JSON_S("retained_size")
   2921         "," JSON_S("dominator")
   2922         "," JSON_S("children_count")
   2923         "," JSON_S("children"))
   2924     "," JSON_S("types") ":" JSON_A(
   2925         JSON_A(
   2926             JSON_S("hidden")
   2927             "," JSON_S("array")
   2928             "," JSON_S("string")
   2929             "," JSON_S("object")
   2930             "," JSON_S("code")
   2931             "," JSON_S("closure")
   2932             "," JSON_S("regexp")
   2933             "," JSON_S("number")
   2934             "," JSON_S("native"))
   2935         "," JSON_S("string")
   2936         "," JSON_S("number")
   2937         "," JSON_S("number")
   2938         "," JSON_S("number")
   2939         "," JSON_S("number")
   2940         "," JSON_S("number")
   2941         "," JSON_O(
   2942             JSON_S("fields") ":" JSON_A(
   2943                 JSON_S("type")
   2944                 "," JSON_S("name_or_index")
   2945                 "," JSON_S("to_node"))
   2946             "," JSON_S("types") ":" JSON_A(
   2947                 JSON_A(
   2948                     JSON_S("context")
   2949                     "," JSON_S("element")
   2950                     "," JSON_S("property")
   2951                     "," JSON_S("internal")
   2952                     "," JSON_S("hidden")
   2953                     "," JSON_S("shortcut"))
   2954                 "," JSON_S("string_or_number")
   2955                 "," JSON_S("node"))))));
   2956 #undef JSON_S
   2957 #undef JSON_O
   2958 #undef JSON_A
   2959 
   2960   const int node_fields_count = 7;
   2961   // type,name,id,self_size,retained_size,dominator,children_count.
   2962   const int edge_fields_count = 3;  // type,name|index,to_node.
   2963   List<HashMap::Entry*> sorted_nodes;
   2964   SortHashMap(&nodes_, &sorted_nodes);
   2965   // Rewrite node ids, so they refer to actual array positions.
   2966   if (sorted_nodes.length() > 1) {
   2967     // Nodes start from array index 1.
   2968     int prev_value = 1;
   2969     sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value);
   2970     for (int i = 1; i < sorted_nodes.length(); ++i) {
   2971       HeapEntry* prev_heap_entry =
   2972           reinterpret_cast<HeapEntry*>(sorted_nodes[i-1]->key);
   2973       prev_value += node_fields_count +
   2974           prev_heap_entry->children().length() * edge_fields_count;
   2975       sorted_nodes[i]->value = reinterpret_cast<void*>(prev_value);
   2976     }
   2977   }
   2978   for (int i = 0; i < sorted_nodes.length(); ++i) {
   2979     SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key));
   2980     if (writer_->aborted()) return;
   2981   }
   2982 }
   2983 
   2984 
   2985 void HeapSnapshotJSONSerializer::SerializeSnapshot() {
   2986   writer_->AddString("\"title\":\"");
   2987   writer_->AddString(snapshot_->title());
   2988   writer_->AddString("\"");
   2989   writer_->AddString(",\"uid\":");
   2990   writer_->AddNumber(snapshot_->uid());
   2991 }
   2992 
   2993 
   2994 static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) {
   2995   static const char hex_chars[] = "0123456789ABCDEF";
   2996   w->AddString("\\u");
   2997   w->AddCharacter(hex_chars[(u >> 12) & 0xf]);
   2998   w->AddCharacter(hex_chars[(u >> 8) & 0xf]);
   2999   w->AddCharacter(hex_chars[(u >> 4) & 0xf]);
   3000   w->AddCharacter(hex_chars[u & 0xf]);
   3001 }
   3002 
   3003 void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
   3004   writer_->AddCharacter('\n');
   3005   writer_->AddCharacter('\"');
   3006   for ( ; *s != '\0'; ++s) {
   3007     switch (*s) {
   3008       case '\b':
   3009         writer_->AddString("\\b");
   3010         continue;
   3011       case '\f':
   3012         writer_->AddString("\\f");
   3013         continue;
   3014       case '\n':
   3015         writer_->AddString("\\n");
   3016         continue;
   3017       case '\r':
   3018         writer_->AddString("\\r");
   3019         continue;
   3020       case '\t':
   3021         writer_->AddString("\\t");
   3022         continue;
   3023       case '\"':
   3024       case '\\':
   3025         writer_->AddCharacter('\\');
   3026         writer_->AddCharacter(*s);
   3027         continue;
   3028       default:
   3029         if (*s > 31 && *s < 128) {
   3030           writer_->AddCharacter(*s);
   3031         } else if (*s <= 31) {
   3032           // Special character with no dedicated literal.
   3033           WriteUChar(writer_, *s);
   3034         } else {
   3035           // Convert UTF-8 into \u UTF-16 literal.
   3036           unsigned length = 1, cursor = 0;
   3037           for ( ; length <= 4 && *(s + length) != '\0'; ++length) { }
   3038           unibrow::uchar c = unibrow::Utf8::CalculateValue(s, length, &cursor);
   3039           if (c != unibrow::Utf8::kBadChar) {
   3040             WriteUChar(writer_, c);
   3041             ASSERT(cursor != 0);
   3042             s += cursor - 1;
   3043           } else {
   3044             writer_->AddCharacter('?');
   3045           }
   3046         }
   3047     }
   3048   }
   3049   writer_->AddCharacter('\"');
   3050 }
   3051 
   3052 
   3053 void HeapSnapshotJSONSerializer::SerializeStrings() {
   3054   List<HashMap::Entry*> sorted_strings;
   3055   SortHashMap(&strings_, &sorted_strings);
   3056   writer_->AddString("\"<dummy>\"");
   3057   for (int i = 0; i < sorted_strings.length(); ++i) {
   3058     writer_->AddCharacter(',');
   3059     SerializeString(
   3060         reinterpret_cast<const unsigned char*>(sorted_strings[i]->key));
   3061     if (writer_->aborted()) return;
   3062   }
   3063 }
   3064 
   3065 
   3066 template<typename T>
   3067 inline static int SortUsingEntryValue(const T* x, const T* y) {
   3068   uintptr_t x_uint = reinterpret_cast<uintptr_t>((*x)->value);
   3069   uintptr_t y_uint = reinterpret_cast<uintptr_t>((*y)->value);
   3070   if (x_uint > y_uint) {
   3071     return 1;
   3072   } else if (x_uint == y_uint) {
   3073     return 0;
   3074   } else {
   3075     return -1;
   3076   }
   3077 }
   3078 
   3079 
   3080 void HeapSnapshotJSONSerializer::SortHashMap(
   3081     HashMap* map, List<HashMap::Entry*>* sorted_entries) {
   3082   for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p))
   3083     sorted_entries->Add(p);
   3084   sorted_entries->Sort(SortUsingEntryValue);
   3085 }
   3086 
   3087 
   3088 String* GetConstructorNameForHeapProfile(JSObject* object) {
   3089   if (object->IsJSFunction()) return HEAP->closure_symbol();
   3090   return object->constructor_name();
   3091 }
   3092 
   3093 } }  // namespace v8::internal
   3094 
   3095 #endif  // ENABLE_LOGGING_AND_PROFILING
   3096