Upstream version 11.39.244.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-heap-profiler.cc
index f1ccc57..6842b1d 100644 (file)
 
 #include <ctype.h>
 
-#include "v8.h"
-
-#include "allocation-tracker.h"
-#include "cctest.h"
-#include "hashmap.h"
-#include "heap-profiler.h"
-#include "snapshot.h"
-#include "debug.h"
-#include "utils-inl.h"
-#include "../include/v8-profiler.h"
+#include "src/v8.h"
+
+#include "include/v8-profiler.h"
+#include "src/allocation-tracker.h"
+#include "src/debug.h"
+#include "src/hashmap.h"
+#include "src/heap-profiler.h"
+#include "src/snapshot.h"
+#include "src/utils-inl.h"
+#include "src/xdk-utils.h"
+#include "test/cctest/cctest.h"
 
 using i::AllocationTraceNode;
 using i::AllocationTraceTree;
@@ -441,11 +442,10 @@ TEST(HeapSnapshotConsString) {
   CHECK_EQ(1, global->InternalFieldCount());
 
   i::Factory* factory = CcTest::i_isolate()->factory();
-  i::Handle<i::String> first =
-      factory->NewStringFromAscii(i::CStrVector("0123456789"));
-  i::Handle<i::String> second =
-      factory->NewStringFromAscii(i::CStrVector("0123456789"));
-  i::Handle<i::String> cons_string = factory->NewConsString(first, second);
+  i::Handle<i::String> first = factory->NewStringFromStaticChars("0123456789");
+  i::Handle<i::String> second = factory->NewStringFromStaticChars("0123456789");
+  i::Handle<i::String> cons_string =
+      factory->NewConsString(first, second).ToHandleChecked();
 
   global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
 
@@ -472,6 +472,174 @@ TEST(HeapSnapshotConsString) {
 }
 
 
+TEST(HeapSnapshotSymbol) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun("a = Symbol('mySymbol');\n");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("Symbol"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* a =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
+  CHECK_NE(NULL, a);
+  CHECK_EQ(a->GetType(), v8::HeapGraphNode::kSymbol);
+  CHECK_EQ(v8_str("symbol"), a->GetName());
+  const v8::HeapGraphNode* name =
+      GetProperty(a, v8::HeapGraphEdge::kInternal, "name");
+  CHECK_NE(NULL, name);
+  CHECK_EQ(v8_str("mySymbol"), name->GetName());
+}
+
+
+TEST(HeapSnapshotWeakCollection) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun(
+      "k = {}; v = {}; s = 'str';\n"
+      "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n"
+      "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* k =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
+  CHECK_NE(NULL, k);
+  const v8::HeapGraphNode* v =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
+  CHECK_NE(NULL, v);
+  const v8::HeapGraphNode* s =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
+  CHECK_NE(NULL, s);
+
+  const v8::HeapGraphNode* ws =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "ws");
+  CHECK_NE(NULL, ws);
+  CHECK_EQ(v8::HeapGraphNode::kObject, ws->GetType());
+  CHECK_EQ(v8_str("WeakSet"), ws->GetName());
+
+  const v8::HeapGraphNode* ws_table =
+      GetProperty(ws, v8::HeapGraphEdge::kInternal, "table");
+  CHECK_EQ(v8::HeapGraphNode::kArray, ws_table->GetType());
+  CHECK_GT(ws_table->GetChildrenCount(), 0);
+  int weak_entries = 0;
+  for (int i = 0, count = ws_table->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = ws_table->GetChild(i);
+    if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue;
+    if (k->GetId() == prop->GetToNode()->GetId()) {
+      ++weak_entries;
+    }
+  }
+  CHECK_EQ(1, weak_entries);
+  const v8::HeapGraphNode* ws_s =
+      GetProperty(ws, v8::HeapGraphEdge::kProperty, "str");
+  CHECK_NE(NULL, ws_s);
+  CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(ws_s->GetId()));
+
+  const v8::HeapGraphNode* wm =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "wm");
+  CHECK_NE(NULL, wm);
+  CHECK_EQ(v8::HeapGraphNode::kObject, wm->GetType());
+  CHECK_EQ(v8_str("WeakMap"), wm->GetName());
+
+  const v8::HeapGraphNode* wm_table =
+      GetProperty(wm, v8::HeapGraphEdge::kInternal, "table");
+  CHECK_EQ(v8::HeapGraphNode::kArray, wm_table->GetType());
+  CHECK_GT(wm_table->GetChildrenCount(), 0);
+  weak_entries = 0;
+  for (int i = 0, count = wm_table->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = wm_table->GetChild(i);
+    if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue;
+    const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
+    if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
+      ++weak_entries;
+    }
+  }
+  CHECK_EQ(2, weak_entries);
+  const v8::HeapGraphNode* wm_s =
+      GetProperty(wm, v8::HeapGraphEdge::kProperty, "str");
+  CHECK_NE(NULL, wm_s);
+  CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(wm_s->GetId()));
+}
+
+
+TEST(HeapSnapshotCollection) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun(
+      "k = {}; v = {}; s = 'str';\n"
+      "set = new Set(); set.add(k); set.add(v); set[s] = s;\n"
+      "map = new Map(); map.set(k, v); map[s] = s;\n");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("Collections"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* k =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
+  CHECK_NE(NULL, k);
+  const v8::HeapGraphNode* v =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
+  CHECK_NE(NULL, v);
+  const v8::HeapGraphNode* s =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
+  CHECK_NE(NULL, s);
+
+  const v8::HeapGraphNode* set =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "set");
+  CHECK_NE(NULL, set);
+  CHECK_EQ(v8::HeapGraphNode::kObject, set->GetType());
+  CHECK_EQ(v8_str("Set"), set->GetName());
+
+  const v8::HeapGraphNode* set_table =
+      GetProperty(set, v8::HeapGraphEdge::kInternal, "table");
+  CHECK_EQ(v8::HeapGraphNode::kArray, set_table->GetType());
+  CHECK_GT(set_table->GetChildrenCount(), 0);
+  int entries = 0;
+  for (int i = 0, count = set_table->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = set_table->GetChild(i);
+    const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
+    if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
+      ++entries;
+    }
+  }
+  CHECK_EQ(2, entries);
+  const v8::HeapGraphNode* set_s =
+      GetProperty(set, v8::HeapGraphEdge::kProperty, "str");
+  CHECK_NE(NULL, set_s);
+  CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(set_s->GetId()));
+
+  const v8::HeapGraphNode* map =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "map");
+  CHECK_NE(NULL, map);
+  CHECK_EQ(v8::HeapGraphNode::kObject, map->GetType());
+  CHECK_EQ(v8_str("Map"), map->GetName());
+
+  const v8::HeapGraphNode* map_table =
+      GetProperty(map, v8::HeapGraphEdge::kInternal, "table");
+  CHECK_EQ(v8::HeapGraphNode::kArray, map_table->GetType());
+  CHECK_GT(map_table->GetChildrenCount(), 0);
+  entries = 0;
+  for (int i = 0, count = map_table->GetChildrenCount(); i < count; ++i) {
+    const v8::HeapGraphEdge* prop = map_table->GetChild(i);
+    const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
+    if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
+      ++entries;
+    }
+  }
+  CHECK_EQ(2, entries);
+  const v8::HeapGraphNode* map_s =
+      GetProperty(map, v8::HeapGraphEdge::kProperty, "str");
+  CHECK_NE(NULL, map_s);
+  CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(map_s->GetId()));
+}
+
 
 TEST(HeapSnapshotInternalReferences) {
   v8::Isolate* isolate = CcTest::isolate();
@@ -691,11 +859,11 @@ class TestJSONStream : public v8::OutputStream {
     if (abort_countdown_ == 0) return kAbort;
     CHECK_GT(chars_written, 0);
     i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
-    i::OS::MemCopy(chunk.start(), buffer, chars_written);
+    i::MemCopy(chunk.start(), buffer, chars_written);
     return kContinue;
   }
   virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
-    ASSERT(false);
+    DCHECK(false);
     return kAbort;
   }
   void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
