Upstream version 11.39.260.0
[platform/framework/web/crosswalk.git] / src / v8 / src / xdk-allocation.cc
index 311a592..3d33f80 100644 (file)
-// Copyright 2014 the V8 project authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
-\r
-#include <sstream>\r
-#include <string>\r
-\r
-#include "src/v8.h"\r
-\r
-#include "src/xdk-allocation.h"\r
-\r
-#include "frames-inl.h"\r
-#include "src/xdk-utils.h"\r
-\r
-namespace v8 {\r
-namespace internal {\r
-\r
-XDKAllocationTracker::XDKAllocationTracker(HeapProfiler* heap_profiler,\r
-                                           HeapObjectsMap *ids,\r
-                                           StringsStorage *names,\r
-                                           int stackDepth,\r
-                                           bool collectRetention,\r
-                                           bool strict_collection)\r
-    : heap_profiler_(heap_profiler),\r
-    ids_(ids),\r
-    names_(names),\r
-    stackDepth_(stackDepth),\r
-    collectRetention_(collectRetention),\r
-    strict_collection_(strict_collection) {\r
-  references_ = new References();\r
-  aggregated_chunks_ = new AggregatedChunks();\r
-  runtime_info_ = new RuntimeInfo(aggregated_chunks_);\r
-  symbols_ = new SymbolsStorage(ids_->heap(), names_);\r
-  collectedStacks_ = new ShadowStack();\r
-  classNames_ = new ClassNames(names_);\r
-\r
-  List<unsigned> stack_ooc;\r
-  stack_ooc.Add(symbols_->registerSymInfo(1, "OutOfContext", "NoSource",\r
-                                          0, 0));\r
-  outOfContextFrame_ = collectedStacks_->registerStack(stack_ooc);\r
-\r
-  List<unsigned> stack_abc;\r
-  stack_abc.Add(symbols_->registerSymInfo(2, "AllocatedBeforeCollection",\r
-                                          "NoSource", 0, 0));\r
-  AllocatedBeforeCollectionFrame_ = collectedStacks_->registerStack(stack_abc);\r
-\r
-  runtime_info_->InitABCFrame(AllocatedBeforeCollectionFrame_);\r
-\r
-  baseTime_ = v8::base::Time::Now();\r
-  latest_delta_ = 0;\r
-}\r
-\r
-\r
-XDKAllocationTracker::~XDKAllocationTracker() {\r
-  delete collectedStacks_;\r
-  delete classNames_;\r
-  delete aggregated_chunks_;\r
-  delete runtime_info_;\r
-  delete symbols_;\r
-  delete references_;\r
-}\r
-\r
-\r
-// Heap profiler regularly takes time for storing when object was allocated,\r
-// deallocated, when object's retention snapshot was taken, etc\r
-unsigned int XDKAllocationTracker::GetTimeDelta() {\r
-  v8::base::TimeDelta td = v8::base::Time::Now() - baseTime_;\r
-  return static_cast<unsigned int>(td.InMilliseconds());\r
-}\r
-\r
-\r
-void XDKAllocationTracker::OnAlloc(Address addr, int size) {\r
-  DisallowHeapAllocation no_alloc;\r
-  Heap *heap = ids_->heap();\r
-\r
-  // below call saves from the crash during StackTraceFrameIterator creation\r
-  // Mark the new block as FreeSpace to make sure the heap is iterable\r
-  // while we are capturing stack trace.\r
-  FreeListNode::FromAddress(addr)->set_size(heap, size);\r
-\r
-  Isolate *isolate = heap->isolate();\r
-  StackTraceFrameIterator it(isolate);\r
-  List<unsigned> stack;\r
-\r
-  // TODO(amalyshe): checking of isolate->handle_scope_data()->level is quite\r
-  // artificial. need to understand when we can have such behaviour\r
-  // if level == 0 we will crash in getting of source info\r
-  while (isolate->handle_scope_data()->level && !it.done() &&\r
-      stack.length() < stackDepth_) {\r
-    JavaScriptFrame *frame = it.frame();\r
-    if (!frame->function())\r
-      break;\r
-    SharedFunctionInfo *shared = frame->function()->shared();\r
-    if (!shared)\r
-      break;\r
-\r
-    stack.Add(symbols_->FindOrRegisterFrame(frame));\r
-    it.Advance();\r
-  }\r
-\r
-  unsigned sid;\r
-  if (!stack.is_empty()) {\r
-    sid = collectedStacks_->registerStack(stack);\r
-  } else {\r
-    sid = outOfContextFrame_;\r
-  }\r
-\r
-  latest_delta_ = GetTimeDelta();\r
-\r
-  PostCollectedInfo* info = runtime_info_->AddPostCollectedInfo(addr,\r
-                                                                latest_delta_);\r
-  info->size_ = size;\r
-  info->timeStamp_ = latest_delta_;\r
-  info->stackId_ = sid;\r
-  info->className_ = (unsigned int)-1;\r
-  info->dirty_ = false;\r
-}\r
-\r
-\r
-void XDKAllocationTracker::OnMove(Address from, Address to, int size) {\r
-  DisallowHeapAllocation no_alloc;\r
-  // look for the prev address\r
-  PostCollectedInfo* info_from = runtime_info_->FindPostCollectedInfo(from);\r
-  if (info_from == NULL) {\r
-    return;\r
-  }\r
-\r
-  runtime_info_->AddPostCollectedInfo(to, latest_delta_, info_from);\r
-  runtime_info_->RemoveInfo(from);\r
-}\r
-\r
-\r
-HeapEventXDK* XDKAllocationTracker::stopTracking() {\r
-  std::string symbols, types, frames, chunks, retentions;\r
-  SerializeChunk(&symbols, &types, &frames, &chunks, &retentions);\r
-  CollectFreedObjects(true);\r
-  std::string symbolsA, typesA, framesA, chunksA, retentionsA;\r
-  SerializeChunk(&symbolsA, &typesA, &framesA, &chunksA, &retentionsA, true);\r
-\r
-  // TODO(amalyshe): check who releases this object - new HeapEventXDK\r
-  return (new HeapEventXDK(GetTimeDelta(), symbols+symbolsA, types+typesA,\r
-      frames+framesA, chunks+chunksA, ""));\r
-}\r
-\r
-\r
-void XDKAllocationTracker::CollectFreedObjects(bool bAll, bool initPreCollect) {\r
-  clearIndividualReteiners();\r
-  if (collectRetention_) {\r
-    XDKSnapshotFiller filler(ids_, names_, this);\r
-    HeapSnapshotGenerator generator(heap_profiler_, NULL, NULL, NULL,\r
-                                    ids_->heap(), &filler);\r
-    generator.GenerateSnapshot();\r
-  }\r
-\r
-  Heap *heap = ids_->heap();\r
-  if (!heap) {\r
-    return;\r
-  }\r
-\r
-  unsigned int ts = GetTimeDelta();\r
-  if (bAll) {\r
-    ts += RETAINED_DELTA;\r
-  }\r
-\r
-  // CDT heap profiler calls CollectAllGarbage twice because after the first\r
-  // pass there are weak retained object not collected, but due to perf issues\r
-  // and because we do garbage collection regularly, we leave here only one call\r
-  // only for strict collection like in test where we need to make sure that\r
-  // object is definitely collected, we collect twice\r
-  heap->CollectAllGarbage(\r
-      Heap::kMakeHeapIterableMask,\r
-      "XDKAllocationTracker::CollectFreedObjects");\r
-  if (strict_collection_) {\r
-    heap->CollectAllGarbage(\r
-        Heap::kMakeHeapIterableMask,\r
-        "XDKAllocationTracker::CollectFreedObjects");\r
-  }\r
-  std::map<Address, RefSet> individualReteiners;\r
-\r
-  // TODO(amalyshe): check what DisallowHeapAllocation no_alloc means because in\r
-  // standalone v8 this part is crashed if DisallowHeapAllocation is defined\r
-  // DisallowHeapAllocation no_alloc;\r
-  if (!bAll) {\r
-    HeapIterator iterator(heap);\r
-    HeapObject* obj = iterator.next();\r
-    for (;\r
-         obj != NULL;\r
-         obj = iterator.next()) {\r
-      Address addr = obj->address();\r
-\r
-      PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(addr);\r
-      if (!info) {\r
-        // if we don't find info, we consider it as pre collection allocated\r
-        // object. need to add to the full picture for retentions\r
-        if (initPreCollect) {\r
-          info = runtime_info_->AddPreCollectionInfo(addr, obj->Size());\r
-        }\r
-      }\r
-\r
-      if (info) {\r
-        info->dirty_ = true;\r
-      }\r
-      // check of the class name and its initialization\r
-      if ((info && info->className_ == (unsigned)-1) || !info) {\r
-        InitClassName(addr, ts, obj->Size());\r
-      }\r
-    }\r
-  }\r
-\r
-  if (collectRetention_) {\r
-    std::map<Address, RefSet>::const_iterator citir =\r
-        individualReteiners_.begin();\r
-    while (citir != individualReteiners_.end()) {\r
-      PostCollectedInfo* infoChild =\r
-          runtime_info_->FindPostCollectedInfo(citir->first);\r
-      if (infoChild) {\r
-        RefId rfId;\r
-        rfId.stackId_ = infoChild->stackId_;\r
-        rfId.classId_ = infoChild->className_;\r
-\r
-        references_->addReference(rfId, citir->second, infoChild->timeStamp_);\r
-      }\r
-      citir++;\r
-    }\r
-  }\r
-\r
-  runtime_info_->CollectGarbaged(ts);\r
-}\r
-\r
-\r
-void XDKAllocationTracker::SerializeChunk(std::string* symbols,\r
-                                          std::string* types,\r
-                                          std::string* frames,\r
-                                          std::string* chunks,\r
-                                          std::string* retentions,\r
-                                          bool final) {\r
-  if (final) {\r
-    *symbols = symbols_->SerializeChunk();\r
-    *types = classNames_->SerializeChunk();\r
-  }\r
-  *frames = collectedStacks_->SerializeChunk();\r
-  *chunks = aggregated_chunks_->SerializeChunk();\r
-\r
-  *retentions = references_->serialize();\r
-  std::stringstream retentionsT;\r
-  retentionsT << GetTimeDelta() << std::endl << retentions->c_str();\r
-  *retentions = retentionsT.str();\r
-  references_->clear();\r
-}\r
-\r
-\r
-OutputStream::WriteResult XDKAllocationTracker::SendChunk(\r
-    OutputStream* stream) {\r
-  // go over all aggregated_ and send data to the stream\r
-  std::string symbols, types, frames, chunks, retentions;\r
-  SerializeChunk(&symbols, &types, &frames, &chunks, &retentions);\r
-\r
-  OutputStream::WriteResult ret = stream->WriteHeapXDKChunk(\r
-      symbols.c_str(), symbols.length(),\r
-      frames.c_str(), frames.length(),\r
-      types.c_str(), types.length(),\r
-      chunks.c_str(), chunks.length(),\r
-      retentions.c_str(), retentions.length());\r
-  return ret;\r
-}\r
-\r
-\r
-unsigned XDKAllocationTracker::GetTraceNodeId(Address address) {\r
-    PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(address);\r
-    if (info) {\r
-      return info->stackId_;\r
-    } else {\r
-      return AllocatedBeforeCollectionFrame_;\r
-    }\r
-}\r
-\r
-\r
-void XDKAllocationTracker::clearIndividualReteiners() {\r
-  individualReteiners_.clear();\r
-}\r
-\r
-\r
-std::map<Address, RefSet>* XDKAllocationTracker::GetIndividualReteiners() {\r
-  return &individualReteiners_;\r
-}\r
-\r
-\r
-unsigned XDKAllocationTracker::FindClassName(Address address) {\r
-  PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(address);\r
-  if (info) {\r
-    return info->className_;\r
-  } else {\r
-    return (unsigned)-1;\r
-  }\r
-}\r
-\r
-\r
-unsigned XDKAllocationTracker::InitClassName(Address address, unsigned ts,\r
-                                             unsigned size) {\r
-  unsigned id = -2;\r
-  PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(address);\r
-  if (!info) {\r
-    info = runtime_info_->AddPostCollectedInfo(address, ts);\r
-    info->className_ = -1;\r
-    info->stackId_ = outOfContextFrame_;\r
-    info->timeStamp_ = ts;\r
-    info->size_ = size;\r
-  }\r
-  if (info->className_ == (unsigned)-1) {\r
-    String* str = classNames_->GetConstructorName(address);\r
-    if (str) {\r
-      // get const char*, it's safe because pointer will be retained in the\r
-      // name_ until it is destroyed\r
-      id = classNames_->registerName(names_->GetName(str));\r
-    }\r
-  }\r
-  info->className_ = id;\r
-  return id;\r
-}\r
-\r
-\r
-unsigned XDKAllocationTracker::FindOrInitClassName(Address address,\r
-                                                   unsigned ts) {\r
-  unsigned id = FindClassName(address);\r
-  if (id == (unsigned)-1) {\r
-    // TODO(amalyshe) check if 0 size here is appropriate\r
-    id = InitClassName(address, ts, 0);\r
-  }\r
-  return id;\r
-}\r
-\r
-\r
-// -----------------------------------------------------------------------------\r
-// this is almost a copy and duplication of\r
-// V8HeapExplorer::AddEntry. refactoring is impossible because\r
-// heap-snapshot-generator rely on it's structure which is not fully suitable\r
-// for us.\r
-HeapEntry* XDKSnapshotFiller::AddEntry(HeapThing ptr,\r
-                                       HeapEntriesAllocator* allocator) {\r
-  HeapObject* object = reinterpret_cast<HeapObject*>(ptr);\r
-  if (object->IsJSFunction()) {\r
-    JSFunction* func = JSFunction::cast(object);\r
-    SharedFunctionInfo* shared = func->shared();\r
-    const char* name = shared->bound() ? "native_bind" :\r
-        names_->GetName(String::cast(shared->name()));\r
-    return AddEntry(ptr, object, HeapEntry::kClosure, name);\r
-  } else if (object->IsJSRegExp()) {\r
-    JSRegExp* re = JSRegExp::cast(object);\r
-    return AddEntry(ptr, object,\r
-                    HeapEntry::kRegExp,\r
-                    names_->GetName(re->Pattern()));\r
-  } else if (object->IsJSObject()) {\r
-    return AddEntry(ptr, object, HeapEntry::kObject, "");\r
-  } else if (object->IsString()) {\r
-    String* string = String::cast(object);\r
-    if (string->IsConsString())\r
-      return AddEntry(ptr, object,\r
-                      HeapEntry::kConsString,\r
-                      "(concatenated string)");\r
-    if (string->IsSlicedString())\r
-      return AddEntry(ptr, object,\r
-                      HeapEntry::kSlicedString,\r
-                      "(sliced string)");\r
-    return AddEntry(ptr, object,\r
-                    HeapEntry::kString,\r
-                    names_->GetName(String::cast(object)));\r
-  } else if (object->IsSymbol()) {\r
-    return AddEntry(ptr, object, HeapEntry::kSymbol, "symbol");\r
-  } else if (object->IsCode()) {\r
-    return AddEntry(ptr, object, HeapEntry::kCode, "");\r
-  } else if (object->IsSharedFunctionInfo()) {\r
-    String* name = String::cast(SharedFunctionInfo::cast(object)->name());\r
-    return AddEntry(ptr, object,\r
-                    HeapEntry::kCode,\r
-                    names_->GetName(name));\r
-  } else if (object->IsScript()) {\r
-    Object* name = Script::cast(object)->name();\r
-    return AddEntry(ptr, object,\r
-                    HeapEntry::kCode,\r
-                    name->IsString()\r
-                        ? names_->GetName(String::cast(name))\r
-                        : "");\r
-  } else if (object->IsNativeContext()) {\r
-    return AddEntry(ptr, object, HeapEntry::kHidden, "system / NativeContext");\r
-  } else if (object->IsContext()) {\r
-    return AddEntry(ptr, object, HeapEntry::kObject, "system / Context");\r
-  } else if (object->IsFixedArray() ||\r
-             object->IsFixedDoubleArray() ||\r
-             object->IsByteArray() ||\r
-             object->IsExternalArray()) {\r
-    return AddEntry(ptr, object, HeapEntry::kArray, "");\r
-  } else if (object->IsHeapNumber()) {\r
-    return AddEntry(ptr, object, HeapEntry::kHeapNumber, "number");\r
-  }\r
-\r
-  return AddEntry(ptr, object, HeapEntry::kHidden, "system / NOT SUPORTED YET");\r
-}\r
-\r
-\r
-HeapEntry* XDKSnapshotFiller::AddEntry(HeapThing thing,\r
-                    HeapObject* object,\r
-                    HeapEntry::Type type,\r
-                    const char* name) {\r
-  Address address = object->address();\r
-  unsigned trace_node_id = 0;\r
-  trace_node_id = allocation_tracker_->GetTraceNodeId(address);\r
-\r
-  // cannot store pointer in the map because List reallcoates content regularly\r
-  // and the only  one way to find the entry - by index. so, index is cached in\r
-  // the map\r
-  // TODO(amalyshe): need to reuse type. it seems it is important\r
-  HeapEntry entry(NULL, &heap_entries_list_, type, name, 0, 0,\r
-                  trace_node_id);\r
-  heap_entries_list_.Add(entry);\r
-  HeapEntry* pEntry = &heap_entries_list_.last();\r
-\r
-  HashMap::Entry* cache_entry = heap_entries_.Lookup(thing, Hash(thing), true);\r
-  DCHECK(cache_entry->value == NULL);\r
-  int index = pEntry->index();\r
-  cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(index));\r
-\r
-  // TODO(amalyshe): it seems this storage might be optimized\r
-  HashMap::Entry* address_entry = index_to_address_.Lookup(\r
-      reinterpret_cast<void*>(index+1), HashInt(index+1), true);\r
-  address_entry->value = reinterpret_cast<void*>(address);\r
-\r
-  return pEntry;\r
-}\r
-\r
-\r
-HeapEntry* XDKSnapshotFiller::FindEntry(HeapThing thing) {\r
-  HashMap::Entry* cache_entry = heap_entries_.Lookup(thing, Hash(thing), false);\r
-  if (cache_entry == NULL) return NULL;\r
-  return &heap_entries_list_[static_cast<int>(\r
-      reinterpret_cast<intptr_t>(cache_entry->value))];\r
-}\r
-\r
-\r
-HeapEntry* XDKSnapshotFiller::FindOrAddEntry(HeapThing ptr,\r
-                                             HeapEntriesAllocator* allocator) {\r
-  HeapEntry* entry = FindEntry(ptr);\r
-  return entry != NULL ? entry : AddEntry(ptr, allocator);\r
-}\r
-\r
-\r
-void XDKSnapshotFiller::SetIndexedReference(HeapGraphEdge::Type type,\r
-    int parent,\r
-    int index,\r
-    HeapEntry* child_entry) {\r
-  if (child_entry->trace_node_id() < 3) {\r
-    return;\r
-  }\r
-  HashMap::Entry* address_entry_child = index_to_address_.Lookup(\r
-      reinterpret_cast<void*>(child_entry->index()+1),\r
-      HashInt(child_entry->index()+1), false);\r
-  DCHECK(address_entry_child != NULL);\r
-  if (!address_entry_child) {\r
-    return;\r
-  }\r
-\r
-  Address child_addr = reinterpret_cast<Address>(address_entry_child->value);\r
-\r
-  std::map<Address, RefSet>* individualReteiners =\r
-      allocation_tracker_->GetIndividualReteiners();\r
-  // get the parent's address, constructor name and form the RefId\r
-  HashMap::Entry* address_entry = index_to_address_.Lookup(\r
-      reinterpret_cast<void*>(parent+1), HashInt(parent+1), false);\r
-  DCHECK(address_entry != NULL);\r
-  if (!address_entry) {\r
-    return;\r
-  }\r
-  HeapEntry* parent_entry = &(heap_entries_list_[parent]);\r
-  Address parent_addr = reinterpret_cast<Address>(address_entry->value);\r
-  RefId parent_ref_id;\r
-  parent_ref_id.stackId_ = parent_entry->trace_node_id();\r
-  parent_ref_id.classId_ =\r
-      allocation_tracker_->FindOrInitClassName(parent_addr, 0);\r
-\r
-  std::stringstream str;\r
-  str << index << " element in Array";\r
-  parent_ref_id.field_ = str.str();\r
-\r
-  (*individualReteiners)[child_addr].references_.insert(parent_ref_id);\r
-}\r
-\r
-\r
-void XDKSnapshotFiller::SetIndexedAutoIndexReference(HeapGraphEdge::Type type,\r
-    int parent,\r
-    HeapEntry* child_entry) {\r
-}\r
-\r
-\r
-void XDKSnapshotFiller::SetNamedReference(HeapGraphEdge::Type type,\r
-    int parent,\r
-    const char* reference_name,\r
-    HeapEntry* child_entry) {\r
-  if (child_entry->trace_node_id() < 3) {\r
-    return;\r
-  }\r
-\r
-  std::map<Address, RefSet>* individualReteiners =\r
-      allocation_tracker_->GetIndividualReteiners();\r
-  // get the parent's address, constructor name and form the RefId\r
-  HashMap::Entry* address_entry = index_to_address_.Lookup(\r
-      reinterpret_cast<void*>(parent+1), HashInt(parent+1), false);\r
-  DCHECK(address_entry != NULL);\r
-  if (!address_entry) {\r
-    return;\r
-  }\r
-  HeapEntry* parent_entry = &(heap_entries_list_[parent]);\r
-  Address parent_addr = reinterpret_cast<Address>(address_entry->value);\r
-  RefId parent_ref_id;\r
-  parent_ref_id.stackId_ = parent_entry->trace_node_id();\r
-  // TODO(amalyshe): need to get access to classNames_\r
-  parent_ref_id.classId_ =\r
-      allocation_tracker_->FindOrInitClassName(parent_addr, 0);\r
-  parent_ref_id.field_ = reference_name;\r
-\r
-  HashMap::Entry* address_entry_child = index_to_address_.Lookup(\r
-      reinterpret_cast<void*>(child_entry->index()+1),\r
-      HashInt(child_entry->index()+1), false);\r
-  DCHECK(address_entry_child != NULL);\r
-  if (!address_entry_child) {\r
-    return;\r
-  }\r
-  Address child_addr = reinterpret_cast<Address>(address_entry_child->value);\r
-\r
-  (*individualReteiners)[child_addr].references_.insert(parent_ref_id);\r
-}\r
-\r
-\r
-void XDKSnapshotFiller::SetNamedAutoIndexReference(HeapGraphEdge::Type type,\r
-                                int parent,\r
-                                HeapEntry* child_entry) {\r
-}\r
-\r
-\r
-}\r
-}  // namespace v8::internal\r
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+#include <string>
+
+#include "src/v8.h"
+
+#include "src/xdk-allocation.h"
+
+#include "frames-inl.h"
+#include "src/xdk-utils.h"
+
+namespace v8 {
+namespace internal {
+
+XDKAllocationTracker::XDKAllocationTracker(HeapProfiler* heap_profiler,
+                                           HeapObjectsMap *ids,
+                                           StringsStorage *names,
+                                           int stackDepth,
+                                           bool collectRetention,
+                                           bool strict_collection)
+    : heap_profiler_(heap_profiler),
+    ids_(ids),
+    names_(names),
+    stackDepth_(stackDepth),
+    collectRetention_(collectRetention),
+    strict_collection_(strict_collection) {
+  references_ = new References();
+  aggregated_chunks_ = new AggregatedChunks();
+  runtime_info_ = new RuntimeInfo(aggregated_chunks_);
+  symbols_ = new SymbolsStorage(ids_->heap(), names_);
+  collectedStacks_ = new ShadowStack();
+  classNames_ = new ClassNames(names_);
+
+  List<unsigned> stack_ooc;
+  stack_ooc.Add(symbols_->registerSymInfo(1, "OutOfContext", "NoSource",
+                                          0, 0));
+  outOfContextFrame_ = collectedStacks_->registerStack(stack_ooc);
+
+  List<unsigned> stack_abc;
+  stack_abc.Add(symbols_->registerSymInfo(2, "AllocatedBeforeCollection",
+                                          "NoSource", 0, 0));
+  AllocatedBeforeCollectionFrame_ = collectedStacks_->registerStack(stack_abc);
+
+  runtime_info_->InitABCFrame(AllocatedBeforeCollectionFrame_);
+
+  baseTime_ = v8::base::Time::Now();
+  latest_delta_ = 0;
+}
+
+
+XDKAllocationTracker::~XDKAllocationTracker() {
+  delete collectedStacks_;
+  delete classNames_;
+  delete aggregated_chunks_;
+  delete runtime_info_;
+  delete symbols_;
+  delete references_;
+}
+
+
+// Heap profiler regularly takes time for storing when object was allocated,
+// deallocated, when object's retention snapshot was taken, etc
+unsigned int XDKAllocationTracker::GetTimeDelta() {
+  v8::base::TimeDelta td = v8::base::Time::Now() - baseTime_;
+  return static_cast<unsigned int>(td.InMilliseconds());
+}
+
+
+void XDKAllocationTracker::OnAlloc(Address addr, int size) {
+  DisallowHeapAllocation no_alloc;
+  Heap *heap = ids_->heap();
+
+  // below call saves from the crash during StackTraceFrameIterator creation
+  // Mark the new block as FreeSpace to make sure the heap is iterable
+  // while we are capturing stack trace.
+  FreeListNode::FromAddress(addr)->set_size(heap, size);
+
+  Isolate *isolate = heap->isolate();
+  StackTraceFrameIterator it(isolate);
+  List<unsigned> stack;
+
+  // TODO(amalyshe): checking of isolate->handle_scope_data()->level is quite
+  // artificial. need to understand when we can have such behaviour
+  // if level == 0 we will crash in getting of source info
+  while (isolate->handle_scope_data()->level && !it.done() &&
+      stack.length() < stackDepth_) {
+    JavaScriptFrame *frame = it.frame();
+    if (!frame->function())
+      break;
+    SharedFunctionInfo *shared = frame->function()->shared();
+    if (!shared)
+      break;
+
+    stack.Add(symbols_->FindOrRegisterFrame(frame));
+    it.Advance();
+  }
+
+  unsigned sid;
+  if (!stack.is_empty()) {
+    sid = collectedStacks_->registerStack(stack);
+  } else {
+    sid = outOfContextFrame_;
+  }
+
+  latest_delta_ = GetTimeDelta();
+
+  PostCollectedInfo* info = runtime_info_->AddPostCollectedInfo(addr,
+                                                                latest_delta_);
+  info->size_ = size;
+  info->timeStamp_ = latest_delta_;
+  info->stackId_ = sid;
+  info->className_ = (unsigned int)-1;
+  info->dirty_ = false;
+}
+
+
+void XDKAllocationTracker::OnMove(Address from, Address to, int size) {
+  DisallowHeapAllocation no_alloc;
+  // look for the prev address
+  PostCollectedInfo* info_from = runtime_info_->FindPostCollectedInfo(from);
+  if (info_from == NULL) {
+    return;
+  }
+
+  runtime_info_->AddPostCollectedInfo(to, latest_delta_, info_from);
+  runtime_info_->RemoveInfo(from);
+}
+
+
+HeapEventXDK* XDKAllocationTracker::stopTracking() {
+  std::string symbols, types, frames, chunks, retentions;
+  SerializeChunk(&symbols, &types, &frames, &chunks, &retentions);
+  CollectFreedObjects(true);
+  std::string symbolsA, typesA, framesA, chunksA, retentionsA;
+  SerializeChunk(&symbolsA, &typesA, &framesA, &chunksA, &retentionsA, true);
+
+  // TODO(amalyshe): check who releases this object - new HeapEventXDK
+  return (new HeapEventXDK(GetTimeDelta(), symbols+symbolsA, types+typesA,
+      frames+framesA, chunks+chunksA, ""));
+}
+
+
+void XDKAllocationTracker::CollectFreedObjects(bool bAll, bool initPreCollect) {
+  clearIndividualReteiners();
+  if (collectRetention_) {
+    XDKSnapshotFiller filler(ids_, names_, this);
+    HeapSnapshotGenerator generator(heap_profiler_, NULL, NULL, NULL,
+                                    ids_->heap(), &filler);
+    generator.GenerateSnapshot();
+  }
+
+  Heap *heap = ids_->heap();
+  if (!heap) {
+    return;
+  }
+
+  unsigned int ts = GetTimeDelta();
+  if (bAll) {
+    ts += RETAINED_DELTA;
+  }
+
+  // CDT heap profiler calls CollectAllGarbage twice because after the first
+  // pass there are weak retained object not collected, but due to perf issues
+  // and because we do garbage collection regularly, we leave here only one call
+  // only for strict collection like in test where we need to make sure that
+  // object is definitely collected, we collect twice
+  heap->CollectAllGarbage(
+      Heap::kMakeHeapIterableMask,
+      "XDKAllocationTracker::CollectFreedObjects");
+  if (strict_collection_) {
+    heap->CollectAllGarbage(
+        Heap::kMakeHeapIterableMask,
+        "XDKAllocationTracker::CollectFreedObjects");
+  }
+  std::map<Address, RefSet> individualReteiners;
+
+  // TODO(amalyshe): check what DisallowHeapAllocation no_alloc means because in
+  // standalone v8 this part is crashed if DisallowHeapAllocation is defined
+  // DisallowHeapAllocation no_alloc;
+  if (!bAll) {
+    HeapIterator iterator(heap);
+    HeapObject* obj = iterator.next();
+    for (;
+         obj != NULL;
+         obj = iterator.next()) {
+      Address addr = obj->address();
+
+      PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(addr);
+      if (!info) {
+        // if we don't find info, we consider it as pre collection allocated
+        // object. need to add to the full picture for retentions
+        if (initPreCollect) {
+          info = runtime_info_->AddPreCollectionInfo(addr, obj->Size());
+        }
+      }
+
+      if (info) {
+        info->dirty_ = true;
+      }
+      // check of the class name and its initialization
+      if ((info && info->className_ == (unsigned)-1) || !info) {
+        InitClassName(addr, ts, obj->Size());
+      }
+    }
+  }
+
+  if (collectRetention_) {
+    std::map<Address, RefSet>::const_iterator citir =
+        individualReteiners_.begin();
+    while (citir != individualReteiners_.end()) {
+      PostCollectedInfo* infoChild =
+          runtime_info_->FindPostCollectedInfo(citir->first);
+      if (infoChild) {
+        RefId rfId;
+        rfId.stackId_ = infoChild->stackId_;
+        rfId.classId_ = infoChild->className_;
+
+        references_->addReference(rfId, citir->second, infoChild->timeStamp_);
+      }
+      citir++;
+    }
+  }
+
+  runtime_info_->CollectGarbaged(ts);
+}
+
+
+void XDKAllocationTracker::SerializeChunk(std::string* symbols,
+                                          std::string* types,
+                                          std::string* frames,
+                                          std::string* chunks,
+                                          std::string* retentions,
+                                          bool final) {
+  if (final) {
+    *symbols = symbols_->SerializeChunk();
+    *types = classNames_->SerializeChunk();
+  }
+  *frames = collectedStacks_->SerializeChunk();
+  *chunks = aggregated_chunks_->SerializeChunk();
+
+  *retentions = references_->serialize();
+  std::stringstream retentionsT;
+  retentionsT << GetTimeDelta() << std::endl << retentions->c_str();
+  *retentions = retentionsT.str();
+  references_->clear();
+}
+
+
+OutputStream::WriteResult XDKAllocationTracker::SendChunk(
+    OutputStream* stream) {
+  // go over all aggregated_ and send data to the stream
+  std::string symbols, types, frames, chunks, retentions;
+  SerializeChunk(&symbols, &types, &frames, &chunks, &retentions);
+
+  OutputStream::WriteResult ret = stream->WriteHeapXDKChunk(
+      symbols.c_str(), symbols.length(),
+      frames.c_str(), frames.length(),
+      types.c_str(), types.length(),
+      chunks.c_str(), chunks.length(),
+      retentions.c_str(), retentions.length());
+  return ret;
+}
+
+
+unsigned XDKAllocationTracker::GetTraceNodeId(Address address) {
+    PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(address);
+    if (info) {
+      return info->stackId_;
+    } else {
+      return AllocatedBeforeCollectionFrame_;
+    }
+}
+
+
+void XDKAllocationTracker::clearIndividualReteiners() {
+  individualReteiners_.clear();
+}
+
+
+std::map<Address, RefSet>* XDKAllocationTracker::GetIndividualReteiners() {
+  return &individualReteiners_;
+}
+
+
+unsigned XDKAllocationTracker::FindClassName(Address address) {
+  PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(address);
+  if (info) {
+    return info->className_;
+  } else {
+    return (unsigned)-1;
+  }
+}
+
+
+unsigned XDKAllocationTracker::InitClassName(Address address, unsigned ts,
+                                             unsigned size) {
+  unsigned id = -2;
+  PostCollectedInfo* info = runtime_info_->FindPostCollectedInfo(address);
+  if (!info) {
+    info = runtime_info_->AddPostCollectedInfo(address, ts);
+    info->className_ = -1;
+    info->stackId_ = outOfContextFrame_;
+    info->timeStamp_ = ts;
+    info->size_ = size;
+  }
+  if (info->className_ == (unsigned)-1) {
+    String* str = classNames_->GetConstructorName(address);
+    if (str) {
+      // get const char*, it's safe because pointer will be retained in the
+      // name_ until it is destroyed
+      id = classNames_->registerName(names_->GetName(str));
+    }
+  }
+  info->className_ = id;
+  return id;
+}
+
+
+unsigned XDKAllocationTracker::FindOrInitClassName(Address address,
+                                                   unsigned ts) {
+  unsigned id = FindClassName(address);
+  if (id == (unsigned)-1) {
+    // TODO(amalyshe) check if 0 size here is appropriate
+    id = InitClassName(address, ts, 0);
+  }
+  return id;
+}
+
+
+// -----------------------------------------------------------------------------
+// this is almost a copy and duplication of
+// V8HeapExplorer::AddEntry. refactoring is impossible because
+// heap-snapshot-generator rely on it's structure which is not fully suitable
+// for us.
+HeapEntry* XDKSnapshotFiller::AddEntry(HeapThing ptr,
+                                       HeapEntriesAllocator* allocator) {
+  HeapObject* object = reinterpret_cast<HeapObject*>(ptr);
+  if (object->IsJSFunction()) {
+    JSFunction* func = JSFunction::cast(object);
+    SharedFunctionInfo* shared = func->shared();
+    const char* name = shared->bound() ? "native_bind" :
+        names_->GetName(String::cast(shared->name()));
+    return AddEntry(ptr, object, HeapEntry::kClosure, name);
+  } else if (object->IsJSRegExp()) {
+    JSRegExp* re = JSRegExp::cast(object);
+    return AddEntry(ptr, object,
+                    HeapEntry::kRegExp,
+                    names_->GetName(re->Pattern()));
+  } else if (object->IsJSObject()) {
+    return AddEntry(ptr, object, HeapEntry::kObject, "");
+  } else if (object->IsString()) {
+    String* string = String::cast(object);
+    if (string->IsConsString())
+      return AddEntry(ptr, object,
+                      HeapEntry::kConsString,
+                      "(concatenated string)");
+    if (string->IsSlicedString())
+      return AddEntry(ptr, object,
+                      HeapEntry::kSlicedString,
+                      "(sliced string)");
+    return AddEntry(ptr, object,
+                    HeapEntry::kString,
+                    names_->GetName(String::cast(object)));
+  } else if (object->IsSymbol()) {
+    return AddEntry(ptr, object, HeapEntry::kSymbol, "symbol");
+  } else if (object->IsCode()) {
+    return AddEntry(ptr, object, HeapEntry::kCode, "");
+  } else if (object->IsSharedFunctionInfo()) {
+    String* name = String::cast(SharedFunctionInfo::cast(object)->name());
+    return AddEntry(ptr, object,
+                    HeapEntry::kCode,
+                    names_->GetName(name));
+  } else if (object->IsScript()) {
+    Object* name = Script::cast(object)->name();
+    return AddEntry(ptr, object,
+                    HeapEntry::kCode,
+                    name->IsString()
+                        ? names_->GetName(String::cast(name))
+                        : "");
+  } else if (object->IsNativeContext()) {
+    return AddEntry(ptr, object, HeapEntry::kHidden, "system / NativeContext");
+  } else if (object->IsContext()) {
+    return AddEntry(ptr, object, HeapEntry::kObject, "system / Context");
+  } else if (object->IsFixedArray() ||
+             object->IsFixedDoubleArray() ||
+             object->IsByteArray() ||
+             object->IsExternalArray()) {
+    return AddEntry(ptr, object, HeapEntry::kArray, "");
+  } else if (object->IsHeapNumber()) {
+    return AddEntry(ptr, object, HeapEntry::kHeapNumber, "number");
+  }
+
+  return AddEntry(ptr, object, HeapEntry::kHidden, "system / NOT SUPORTED YET");
+}
+
+
+HeapEntry* XDKSnapshotFiller::AddEntry(HeapThing thing,
+                    HeapObject* object,
+                    HeapEntry::Type type,
+                    const char* name) {
+  Address address = object->address();
+  unsigned trace_node_id = 0;
+  trace_node_id = allocation_tracker_->GetTraceNodeId(address);
+
+  // cannot store pointer in the map because List reallcoates content regularly
+  // and the only  one way to find the entry - by index. so, index is cached in
+  // the map
+  // TODO(amalyshe): need to reuse type. it seems it is important
+  HeapEntry entry(NULL, &heap_entries_list_, type, name, 0, 0,
+                  trace_node_id);
+  heap_entries_list_.Add(entry);
+  HeapEntry* pEntry = &heap_entries_list_.last();
+
+  HashMap::Entry* cache_entry = heap_entries_.Lookup(thing, Hash(thing), true);
+  DCHECK(cache_entry->value == NULL);
+  int index = pEntry->index();
+  cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(index));
+
+  // TODO(amalyshe): it seems this storage might be optimized
+  HashMap::Entry* address_entry = index_to_address_.Lookup(
+      reinterpret_cast<void*>(index+1), HashInt(index+1), true);
+  address_entry->value = reinterpret_cast<void*>(address);
+
+  return pEntry;
+}
+
+
+HeapEntry* XDKSnapshotFiller::FindEntry(HeapThing thing) {
+  HashMap::Entry* cache_entry = heap_entries_.Lookup(thing, Hash(thing), false);
+  if (cache_entry == NULL) return NULL;
+  return &heap_entries_list_[static_cast<int>(
+      reinterpret_cast<intptr_t>(cache_entry->value))];
+}
+
+
+HeapEntry* XDKSnapshotFiller::FindOrAddEntry(HeapThing ptr,
+                                             HeapEntriesAllocator* allocator) {
+  HeapEntry* entry = FindEntry(ptr);
+  return entry != NULL ? entry : AddEntry(ptr, allocator);
+}
+
+
+void XDKSnapshotFiller::SetIndexedReference(HeapGraphEdge::Type type,
+    int parent,
+    int index,
+    HeapEntry* child_entry) {
+  if (child_entry->trace_node_id() < 3) {
+    return;
+  }
+  HashMap::Entry* address_entry_child = index_to_address_.Lookup(
+      reinterpret_cast<void*>(child_entry->index()+1),
+      HashInt(child_entry->index()+1), false);
+  DCHECK(address_entry_child != NULL);
+  if (!address_entry_child) {
+    return;
+  }
+
+  Address child_addr = reinterpret_cast<Address>(address_entry_child->value);
+
+  std::map<Address, RefSet>* individualReteiners =
+      allocation_tracker_->GetIndividualReteiners();
+  // get the parent's address, constructor name and form the RefId
+  HashMap::Entry* address_entry = index_to_address_.Lookup(
+      reinterpret_cast<void*>(parent+1), HashInt(parent+1), false);
+  DCHECK(address_entry != NULL);
+  if (!address_entry) {
+    return;
+  }
+  HeapEntry* parent_entry = &(heap_entries_list_[parent]);
+  Address parent_addr = reinterpret_cast<Address>(address_entry->value);
+  RefId parent_ref_id;
+  parent_ref_id.stackId_ = parent_entry->trace_node_id();
+  parent_ref_id.classId_ =
+      allocation_tracker_->FindOrInitClassName(parent_addr, 0);
+
+  std::stringstream str;
+  str << index << " element in Array";
+  parent_ref_id.field_ = str.str();
+
+  (*individualReteiners)[child_addr].references_.insert(parent_ref_id);
+}
+
+
+void XDKSnapshotFiller::SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
+    int parent,
+    HeapEntry* child_entry) {
+}
+
+
+void XDKSnapshotFiller::SetNamedReference(HeapGraphEdge::Type type,
+    int parent,
+    const char* reference_name,
+    HeapEntry* child_entry) {
+  if (child_entry->trace_node_id() < 3) {
+    return;
+  }
+
+  std::map<Address, RefSet>* individualReteiners =
+      allocation_tracker_->GetIndividualReteiners();
+  // get the parent's address, constructor name and form the RefId
+  HashMap::Entry* address_entry = index_to_address_.Lookup(
+      reinterpret_cast<void*>(parent+1), HashInt(parent+1), false);
+  DCHECK(address_entry != NULL);
+  if (!address_entry) {
+    return;
+  }
+  HeapEntry* parent_entry = &(heap_entries_list_[parent]);
+  Address parent_addr = reinterpret_cast<Address>(address_entry->value);
+  RefId parent_ref_id;
+  parent_ref_id.stackId_ = parent_entry->trace_node_id();
+  // TODO(amalyshe): need to get access to classNames_
+  parent_ref_id.classId_ =
+      allocation_tracker_->FindOrInitClassName(parent_addr, 0);
+  parent_ref_id.field_ = reference_name;
+
+  HashMap::Entry* address_entry_child = index_to_address_.Lookup(
+      reinterpret_cast<void*>(child_entry->index()+1),
+      HashInt(child_entry->index()+1), false);
+  DCHECK(address_entry_child != NULL);
+  if (!address_entry_child) {
+    return;
+  }
+  Address child_addr = reinterpret_cast<Address>(address_entry_child->value);
+
+  (*individualReteiners)[child_addr].references_.insert(parent_ref_id);
+}
+
+
+void XDKSnapshotFiller::SetNamedAutoIndexReference(HeapGraphEdge::Type type,
+                                int parent,
+                                HeapEntry* child_entry) {
+}
+
+
+}
+}  // namespace v8::internal