| Index: src/profile-generator.cc
 | 
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc
 | 
| index 7054b125950863776f41a5555d8aeaf807bb5a83..01c4e4fe8709a2eb4e1030bba3d828c7d9c4e7d6 100644
 | 
| --- a/src/profile-generator.cc
 | 
| +++ b/src/profile-generator.cc
 | 
| @@ -798,83 +798,102 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -HeapGraphEdge::HeapGraphEdge(Type type,
 | 
| -                             const char* name,
 | 
| -                             HeapEntry* from,
 | 
| -                             HeapEntry* to)
 | 
| -    : type_(type), name_(name), from_(from), to_(to) {
 | 
| -  ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ == INTERNAL);
 | 
| +void HeapGraphEdge::Init(
 | 
| +    int child_index, Type type, const char* name, HeapEntry* to) {
 | 
| +  ASSERT(type == kContextVariable || type == kProperty || type == kInternal);
 | 
| +  child_index_ = child_index;
 | 
| +  type_ = type;
 | 
| +  name_ = name;
 | 
| +  to_ = to;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -HeapGraphEdge::HeapGraphEdge(int index,
 | 
| -                             HeapEntry* from,
 | 
| -                             HeapEntry* to)
 | 
| -    : type_(ELEMENT), index_(index), from_(from), to_(to) {
 | 
| +void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
 | 
| +  child_index_ = child_index;
 | 
| +  type_ = kElement;
 | 
| +  index_ = index;
 | 
| +  to_ = to;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static void DeleteHeapGraphEdge(HeapGraphEdge** edge_ptr) {
 | 
| -  delete *edge_ptr;
 | 
| +HeapEntry* HeapGraphEdge::From() {
 | 
| +  return reinterpret_cast<HeapEntry*>(this - child_index_) - 1;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
 | 
| -  delete *path_ptr;
 | 
| +void HeapEntry::Init(HeapSnapshot* snapshot,
 | 
| +                     int children_count,
 | 
| +                     int retainers_count) {
 | 
| +  Init(snapshot, kInternal, "", 0, 0, children_count, retainers_count);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -HeapEntry::~HeapEntry() {
 | 
| -  children_.Iterate(DeleteHeapGraphEdge);
 | 
| -  retaining_paths_.Iterate(DeleteHeapGraphPath);
 | 
| +void HeapEntry::Init(HeapSnapshot* snapshot,
 | 
| +                     Type type,
 | 
| +                     const char* name,
 | 
| +                     uint64_t id,
 | 
| +                     int self_size,
 | 
| +                     int children_count,
 | 
| +                     int retainers_count) {
 | 
| +  snapshot_ = snapshot;
 | 
| +  type_ = type;
 | 
| +  painted_ = kUnpainted;
 | 
| +  calculated_data_index_ = kNoCalculatedData;
 | 
| +  name_ = name;
 | 
| +  id_ = id;
 | 
| +  self_size_ = self_size;
 | 
| +  children_count_ = children_count;
 | 
| +  retainers_count_ = retainers_count;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapEntry::AddEdge(HeapGraphEdge* edge) {
 | 
| -  children_.Add(edge);
 | 
| -  edge->to()->retainers_.Add(edge);
 | 
| +void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
 | 
| +                                  int child_index,
 | 
| +                                  const char* name,
 | 
| +                                  HeapEntry* entry,
 | 
| +                                  int retainer_index) {
 | 
| +  children_arr()[child_index].Init(child_index, type, name, entry);
 | 
| +  entry->retainers_arr()[retainer_index] = children_arr() + child_index;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
 | 
| -  AddEdge(
 | 
| -      new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry));
 | 
| +void HeapEntry::SetElementReference(
 | 
| +    int child_index, int index, HeapEntry* entry, int retainer_index) {
 | 
| +  children_arr()[child_index].Init(child_index, index, entry);
 | 
| +  entry->retainers_arr()[retainer_index] = children_arr() + child_index;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapEntry::SetElementReference(int index, HeapEntry* entry) {
 | 
| -  AddEdge(new HeapGraphEdge(index, this, entry));
 | 
| +void HeapEntry::SetUnidirElementReference(
 | 
| +    int child_index, int index, HeapEntry* entry) {
 | 
| +  children_arr()[child_index].Init(child_index, index, entry);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapEntry::SetInternalReference(const char* name, HeapEntry* entry) {
 | 
| -  AddEdge(new HeapGraphEdge(HeapGraphEdge::INTERNAL, name, this, entry));
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
 | 
| -  AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry));
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::SetAutoIndexReference(HeapEntry* entry) {
 | 
| -  SetElementReference(next_auto_index_++, entry);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::SetUnidirAutoIndexReference(HeapEntry* entry) {
 | 
| -  children_.Add(new HeapGraphEdge(next_auto_index_++, this, entry));
 | 
| +int HeapEntry::ReachableSize() {
 | 
| +  if (calculated_data_index_ == kNoCalculatedData) {
 | 
| +    calculated_data_index_ = snapshot_->AddCalculatedData();
 | 
| +  }
 | 
| +  return snapshot_->GetCalculatedData(
 | 
| +      calculated_data_index_).ReachableSize(this);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -int HeapEntry::TotalSize() {
 | 
| -  return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize();
 | 
| +int HeapEntry::RetainedSize() {
 | 
| +  if (calculated_data_index_ == kNoCalculatedData) {
 | 
| +    calculated_data_index_ = snapshot_->AddCalculatedData();
 | 
| +  }
 | 
| +  return snapshot_->GetCalculatedData(
 | 
| +      calculated_data_index_).RetainedSize(this);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -int HeapEntry::NonSharedTotalSize() {
 | 
| -  return non_shared_total_size_ != kUnknownSize ?
 | 
| -      non_shared_total_size_ : CalculateNonSharedTotalSize();
 | 
| +List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
 | 
| +  if (calculated_data_index_ == kNoCalculatedData) {
 | 
| +    calculated_data_index_ = snapshot_->AddCalculatedData();
 | 
| +  }
 | 
| +  return snapshot_->GetCalculatedData(
 | 
| +      calculated_data_index_).GetRetainingPaths(this);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -882,16 +901,16 @@ template<class Visitor>
 | 
|  void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) {
 | 
|    List<HeapEntry*> list(10);
 | 
|    list.Add(this);
 | 
| -  this->PaintReachable();
 | 
| +  this->paint_reachable();
 | 
|    visitor->Apply(this);
 | 
|    while (!list.is_empty()) {
 | 
|      HeapEntry* entry = list.RemoveLast();
 | 
| -    const int children_count = entry->children_.length();
 | 
| -    for (int i = 0; i < children_count; ++i) {
 | 
| -      HeapEntry* child = entry->children_[i]->to();
 | 
| +    Vector<HeapGraphEdge> children = entry->children();
 | 
| +    for (int i = 0; i < children.length(); ++i) {
 | 
| +      HeapEntry* child = children[i].to();
 | 
|        if (!child->painted_reachable()) {
 | 
|          list.Add(child);
 | 
| -        child->PaintReachable();
 | 
| +        child->paint_reachable();
 | 
|          visitor->Apply(child);
 | 
|        }
 | 
|      }
 | 
| @@ -910,78 +929,158 @@ void HeapEntry::PaintAllReachable() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -class TotalSizeCalculator {
 | 
| - public:
 | 
| -  TotalSizeCalculator()
 | 
| -      : total_size_(0) {
 | 
| +void HeapEntry::Print(int max_depth, int indent) {
 | 
| +  OS::Print("%6d %6d %6d [%ld] ",
 | 
| +            self_size(), ReachableSize(), RetainedSize(), id_);
 | 
| +  if (type() != kString) {
 | 
| +    OS::Print("%s %.40s\n", TypeAsString(), name_);
 | 
| +  } else {
 | 
| +    OS::Print("\"");
 | 
| +    const char* c = name_;
 | 
| +    while (*c && (c - name_) <= 40) {
 | 
| +      if (*c != '\n')
 | 
| +        OS::Print("%c", *c);
 | 
| +      else
 | 
| +        OS::Print("\\n");
 | 
| +      ++c;
 | 
| +    }
 | 
| +    OS::Print("\"\n");
 | 
|    }
 | 
| +  if (--max_depth == 0) return;
 | 
| +  Vector<HeapGraphEdge> ch = children();
 | 
| +  for (int i = 0; i < ch.length(); ++i) {
 | 
| +    HeapGraphEdge& edge = ch[i];
 | 
| +    switch (edge.type()) {
 | 
| +      case HeapGraphEdge::kContextVariable:
 | 
| +        OS::Print("  %*c #%s: ", indent, ' ', edge.name());
 | 
| +        break;
 | 
| +      case HeapGraphEdge::kElement:
 | 
| +        OS::Print("  %*c %d: ", indent, ' ', edge.index());
 | 
| +        break;
 | 
| +      case HeapGraphEdge::kInternal:
 | 
| +        OS::Print("  %*c $%s: ", indent, ' ', edge.name());
 | 
| +        break;
 | 
| +      case HeapGraphEdge::kProperty:
 | 
| +        OS::Print("  %*c %s: ", indent, ' ', edge.name());
 | 
| +        break;
 | 
| +      default:
 | 
| +        OS::Print("!!! unknown edge type: %d ", edge.type());
 | 
| +    }
 | 
| +    edge.to()->Print(max_depth, indent + 2);
 | 
| +  }
 | 
| +}
 | 
|  
 | 
| -  int total_size() const { return total_size_; }
 | 
|  
 | 
| -  void Apply(HeapEntry* entry) {
 | 
| -    total_size_ += entry->self_size();
 | 
| +const char* HeapEntry::TypeAsString() {
 | 
| +  switch (type()) {
 | 
| +    case kInternal: return "/internal/";
 | 
| +    case kObject: return "/object/";
 | 
| +    case kClosure: return "/closure/";
 | 
| +    case kString: return "/string/";
 | 
| +    case kCode: return "/code/";
 | 
| +    case kArray: return "/array/";
 | 
| +    default: return "???";
 | 
|    }
 | 
| +}
 | 
|  
 | 
| - private:
 | 
| -  int total_size_;
 | 
| -};
 | 
|  
 | 
| -int HeapEntry::CalculateTotalSize() {
 | 
| -  snapshot_->ClearPaint();
 | 
| -  TotalSizeCalculator calc;
 | 
| -  ApplyAndPaintAllReachable(&calc);
 | 
| -  total_size_ = calc.total_size();
 | 
| -  return total_size_;
 | 
| +int HeapEntry::EntriesSize(int entries_count,
 | 
| +                           int children_count,
 | 
| +                           int retainers_count) {
 | 
| +  return sizeof(HeapEntry) * entries_count         // NOLINT
 | 
| +      + sizeof(HeapGraphEdge) * children_count     // NOLINT
 | 
| +      + sizeof(HeapGraphEdge*) * retainers_count;  // NOLINT
 | 
|  }
 | 
|  
 | 
|  
 | 
| -class NonSharedSizeCalculator {
 | 
| +static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
 | 
| +  delete *path_ptr;
 | 
| +}
 | 
| +
 | 
| +void HeapEntryCalculatedData::Dispose() {
 | 
| +  if (retaining_paths_ != NULL) retaining_paths_->Iterate(DeleteHeapGraphPath);
 | 
| +  delete retaining_paths_;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +int HeapEntryCalculatedData::ReachableSize(HeapEntry* entry) {
 | 
| +  if (reachable_size_ == kUnknownSize) CalculateSizes(entry);
 | 
| +  return reachable_size_;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +int HeapEntryCalculatedData::RetainedSize(HeapEntry* entry) {
 | 
| +  if (retained_size_ == kUnknownSize) CalculateSizes(entry);
 | 
| +  return retained_size_;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +class ReachableSizeCalculator {
 | 
|   public:
 | 
| -  NonSharedSizeCalculator()
 | 
| -      : non_shared_total_size_(0) {
 | 
| +  ReachableSizeCalculator()
 | 
| +      : reachable_size_(0) {
 | 
|    }
 | 
|  
 | 
| -  int non_shared_total_size() const { return non_shared_total_size_; }
 | 
| +  int reachable_size() const { return reachable_size_; }
 | 
|  
 | 
|    void Apply(HeapEntry* entry) {
 | 
| -    if (entry->painted_reachable()) {
 | 
| -      non_shared_total_size_ += entry->self_size();
 | 
| +    reachable_size_ += entry->self_size();
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  int reachable_size_;
 | 
| +};
 | 
| +
 | 
| +class RetainedSizeCalculator {
 | 
| + public:
 | 
| +  RetainedSizeCalculator()
 | 
| +      : retained_size_(0) {
 | 
| +  }
 | 
| +
 | 
| +  int reained_size() const { return retained_size_; }
 | 
| +
 | 
| +  void Apply(HeapEntry** entry_ptr) {
 | 
| +    if ((*entry_ptr)->painted_reachable()) {
 | 
| +      retained_size_ += (*entry_ptr)->self_size();
 | 
|      }
 | 
|    }
 | 
|  
 | 
|   private:
 | 
| -  int non_shared_total_size_;
 | 
| +  int retained_size_;
 | 
|  };
 | 
|  
 | 
| -int HeapEntry::CalculateNonSharedTotalSize() {
 | 
| -  // To calculate non-shared total size, first we paint all reachable
 | 
| -  // nodes in one color, then we paint all nodes reachable from other
 | 
| -  // nodes with a different color. Then we consider only nodes painted
 | 
| -  // with the first color for calculating the total size.
 | 
| -  snapshot_->ClearPaint();
 | 
| -  PaintAllReachable();
 | 
| +void HeapEntryCalculatedData::CalculateSizes(HeapEntry* entry) {
 | 
| +  // To calculate retained size, first we paint all reachable nodes in
 | 
| +  // one color (and calculate reachable size as a byproduct), then we
 | 
| +  // paint (or re-paint) all nodes reachable from other nodes with a
 | 
| +  // different color. Then we consider only nodes painted with the
 | 
| +  // first color for calculating the retained size.
 | 
| +  entry->snapshot()->ClearPaint();
 | 
| +  ReachableSizeCalculator rch_size_calc;
 | 
| +  entry->ApplyAndPaintAllReachable(&rch_size_calc);
 | 
| +  reachable_size_ = rch_size_calc.reachable_size();
 | 
|  
 | 
|    List<HeapEntry*> list(10);
 | 
| -  if (this != snapshot_->root()) {
 | 
| -    list.Add(snapshot_->root());
 | 
| -    snapshot_->root()->PaintReachableFromOthers();
 | 
| +  HeapEntry* root = entry->snapshot()->root();
 | 
| +  if (entry != root) {
 | 
| +    list.Add(root);
 | 
| +    root->paint_reachable_from_others();
 | 
|    }
 | 
|    while (!list.is_empty()) {
 | 
| -    HeapEntry* entry = list.RemoveLast();
 | 
| -    const int children_count = entry->children_.length();
 | 
| -    for (int i = 0; i < children_count; ++i) {
 | 
| -      HeapEntry* child = entry->children_[i]->to();
 | 
| -      if (child != this && child->not_painted_reachable_from_others()) {
 | 
| +    HeapEntry* curr = list.RemoveLast();
 | 
| +    Vector<HeapGraphEdge> children = curr->children();
 | 
| +    for (int i = 0; i < children.length(); ++i) {
 | 
| +      HeapEntry* child = children[i].to();
 | 
| +      if (child != entry && child->not_painted_reachable_from_others()) {
 | 
|          list.Add(child);
 | 
| -        child->PaintReachableFromOthers();
 | 
| +        child->paint_reachable_from_others();
 | 
|        }
 | 
|      }
 | 
|    }
 | 
|  
 | 
| -  NonSharedSizeCalculator calculator;
 | 
| -  snapshot_->IterateEntries(&calculator);
 | 
| -  non_shared_total_size_ = calculator.non_shared_total_size();
 | 
| -  return non_shared_total_size_;
 | 
| +  RetainedSizeCalculator ret_size_calc;
 | 
| +  entry->snapshot()->IterateEntries(&ret_size_calc);
 | 
| +  retained_size_ = ret_size_calc.reained_size();
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1019,124 +1118,33 @@ class CachedHeapGraphPath {
 | 
|  };
 | 
|  
 | 
|  
 | 
| -const List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
 | 
| -  if (retaining_paths_.length() == 0 && retainers_.length() != 0) {
 | 
| +List<HeapGraphPath*>* HeapEntryCalculatedData::GetRetainingPaths(
 | 
| +    HeapEntry* entry) {
 | 
| +  if (retaining_paths_ == NULL) retaining_paths_ = new List<HeapGraphPath*>(4);
 | 
| +  if (retaining_paths_->length() == 0 && entry->retainers().length() != 0) {
 | 
|      CachedHeapGraphPath path;
 | 
| -    FindRetainingPaths(this, &path);
 | 
| +    FindRetainingPaths(entry, &path);
 | 
|    }
 | 
| -  return &retaining_paths_;
 | 
| +  return retaining_paths_;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapEntry::FindRetainingPaths(HeapEntry* node,
 | 
| -                                   CachedHeapGraphPath* prev_path) {
 | 
| -  for (int i = 0; i < node->retainers_.length(); ++i) {
 | 
| -    HeapGraphEdge* ret_edge = node->retainers_[i];
 | 
| -    if (prev_path->ContainsNode(ret_edge->from())) continue;
 | 
| -    if (ret_edge->from() != snapshot_->root()) {
 | 
| +void HeapEntryCalculatedData::FindRetainingPaths(
 | 
| +    HeapEntry* entry,
 | 
| +    CachedHeapGraphPath* prev_path) {
 | 
| +  Vector<HeapGraphEdge*> retainers = entry->retainers();
 | 
| +  for (int i = 0; i < retainers.length(); ++i) {
 | 
| +    HeapGraphEdge* ret_edge = retainers[i];
 | 
| +    if (prev_path->ContainsNode(ret_edge->From())) continue;
 | 
| +    if (ret_edge->From() != entry->snapshot()->root()) {
 | 
|        CachedHeapGraphPath path(*prev_path);
 | 
|        path.Add(ret_edge);
 | 
| -      FindRetainingPaths(ret_edge->from(), &path);
 | 
| +      FindRetainingPaths(ret_edge->From(), &path);
 | 
|      } else {
 | 
|        HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path());
 | 
|        ret_path->Set(0, ret_edge);
 | 
| -      retaining_paths_.Add(ret_path);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static void RemoveEdge(List<HeapGraphEdge*>* list, HeapGraphEdge* edge) {
 | 
| -  for (int i = 0; i < list->length(); ) {
 | 
| -    if (list->at(i) == edge) {
 | 
| -      list->Remove(i);
 | 
| -      return;
 | 
| -    } else {
 | 
| -      ++i;
 | 
| -    }
 | 
| -  }
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::RemoveChild(HeapGraphEdge* edge) {
 | 
| -  RemoveEdge(&children_, edge);
 | 
| -  delete edge;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::RemoveRetainer(HeapGraphEdge* edge) {
 | 
| -  RemoveEdge(&retainers_, edge);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::CutEdges() {
 | 
| -  for (int i = 0; i < children_.length(); ++i) {
 | 
| -    HeapGraphEdge* edge = children_[i];
 | 
| -    edge->to()->RemoveRetainer(edge);
 | 
| -  }
 | 
| -  children_.Iterate(DeleteHeapGraphEdge);
 | 
| -  children_.Clear();
 | 
| -
 | 
| -  for (int i = 0; i < retainers_.length(); ++i) {
 | 
| -    HeapGraphEdge* edge = retainers_[i];
 | 
| -    edge->from()->RemoveChild(edge);
 | 
| -  }
 | 
| -  retainers_.Clear();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntry::Print(int max_depth, int indent) {
 | 
| -  OS::Print("%6d %6d %6d [%ld] ",
 | 
| -            self_size_, TotalSize(), NonSharedTotalSize(), id_);
 | 
| -  if (type_ != STRING) {
 | 
| -    OS::Print("%s %.40s\n", TypeAsString(), name_);
 | 
| -  } else {
 | 
| -    OS::Print("\"");
 | 
| -    const char* c = name_;
 | 
| -    while (*c && (c - name_) <= 40) {
 | 
| -      if (*c != '\n')
 | 
| -        OS::Print("%c", *c);
 | 
| -      else
 | 
| -        OS::Print("\\n");
 | 
| -      ++c;
 | 
| +      retaining_paths_->Add(ret_path);
 | 
|      }
 | 
| -    OS::Print("\"\n");
 | 
| -  }
 | 
| -  if (--max_depth == 0) return;
 | 
| -  const int children_count = children_.length();
 | 
| -  for (int i = 0; i < children_count; ++i) {
 | 
| -    HeapGraphEdge* edge = children_[i];
 | 
| -    switch (edge->type()) {
 | 
| -      case HeapGraphEdge::CONTEXT_VARIABLE:
 | 
| -        OS::Print("  %*c #%s: ", indent, ' ', edge->name());
 | 
| -        break;
 | 
| -      case HeapGraphEdge::ELEMENT:
 | 
| -        OS::Print("  %*c %d: ", indent, ' ', edge->index());
 | 
| -        break;
 | 
| -      case HeapGraphEdge::INTERNAL:
 | 
| -        OS::Print("  %*c $%s: ", indent, ' ', edge->name());
 | 
| -        break;
 | 
| -      case HeapGraphEdge::PROPERTY:
 | 
| -        OS::Print("  %*c %s: ", indent, ' ', edge->name());
 | 
| -        break;
 | 
| -      default:
 | 
| -        OS::Print("!!! unknown edge type: %d ", edge->type());
 | 
| -    }
 | 
| -    edge->to()->Print(max_depth, indent + 2);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -const char* HeapEntry::TypeAsString() {
 | 
| -  switch (type_) {
 | 
| -    case INTERNAL: return "/internal/";
 | 
| -    case OBJECT: return "/object/";
 | 
| -    case CLOSURE: return "/closure/";
 | 
| -    case STRING: return "/string/";
 | 
| -    case CODE: return "/code/";
 | 
| -    case ARRAY: return "/array/";
 | 
| -    default: return "???";
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -1151,21 +1159,21 @@ HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path)
 | 
|  
 | 
|  
 | 
|  void HeapGraphPath::Print() {
 | 
| -  path_[0]->from()->Print(1, 0);
 | 
| +  path_[0]->From()->Print(1, 0);
 | 
|    for (int i = 0; i < path_.length(); ++i) {
 | 
|      OS::Print(" -> ");
 | 
|      HeapGraphEdge* edge = path_[i];
 | 
|      switch (edge->type()) {
 | 
| -      case HeapGraphEdge::CONTEXT_VARIABLE:
 | 
| +      case HeapGraphEdge::kContextVariable:
 | 
|          OS::Print("[#%s] ", edge->name());
 | 
|          break;
 | 
| -      case HeapGraphEdge::ELEMENT:
 | 
| +      case HeapGraphEdge::kElement:
 | 
|          OS::Print("[%d] ", edge->index());
 | 
|          break;
 | 
| -      case HeapGraphEdge::INTERNAL:
 | 
| +      case HeapGraphEdge::kInternal:
 | 
|          OS::Print("[$%s] ", edge->name());
 | 
|          break;
 | 
| -      case HeapGraphEdge::PROPERTY:
 | 
| +      case HeapGraphEdge::kProperty:
 | 
|          OS::Print("[%s] ", edge->name());
 | 
|          break;
 | 
|        default:
 | 
| @@ -1177,76 +1185,8 @@ void HeapGraphPath::Print() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -class IndexedReferencesExtractor : public ObjectVisitor {
 | 
| - public:
 | 
| -  IndexedReferencesExtractor(HeapSnapshot* snapshot, HeapEntry* parent)
 | 
| -      : snapshot_(snapshot),
 | 
| -        parent_(parent) {
 | 
| -  }
 | 
| -
 | 
| -  void VisitPointer(Object** o) {
 | 
| -    if (!(*o)->IsHeapObject()) return;
 | 
| -    HeapEntry* entry = snapshot_->GetEntry(HeapObject::cast(*o));
 | 
| -    if (entry != NULL) {
 | 
| -      parent_->SetAutoIndexReference(entry);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void VisitPointers(Object** start, Object** end) {
 | 
| -    for (Object** p = start; p < end; p++) VisitPointer(p);
 | 
| -  }
 | 
| -
 | 
| - private:
 | 
| -  HeapSnapshot* snapshot_;
 | 
| -  HeapEntry* parent_;
 | 
| -};
 | 
| -
 | 
| -
 | 
| -HeapEntriesMap::HeapEntriesMap()
 | 
| -    : entries_(HeapObjectsMatch) {
 | 
| -}
 | 
| -
 | 
| -
 | 
| -HeapEntriesMap::~HeapEntriesMap() {
 | 
| -  for (HashMap::Entry* p = entries_.Start();
 | 
| -       p != NULL;
 | 
| -       p = entries_.Next(p)) {
 | 
| -    if (!IsAlias(p->value)) delete reinterpret_cast<HeapEntry*>(p->value);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntriesMap::Alias(HeapObject* object, HeapEntry* entry) {
 | 
| -  HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
 | 
| -  if (cache_entry->value == NULL)
 | 
| -    cache_entry->value = reinterpret_cast<void*>(
 | 
| -        reinterpret_cast<intptr_t>(entry) | kAliasTag);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntriesMap::Apply(void (HeapEntry::*Func)(void)) {
 | 
| -  for (HashMap::Entry* p = entries_.Start();
 | 
| -       p != NULL;
 | 
| -       p = entries_.Next(p)) {
 | 
| -    if (!IsAlias(p->value)) (reinterpret_cast<HeapEntry*>(p->value)->*Func)();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -HeapEntry* HeapEntriesMap::Map(HeapObject* object) {
 | 
| -  HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false);
 | 
| -  return cache_entry != NULL ?
 | 
| -      reinterpret_cast<HeapEntry*>(
 | 
| -          reinterpret_cast<intptr_t>(cache_entry->value) & (~kAliasTag)) : NULL;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) {
 | 
| -  HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
 | 
| -  ASSERT(cache_entry->value == NULL);
 | 
| -  cache_entry->value = entry;
 | 
| -}
 | 
| -
 | 
| +HeapObject *const HeapSnapshot::kInternalRootObject =
 | 
| +    reinterpret_cast<HeapObject*>(1);
 | 
|  
 | 
|  HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
 | 
|                             const char* title,
 | 
| @@ -1254,176 +1194,151 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
 | 
|      : collection_(collection),
 | 
|        title_(title),
 | 
|        uid_(uid),
 | 
| -      root_(this),
 | 
| -      sorted_entries_(NULL) {
 | 
| +      root_entry_index_(-1),
 | 
| +      raw_entries_(NULL),
 | 
| +      entries_sorted_(false) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -HeapSnapshot::~HeapSnapshot() {
 | 
| -  delete sorted_entries_;
 | 
| +static void DisposeCalculatedData(HeapEntryCalculatedData* cdata) {
 | 
| +  cdata->Dispose();
 | 
|  }
 | 
|  
 | 
| -
 | 
| -void HeapSnapshot::ClearPaint() {
 | 
| -  root_.ClearPaint();
 | 
| -  entries_.Apply(&HeapEntry::ClearPaint);
 | 
| +HeapSnapshot::~HeapSnapshot() {
 | 
| +  DeleteArray(raw_entries_);
 | 
| +  calculated_data_.Iterate(DisposeCalculatedData);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -HeapEntry* HeapSnapshot::GetEntry(Object* obj) {
 | 
| -  if (!obj->IsHeapObject()) return NULL;
 | 
| -  HeapObject* object = HeapObject::cast(obj);
 | 
| +void HeapSnapshot::AllocateEntries(int entries_count,
 | 
| +                                   int children_count,
 | 
| +                                   int retainers_count) {
 | 
| +  ASSERT(raw_entries_ == NULL);
 | 
| +  raw_entries_ = NewArray<char>(
 | 
| +      HeapEntry::EntriesSize(entries_count, children_count, retainers_count));
 | 
| +}
 | 
|  
 | 
| -  {
 | 
| -    HeapEntry* existing = FindEntry(object);
 | 
| -    if (existing != NULL) return existing;
 | 
| -  }
 | 
|  
 | 
| -  // Add new entry.
 | 
| -  if (object->IsJSFunction()) {
 | 
| +HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
 | 
| +                                  int children_count,
 | 
| +                                  int retainers_count) {
 | 
| +  if (object == kInternalRootObject) {
 | 
| +    ASSERT(root_entry_index_ == -1);
 | 
| +    root_entry_index_ = entries_.length();
 | 
| +    HeapEntry* entry = GetNextEntryToInit();
 | 
| +    entry->Init(this, children_count, retainers_count);
 | 
| +    return entry;
 | 
| +  } else if (object->IsJSFunction()) {
 | 
|      JSFunction* func = JSFunction::cast(object);
 | 
|      SharedFunctionInfo* shared = func->shared();
 | 
|      String* name = String::cast(shared->name())->length() > 0 ?
 | 
|          String::cast(shared->name()) : shared->inferred_name();
 | 
| -    return AddEntry(object, HeapEntry::CLOSURE, collection_->GetName(name));
 | 
| +    return AddEntry(object,
 | 
| +                    HeapEntry::kClosure,
 | 
| +                    collection_->GetName(name),
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    } else if (object->IsJSObject()) {
 | 
|      return AddEntry(object,
 | 
| -                    HeapEntry::OBJECT,
 | 
| +                    HeapEntry::kObject,
 | 
|                      collection_->GetName(
 | 
| -                        JSObject::cast(object)->constructor_name()));
 | 
| -  } else if (object->IsJSGlobalPropertyCell()) {
 | 
| -    HeapEntry* value = GetEntry(JSGlobalPropertyCell::cast(object)->value());
 | 
| -    // If GPC references an object that we have interest in, add the object.
 | 
| -    // We don't store HeapEntries for GPCs. Instead, we make our hash map
 | 
| -    // to point to object's HeapEntry by GPCs address.
 | 
| -    if (value != NULL) AddEntryAlias(object, value);
 | 
| -    return value;
 | 
| +                        JSObject::cast(object)->constructor_name()),
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    } else if (object->IsString()) {
 | 
|      return AddEntry(object,
 | 
| -                    HeapEntry::STRING,
 | 
| -                    collection_->GetName(String::cast(object)));
 | 
| +                    HeapEntry::kString,
 | 
| +                    collection_->GetName(String::cast(object)),
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    } else if (object->IsCode()) {
 | 
| -    return AddEntry(object, HeapEntry::CODE);
 | 
| +    return AddEntry(object,
 | 
| +                    HeapEntry::kCode,
 | 
| +                    "",
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    } else if (object->IsSharedFunctionInfo()) {
 | 
|      SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
 | 
|      String* name = String::cast(shared->name())->length() > 0 ?
 | 
|          String::cast(shared->name()) : shared->inferred_name();
 | 
| -    return AddEntry(object, HeapEntry::CODE, collection_->GetName(name));
 | 
| +    return AddEntry(object,
 | 
| +                    HeapEntry::kCode,
 | 
| +                    collection_->GetName(name),
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    } else if (object->IsScript()) {
 | 
|      Script* script = Script::cast(object);
 | 
|      return AddEntry(object,
 | 
| -                    HeapEntry::CODE,
 | 
| +                    HeapEntry::kCode,
 | 
|                      script->name()->IsString() ?
 | 
| -                    collection_->GetName(String::cast(script->name())) : "");
 | 
| +                    collection_->GetName(String::cast(script->name())) : "",
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    } else if (object->IsFixedArray()) {
 | 
| -    return AddEntry(object, HeapEntry::ARRAY);
 | 
| +    return AddEntry(object,
 | 
| +                    HeapEntry::kArray,
 | 
| +                    "",
 | 
| +                    children_count,
 | 
| +                    retainers_count);
 | 
|    }
 | 
|    // No interest in this object.
 | 
|    return NULL;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapSnapshot::SetClosureReference(HeapEntry* parent,
 | 
| -                                       String* reference_name,
 | 
| -                                       Object* child) {
 | 
| -  HeapEntry* child_entry = GetEntry(child);
 | 
| -  if (child_entry != NULL) {
 | 
| -    parent->SetClosureReference(
 | 
| -        collection_->GetName(reference_name), child_entry);
 | 
| -  }
 | 
| +bool HeapSnapshot::WillAddEntry(HeapObject* object) {
 | 
| +  return object == kInternalRootObject
 | 
| +      || object->IsJSFunction()
 | 
| +      || object->IsJSObject()
 | 
| +      || object->IsString()
 | 
| +      || object->IsCode()
 | 
| +      || object->IsSharedFunctionInfo()
 | 
| +      || object->IsScript()
 | 
| +      || object->IsFixedArray();
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapSnapshot::SetElementReference(HeapEntry* parent,
 | 
| -                                       int index,
 | 
| -                                       Object* child) {
 | 
| -  HeapEntry* child_entry = GetEntry(child);
 | 
| -  if (child_entry != NULL) {
 | 
| -    parent->SetElementReference(index, child_entry);
 | 
| -  }
 | 
| +static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
 | 
| +  (*entry_ptr)->clear_paint();
 | 
|  }
 | 
|  
 | 
| -
 | 
| -void HeapSnapshot::SetInternalReference(HeapEntry* parent,
 | 
| -                                        const char* reference_name,
 | 
| -                                        Object* child) {
 | 
| -  HeapEntry* child_entry = GetEntry(child);
 | 
| -  if (child_entry != NULL) {
 | 
| -    parent->SetInternalReference(reference_name, child_entry);
 | 
| -  }
 | 
| +void HeapSnapshot::ClearPaint() {
 | 
| +  entries_.Iterate(HeapEntryClearPaint);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HeapSnapshot::SetPropertyReference(HeapEntry* parent,
 | 
| -                                        String* reference_name,
 | 
| -                                        Object* child) {
 | 
| -  HeapEntry* child_entry = GetEntry(child);
 | 
| -  if (child_entry != NULL) {
 | 
| -    parent->SetPropertyReference(
 | 
| -        collection_->GetName(reference_name), child_entry);
 | 
| -  }
 | 
| +int HeapSnapshot::AddCalculatedData() {
 | 
| +  calculated_data_.Add(HeapEntryCalculatedData());
 | 
| +  return calculated_data_.length() - 1;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
 | 
|                                    HeapEntry::Type type,
 | 
| -                                  const char* name) {
 | 
| -  HeapEntry* entry = new HeapEntry(this,
 | 
| -                                   type,
 | 
| -                                   name,
 | 
| -                                   collection_->GetObjectId(object->address()),
 | 
| -                                   GetObjectSize(object),
 | 
| -                                   GetObjectSecurityToken(object));
 | 
| -  entries_.Pair(object, entry);
 | 
| -
 | 
| -  // Detect, if this is a JS global object of the current context, and
 | 
| -  // add it to snapshot's roots. There can be several JS global objects
 | 
| -  // in a context.
 | 
| -  if (object->IsJSGlobalProxy()) {
 | 
| -    int global_security_token = GetGlobalSecurityToken();
 | 
| -    int object_security_token =
 | 
| -        collection_->token_enumerator()->GetTokenId(
 | 
| -            Context::cast(
 | 
| -                JSGlobalProxy::cast(object)->context())->security_token());
 | 
| -    if (object_security_token == TokenEnumerator::kNoSecurityToken
 | 
| -        || object_security_token == global_security_token) {
 | 
| -      HeapEntry* global_object_entry =
 | 
| -          GetEntry(HeapObject::cast(object->map()->prototype()));
 | 
| -      ASSERT(global_object_entry != NULL);
 | 
| -      root_.SetAutoIndexReference(global_object_entry);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| +                                  const char* name,
 | 
| +                                  int children_count,
 | 
| +                                  int retainers_count) {
 | 
| +  HeapEntry* entry = GetNextEntryToInit();
 | 
| +  entry->Init(this,
 | 
| +              type,
 | 
| +              name,
 | 
| +              collection_->GetObjectId(object->address()),
 | 
| +              GetObjectSize(object),
 | 
| +              children_count,
 | 
| +              retainers_count);
 | 
|    return entry;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -class EdgesCutter {
 | 
| - public:
 | 
| -  explicit EdgesCutter(int global_security_token)
 | 
| -      : global_security_token_(global_security_token) {
 | 
| -  }
 | 
| -
 | 
| -  void Apply(HeapEntry* entry) {
 | 
| -    if (entry->security_token_id() != TokenEnumerator::kNoSecurityToken
 | 
| -        && entry->security_token_id() != global_security_token_) {
 | 
| -      entry->CutEdges();
 | 
| -    }
 | 
| +HeapEntry* HeapSnapshot::GetNextEntryToInit() {
 | 
| +  if (entries_.length() > 0) {
 | 
| +    HeapEntry* last_entry = entries_.last();
 | 
| +    entries_.Add(reinterpret_cast<HeapEntry*>(
 | 
| +        reinterpret_cast<char*>(last_entry) + last_entry->EntrySize()));
 | 
| +  } else {
 | 
| +    entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_));
 | 
|    }
 | 
| -
 | 
| - private:
 | 
| -  const int global_security_token_;
 | 
| -};
 | 
| -
 | 
| -void HeapSnapshot::CutObjectsFromForeignSecurityContexts() {
 | 
| -  EdgesCutter cutter(GetGlobalSecurityToken());
 | 
| -  entries_.Apply(&cutter);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -int HeapSnapshot::GetGlobalSecurityToken() {
 | 
| -  return collection_->token_enumerator()->GetTokenId(
 | 
| -      Top::context()->global()->global_context()->security_token());
 | 
| +  return entries_.last();
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1433,16 +1348,6 @@ int HeapSnapshot::GetObjectSize(HeapObject* obj) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -int HeapSnapshot::GetObjectSecurityToken(HeapObject* obj) {
 | 
| -  if (obj->IsGlobalContext()) {
 | 
| -    return collection_->token_enumerator()->GetTokenId(
 | 
| -        Context::cast(obj)->security_token());
 | 
| -  } else {
 | 
| -    return TokenEnumerator::kNoSecurityToken;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
|  int HeapSnapshot::CalculateNetworkSize(JSObject* obj) {
 | 
|    int size = obj->Size();
 | 
|    // If 'properties' and 'elements' are non-empty (thus, non-shared),
 | 
| @@ -1467,15 +1372,10 @@ int HeapSnapshot::CalculateNetworkSize(JSObject* obj) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -class EntriesCollector {
 | 
| - public:
 | 
| -  explicit EntriesCollector(List<HeapEntry*>* list) : list_(list) { }
 | 
| -  void Apply(HeapEntry* entry) {
 | 
| -    list_->Add(entry);
 | 
| -  }
 | 
| - private:
 | 
| -  List<HeapEntry*>* list_;
 | 
| -};
 | 
| +HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
 | 
| +  return collection_->CompareSnapshots(this, snapshot);
 | 
| +}
 | 
| +
 | 
|  
 | 
|  template<class T>
 | 
|  static int SortByIds(const T* entry1_ptr,
 | 
| @@ -1485,22 +1385,16 @@ static int SortByIds(const T* entry1_ptr,
 | 
|  }
 | 
|  
 | 
|  List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
 | 
| -  if (sorted_entries_ != NULL) return sorted_entries_;
 | 
| -  sorted_entries_ = new List<HeapEntry*>(entries_.capacity());
 | 
| -  EntriesCollector collector(sorted_entries_);
 | 
| -  entries_.Apply(&collector);
 | 
| -  sorted_entries_->Sort(SortByIds);
 | 
| -  return sorted_entries_;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
 | 
| -  return collection_->CompareSnapshots(this, snapshot);
 | 
| +  if (!entries_sorted_) {
 | 
| +    entries_.Sort(SortByIds);
 | 
| +    entries_sorted_ = true;
 | 
| +  }
 | 
| +  return &entries_;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void HeapSnapshot::Print(int max_depth) {
 | 
| -  root_.Print(max_depth, 0);
 | 
| +  root()->Print(max_depth, 0);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1635,53 +1529,343 @@ HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots(
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HeapEntriesMap::HeapEntriesMap()
 | 
| +    : entries_(HeapObjectsMatch),
 | 
| +      entries_count_(0),
 | 
| +      total_children_count_(0),
 | 
| +      total_retainers_count_(0) {
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HeapEntriesMap::~HeapEntriesMap() {
 | 
| +  for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) {
 | 
| +    if (!IsAlias(p->value)) delete reinterpret_cast<EntryInfo*>(p->value);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapEntriesMap::Alias(HeapObject* from, HeapObject* to) {
 | 
| +  HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true);
 | 
| +  HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
 | 
| +  if (from_cache_entry->value == NULL) {
 | 
| +    ASSERT(to_cache_entry != NULL);
 | 
| +    from_cache_entry->value = MakeAlias(to_cache_entry->value);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HeapEntry* HeapEntriesMap::Map(HeapObject* object) {
 | 
| +  HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false);
 | 
| +  if (cache_entry != NULL) {
 | 
| +    EntryInfo* entry_info =
 | 
| +        reinterpret_cast<EntryInfo*>(Unalias(cache_entry->value));
 | 
| +    return entry_info->entry;
 | 
| +  } else {
 | 
| +    return NULL;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) {
 | 
| +  HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
 | 
| +  ASSERT(cache_entry->value == NULL);
 | 
| +  cache_entry->value = new EntryInfo(entry);
 | 
| +  ++entries_count_;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to,
 | 
| +                                    int* prev_children_count,
 | 
| +                                    int* prev_retainers_count) {
 | 
| +  HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true);
 | 
| +  HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
 | 
| +  ASSERT(from_cache_entry != NULL);
 | 
| +  ASSERT(to_cache_entry != NULL);
 | 
| +  EntryInfo* from_entry_info =
 | 
| +      reinterpret_cast<EntryInfo*>(Unalias(from_cache_entry->value));
 | 
| +  EntryInfo* to_entry_info =
 | 
| +      reinterpret_cast<EntryInfo*>(Unalias(to_cache_entry->value));
 | 
| +  if (prev_children_count)
 | 
| +    *prev_children_count = from_entry_info->children_count;
 | 
| +  if (prev_retainers_count)
 | 
| +    *prev_retainers_count = to_entry_info->retainers_count;
 | 
| +  ++from_entry_info->children_count;
 | 
| +  ++to_entry_info->retainers_count;
 | 
| +  ++total_children_count_;
 | 
| +  ++total_retainers_count_;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +template<class Visitor>
 | 
| +void HeapEntriesMap::UpdateEntries(Visitor* visitor) {
 | 
| +  for (HashMap::Entry* p = entries_.Start();
 | 
| +       p != NULL;
 | 
| +       p = entries_.Next(p)) {
 | 
| +    if (!IsAlias(p->value)) {
 | 
| +      EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
 | 
| +      entry_info->entry = visitor->GetEntry(
 | 
| +          reinterpret_cast<HeapObject*>(p->key),
 | 
| +          entry_info->children_count,
 | 
| +          entry_info->retainers_count);
 | 
| +      entry_info->children_count = 0;
 | 
| +      entry_info->retainers_count = 0;
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot)
 | 
| -    : snapshot_(snapshot) {
 | 
| +    : snapshot_(snapshot),
 | 
| +      collection_(snapshot->collection()),
 | 
| +      filler_(NULL) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HeapEntry *const
 | 
| +HeapSnapshotGenerator::SnapshotFillerInterface::kHeapEntryPlaceholder =
 | 
| +    reinterpret_cast<HeapEntry*>(1);
 | 
| +
 | 
| +class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface {
 | 
| + public:
 | 
| +  explicit SnapshotCounter(HeapEntriesMap* entries)
 | 
| +      : entries_(entries) { }
 | 
| +  HeapEntry* AddEntry(HeapObject* obj) {
 | 
| +    entries_->Pair(obj, kHeapEntryPlaceholder);
 | 
| +    return kHeapEntryPlaceholder;
 | 
| +  }
 | 
| +  void SetElementReference(HeapObject* parent_obj,
 | 
| +                           HeapEntry*,
 | 
| +                           int,
 | 
| +                           Object* child_obj,
 | 
| +                           HeapEntry*) {
 | 
| +    entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
 | 
| +  }
 | 
| +  void SetNamedReference(HeapGraphEdge::Type,
 | 
| +                         HeapObject* parent_obj,
 | 
| +                         HeapEntry*,
 | 
| +                         const char*,
 | 
| +                         Object* child_obj,
 | 
| +                         HeapEntry*) {
 | 
| +    entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
 | 
| +  }
 | 
| +  void SetRootReference(Object* child_obj, HeapEntry*) {
 | 
| +    entries_->CountReference(
 | 
| +        HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj));
 | 
| +  }
 | 
| + private:
 | 
| +  HeapEntriesMap* entries_;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface {
 | 
| + public:
 | 
| +  explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
 | 
| +      : snapshot_(snapshot),
 | 
| +        collection_(snapshot->collection()),
 | 
| +        entries_(entries) { }
 | 
| +  HeapEntry* AddEntry(HeapObject* obj) {
 | 
| +    UNREACHABLE();
 | 
| +    return NULL;
 | 
| +  }
 | 
| +  void SetElementReference(HeapObject* parent_obj,
 | 
| +                           HeapEntry* parent_entry,
 | 
| +                           int index,
 | 
| +                           Object* child_obj,
 | 
| +                           HeapEntry* child_entry) {
 | 
| +    int child_index, retainer_index;
 | 
| +    entries_->CountReference(parent_obj, HeapObject::cast(child_obj),
 | 
| +                             &child_index, &retainer_index);
 | 
| +    parent_entry->SetElementReference(
 | 
| +        child_index, index, child_entry, retainer_index);
 | 
| +  }
 | 
| +  void SetNamedReference(HeapGraphEdge::Type type,
 | 
| +                         HeapObject* parent_obj,
 | 
| +                         HeapEntry* parent_entry,
 | 
| +                         const char* reference_name,
 | 
| +                         Object* child_obj,
 | 
| +                         HeapEntry* child_entry) {
 | 
| +    int child_index, retainer_index;
 | 
| +    entries_->CountReference(parent_obj, HeapObject::cast(child_obj),
 | 
| +                             &child_index, &retainer_index);
 | 
| +    parent_entry->SetNamedReference(type,
 | 
| +                              child_index,
 | 
| +                              reference_name,
 | 
| +                              child_entry,
 | 
| +                              retainer_index);
 | 
| +  }
 | 
| +  void SetRootReference(Object* child_obj, HeapEntry* child_entry) {
 | 
| +    int child_index, retainer_index;
 | 
| +    entries_->CountReference(
 | 
| +        HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj),
 | 
| +        &child_index, &retainer_index);
 | 
| +    snapshot_->root()->SetElementReference(
 | 
| +        child_index, child_index + 1, child_entry, retainer_index);
 | 
| +  }
 | 
| + private:
 | 
| +  HeapSnapshot* snapshot_;
 | 
| +  HeapSnapshotsCollection* collection_;
 | 
| +  HeapEntriesMap* entries_;
 | 
| +};
 | 
| +
 | 
| +class SnapshotAllocator {
 | 
| + public:
 | 
| +  explicit SnapshotAllocator(HeapSnapshot* snapshot)
 | 
| +      : snapshot_(snapshot) { }
 | 
| +  HeapEntry* GetEntry(
 | 
| +      HeapObject* obj, int children_count, int retainers_count) {
 | 
| +    HeapEntry* entry =
 | 
| +        snapshot_->AddEntry(obj, children_count, retainers_count);
 | 
| +    ASSERT(entry != NULL);
 | 
| +    return entry;
 | 
| +  }
 | 
| + private:
 | 
| +  HeapSnapshot* snapshot_;
 | 
| +};
 | 
| +
 | 
|  void HeapSnapshotGenerator::GenerateSnapshot() {
 | 
|    AssertNoAllocation no_alloc;
 | 
|  
 | 
| -  // Iterate heap contents.
 | 
| -  HeapIterator iterator;
 | 
| -  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
 | 
| +  // Pass 1. Iterate heap contents to count entries and references.
 | 
| +  SnapshotCounter counter(&entries_);
 | 
| +  filler_ = &counter;
 | 
| +  filler_->AddEntry(HeapSnapshot::kInternalRootObject);
 | 
| +  HeapIterator iterator1;
 | 
| +  for (HeapObject* obj = iterator1.next();
 | 
| +       obj != NULL;
 | 
| +       obj = iterator1.next()) {
 | 
|      ExtractReferences(obj);
 | 
|    }
 | 
|  
 | 
| -  snapshot_->CutObjectsFromForeignSecurityContexts();
 | 
| +  // Allocate and fill entries in the snapshot, allocate references.
 | 
| +  snapshot_->AllocateEntries(entries_.entries_count(),
 | 
| +                             entries_.total_children_count(),
 | 
| +                             entries_.total_retainers_count());
 | 
| +  SnapshotAllocator allocator(snapshot_);
 | 
| +  entries_.UpdateEntries(&allocator);
 | 
| +
 | 
| +  // Pass 2. Fill references.
 | 
| +  SnapshotFiller filler(snapshot_, &entries_);
 | 
| +  filler_ = &filler;
 | 
| +  HeapIterator iterator2;
 | 
| +  for (HeapObject* obj = iterator2.next();
 | 
| +       obj != NULL;
 | 
| +       obj = iterator2.next()) {
 | 
| +    ExtractReferences(obj);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) {
 | 
| +  if (!obj->IsHeapObject()) return NULL;
 | 
| +  HeapObject* object = HeapObject::cast(obj);
 | 
| +  HeapEntry* entry = entries_.Map(object);
 | 
| +
 | 
| +  // A new entry.
 | 
| +  if (entry == NULL) {
 | 
| +    if (obj->IsJSGlobalPropertyCell()) {
 | 
| +      Object* cell_target = JSGlobalPropertyCell::cast(obj)->value();
 | 
| +      entry = GetEntry(cell_target);
 | 
| +      // If GPC references an object that we have interest in (see
 | 
| +      // HeapSnapshot::AddEntry, WillAddEntry), add the object.  We
 | 
| +      // don't store HeapEntries for GPCs. Instead, we make our hash
 | 
| +      // map to point to object's HeapEntry by GPCs address.
 | 
| +      if (entry != NULL) {
 | 
| +        entries_.Alias(object, HeapObject::cast(cell_target));
 | 
| +      }
 | 
| +      return entry;
 | 
| +    }
 | 
| +
 | 
| +    if (snapshot_->WillAddEntry(object)) entry = filler_->AddEntry(object);
 | 
| +  }
 | 
| +
 | 
| +  return entry;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +int HeapSnapshotGenerator::GetGlobalSecurityToken() {
 | 
| +  return collection_->token_enumerator()->GetTokenId(
 | 
| +      Top::context()->global()->global_context()->security_token());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +int HeapSnapshotGenerator::GetObjectSecurityToken(HeapObject* obj) {
 | 
| +  if (obj->IsGlobalContext()) {
 | 
| +    return collection_->token_enumerator()->GetTokenId(
 | 
| +        Context::cast(obj)->security_token());
 | 
| +  } else {
 | 
| +    return TokenEnumerator::kNoSecurityToken;
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  
 | 
| +class IndexedReferencesExtractor : public ObjectVisitor {
 | 
| + public:
 | 
| +  IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
 | 
| +                             HeapObject* parent_obj,
 | 
| +                             HeapEntry* parent_entry)
 | 
| +      : generator_(generator),
 | 
| +        parent_obj_(parent_obj),
 | 
| +        parent_(parent_entry),
 | 
| +        next_index_(1) {
 | 
| +  }
 | 
| +
 | 
| +  void VisitPointer(Object** o) {
 | 
| +    generator_->SetElementReference(parent_obj_, parent_, next_index_++, *o);
 | 
| +  }
 | 
| +
 | 
| +  void VisitPointers(Object** start, Object** end) {
 | 
| +    for (Object** p = start; p < end; p++) VisitPointer(p);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  HeapSnapshotGenerator* generator_;
 | 
| +  HeapObject* parent_obj_;
 | 
| +  HeapEntry* parent_;
 | 
| +  int next_index_;
 | 
| +};
 | 
| +
 | 
| +
 | 
|  void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
 | 
| -  HeapEntry* entry = snapshot_->GetEntry(obj);
 | 
| -  if (entry == NULL) return;
 | 
| -  if (entry->visited()) return;
 | 
| +  // We need to reference JS global objects from snapshot's root.
 | 
| +  // We also need to only include global objects from the current
 | 
| +  // security context. And we don't want to add the global proxy,
 | 
| +  // as we don't have a special type for it.
 | 
| +  if (obj->IsJSGlobalProxy()) {
 | 
| +    int global_security_token = GetGlobalSecurityToken();
 | 
| +    JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
 | 
| +    int object_security_token =
 | 
| +        collection_->token_enumerator()->GetTokenId(
 | 
| +            Context::cast(proxy->context())->security_token());
 | 
| +    if (object_security_token == TokenEnumerator::kNoSecurityToken
 | 
| +        || object_security_token == global_security_token) {
 | 
| +      SetRootReference(proxy->map()->prototype());
 | 
| +    }
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  HeapEntry* entry = GetEntry(obj);
 | 
| +  if (entry == NULL) return;  // No interest in this object.
 | 
|  
 | 
|    if (obj->IsJSObject()) {
 | 
|      JSObject* js_obj = JSObject::cast(obj);
 | 
|      ExtractClosureReferences(js_obj, entry);
 | 
|      ExtractPropertyReferences(js_obj, entry);
 | 
|      ExtractElementReferences(js_obj, entry);
 | 
| -    snapshot_->SetPropertyReference(
 | 
| -        entry, Heap::prototype_symbol(), js_obj->map()->prototype());
 | 
| -  } else if (obj->IsJSGlobalPropertyCell()) {
 | 
| -    JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(obj);
 | 
| -    snapshot_->SetElementReference(entry, 0, cell->value());
 | 
| +    SetPropertyReference(
 | 
| +        obj, entry, Heap::prototype_symbol(), js_obj->map()->prototype());
 | 
|    } else if (obj->IsString()) {
 | 
|      if (obj->IsConsString()) {
 | 
|        ConsString* cs = ConsString::cast(obj);
 | 
| -      snapshot_->SetElementReference(entry, 0, cs->first());
 | 
| -      snapshot_->SetElementReference(entry, 1, cs->second());
 | 
| +      SetElementReference(obj, entry, 0, cs->first());
 | 
| +      SetElementReference(obj, entry, 1, cs->second());
 | 
|      }
 | 
|    } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
 | 
| -    IndexedReferencesExtractor refs_extractor(snapshot_, entry);
 | 
| +    IndexedReferencesExtractor refs_extractor(this, obj, entry);
 | 
|      obj->Iterate(&refs_extractor);
 | 
|    } else if (obj->IsFixedArray()) {
 | 
| -    IndexedReferencesExtractor refs_extractor(snapshot_, entry);
 | 
| +    IndexedReferencesExtractor refs_extractor(this, obj, entry);
 | 
|      obj->Iterate(&refs_extractor);
 | 
|    }
 | 
| -  entry->MarkAsVisited();
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1700,10 +1884,10 @@ void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj,
 | 
|        String* local_name = *zone_scope_info.LocalName(i);
 | 
|        int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL);
 | 
|        if (idx >= 0 && idx < context->length()) {
 | 
| -        snapshot_->SetClosureReference(entry, local_name, context->get(idx));
 | 
| +        SetClosureReference(js_obj, entry, local_name, context->get(idx));
 | 
|        }
 | 
|      }
 | 
| -    snapshot_->SetInternalReference(entry, "code", func->shared());
 | 
| +    SetInternalReference(js_obj, entry, "code", func->shared());
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -1716,13 +1900,13 @@ void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj,
 | 
|        switch (descs->GetType(i)) {
 | 
|          case FIELD: {
 | 
|            int index = descs->GetFieldIndex(i);
 | 
| -          snapshot_->SetPropertyReference(
 | 
| -              entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
 | 
| +          SetPropertyReference(
 | 
| +              js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
 | 
|            break;
 | 
|          }
 | 
|          case CONSTANT_FUNCTION:
 | 
| -          snapshot_->SetPropertyReference(
 | 
| -              entry, descs->GetKey(i), descs->GetConstantFunction(i));
 | 
| +          SetPropertyReference(
 | 
| +              js_obj, entry, descs->GetKey(i), descs->GetConstantFunction(i));
 | 
|            break;
 | 
|          default: ;
 | 
|        }
 | 
| @@ -1733,8 +1917,8 @@ void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj,
 | 
|      for (int i = 0; i < length; ++i) {
 | 
|        Object* k = dictionary->KeyAt(i);
 | 
|        if (dictionary->IsKey(k)) {
 | 
| -        snapshot_->SetPropertyReference(
 | 
| -            entry, String::cast(k), dictionary->ValueAt(i));
 | 
| +        SetPropertyReference(
 | 
| +            js_obj, entry, String::cast(k), dictionary->ValueAt(i));
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| @@ -1750,7 +1934,7 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj,
 | 
|          elements->length();
 | 
|      for (int i = 0; i < length; ++i) {
 | 
|        if (!elements->get(i)->IsTheHole()) {
 | 
| -        snapshot_->SetElementReference(entry, i, elements->get(i));
 | 
| +        SetElementReference(js_obj, entry, i, elements->get(i));
 | 
|        }
 | 
|      }
 | 
|    } else if (js_obj->HasDictionaryElements()) {
 | 
| @@ -1761,13 +1945,90 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj,
 | 
|        if (dictionary->IsKey(k)) {
 | 
|          ASSERT(k->IsNumber());
 | 
|          uint32_t index = static_cast<uint32_t>(k->Number());
 | 
| -        snapshot_->SetElementReference(entry, index, dictionary->ValueAt(i));
 | 
| +        SetElementReference(js_obj, entry, index, dictionary->ValueAt(i));
 | 
|        }
 | 
|      }
 | 
|    }
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj,
 | 
| +                                                HeapEntry* parent_entry,
 | 
| +                                                String* reference_name,
 | 
| +                                                Object* child_obj) {
 | 
| +  HeapEntry* child_entry = GetEntry(child_obj);
 | 
| +  if (child_entry != NULL) {
 | 
| +    filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
 | 
| +                               parent_obj,
 | 
| +                               parent_entry,
 | 
| +                               collection_->GetName(reference_name),
 | 
| +                               child_obj,
 | 
| +                               child_entry);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj,
 | 
| +                                                HeapEntry* parent_entry,
 | 
| +                                                int index,
 | 
| +                                                Object* child_obj) {
 | 
| +  HeapEntry* child_entry = GetEntry(child_obj);
 | 
| +  if (child_entry != NULL) {
 | 
| +    filler_->SetElementReference(
 | 
| +        parent_obj, parent_entry, index, child_obj, child_entry);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj,
 | 
| +                                                 HeapEntry* parent_entry,
 | 
| +                                                 const char* reference_name,
 | 
| +                                                 Object* child_obj) {
 | 
| +  HeapEntry* child_entry = GetEntry(child_obj);
 | 
| +  if (child_entry != NULL) {
 | 
| +    filler_->SetNamedReference(HeapGraphEdge::kInternal,
 | 
| +                               parent_obj,
 | 
| +                               parent_entry,
 | 
| +                               reference_name,
 | 
| +                               child_obj,
 | 
| +                               child_entry);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj,
 | 
| +                                                 HeapEntry* parent_entry,
 | 
| +                                                 String* reference_name,
 | 
| +                                                 Object* child_obj) {
 | 
| +  HeapEntry* child_entry = GetEntry(child_obj);
 | 
| +  if (child_entry != NULL) {
 | 
| +    filler_->SetNamedReference(HeapGraphEdge::kProperty,
 | 
| +                               parent_obj,
 | 
| +                               parent_entry,
 | 
| +                               collection_->GetName(reference_name),
 | 
| +                               child_obj,
 | 
| +                               child_entry);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapSnapshotGenerator::SetRootReference(Object* child_obj) {
 | 
| +  HeapEntry* child_entry = GetEntry(child_obj);
 | 
| +  ASSERT(child_entry != NULL);
 | 
| +  filler_->SetRootReference(child_obj, child_entry);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) {
 | 
| +  raw_additions_root_ =
 | 
| +      NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0));
 | 
| +  additions_root()->Init(snapshot2_, additions_count, 0);
 | 
| +  raw_deletions_root_ =
 | 
| +      NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0));
 | 
| +  deletions_root()->Init(snapshot1_, deletions_count, 0);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) {
 | 
|    delete *diff_ptr;
 | 
|  }
 | 
| @@ -1779,8 +2040,6 @@ HeapSnapshotsComparator::~HeapSnapshotsComparator() {
 | 
|  
 | 
|  HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1,
 | 
|                                                      HeapSnapshot* snapshot2) {
 | 
| -  HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2);
 | 
| -  diffs_.Add(diff);
 | 
|    List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList();
 | 
|    List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList();
 | 
|    int i = 0, j = 0;
 | 
| @@ -1810,17 +2069,33 @@ HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1,
 | 
|  
 | 
|    snapshot1->ClearPaint();
 | 
|    snapshot1->root()->PaintAllReachable();
 | 
| +  snapshot2->ClearPaint();
 | 
| +  snapshot2->root()->PaintAllReachable();
 | 
| +  int reachable_deleted_entries = 0, reachable_added_entries = 0;
 | 
| +  for (int i = 0; i < deleted_entries.length(); ++i) {
 | 
| +    HeapEntry* entry = deleted_entries[i];
 | 
| +    if (entry->painted_reachable()) ++reachable_deleted_entries;
 | 
| +  }
 | 
| +  for (int i = 0; i < added_entries.length(); ++i) {
 | 
| +    HeapEntry* entry = added_entries[i];
 | 
| +    if (entry->painted_reachable()) ++reachable_added_entries;
 | 
| +  }
 | 
| +
 | 
| +  HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2);
 | 
| +  diffs_.Add(diff);
 | 
| +  diff->CreateRoots(reachable_added_entries, reachable_deleted_entries);
 | 
| +
 | 
| +  int del_child_index = 0, deleted_entry_index = 1;
 | 
|    for (int i = 0; i < deleted_entries.length(); ++i) {
 | 
|      HeapEntry* entry = deleted_entries[i];
 | 
|      if (entry->painted_reachable())
 | 
| -      diff->AddDeletedEntry(entry);
 | 
| +      diff->AddDeletedEntry(del_child_index++, deleted_entry_index++, entry);
 | 
|    }
 | 
| -  snapshot2->ClearPaint();
 | 
| -  snapshot2->root()->PaintAllReachable();
 | 
| +  int add_child_index = 0, added_entry_index = 1;
 | 
|    for (int i = 0; i < added_entries.length(); ++i) {
 | 
|      HeapEntry* entry = added_entries[i];
 | 
|      if (entry->painted_reachable())
 | 
| -      diff->AddAddedEntry(entry);
 | 
| +      diff->AddAddedEntry(add_child_index++, added_entry_index++, entry);
 | 
|    }
 | 
|    return diff;
 | 
|  }
 | 
| 
 |