@@ -708,9 +876,9 @@ class TestJSONStream : public v8::OutputStream {
   int abort_countdown_;
 };
 
-class AsciiResource: public v8::String::ExternalAsciiStringResource {
+class OneByteResource : public v8::String::ExternalOneByteStringResource {
  public:
-  explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
+  explicit OneByteResource(i::Vector<char> string) : data_(string.start()) {
     length_ = string.length();
   }
   virtual const char* data() const { return data_; }
@@ -746,7 +914,7 @@ TEST(HeapSnapshotJSONSerialization) {
   stream.WriteTo(json);
 
   // Verify that snapshot string is valid JSON.
-  AsciiResource* json_res = new AsciiResource(json);
+  OneByteResource* json_res = new OneByteResource(json);
   v8::Local<v8::String> json_string =
       v8::String::NewExternal(env->GetIsolate(), json_res);
   env->Global()->Set(v8_str("json_snapshot"), json_string);
@@ -864,13 +1032,13 @@ class TestStatsStream : public v8::OutputStream {
   virtual ~TestStatsStream() {}
   virtual void EndOfStream() { ++eos_signaled_; }
   virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
-    ASSERT(false);
+    DCHECK(false);
     return kAbort;
   }
   virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
                                           int updates_written) {
     ++intervals_count_;
-    ASSERT(updates_written);
+    DCHECK(updates_written);
     updates_written_ += updates_written;
     entries_count_ = 0;
     if (first_interval_index_ == -1 && updates_written != 0)
@@ -1555,9 +1723,9 @@ TEST(GlobalObjectFields) {
   const v8::HeapGraphNode* global_context =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context");
   CHECK_NE(NULL, global_context);
-  const v8::HeapGraphNode* global_receiver =
-      GetProperty(global, v8::HeapGraphEdge::kInternal, "global_receiver");
-  CHECK_NE(NULL, global_receiver);
+  const v8::HeapGraphNode* global_proxy =
+      GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
+  CHECK_NE(NULL, global_proxy);
 }
 
 
@@ -1602,7 +1770,7 @@ TEST(GetHeapValueForNode) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
-  CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };");
+  CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };");
   const v8::HeapSnapshot* snapshot =
       heap_profiler->TakeHeapSnapshot(v8_str("value"));
   CHECK(ValidateSnapshot(snapshot));
@@ -1623,10 +1791,9 @@ TEST(GetHeapValueForNode) {
   CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId()));
   const v8::HeapGraphNode* n_prop =
       GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
