test-heap-profiler.cc revision 3bec4d28b1f388dbc06a9c4276e1a03e86c52b04
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2009 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Tests for heap profiler 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h" 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "heap-profiler.h" 99dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen#include "snapshot.h" 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "string-stream.h" 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "cctest.h" 126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#include "zone-inl.h" 139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen#include "../include/v8-profiler.h" 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace i = v8::internal; 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::ClustersCoarser; 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsCluster; 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsRetainerTree; 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsClusterTree; 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::RetainerHeapProfile; 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileAndRunScript(const char *src) { 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::Script::Compile(v8::String::New(src))->Run(); 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace { 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile { 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ConstructorHeapProfileTestHelper() 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : i::ConstructorHeapProfile(), 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))), 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block f_count_(0) { 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void Call(const JSObjectsCluster& cluster, 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const i::NumberAndSizeInfo& number_and_size) { 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (f_name_->Equals(cluster.constructor())) { 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(f_count_, 0); 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block f_count_ = number_and_size.number(); 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_GT(f_count_, 0); 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int f_count() { return f_count_; } 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::Handle<i::String> f_name_; 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int f_count_; 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} // namespace 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ConstructorProfile) { 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::HandleScope scope; 593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompileAndRunScript( 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function F() {} // A constructor\n" 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "var f1 = new F();\n" 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "var f2 = new F();\n"); 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ConstructorHeapProfileTestHelper cons_profile; 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::AssertNoAllocation no_alloc; 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::HeapIterator iterator; 69d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cons_profile.CollectStats(obj); 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(0, cons_profile.f_count()); 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cons_profile.PrintStats(); 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(2, cons_profile.f_count()); 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree, 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::String* constructor, 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int instance, 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster* ref1 = NULL, 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster* ref2 = NULL, 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster* ref3 = NULL) { 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance)); 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsClusterTree* o_tree = new JSObjectsClusterTree(); 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsClusterTree::Locator o_loc; 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc); 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc); 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc); 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsRetainerTree::Locator loc; 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block tree->Insert(o, &loc); 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loc.set_value(o_tree); 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return o; 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void AddSelfReferenceToTree(JSObjectsRetainerTree* tree, 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster* self_ref) { 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsRetainerTree::Locator loc; 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK(tree->Find(*self_ref, &loc)); 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsClusterTree::Locator o_loc; 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(NULL, loc.value()); 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block loc.value()->Insert(*self_ref, &o_loc); 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic inline void CheckEqualsHelper(const char* file, int line, 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* expected_source, 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const JSObjectsCluster& expected, 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* value_source, 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const JSObjectsCluster& value) { 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (JSObjectsCluster::Compare(expected, value) != 0) { 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::HeapStringAllocator allocator; 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::StringStream stream(&allocator); 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream.Add("# Expected: "); 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expected.DebugPrint(&stream); 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream.Add("\n# Found: "); 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.DebugPrint(&stream); 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s", 119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expected_source, value_source, 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *stream.ToCString()); 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic inline void CheckNonEqualsHelper(const char* file, int line, 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* expected_source, 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const JSObjectsCluster& expected, 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* value_source, 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const JSObjectsCluster& value) { 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (JSObjectsCluster::Compare(expected, value) == 0) { 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::HeapStringAllocator allocator; 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::StringStream stream(&allocator); 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream.Add("# !Expected: "); 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expected.DebugPrint(&stream); 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream.Add("\n# Found: "); 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value.DebugPrint(&stream); 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s", 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block expected_source, value_source, 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *stream.ToCString()); 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSimple) { 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::HandleScope scope; 1463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::ZoneScope zn_scope(i::DELETE_ON_EXIT); 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsRetainerTree tree; 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster function(i::Heap::function_class_symbol()); 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A"))); 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B"))); 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o1 <- Function 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o1 = 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function); 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o2 <- Function 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o2 = 160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function); 161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o3 <- A, B 162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o3 = 163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b); 164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o4 <- B, A 165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o4 = 166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a); 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o5 <- A, B, Function 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o5 = 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500, 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &a, &b, &function); 171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ClustersCoarser coarser; 173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block coarser.Process(&tree); 174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2)); 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4)); 177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3)); 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5)); 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserMultipleConstructors) { 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::HandleScope scope; 1843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::ZoneScope zn_scope(i::DELETE_ON_EXIT); 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsRetainerTree tree; 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster function(i::Heap::function_class_symbol()); 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o1 <- Function 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o1 = 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function); 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a1 <- Function 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster a1 = 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function); 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o2 <- Function 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o2 = 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function); 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // a2 <- Function 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster a2 = 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function); 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ClustersCoarser coarser; 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block coarser.Process(&tree); 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2)); 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2)); 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserPathsTraversal) { 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::HandleScope scope; 2143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::ZoneScope zn_scope(i::DELETE_ON_EXIT); 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsRetainerTree tree; 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // On the following graph: 221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // p 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // <- o21 <- o11 <- 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // q o 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // <- o22 <- o12 <- 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we expect that coarser will deduce equivalences: p ~ q ~ r, 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // o21 ~ o22, and o11 ~ o12. 230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o = 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100); 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o11 = 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o); 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o12 = 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o); 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o21 = 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11); 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o22 = 240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12); 241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster p = 242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21); 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster q = 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22); 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster r = 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22); 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ClustersCoarser coarser; 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block coarser.Process(&tree); 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o)); 252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11)); 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12)); 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22)); 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21)); 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p)); 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q)); 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r)); 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p)); 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p)); 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSelf) { 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::HandleScope scope; 2663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::ZoneScope zn_scope(i::DELETE_ON_EXIT); 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsRetainerTree tree; 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // On the following graph: 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // p (self-referencing) 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // <- o1 <- 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // q (self-referencing) o 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // <- o2 <- 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r (self-referencing) 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2; 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o = 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100); 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o1 = 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o); 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster o2 = 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o); 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster p = 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1); 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddSelfReferenceToTree(&tree, &p); 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster q = 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2); 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddSelfReferenceToTree(&tree, &q); 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObjectsCluster r = 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2); 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AddSelfReferenceToTree(&tree, &r); 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ClustersCoarser coarser; 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block coarser.Process(&tree); 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o)); 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1)); 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2)); 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p)); 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q)); 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r)); 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p)); 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace { 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass RetainerProfilePrinter : public RetainerHeapProfile::Printer { 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {} 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void PrintRetainers(const JSObjectsCluster& cluster, 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const i::StringStream& retainers) { 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block cluster.Print(&stream_); 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream_.Add("%s", *(retainers.ToCString())); 321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream_.Put('\0'); 322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* GetRetainers(const char* constructor) { 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FillLines(); 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const size_t cons_len = strlen(constructor); 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < lines_.length(); ++i) { 328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (strncmp(constructor, lines_[i], cons_len) == 0 && 329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block lines_[i][cons_len] == ',') { 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return lines_[i] + cons_len + 1; 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return NULL; 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void FillLines() { 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (lines_.length() > 0) return; 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream_.Put('\0'); 340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stream_str_ = stream_.ToCString(); 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* pos = *stream_str_; 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (pos != NULL && *pos != '\0') { 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block lines_.Add(pos); 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pos = strchr(pos, '\0'); 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (pos != NULL) ++pos; 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::HeapStringAllocator allocator_; 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::StringStream stream_; 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::SmartPointer<const char> stream_str_; 352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::List<const char*> lines_; 353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} // namespace 356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(RetainerProfile) { 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::HandleScope scope; 3603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompileAndRunScript( 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function A() {}\n" 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function B(x) { this.x = x; }\n" 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function C(x) { this.x1 = x; this.x2 = x; }\n" 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "var a = new A();\n" 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "var b1 = new B(a), b2 = new B(a);\n" 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "var c = new C(a);"); 369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RetainerHeapProfile ret_profile; 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::AssertNoAllocation no_alloc; 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::HeapIterator iterator; 373d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ret_profile.CollectStats(obj); 375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RetainerProfilePrinter printer; 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ret_profile.DebugPrintStats(&printer); 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* retainers_of_a = printer.GetRetainers("A"); 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The order of retainers is unspecified, so we check string length, and 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // verify each retainer separately. 380d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"), 381d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block i::StrLength(retainers_of_a)); 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK(strstr(retainers_of_a, "(global property);1") != NULL); 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK(strstr(retainers_of_a, "B;2") != NULL); 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK(strstr(retainers_of_a, "C;2") != NULL); 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ("(global property);2", printer.GetRetainers("B")); 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ("(global property);1", printer.GetRetainers("C")); 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 3909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsennamespace { 3919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 3929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenclass NamedEntriesDetector { 3939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen public: 3949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen NamedEntriesDetector() 3959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen : has_A1(false), has_B1(false), has_C1(false), 3969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen has_A2(false), has_B2(false), has_C2(false) { 3979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 3989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 3999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen void Apply(i::HeapEntry* entry) { 4009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const char* node_name = entry->name(); 4019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("A1", node_name) == 0 4029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && entry->GetRetainingPaths()->length() > 0) has_A1 = true; 4039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("B1", node_name) == 0 4049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && entry->GetRetainingPaths()->length() > 0) has_B1 = true; 4059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("C1", node_name) == 0 4069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && entry->GetRetainingPaths()->length() > 0) has_C1 = true; 4079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("A2", node_name) == 0 4089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && entry->GetRetainingPaths()->length() > 0) has_A2 = true; 4099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("B2", node_name) == 0 4109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && entry->GetRetainingPaths()->length() > 0) has_B2 = true; 4119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("C2", node_name) == 0 4129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && entry->GetRetainingPaths()->length() > 0) has_C2 = true; 4139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 4149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_A1; 4169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_B1; 4179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_C1; 4189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_A2; 4199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_B2; 4209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_C2; 4219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}; 4229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} // namespace 4249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic const v8::HeapGraphNode* GetGlobalObject( 4279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapSnapshot* snapshot) { 4283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ(1, snapshot->GetRoot()->GetChildrenCount()); 4293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch return snapshot->GetRoot()->GetChild(0)->GetToNode(); 4309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} 4319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4339dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node, 4349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::HeapGraphEdge::Type type, 4359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const char* name) { 4369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { 4379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphEdge* prop = node->GetChild(i); 4389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::String::AsciiValue prop_name(prop->GetName()); 4399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (prop->GetType() == type && strcmp(name, *prop_name) == 0) 4409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen return prop->GetToNode(); 4419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 4429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen return NULL; 4439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} 4449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochstatic bool IsNodeRetainedAs(const v8::HeapGraphNode* node, 4473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HeapGraphEdge::Type type, 4483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const char* name) { 4493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) { 4503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphEdge* prop = node->GetRetainer(i); 4513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::String::AsciiValue prop_name(prop->GetName()); 4523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (prop->GetType() == type && strcmp(name, *prop_name) == 0) 4533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch return true; 4543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 4553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch return false; 4563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch} 4573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 4583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 4599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic bool HasString(const v8::HeapGraphNode* node, const char* contents) { 4609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { 4619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphEdge* prop = node->GetChild(i); 4629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* node = prop->GetToNode(); 4639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (node->GetType() == v8::HeapGraphNode::STRING) { 4649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::String::AsciiValue node_name(node->GetName()); 4659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp(contents, *node_name) == 0) return true; 4669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 4679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 4689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen return false; 4699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} 4709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4729dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshot) { 4739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::HandleScope scope; 4749dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::Handle<v8::String> token1 = v8::String::New("token1"); 4753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env1; 4769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen env1->SetSecurityToken(token1); 4779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CompileAndRunScript( 4799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function A1() {}\n" 4809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function B1(x) { this.x = x; }\n" 4819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function C1(x) { this.x1 = x; this.x2 = x; }\n" 4829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "var a1 = new A1();\n" 4839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "var b1_1 = new B1(a1), b1_2 = new B1(a1);\n" 4849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "var c1 = new C1(a1);"); 4859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::Handle<v8::String> token2 = v8::String::New("token2"); 4873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env2; 4889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen env2->SetSecurityToken(token2); 4899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 4909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CompileAndRunScript( 4919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function A2() {}\n" 4929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function B2(x) { return function() { return typeof x; }; }\n" 4939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n" 4949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "var a2 = new A2();\n" 4959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n" 4969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "var c2 = new C2(a2);"); 4979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapSnapshot* snapshot_env2 = 4989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::HeapProfiler::TakeSnapshot(v8::String::New("env2")); 4999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); 5009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Verify, that JS global object of env2 doesn't have '..1' 5029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // properties, but has '..2' properties. 5039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a1")); 5049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_1")); 5059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_2")); 5069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c1")); 5079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* a2_node = 5089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a2"); 5099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, a2_node); 5109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_1")); 5119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_2")); 5129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c2")); 5139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Verify that anything related to '[ABC]1' is not reachable. 5159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen NamedEntriesDetector det; 5169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen i::HeapSnapshot* i_snapshot_env2 = 5179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const_cast<i::HeapSnapshot*>( 5189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2)); 5199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen i_snapshot_env2->IterateEntries(&det); 5209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(!det.has_A1); 5219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(!det.has_B1); 5229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(!det.has_C1); 5239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(det.has_A2); 5249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(det.has_B2); 5259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(det.has_C2); 5269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Verify 'a2' object retainers. They are: 5289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // - (global object).a2 5299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // - c2.x1, c2.x2, c2[1] 5309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // - b2_1 and b2_2 closures: via 'x' variable 5319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(6, a2_node->GetRetainingPathsCount()); 5329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_global_obj_a2_ref = false; 5339dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false; 5349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool has_b2_1_x_ref = false, has_b2_2_x_ref = false; 5359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) { 5369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i); 5379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const int edges_count = path->GetEdgesCount(); 5389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_GT(edges_count, 0); 5399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1); 5409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::String::AsciiValue last_edge_name(last_edge->GetName()); 5419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("a2", *last_edge_name) == 0 5429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY) { 5439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen has_global_obj_a2_ref = true; 5449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen continue; 5459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 5469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_GT(edges_count, 1); 5479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2); 5489dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::String::AsciiValue prev_edge_name(prev_edge->GetName()); 5499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("x1", *last_edge_name) == 0 5509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY 5519dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true; 5529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("x2", *last_edge_name) == 0 5539dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY 5549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true; 5559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("1", *last_edge_name) == 0 5569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && last_edge->GetType() == v8::HeapGraphEdge::ELEMENT 5579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true; 5589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("x", *last_edge_name) == 0 5599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && last_edge->GetType() == v8::HeapGraphEdge::CONTEXT_VARIABLE 5609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true; 5619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (strcmp("x", *last_edge_name) == 0 5629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && last_edge->GetType() == v8::HeapGraphEdge::CONTEXT_VARIABLE 5639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; 5649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 5659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(has_global_obj_a2_ref); 5669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(has_c2_x1_ref); 5679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(has_c2_x2_ref); 5689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(has_c2_1_ref); 5699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(has_b2_1_x_ref); 5709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(has_b2_2_x_ref); 5719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} 5729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5749dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshotCodeObjects) { 5759dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::HandleScope scope; 5763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 5779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CompileAndRunScript( 5799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function lazy(x) { return x - 1; }\n" 5809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "function compiled(x) { return x + 1; }\n" 5819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen "compiled(1)"); 5829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapSnapshot* snapshot = 5839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen v8::HeapProfiler::TakeSnapshot(v8::String::New("code")); 5849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* global = GetGlobalObject(snapshot); 5869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* compiled = 5879dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GetProperty(global, v8::HeapGraphEdge::PROPERTY, "compiled"); 5889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, compiled); 5899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(v8::HeapGraphNode::CLOSURE, compiled->GetType()); 5909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* lazy = 5919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GetProperty(global, v8::HeapGraphEdge::PROPERTY, "lazy"); 5929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, lazy); 5939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_EQ(v8::HeapGraphNode::CLOSURE, lazy->GetType()); 5949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 5959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Find references to code. 5969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* compiled_code = 5979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GetProperty(compiled, v8::HeapGraphEdge::INTERNAL, "code"); 5989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, compiled_code); 5999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* lazy_code = 6009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GetProperty(lazy, v8::HeapGraphEdge::INTERNAL, "code"); 6019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK_NE(NULL, lazy_code); 6029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 6039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Verify that non-compiled code doesn't contain references to "x" 6043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // literal, while compiled code does. The scope info is stored in FixedArray 6053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // objects attached to the SharedFunctionInfo. 6069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen bool compiled_references_x = false, lazy_references_x = false; 6079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) { 6089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphEdge* prop = compiled_code->GetChild(i); 6099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* node = prop->GetToNode(); 6103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (node->GetType() == v8::HeapGraphNode::ARRAY) { 6119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (HasString(node, "x")) { 6129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen compiled_references_x = true; 6139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen break; 6149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 6159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 6169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 6179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) { 6189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphEdge* prop = lazy_code->GetChild(i); 6199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen const v8::HeapGraphNode* node = prop->GetToNode(); 6203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (node->GetType() == v8::HeapGraphNode::ARRAY) { 6219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (HasString(node, "x")) { 6229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen lazy_references_x = true; 6239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen break; 6249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 6259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 6269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 6279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(compiled_references_x); 6289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen CHECK(!lazy_references_x); 6299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} 6309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 6313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Trying to introduce a check helper for uint64_t causes many 6333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// overloading ambiguities, so it seems easier just to cast 6343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// them to a signed type. 6353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch#define CHECK_EQ_UINT64_T(a, b) \ 6363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b)) 6373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch#define CHECK_NE_UINT64_T(a, b) do \ 6383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch { \ 6393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch bool ne = a != b; \ 6403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(ne); \ 6413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } while (false) 6423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapEntryIdsAndGC) { 6443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HandleScope scope; 6453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 6463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CompileAndRunScript( 6483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "function A() {}\n" 6493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "function B(x) { this.x = x; }\n" 6503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "var a = new A();\n" 6513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "var b = new B(a);"); 6523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapSnapshot* snapshot1 = 6533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HeapProfiler::TakeSnapshot(v8::String::New("s1")); 6543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch i::Heap::CollectAllGarbage(true); // Enforce compaction. 6563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapSnapshot* snapshot2 = 6583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HeapProfiler::TakeSnapshot(v8::String::New("s2")); 6593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1); 6613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2); 6623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_NE_UINT64_T(0, global1->GetId()); 6633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId()); 6643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* A1 = 6653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "A"); 6663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* A2 = 6673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "A"); 6683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_NE_UINT64_T(0, A1->GetId()); 6693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId()); 6703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* B1 = 6713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "B"); 6723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* B2 = 6733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "B"); 6743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_NE_UINT64_T(0, B1->GetId()); 6753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId()); 6763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* a1 = 6773bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "a"); 6783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* a2 = 6793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "a"); 6803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_NE_UINT64_T(0, a1->GetId()); 6813bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId()); 6823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* b1 = 6833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "b"); 6843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* b2 = 6853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "b"); 6863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_NE_UINT64_T(0, b1->GetId()); 6873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId()); 6883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch} 6893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapSnapshotsDiff) { 6923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HandleScope scope; 6933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LocalContext env; 6943bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 6953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CompileAndRunScript( 6963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "function A() {}\n" 6973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "function B(x) { this.x = x; }\n" 6983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "var a = new A();\n" 6993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "var b = new B(a);"); 7003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapSnapshot* snapshot1 = 7013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HeapProfiler::TakeSnapshot(v8::String::New("s1")); 7023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 7033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CompileAndRunScript( 7043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "delete a;\n" 7053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "b.x = null;\n" 7063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "var a = new A();\n" 7073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch "var b2 = new B(a);"); 7083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapSnapshot* snapshot2 = 7093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::HeapProfiler::TakeSnapshot(v8::String::New("s2")); 7103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 7113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapSnapshotsDiff* diff = snapshot1->CompareWith(snapshot2); 7123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 7133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Verify additions: ensure that addition of A and B was detected. 7143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot(); 7153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch bool found_A = false, found_B = false; 7163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch uint64_t s1_A_id = 0; 7173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) { 7183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphEdge* prop = additions_root->GetChild(i); 7193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* node = prop->GetToNode(); 7203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (node->GetType() == v8::HeapGraphNode::OBJECT) { 7213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::String::AsciiValue node_name(node->GetName()); 7223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (strcmp(*node_name, "A") == 0) { 7233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::PROPERTY, "a")); 7243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(!found_A); 7253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch found_A = true; 7263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch s1_A_id = node->GetId(); 7273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } else if (strcmp(*node_name, "B") == 0) { 7283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::PROPERTY, "b2")); 7293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(!found_B); 7303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch found_B = true; 7313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 7323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 7333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 7343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(found_A); 7353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(found_B); 7363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 7373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Verify deletions: ensure that deletion of A was detected. 7383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot(); 7393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch bool found_A_del = false; 7403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch uint64_t s2_A_id = 0; 7413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) { 7423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphEdge* prop = deletions_root->GetChild(i); 7433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const v8::HeapGraphNode* node = prop->GetToNode(); 7443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (node->GetType() == v8::HeapGraphNode::OBJECT) { 7453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch v8::String::AsciiValue node_name(node->GetName()); 7463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (strcmp(*node_name, "A") == 0) { 7473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::PROPERTY, "a")); 7483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(!found_A_del); 7493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch found_A_del = true; 7503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch s2_A_id = node->GetId(); 7513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 7523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 7533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 7543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(found_A_del); 7553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK_NE_UINT64_T(0, s1_A_id); 7563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CHECK(s1_A_id != s2_A_id); 7573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch} 7583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif // ENABLE_LOGGING_AND_PROFILING 760