-  v8::Local<v8::Number> js_n_prop =
-      js_obj->Get(v8_str("n_prop")).As<v8::Number>();
-  CHECK(js_n_prop->NumberValue() ==
-        heap_profiler->FindObjectById(n_prop->GetId())->NumberValue());
+  v8::Local<v8::String> js_n_prop =
+      js_obj->Get(v8_str("n_prop")).As<v8::String>();
+  CHECK(js_n_prop == heap_profiler->FindObjectById(n_prop->GetId()));
 }
 
 
@@ -1697,12 +1864,16 @@ TEST(GetConstructorName) {
       "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
   v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
   i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
-  CHECK_EQ(0, StringCmp(
-      "Constructor3", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
+  // TODO(verwaest): Restore to Constructor3 once supported by the
+  // heap-snapshot-generator.
+  CHECK_EQ(
+      0, StringCmp("Object", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
   v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
   i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
-  CHECK_EQ(0, StringCmp(
-      "Constructor4", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
+  // TODO(verwaest): Restore to Constructor4 once supported by the
+  // heap-snapshot-generator.
+  CHECK_EQ(
+      0, StringCmp("Object", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
   v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
   i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
   CHECK_EQ(0, StringCmp(
@@ -1817,6 +1988,46 @@ TEST(HiddenPropertiesFastCase) {
 }
 
 
+TEST(AccessorInfo) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun("function foo(x) { }\n");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("AccessorInfoTest"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* foo =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
+  CHECK_NE(NULL, foo);
+  const v8::HeapGraphNode* map =
+      GetProperty(foo, v8::HeapGraphEdge::kInternal, "map");
+  CHECK_NE(NULL, map);
+  const v8::HeapGraphNode* descriptors =
+      GetProperty(map, v8::HeapGraphEdge::kInternal, "descriptors");
+  CHECK_NE(NULL, descriptors);
+  const v8::HeapGraphNode* length_name =
+      GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "2");
+  CHECK_NE(NULL, length_name);
+  CHECK_EQ("length", *v8::String::Utf8Value(length_name->GetName()));
+  const v8::HeapGraphNode* length_accessor =
+      GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "4");
+  CHECK_NE(NULL, length_accessor);
+  CHECK_EQ("system / ExecutableAccessorInfo",
+           *v8::String::Utf8Value(length_accessor->GetName()));
+  const v8::HeapGraphNode* name =
+      GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "name");
+  CHECK_NE(NULL, name);
+  const v8::HeapGraphNode* getter =
+      GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "getter");
+  CHECK_NE(NULL, getter);
+  const v8::HeapGraphNode* setter =
+      GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "setter");
+  CHECK_NE(NULL, setter);
+}
+
+
 bool HasWeakEdge(const v8::HeapGraphNode* node) {
   for (int i = 0; i < node->GetChildrenCount(); ++i) {
     const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
@@ -1884,13 +2095,12 @@ TEST(SfiAndJsFunctionWeakRefs) {
 }
 
 
-#ifdef ENABLE_DEBUGGER_SUPPORT
 TEST(NoDebugObjectInSnapshot) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
-  CcTest::i_isolate()->debug()->Load();
+  CHECK(CcTest::i_isolate()->debug()->Load());
   CompileRun("foo = {};");
   const v8::HeapSnapshot* snapshot =
       heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
@@ -1909,7 +2119,6 @@ TEST(NoDebugObjectInSnapshot) {
   }
   CHECK_EQ(1, globals_count);
 }
-#endif  // ENABLE_DEBUGGER_SUPPORT
 
 
 TEST(AllStrongGcRootsHaveNames) {
@@ -2020,7 +2229,7 @@ TEST(ManyLocalsInSharedContext) {
   // ... well check just every 15th because otherwise it's too slow in debug.
   for (int i = 0; i < num_objects - 1; i += 15) {
     i::EmbeddedVector<char, 100> var_name;
-    i::OS::SNPrintF(var_name, "f_%d", i);
+    i::SNPrintF(var_name, "f_%d", i);
     const v8::HeapGraphNode* f_object = GetProperty(
         context_object, v8::HeapGraphEdge::kContextVariable, var_name.start());
     CHECK_NE(NULL, f_object);
@@ -2115,7 +2324,7 @@ static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
       v8::String::Utf8Value edge_name(edge->GetName());
       v8::String::Utf8Value node_name(to_node->GetName());
       i::EmbeddedVector<char, 100> name;
-      i::OS::SNPrintF(name, "%s::%s", *edge_name, *node_name);
+      i::SNPrintF(name, "%s::%s", *edge_name, *node_name);
       if (strstr(name.start(), path[current_depth])) {
         node = to_node;
         break;
@@ -2143,7 +2352,7 @@ TEST(CheckCodeNames) {
     "::(ArraySingleArgumentConstructorStub code)"
   };
   const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
-      stub_path, ARRAY_SIZE(stub_path));
+      stub_path, arraysize(stub_path));
   CHECK_NE(NULL, node);
 
   const char* builtin_path1[] = {
@@ -2151,18 +2360,15 @@ TEST(CheckCodeNames) {
     "::(Builtins)",
     "::(KeyedLoadIC_Generic builtin)"
   };
-  node = GetNodeByPath(snapshot, builtin_path1, ARRAY_SIZE(builtin_path1));
+  node = GetNodeByPath(snapshot, builtin_path1, arraysize(builtin_path1));
   CHECK_NE(NULL, node);
 
-  const char* builtin_path2[] = {
-    "::(GC roots)",
-    "::(Builtins)",
-    "::(CompileUnoptimized builtin)"
-  };
-  node = GetNodeByPath(snapshot, builtin_path2, ARRAY_SIZE(builtin_path2));
+  const char* builtin_path2[] = {"::(GC roots)", "::(Builtins)",
+                                 "::(CompileLazy builtin)"};
+  node = GetNodeByPath(snapshot, builtin_path2, arraysize(builtin_path2));
   CHECK_NE(NULL, node);
   v8::String::Utf8Value node_name(node->GetName());
-  CHECK_EQ("(CompileUnoptimized builtin)", *node_name);
+  CHECK_EQ("(CompileLazy builtin)", *node_name);
 }
 
 
@@ -2242,7 +2448,7 @@ TEST(ArrayGrowLeftTrim) {
     "for (var i = 0; i < 3; ++i)\n"
     "    a.shift();\n");
 
-  const char* names[] = { "(anonymous function)" };
+  const char* names[] = {""};
   AllocationTracker* tracker =
       reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
   CHECK_NE(NULL, tracker);
@@ -2252,7 +2458,7 @@ TEST(ArrayGrowLeftTrim) {
   tracker->trace_tree()->Print(tracker);
 
   AllocationTraceNode* node =
-      FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
+      FindNode(tracker, Vector<const char*>(names, arraysize(names)));
   CHECK_NE(NULL, node);
   CHECK_GE(node->allocation_count(), 2);
   CHECK_GE(node->allocation_size(), 4 * 5);
@@ -2277,10 +2483,9 @@ TEST(TrackHeapAllocations) {
   // Print for better diagnostics in case of failure.
   tracker->trace_tree()->Print(tracker);
 
-  const char* names[] =
-      { "(anonymous function)", "start", "f_0_0", "f_0_1", "f_0_2" };
+  const char* names[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"};
   AllocationTraceNode* node =
-      FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
+      FindNode(tracker, Vector<const char*>(names, arraysize(names)));
   CHECK_NE(NULL, node);
   CHECK_GE(node->allocation_count(), 100);
   CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
@@ -2313,7 +2518,7 @@ TEST(TrackBumpPointerAllocations) {
   LocalContext env;
 
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
-  const char* names[] = { "(anonymous function)", "start", "f_0", "f_1" };
+  const char* names[] = {"", "start", "f_0", "f_1"};
   // First check that normally all allocations are recorded.
   {
     heap_profiler->StartTrackingHeapObjects(true);
@@ -2329,7 +2534,7 @@ TEST(TrackBumpPointerAllocations) {
     tracker->trace_tree()->Print(tracker);
 
     AllocationTraceNode* node =
-        FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
+        FindNode(tracker, Vector<const char*>(names, arraysize(names)));
     CHECK_NE(NULL, node);
     CHECK_GE(node->allocation_count(), 100);
     CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
@@ -2355,7 +2560,7 @@ TEST(TrackBumpPointerAllocations) {
     tracker->trace_tree()->Print(tracker);
 
     AllocationTraceNode* node =
-        FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
+        FindNode(tracker, Vector<const char*>(names, arraysize(names)));
     CHECK_NE(NULL, node);
     CHECK_LT(node->allocation_count(), 100);
 
@@ -2385,7 +2590,7 @@ TEST(TrackV8ApiAllocation) {
   tracker->trace_tree()->Print(tracker);
 
   AllocationTraceNode* node =
-      FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
+      FindNode(tracker, Vector<const char*>(names, arraysize(names)));
   CHECK_NE(NULL, node);
   CHECK_GE(node->allocation_count(), 2);
   CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
@@ -2447,7 +2652,7 @@ TEST(ArrayBufferSharedBackingStore) {
 
   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
   void* data = ab_contents.Data();
-  ASSERT(data != NULL);
+  DCHECK(data != NULL);
   v8::Local<v8::ArrayBuffer> ab2 =
       v8::ArrayBuffer::New(isolate, data, ab_contents.ByteLength());
   CHECK(ab2->IsExternal());
@@ -2487,8 +2692,7 @@ TEST(BoxObject) {
   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
 
   i::Factory* factory = CcTest::i_isolate()->factory();
-  i::Handle<i::String> string =
-      factory->NewStringFromAscii(i::CStrVector("string"));
+  i::Handle<i::String> string = factory->NewStringFromStaticChars("string");
   i::Handle<i::Object> box = factory->NewBox(string);
   global->Set(0, v8::ToApiHandle<v8::Object>(box));
 
@@ -2508,6 +2712,41 @@ TEST(BoxObject) {
 }
 
 
+TEST(WeakContainers) {
+  i::FLAG_allow_natives_syntax = true;
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  if (!CcTest::i_isolate()->use_crankshaft()) return;
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  CompileRun(
+      "function foo(a) { return a.x; }\n"
+      "obj = {x : 123};\n"
+      "foo(obj);\n"
+      "foo(obj);\n"
+      "%OptimizeFunctionOnNextCall(foo);\n"
+      "foo(obj);\n");
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  const v8::HeapGraphNode* obj =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
+  CHECK_NE(NULL, obj);
+  const v8::HeapGraphNode* map =
+      GetProperty(obj, v8::HeapGraphEdge::kInternal, "map");
+  CHECK_NE(NULL, map);
+  const v8::HeapGraphNode* dependent_code =
+      GetProperty(map, v8::HeapGraphEdge::kInternal, "dependent_code");
+  if (!dependent_code) return;
+  int count = dependent_code->GetChildrenCount();
+  CHECK_NE(0, count);
+  for (int i = 0; i < count; ++i) {
+    const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
+    CHECK_EQ(v8::HeapGraphEdge::kWeak, prop->GetType());
+  }
+}
+
+
 static inline i::Address ToAddress(int n) {
   return reinterpret_cast<i::Address>(n);
 }
@@ -2566,3 +2805,375 @@ TEST(AddressToTraceMap) {
   CHECK_EQ(0, static_cast<int>(map.size()));
   CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x400)));
 }
+
+struct TestObjectInfo {
+  std::vector<std::string> bu_call_stack_;
+  std::string type_;
+  unsigned number_of_objects_;
+};
+
+struct TestFrameInfo {
+  unsigned frame_id_;
+  unsigned callsite_;
+  unsigned parent_;
+};
+
+struct Chunk {
+  unsigned time_begin_;
+  unsigned time_end_;
+  unsigned frame_id_;
+  unsigned type_id_;
+  unsigned size_;
+  unsigned number_of_objects_;
+};
+
+class XDKHPOutputChecker {
+ public:
+  // If info.number_of_objects_ is not eq 0, then it participates in the search
+  // and we look for the record by 3 parameters. In other case we look for the
+  // chunk by call stack and type id only
+  bool checkObjectsExists(const TestObjectInfo& info, std::string chunk) {
+    std::vector<Chunk> chunks = parseChunk(chunk);
+    // look for the frame id, which correspond to the passed stack
+    // get the type id:
+    std::vector<unsigned> frames = findFrame(info.bu_call_stack_);
+    unsigned type_id = types_[info.type_];
+    for (size_t i = 0; i < chunks.size(); i++) {
+      for (size_t j = 0; j < frames.size(); j++) {
+        if (chunks[i].frame_id_ == frames[j] && chunks[i].type_id_ == type_id &&
+            (info.number_of_objects_ ? chunks[i].number_of_objects_ ==
+            info.number_of_objects_ : true)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+  void parse(const char* symbols, const char* frames, const char* types) {
+    std::string symbols_std_ = symbols;
+    std::string frames_std_ = frames;
+    std::string types_std_ = types;
+    {
+      // parse symbols, don't care of line and column
+      size_t s1_pos = 0, s2_pos = 0;
+      int sym_id;
+      std::string function_name;
+      while (s2_pos != symbols_std_.npos) {
+        // look for the \n symbol
+        // format: symId, funcId, funcName, line, column
+        s2_pos = symbols_std_.find("\n", s1_pos);
+        if (s2_pos != symbols_std_.npos) {
+          int sym_id_e = symbols_std_.find(",", s1_pos);
+          std::string sym_id_s = symbols_std_.substr(s1_pos, sym_id_e - s1_pos);
+          sym_id = atoi(sym_id_s.c_str());
+          int func_id_e = symbols_std_.find(",", sym_id_e + 1);
+          int finc_name_e = symbols_std_.find(",", func_id_e + 1);
+          function_name = symbols_std_.substr(func_id_e + 1, finc_name_e -
+              func_id_e - 1);
+          symbols_[function_name] = sym_id;
+          s1_pos = s2_pos + 1;
+        }
+      }
+    }
+    {
+      // parse types
+      size_t s1_pos = 0, s2_pos = 0;
+      unsigned type_id;
+      std::string type_name;
+      while (s2_pos != types_std_.npos) {
+        // look for the \n symbol
+        // format: typeId, typeName
+        s2_pos = types_std_.find("\n", s1_pos);
+        if (s2_pos != types_std_.npos) {
+          int type_id_e = types_std_.find(",", s1_pos);
+          std::string sym_id_s = types_std_.substr(s1_pos, type_id_e - s1_pos);
+          type_id = atoi(sym_id_s.c_str());
+          type_name = types_std_.substr(type_id_e + 1, s2_pos - type_id_e - 1);
+
+          types_[type_name] = type_id;
+          s1_pos = s2_pos + 1;
+        }
+      }
+    }
+    {
+      // parse frames
+      size_t s1_pos = 0, s2_pos = 0;
+      int frame_id, symbol_id, parent_id;
+      while (s2_pos != frames_std_.npos) {
+        // look for the \n symbol
+        // format: frameId, symbolId, parentId
+        s2_pos = frames_std_.find("\n", s1_pos);
+        if (s2_pos != frames_std_.npos) {
+          int frame_id_e = frames_std_.find(",", s1_pos);
+          std::string frame_id_s = frames_std_.substr(s1_pos,
+                                                      frame_id_e - s1_pos);
+          frame_id = atoi(frame_id_s.c_str());
+
+          int symb_id_e = frames_std_.find(",", frame_id_e + 1);
+          std::string symb_id_s = frames_std_.substr(frame_id_e + 1,
+                                                    symb_id_e - frame_id_e - 1);
+          symbol_id = atoi(symb_id_s.c_str());
+
+          int parent_id_e = frames_std_.find(",", symb_id_e + 1);
+          std::string parent_id_s = frames_std_.substr(symb_id_e + 1,
+                                                      s2_pos - parent_id_e - 1);
+          parent_id = atoi(parent_id_s.c_str());
+          TestFrameInfo info;
+          info.callsite_ = symbol_id;
+          info.frame_id_ = frame_id;
+          info.parent_ = parent_id;
+          frames_.push_back(info);
+          s1_pos = s2_pos + 1;
+        }
+      }
+    }
+  }
+
+  std::vector<Chunk> parseChunk(const std::string& chunk_std) {
+    std::vector<Chunk> chunks;
+    {
+      // parse chunks
+      size_t s1_pos = 0, s2_pos = 0;
+      unsigned time_begin, time_end, frame_id, type_id, size, number_of_objects;
+
+      while (s2_pos != chunk_std.npos) {
+        // look for the \n symbol
+        // format: frameId, symbolId, parentId
+        s2_pos = chunk_std.find("\n", s1_pos);
+        if (s2_pos != chunk_std.npos) {
+          int c1_e = chunk_std.find(",", s1_pos);
+          std::string c1_s = chunk_std.substr(s1_pos, c1_e - s1_pos);
+          time_begin = atoi(c1_s.c_str());
+
+          int c2_e = chunk_std.find(",", c1_e + 1);
+          std::string c2_s = chunk_std.substr(c1_e + 1, c2_e - c1_e - 1);
+          time_end = atoi(c2_s.c_str());
+
+          int c3_e = chunk_std.find(",", c2_e + 1);
+          std::string c3_s = chunk_std.substr(c2_e + 1, c3_e - c2_e - 1);
+          frame_id = atoi(c3_s.c_str());
+
+          int c4_e = chunk_std.find(",", c3_e + 1);
+          std::string c4_s = chunk_std.substr(c3_e + 1, c4_e - c3_e - 1);
+          type_id = atoi(c4_s.c_str());
+
+          int c5_e = chunk_std.find(",", c4_e + 1);
+          std::string c5_s = chunk_std.substr(c4_e + 1, c5_e - c4_e - 1);
+          size = atoi(c5_s.c_str());
+
+          int c6_e = chunk_std.find(",", c5_e + 1);
+          std::string c6_s = chunk_std.substr(c5_e + 1, c6_e - c5_e - 1);
+          number_of_objects = atoi(c6_s.c_str());
+
+          Chunk chunk;
+          chunk.frame_id_ = frame_id;
+          chunk.number_of_objects_ = number_of_objects;
+          chunk.size_ = size;
+          chunk.time_begin_ = time_begin;
+          chunk.time_end_ = time_end;
+          chunk.type_id_ = type_id;
+          chunks.push_back(chunk);
+          s1_pos = s2_pos + 1;
+        }
+      }
+    }
+    return chunks;
+  }
+
+ private:
+  size_t getFrameIdx(unsigned frame_id) {
+    for (size_t i = 0; i < frames_.size(); i++) {
+      if (frames_[i].frame_id_ == frame_id) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  std::vector<unsigned> findFrame(std::vector<std::string> bu_call_stack) {
+    std::vector<unsigned> frames;
+
+    std::map<std::string, unsigned>::const_iterator cit =
+        symbols_.find(bu_call_stack[0]);
+    if (cit != symbols_.end()) {
+        // take the cit->second and look for it in the frames
+      for (size_t j = 0; j < frames_.size(); j++) {
+        if (frames_[j].callsite_ == cit->second) {
+          bool good_frame = true;
+          // check all other frames iterating by parents
+          unsigned parent_frame = frames_[j].parent_;
+          for (size_t i = 1; i < bu_call_stack.size() && good_frame; i++) {
+            size_t idx = getFrameIdx(parent_frame);
+            if (idx != (size_t)-1) {
+              TestFrameInfo& parent = frames_[idx];
+              std::map<std::string, unsigned>::const_iterator cit2 =
+                  symbols_.find(bu_call_stack[i]);
+              if (cit2 != symbols_.end()) {
+                if (cit2->second == parent.callsite_) {
+                  parent_frame = parent.parent_;
+                } else {
+                  good_frame = false;
+                }
+              } else {
+                good_frame = false;
+              }
+            } else {
+              good_frame = false;
+            }
+          }
+          if (good_frame) {
+            frames.push_back(frames_[j].frame_id_);
+          }
+        }
+      }
+    }
+    return frames;
+  }
+  std::map<std::string, unsigned> symbols_;
+  std::map<std::string, unsigned> types_;
+  // no need to have fast version, it will not be many frames
+  std::vector<TestFrameInfo> frames_;
+};
+
+class TestStatsStreamXDK : public v8::OutputStream {
+ public:
+  explicit TestStatsStreamXDK(XDKHPOutputChecker* checker) :
+    checker_(checker) {}
+  virtual ~TestStatsStreamXDK() {}
+  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
+    DCHECK(false);
+    return kAbort;
+  }
+  virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* data,
+                                          int count) {
+    DCHECK(false);
+    return kAbort;
+  }
+  virtual WriteResult WriteHeapXDKChunk(const char* symbols, int symbolsSize,
+    const char* frames, int framesSize,
+    const char* types, int typesSize,
+    const char* chunks, int chunksSize,
+    const char* retentions, int retentionSize) {
+    checker_->parse(symbols, frames, types);
+    chunk_ = chunks;
+    return kContinue;
+  }
+  void EndOfStream() {}
+
+  std::string GetChunk() {
+    return chunk_;
+  }
+
+ private:
+  XDKHPOutputChecker* checker_;
+  std::string chunk_;
+};
+
+
+TEST(HeapProfilerXDK) {
+  XDKHPOutputChecker checker;
+  LocalContext env2;
+  v8::HandleScope scope(env2->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env2->GetIsolate()->GetHeapProfiler();
+  TestStatsStreamXDK stream(&checker);
+  heap_profiler->StartTrackingHeapObjectsXDK(8, false, true);
+
+  // To have repeatable test we need to warm-up the heap and optimization v8
+  // techniques (like inlining). So, we create 100 objects, not the only one
+  CompileRun(
+    "function A1() { this.string = 'This is a string';}\n"
+    "function object2() {\n"
+    "  this.elem = [];\n"
+    "  this.third = [];\n"
+    "}"
+    "var globalA2 = [];\n"
+    "function allocFunction2() {\n"
+    "  globalA2.push(new object2());\n"
+    "}\n"
+    "for (var i=0; i<100; i++) allocFunction2();\n");
+
+  heap_profiler->GetHeapXDKStats(&stream);
+  CompileRun("allocFunction2();\n");
+  heap_profiler->GetHeapXDKStats(&stream);
+  CompileRun("delete globalA2[99];\n");
+  heap_profiler->GetHeapXDKStats(&stream);
+  std::string chunk_deleted_globalA2_0_array = stream.GetChunk();
+  v8::HeapEventXDK* event = heap_profiler->StopTrackingHeapObjectsXDK();
+
+  // adding the latest info:
+  checker.parse(event->getSymbols(), event->getFrames(), event->getTypes());
+
+  // here should be 2 arrays and 1 object2
+  TestObjectInfo info_deleted_globalA2_0_array;
+  info_deleted_globalA2_0_array.bu_call_stack_.push_back("object2");
+  info_deleted_globalA2_0_array.bu_call_stack_.push_back("allocFunction2");
+  info_deleted_globalA2_0_array.type_ = "Array";
+  info_deleted_globalA2_0_array.number_of_objects_ = 0;
+  bool idg_arr_jad = checker.checkObjectsExists(
+      info_deleted_globalA2_0_array, chunk_deleted_globalA2_0_array);
+
+  TestObjectInfo info_deleted_globalA2_0;
+  info_deleted_globalA2_0.bu_call_stack_.push_back("allocFunction2");
+  info_deleted_globalA2_0.type_ = "object2";
+  info_deleted_globalA2_0.number_of_objects_ = 1;
+  bool idg_obj_jad = checker.checkObjectsExists(
+      info_deleted_globalA2_0, chunk_deleted_globalA2_0_array);
+
+  // here should be 2 arrays and 1 object2
+  TestObjectInfo info_deleted_globalA2_1_array;
+  info_deleted_globalA2_1_array.bu_call_stack_.push_back("object2");
+  info_deleted_globalA2_1_array.bu_call_stack_.push_back("allocFunction2");
+  info_deleted_globalA2_1_array.type_ = "Array";
+  info_deleted_globalA2_1_array.number_of_objects_ = 2;
+  bool idg_arr_end = checker.checkObjectsExists(
+      info_deleted_globalA2_1_array, event->getChunks());
+
+  TestObjectInfo info_deleted_globalA2_1;
+  info_deleted_globalA2_1.bu_call_stack_.push_back("allocFunction2");
+  info_deleted_globalA2_1.type_ = "object2";
+  info_deleted_globalA2_1.number_of_objects_ = 1;
+  bool idg_obj_end = checker.checkObjectsExists(
+      info_deleted_globalA2_1, event->getChunks());
+  // find objects anywhere
+  CHECK_EQ(true, idg_obj_end || idg_obj_jad);
+  CHECK_EQ(true, idg_arr_end || idg_arr_jad);
+}
+
+
+TEST(HeapProfilerXDKRetentionStorage) {
+  v8::internal::RefId parent;
+  v8::internal::RefId rf11, rf12, rf13, rf21, rf22, rf23;
+  v8::internal::RefSet set1, set2, set3;
+  v8::internal::References refs;
+
+  parent.stackId_ = 99;
+  parent.classId_ = 99;
+
+  rf11.stackId_ = 10; rf11.classId_ = 1; rf11.field_ = "one_";
+  set1.references_.insert(rf11);
+  rf12.stackId_ = 20; rf12.classId_ = 1; rf12.field_ = "two_";
+  set1.references_.insert(rf12);
+  rf13.stackId_ = 30; rf13.classId_ = 2; rf13.field_ = "three_";
+  set1.references_.insert(rf13);
+  refs.addReference(parent, set1, 0);
+
+  rf21.stackId_ = 10; rf21.classId_ = 1; rf21.field_ = "eno_";
+  set2.references_.insert(rf21);
+  rf22.stackId_ = 15; rf22.classId_ = 1; rf22.field_ = "owt_";
+  set2.references_.insert(rf22);
+  rf23.stackId_ = 30; rf23.classId_ = 2; rf23.field_ = "eerht_";
+  set2.references_.insert(rf23);
+  refs.addReference(parent, set2, 0);
+
+  set3.references_.insert(rf11);
+  set3.references_.insert(rf12);
+  set3.references_.insert(rf13);
+  refs.addReference(parent, set3, 0);
+
+  // there should be two records by set1 and one by set2
+  std::string str = refs.serialize();
+
+  CHECK_EQ(true,
+       str.find("99,99,1,0,2,10,1,one_,20,1,two_,30,2,three_") != str.npos &&
+       str.find("99,99,1,0,1,10,1,eno_,15,1,owt_,30,2,eerht_") != str.npos);
+}