blob: a319c4d0e61fc05d9e9c8026686016587ff3170d [file] [log] [blame]
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002//
3// Tests for heap profiler
4
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005#include "v8.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006
7#include "cctest.h"
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008#include "heap-profiler.h"
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00009#include "snapshot.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000010#include "utils-inl.h"
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011#include "../include/v8-profiler.h"
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000012
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013namespace {
14
15class NamedEntriesDetector {
16 public:
17 NamedEntriesDetector()
ager@chromium.org01fe7df2010-11-10 11:59:11 +000018 : has_A2(false), has_B2(false), has_C2(false) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000019 }
20
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000021 void Apply(i::HeapEntry** entry_ptr) {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000022 if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
23 if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
24 if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
25 }
26
27 static bool IsReachableNodeWithName(i::HeapEntry* entry, const char* name) {
28 return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000029 }
30
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000031 bool has_A2;
32 bool has_B2;
33 bool has_C2;
34};
35
36} // namespace
37
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000038
39static const v8::HeapGraphNode* GetGlobalObject(
40 const v8::HeapSnapshot* snapshot) {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +000041 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
42 const v8::HeapGraphNode* global_obj =
43 snapshot->GetRoot()->GetChild(0)->GetToNode();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000044 CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
45 reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +000046 return global_obj;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000047}
48
49
50static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
51 v8::HeapGraphEdge::Type type,
52 const char* name) {
53 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
54 const v8::HeapGraphEdge* prop = node->GetChild(i);
55 v8::String::AsciiValue prop_name(prop->GetName());
56 if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
57 return prop->GetToNode();
58 }
59 return NULL;
60}
61
62
63static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
64 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
65 const v8::HeapGraphEdge* prop = node->GetChild(i);
66 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000067 if (node->GetType() == v8::HeapGraphNode::kString) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000068 v8::String::AsciiValue node_name(node->GetName());
69 if (strcmp(contents, *node_name) == 0) return true;
70 }
71 }
72 return false;
73}
74
75
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000076TEST(HeapSnapshot) {
77 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +000078 LocalContext env2;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000079
vegorov@chromium.org42841962010-10-18 11:18:59 +000080 CompileRun(
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000081 "function A2() {}\n"
82 "function B2(x) { return function() { return typeof x; }; }\n"
83 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
84 "var a2 = new A2();\n"
85 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
86 "var c2 = new C2(a2);");
87 const v8::HeapSnapshot* snapshot_env2 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000088 v8::HeapProfiler::TakeSnapshot(v8_str("env2"));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000089 i::HeapSnapshot* i_snapshot_env2 =
90 const_cast<i::HeapSnapshot*>(
91 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000092 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
93 // Paint all nodes reachable from global object.
94 i_snapshot_env2->ClearPaint();
95 const_cast<i::HeapEntry*>(
96 reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
97
ager@chromium.org01fe7df2010-11-10 11:59:11 +000098 // Verify, that JS global object of env2 has '..2' properties.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000099 const v8::HeapGraphNode* a2_node =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000100 GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000101 CHECK_NE(NULL, a2_node);
102 CHECK_NE(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000103 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000104 CHECK_NE(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000105 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
106 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000107
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000108 NamedEntriesDetector det;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000109 i_snapshot_env2->IterateEntries(&det);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000110 CHECK(det.has_A2);
111 CHECK(det.has_B2);
112 CHECK(det.has_C2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000113}
114
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000115
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000116TEST(HeapSnapshotObjectSizes) {
117 v8::HandleScope scope;
118 LocalContext env;
119
120 // -a-> X1 --a
121 // x -b-> X2 <-|
vegorov@chromium.org42841962010-10-18 11:18:59 +0000122 CompileRun(
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000123 "function X(a, b) { this.a = a; this.b = b; }\n"
124 "x = new X(new X(), new X());\n"
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000125 "(function() { x.a.a = x.b; })();");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000126 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000127 v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000128 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
129 const v8::HeapGraphNode* x =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000130 GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000131 CHECK_NE(NULL, x);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000132 const v8::HeapGraphNode* x1 =
133 GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
134 CHECK_NE(NULL, x1);
135 const v8::HeapGraphNode* x2 =
136 GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
137 CHECK_NE(NULL, x2);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000138
139 // Test approximate sizes.
140 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
141 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
142 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
143 // Test exact sizes.
144 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
145 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
146 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000147}
148
149
150TEST(HeapSnapshotEntryChildren) {
151 v8::HandleScope scope;
152 LocalContext env;
153
vegorov@chromium.org42841962010-10-18 11:18:59 +0000154 CompileRun(
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000155 "function A() { }\n"
156 "a = new A;");
157 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000158 v8::HeapProfiler::TakeSnapshot(v8_str("children"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000159 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
160 for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
161 const v8::HeapGraphEdge* prop = global->GetChild(i);
162 CHECK_EQ(global, prop->GetFromNode());
163 }
164 const v8::HeapGraphNode* a =
165 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
166 CHECK_NE(NULL, a);
167 for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
168 const v8::HeapGraphEdge* prop = a->GetChild(i);
169 CHECK_EQ(a, prop->GetFromNode());
170 }
171}
172
173
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000174TEST(HeapSnapshotCodeObjects) {
175 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000176 LocalContext env;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000177
vegorov@chromium.org42841962010-10-18 11:18:59 +0000178 CompileRun(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000179 "function lazy(x) { return x - 1; }\n"
180 "function compiled(x) { return x + 1; }\n"
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000181 "var anonymous = (function() { return function() { return 0; } })();\n"
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000182 "compiled(1)");
183 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000184 v8::HeapProfiler::TakeSnapshot(v8_str("code"));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000185
186 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
187 const v8::HeapGraphNode* compiled =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000188 GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000189 CHECK_NE(NULL, compiled);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000190 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000191 const v8::HeapGraphNode* lazy =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000192 GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000193 CHECK_NE(NULL, lazy);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000194 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000195 const v8::HeapGraphNode* anonymous =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000196 GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000197 CHECK_NE(NULL, anonymous);
198 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
199 v8::String::AsciiValue anonymous_name(anonymous->GetName());
vegorov@chromium.org42841962010-10-18 11:18:59 +0000200 CHECK_EQ("", *anonymous_name);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000201
202 // Find references to code.
203 const v8::HeapGraphNode* compiled_code =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000204 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000205 CHECK_NE(NULL, compiled_code);
206 const v8::HeapGraphNode* lazy_code =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000207 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000208 CHECK_NE(NULL, lazy_code);
209
210 // Verify that non-compiled code doesn't contain references to "x"
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000211 // literal, while compiled code does. The scope info is stored in FixedArray
212 // objects attached to the SharedFunctionInfo.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000213 bool compiled_references_x = false, lazy_references_x = false;
214 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
215 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
216 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000217 if (node->GetType() == v8::HeapGraphNode::kArray) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000218 if (HasString(node, "x")) {
219 compiled_references_x = true;
220 break;
221 }
222 }
223 }
224 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
225 const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
226 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000227 if (node->GetType() == v8::HeapGraphNode::kArray) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000228 if (HasString(node, "x")) {
229 lazy_references_x = true;
230 break;
231 }
232 }
233 }
234 CHECK(compiled_references_x);
235 CHECK(!lazy_references_x);
236}
237
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000238
vegorov@chromium.org42841962010-10-18 11:18:59 +0000239TEST(HeapSnapshotHeapNumbers) {
240 v8::HandleScope scope;
241 LocalContext env;
242 CompileRun(
243 "a = 1; // a is Smi\n"
244 "b = 2.5; // b is HeapNumber");
245 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000246 v8::HeapProfiler::TakeSnapshot(v8_str("numbers"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000247 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000248 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000249 const v8::HeapGraphNode* b =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000250 GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
vegorov@chromium.org42841962010-10-18 11:18:59 +0000251 CHECK_NE(NULL, b);
252 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
253}
254
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000255TEST(HeapSnapshotSlicedString) {
256 v8::HandleScope scope;
257 LocalContext env;
258 CompileRun(
259 "parent_string = \"123456789.123456789.123456789.123456789.123456789."
260 "123456789.123456789.123456789.123456789.123456789."
261 "123456789.123456789.123456789.123456789.123456789."
262 "123456789.123456789.123456789.123456789.123456789.\";"
263 "child_string = parent_string.slice(100);");
264 const v8::HeapSnapshot* snapshot =
265 v8::HeapProfiler::TakeSnapshot(v8_str("strings"));
266 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
267 const v8::HeapGraphNode* parent_string =
268 GetProperty(global, v8::HeapGraphEdge::kShortcut, "parent_string");
269 CHECK_NE(NULL, parent_string);
270 const v8::HeapGraphNode* child_string =
271 GetProperty(global, v8::HeapGraphEdge::kShortcut, "child_string");
272 CHECK_NE(NULL, child_string);
273 const v8::HeapGraphNode* parent =
274 GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
275 CHECK_EQ(parent_string, parent);
276}
vegorov@chromium.org42841962010-10-18 11:18:59 +0000277
278TEST(HeapSnapshotInternalReferences) {
279 v8::HandleScope scope;
280 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
281 global_template->SetInternalFieldCount(2);
282 LocalContext env(NULL, global_template);
283 v8::Handle<v8::Object> global_proxy = env->Global();
284 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
285 CHECK_EQ(2, global->InternalFieldCount());
286 v8::Local<v8::Object> obj = v8::Object::New();
287 global->SetInternalField(0, v8_num(17));
288 global->SetInternalField(1, obj);
289 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000290 v8::HeapProfiler::TakeSnapshot(v8_str("internals"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000291 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
292 // The first reference will not present, because it's a Smi.
293 CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
294 // The second reference is to an object.
295 CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
296}
297
298
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000299// Trying to introduce a check helper for uint64_t causes many
300// overloading ambiguities, so it seems easier just to cast
301// them to a signed type.
302#define CHECK_EQ_UINT64_T(a, b) \
303 CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000304#define CHECK_NE_UINT64_T(a, b) \
305 CHECK((a) != (b)) // NOLINT
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000306
307TEST(HeapEntryIdsAndGC) {
308 v8::HandleScope scope;
309 LocalContext env;
310
vegorov@chromium.org42841962010-10-18 11:18:59 +0000311 CompileRun(
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000312 "function A() {}\n"
313 "function B(x) { this.x = x; }\n"
314 "var a = new A();\n"
315 "var b = new B(a);");
316 const v8::HeapSnapshot* snapshot1 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000317 v8::HeapProfiler::TakeSnapshot(v8_str("s1"));
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000318
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000319 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000320
321 const v8::HeapSnapshot* snapshot2 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000322 v8::HeapProfiler::TakeSnapshot(v8_str("s2"));
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000323
324 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
325 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
326 CHECK_NE_UINT64_T(0, global1->GetId());
327 CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
328 const v8::HeapGraphNode* A1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000329 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
330 CHECK_NE(NULL, A1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000331 const v8::HeapGraphNode* A2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
333 CHECK_NE(NULL, A2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000334 CHECK_NE_UINT64_T(0, A1->GetId());
335 CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
336 const v8::HeapGraphNode* B1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000337 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
338 CHECK_NE(NULL, B1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000339 const v8::HeapGraphNode* B2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000340 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
341 CHECK_NE(NULL, B2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000342 CHECK_NE_UINT64_T(0, B1->GetId());
343 CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
344 const v8::HeapGraphNode* a1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000345 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
346 CHECK_NE(NULL, a1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000347 const v8::HeapGraphNode* a2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000348 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
349 CHECK_NE(NULL, a2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000350 CHECK_NE_UINT64_T(0, a1->GetId());
351 CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
352 const v8::HeapGraphNode* b1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000353 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
354 CHECK_NE(NULL, b1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000355 const v8::HeapGraphNode* b2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000356 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
357 CHECK_NE(NULL, b2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000358 CHECK_NE_UINT64_T(0, b1->GetId());
359 CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
360}
361
362
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000363TEST(HeapSnapshotRootPreservedAfterSorting) {
364 v8::HandleScope scope;
365 LocalContext env;
366 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 v8::HeapProfiler::TakeSnapshot(v8_str("s"));
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000368 const v8::HeapGraphNode* root1 = snapshot->GetRoot();
369 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
370 snapshot))->GetSortedEntriesList();
371 const v8::HeapGraphNode* root2 = snapshot->GetRoot();
372 CHECK_EQ(root1, root2);
373}
374
375
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000376TEST(HeapEntryDominator) {
377 // The graph looks like this:
378 //
379 // -> node1
380 // a |^
381 // -> node5 ba
382 // a v|
383 // node6 -> node2
384 // b a |^
385 // -> node4 ba
386 // b v|
387 // -> node3
388 //
389 // The dominator for all nodes is node6.
390
391 v8::HandleScope scope;
392 LocalContext env;
393
394 CompileRun(
395 "function X(a, b) { this.a = a; this.b = b; }\n"
396 "node6 = new X(new X(new X()), new X(new X(),new X()));\n"
397 "(function(){\n"
398 "node6.a.a.b = node6.b.a; // node1 -> node2\n"
399 "node6.b.a.a = node6.a.a; // node2 -> node1\n"
400 "node6.b.a.b = node6.b.b; // node2 -> node3\n"
401 "node6.b.b.a = node6.b.a; // node3 -> node2\n"
402 "})();");
403
404 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000405 v8::HeapProfiler::TakeSnapshot(v8_str("dominators"));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000406
407 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
408 CHECK_NE(NULL, global);
409 const v8::HeapGraphNode* node6 =
410 GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
411 CHECK_NE(NULL, node6);
412 const v8::HeapGraphNode* node5 =
413 GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
414 CHECK_NE(NULL, node5);
415 const v8::HeapGraphNode* node4 =
416 GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
417 CHECK_NE(NULL, node4);
418 const v8::HeapGraphNode* node3 =
419 GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
420 CHECK_NE(NULL, node3);
421 const v8::HeapGraphNode* node2 =
422 GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
423 CHECK_NE(NULL, node2);
424 const v8::HeapGraphNode* node1 =
425 GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
426 CHECK_NE(NULL, node1);
427
428 CHECK_EQ(node6, node1->GetDominatorNode());
429 CHECK_EQ(node6, node2->GetDominatorNode());
430 CHECK_EQ(node6, node3->GetDominatorNode());
431 CHECK_EQ(node6, node4->GetDominatorNode());
432 CHECK_EQ(node6, node5->GetDominatorNode());
433}
434
435
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000436namespace {
437
438class TestJSONStream : public v8::OutputStream {
439 public:
440 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
441 explicit TestJSONStream(int abort_countdown)
442 : eos_signaled_(0), abort_countdown_(abort_countdown) {}
443 virtual ~TestJSONStream() {}
444 virtual void EndOfStream() { ++eos_signaled_; }
445 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
446 if (abort_countdown_ > 0) --abort_countdown_;
447 if (abort_countdown_ == 0) return kAbort;
448 CHECK_GT(chars_written, 0);
449 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
450 memcpy(chunk.start(), buffer, chars_written);
451 return kContinue;
452 }
453 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
454 int eos_signaled() { return eos_signaled_; }
455 int size() { return buffer_.size(); }
456 private:
457 i::Collector<char> buffer_;
458 int eos_signaled_;
459 int abort_countdown_;
460};
461
462class AsciiResource: public v8::String::ExternalAsciiStringResource {
463 public:
464 explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
465 length_ = string.length();
466 }
467 virtual const char* data() const { return data_; }
468 virtual size_t length() const { return length_; }
469 private:
470 const char* data_;
471 size_t length_;
472};
473
474} // namespace
475
476TEST(HeapSnapshotJSONSerialization) {
477 v8::HandleScope scope;
478 LocalContext env;
479
480#define STRING_LITERAL_FOR_TEST \
481 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
vegorov@chromium.org42841962010-10-18 11:18:59 +0000482 CompileRun(
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000483 "function A(s) { this.s = s; }\n"
484 "function B(x) { this.x = x; }\n"
485 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
486 "var b = new B(a);");
487 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000488 v8::HeapProfiler::TakeSnapshot(v8_str("json"));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000489 TestJSONStream stream;
490 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
491 CHECK_GT(stream.size(), 0);
492 CHECK_EQ(1, stream.eos_signaled());
493 i::ScopedVector<char> json(stream.size());
494 stream.WriteTo(json);
495
496 // Verify that snapshot string is valid JSON.
497 AsciiResource json_res(json);
498 v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000499 env->Global()->Set(v8_str("json_snapshot"), json_string);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000500 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
501 "var parsed = JSON.parse(json_snapshot); true;");
502 CHECK(!snapshot_parse_result.IsEmpty());
503
504 // Verify that snapshot object has required fields.
505 v8::Local<v8::Object> parsed_snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 env->Global()->Get(v8_str("parsed"))->ToObject();
507 CHECK(parsed_snapshot->Has(v8_str("snapshot")));
508 CHECK(parsed_snapshot->Has(v8_str("nodes")));
509 CHECK(parsed_snapshot->Has(v8_str("strings")));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000510
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000511 // Get node and edge "member" offsets.
512 v8::Local<v8::Value> meta_analysis_result = CompileRun(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000513 "var parsed_meta = parsed.nodes[0];\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000514 "var children_count_offset ="
515 " parsed_meta.fields.indexOf('children_count');\n"
516 "var children_offset ="
517 " parsed_meta.fields.indexOf('children');\n"
518 "var children_meta ="
519 " parsed_meta.types[children_offset];\n"
520 "var child_fields_count = children_meta.fields.length;\n"
521 "var child_type_offset ="
522 " children_meta.fields.indexOf('type');\n"
523 "var child_name_offset ="
524 " children_meta.fields.indexOf('name_or_index');\n"
525 "var child_to_node_offset ="
526 " children_meta.fields.indexOf('to_node');\n"
527 "var property_type ="
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000528 " children_meta.types[child_type_offset].indexOf('property');\n"
529 "var shortcut_type ="
530 " children_meta.types[child_type_offset].indexOf('shortcut');");
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000531 CHECK(!meta_analysis_result.IsEmpty());
532
533 // A helper function for processing encoded nodes.
534 CompileRun(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000535 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000536 " var nodes = parsed.nodes;\n"
537 " var strings = parsed.strings;\n"
538 " for (var i = 0,\n"
539 " count = nodes[pos + children_count_offset] * child_fields_count;\n"
540 " i < count; i += child_fields_count) {\n"
541 " var child_pos = pos + children_offset + i;\n"
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000542 " if (nodes[child_pos + child_type_offset] === prop_type\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000543 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
544 " return nodes[child_pos + child_to_node_offset];\n"
545 " }\n"
546 " return null;\n"
547 "}\n");
548 // Get the string index using the path: <root> -> <global>.b.x.s
549 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
550 "GetChildPosByProperty(\n"
551 " GetChildPosByProperty(\n"
552 " GetChildPosByProperty("
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000553 " parsed.nodes[1 + children_offset + child_to_node_offset],"
554 " \"b\",shortcut_type),\n"
555 " \"x\", property_type),"
556 " \"s\", property_type)");
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000557 CHECK(!string_obj_pos_val.IsEmpty());
558 int string_obj_pos =
559 static_cast<int>(string_obj_pos_val->ToNumber()->Value());
560 v8::Local<v8::Object> nodes_array =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000561 parsed_snapshot->Get(v8_str("nodes"))->ToObject();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000562 int string_index = static_cast<int>(
563 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
564 CHECK_GT(string_index, 0);
565 v8::Local<v8::Object> strings_array =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000566 parsed_snapshot->Get(v8_str("strings"))->ToObject();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000567 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
568 v8::Local<v8::String> ref_string =
569 CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
570#undef STRING_LITERAL_FOR_TEST
571 CHECK_EQ(*v8::String::Utf8Value(ref_string),
572 *v8::String::Utf8Value(string));
573}
574
575
576TEST(HeapSnapshotJSONSerializationAborting) {
577 v8::HandleScope scope;
578 LocalContext env;
579 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000580 v8::HeapProfiler::TakeSnapshot(v8_str("abort"));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000581 TestJSONStream stream(5);
582 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
583 CHECK_GT(stream.size(), 0);
584 CHECK_EQ(0, stream.eos_signaled());
585}
586
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000587
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000588static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
589 const v8::HeapGraphNode* node,
590 int level, int max_level) {
591 if (level > max_level) return;
592 CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
593 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
594 const v8::HeapGraphEdge* prop = node->GetChild(i);
595 const v8::HeapGraphNode* child =
596 snapshot->GetNodeById(prop->GetToNode()->GetId());
597 CHECK_EQ_UINT64_T(prop->GetToNode()->GetId(), child->GetId());
598 CHECK_EQ(prop->GetToNode(), child);
599 CheckChildrenIds(snapshot, child, level + 1, max_level);
600 }
601}
602
603
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000604TEST(HeapSnapshotGetNodeById) {
605 v8::HandleScope scope;
606 LocalContext env;
607
608 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000609 v8::HeapProfiler::TakeSnapshot(v8_str("id"));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000610 const v8::HeapGraphNode* root = snapshot->GetRoot();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000611 CheckChildrenIds(snapshot, root, 0, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612 // Check a big id, which should not exist yet.
613 CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
614}
615
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000616
617namespace {
618
619class TestActivityControl : public v8::ActivityControl {
620 public:
621 explicit TestActivityControl(int abort_count)
622 : done_(0), total_(0), abort_count_(abort_count) {}
623 ControlOption ReportProgressValue(int done, int total) {
624 done_ = done;
625 total_ = total;
626 return --abort_count_ != 0 ? kContinue : kAbort;
627 }
628 int done() { return done_; }
629 int total() { return total_; }
630
631 private:
632 int done_;
633 int total_;
634 int abort_count_;
635};
636}
637
638TEST(TakeHeapSnapshotAborting) {
639 v8::HandleScope scope;
640 LocalContext env;
641
642 const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
643 TestActivityControl aborting_control(3);
644 const v8::HeapSnapshot* no_snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000645 v8::HeapProfiler::TakeSnapshot(v8_str("abort"),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000646 v8::HeapSnapshot::kFull,
647 &aborting_control);
648 CHECK_EQ(NULL, no_snapshot);
649 CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
650 CHECK_GT(aborting_control.total(), aborting_control.done());
651
652 TestActivityControl control(-1); // Don't abort.
653 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000654 v8::HeapProfiler::TakeSnapshot(v8_str("full"),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000655 v8::HeapSnapshot::kFull,
656 &control);
657 CHECK_NE(NULL, snapshot);
658 CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
659 CHECK_EQ(control.total(), control.done());
660 CHECK_GT(control.total(), 0);
661}
662
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000663
664namespace {
665
666class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
667 public:
668 TestRetainedObjectInfo(int hash,
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000669 const char* group_label,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000670 const char* label,
671 intptr_t element_count = -1,
672 intptr_t size = -1)
673 : disposed_(false),
674 hash_(hash),
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000675 group_label_(group_label),
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000676 label_(label),
677 element_count_(element_count),
678 size_(size) {
679 instances.Add(this);
680 }
681 virtual ~TestRetainedObjectInfo() {}
682 virtual void Dispose() {
683 CHECK(!disposed_);
684 disposed_ = true;
685 }
686 virtual bool IsEquivalent(RetainedObjectInfo* other) {
687 return GetHash() == other->GetHash();
688 }
689 virtual intptr_t GetHash() { return hash_; }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000690 virtual const char* GetGroupLabel() { return group_label_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000691 virtual const char* GetLabel() { return label_; }
692 virtual intptr_t GetElementCount() { return element_count_; }
693 virtual intptr_t GetSizeInBytes() { return size_; }
694 bool disposed() { return disposed_; }
695
696 static v8::RetainedObjectInfo* WrapperInfoCallback(
697 uint16_t class_id, v8::Handle<v8::Value> wrapper) {
698 if (class_id == 1) {
699 if (wrapper->IsString()) {
700 v8::String::AsciiValue ascii(wrapper);
701 if (strcmp(*ascii, "AAA") == 0)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000702 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000703 else if (strcmp(*ascii, "BBB") == 0)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000704 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000705 }
706 } else if (class_id == 2) {
707 if (wrapper->IsString()) {
708 v8::String::AsciiValue ascii(wrapper);
709 if (strcmp(*ascii, "CCC") == 0)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000710 return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000711 }
712 }
713 CHECK(false);
714 return NULL;
715 }
716
717 static i::List<TestRetainedObjectInfo*> instances;
718
719 private:
720 bool disposed_;
721 int category_;
722 int hash_;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000723 const char* group_label_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000724 const char* label_;
725 intptr_t element_count_;
726 intptr_t size_;
727};
728
729
730i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
731}
732
733
734static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
735 v8::HeapGraphNode::Type type,
736 const char* name) {
737 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
738 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
739 if (node->GetType() == type && strcmp(name,
740 const_cast<i::HeapEntry*>(
741 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
742 return node;
743 }
744 }
745 return NULL;
746}
747
748
749TEST(HeapSnapshotRetainedObjectInfo) {
750 v8::HandleScope scope;
751 LocalContext env;
752
753 v8::HeapProfiler::DefineWrapperClass(
754 1, TestRetainedObjectInfo::WrapperInfoCallback);
755 v8::HeapProfiler::DefineWrapperClass(
756 2, TestRetainedObjectInfo::WrapperInfoCallback);
757 v8::Persistent<v8::String> p_AAA =
758 v8::Persistent<v8::String>::New(v8_str("AAA"));
759 p_AAA.SetWrapperClassId(1);
760 v8::Persistent<v8::String> p_BBB =
761 v8::Persistent<v8::String>::New(v8_str("BBB"));
762 p_BBB.SetWrapperClassId(1);
763 v8::Persistent<v8::String> p_CCC =
764 v8::Persistent<v8::String>::New(v8_str("CCC"));
765 p_CCC.SetWrapperClassId(2);
766 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
767 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000768 v8::HeapProfiler::TakeSnapshot(v8_str("retained"));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000769
770 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
771 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
772 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
773 delete TestRetainedObjectInfo::instances[i];
774 }
775
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000776 const v8::HeapGraphNode* native_group_aaa = GetNode(
777 snapshot->GetRoot(), v8::HeapGraphNode::kNative, "aaa-group");
778 CHECK_NE(NULL, native_group_aaa);
779 CHECK_EQ(1, native_group_aaa->GetChildrenCount());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000780 const v8::HeapGraphNode* aaa = GetNode(
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000781 native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000782 CHECK_NE(NULL, aaa);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000783 CHECK_EQ(2, aaa->GetChildrenCount());
784
785 const v8::HeapGraphNode* native_group_ccc = GetNode(
786 snapshot->GetRoot(), v8::HeapGraphNode::kNative, "ccc-group");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000787 const v8::HeapGraphNode* ccc = GetNode(
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000788 native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000789 CHECK_NE(NULL, ccc);
790
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000791 const v8::HeapGraphNode* n_AAA = GetNode(
792 aaa, v8::HeapGraphNode::kString, "AAA");
793 CHECK_NE(NULL, n_AAA);
794 const v8::HeapGraphNode* n_BBB = GetNode(
795 aaa, v8::HeapGraphNode::kString, "BBB");
796 CHECK_NE(NULL, n_BBB);
797 CHECK_EQ(1, ccc->GetChildrenCount());
798 const v8::HeapGraphNode* n_CCC = GetNode(
799 ccc, v8::HeapGraphNode::kString, "CCC");
800 CHECK_NE(NULL, n_CCC);
801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000802 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
803 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
804 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000805}
806
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000807
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000808class GraphWithImplicitRefs {
809 public:
810 static const int kObjectsCount = 4;
811 explicit GraphWithImplicitRefs(LocalContext* env) {
812 CHECK_EQ(NULL, instance_);
813 instance_ = this;
814 for (int i = 0; i < kObjectsCount; i++) {
815 objects_[i] = v8::Persistent<v8::Object>::New(v8::Object::New());
816 }
817 (*env)->Global()->Set(v8_str("root_object"), objects_[0]);
818 }
819 ~GraphWithImplicitRefs() {
820 instance_ = NULL;
821 }
822
823 static void gcPrologue() {
824 instance_->AddImplicitReferences();
825 }
826
827 private:
828 void AddImplicitReferences() {
829 // 0 -> 1
830 v8::V8::AddImplicitReferences(
831 v8::Persistent<v8::Object>::Cast(objects_[0]), &objects_[1], 1);
832 // Adding two more references(note length=2 in params): 1 -> 2, 1 -> 3
833 v8::V8::AddImplicitReferences(
834 v8::Persistent<v8::Object>::Cast(objects_[1]), &objects_[2], 2);
835 }
836
837 v8::Persistent<v8::Value> objects_[kObjectsCount];
838 static GraphWithImplicitRefs* instance_;
839};
840
841GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
842
843
844TEST(HeapSnapshotImplicitReferences) {
845 v8::HandleScope scope;
846 LocalContext env;
847
848 GraphWithImplicitRefs graph(&env);
849 v8::V8::SetGlobalGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
850
851 const v8::HeapSnapshot* snapshot =
852 v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs"));
853
854 const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
855 // Use kShortcut type to skip intermediate JSGlobalPropertyCell
856 const v8::HeapGraphNode* obj0 = GetProperty(
857 global_object, v8::HeapGraphEdge::kShortcut, "root_object");
858 CHECK(obj0);
859 CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
860 const v8::HeapGraphNode* obj1 = GetProperty(
861 obj0, v8::HeapGraphEdge::kInternal, "native");
862 CHECK(obj1);
863 int implicit_targets_count = 0;
864 for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
865 const v8::HeapGraphEdge* prop = obj1->GetChild(i);
866 v8::String::AsciiValue prop_name(prop->GetName());
867 if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
868 strcmp("native", *prop_name) == 0) {
869 ++implicit_targets_count;
870 }
871 }
872 CHECK_EQ(2, implicit_targets_count);
873 v8::V8::SetGlobalGCPrologueCallback(NULL);
874}
875
876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000877TEST(DeleteAllHeapSnapshots) {
878 v8::HandleScope scope;
879 LocalContext env;
880
881 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
882 v8::HeapProfiler::DeleteAllSnapshots();
883 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000884 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("1")));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000885 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
886 v8::HeapProfiler::DeleteAllSnapshots();
887 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000888 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("1")));
889 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("2")));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000890 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
891 v8::HeapProfiler::DeleteAllSnapshots();
892 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
893}
894
895
896TEST(DeleteHeapSnapshot) {
897 v8::HandleScope scope;
898 LocalContext env;
899
900 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
901 const v8::HeapSnapshot* s1 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000902 v8::HeapProfiler::TakeSnapshot(v8_str("1"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 CHECK_NE(NULL, s1);
904 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
905 unsigned uid1 = s1->GetUid();
906 CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1));
907 const_cast<v8::HeapSnapshot*>(s1)->Delete();
908 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
909 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1));
910
911 const v8::HeapSnapshot* s2 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000912 v8::HeapProfiler::TakeSnapshot(v8_str("2"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 CHECK_NE(NULL, s2);
914 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
915 unsigned uid2 = s2->GetUid();
916 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
917 CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2));
918 const v8::HeapSnapshot* s3 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919 v8::HeapProfiler::TakeSnapshot(v8_str("3"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 CHECK_NE(NULL, s3);
921 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
922 unsigned uid3 = s3->GetUid();
923 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
924 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
925 const_cast<v8::HeapSnapshot*>(s2)->Delete();
926 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
927 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2));
928 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
929 const_cast<v8::HeapSnapshot*>(s3)->Delete();
930 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
931 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
932}
933
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000934
935TEST(DocumentURL) {
936 v8::HandleScope scope;
937 LocalContext env;
938
939 CompileRun("document = { URL:\"abcdefgh\" };");
940
941 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000942 v8::HeapProfiler::TakeSnapshot(v8_str("document"));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000943 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
944 CHECK_NE(NULL, global);
945 CHECK_EQ("Object / abcdefgh",
946 const_cast<i::HeapEntry*>(
947 reinterpret_cast<const i::HeapEntry*>(global))->name());
948}
949
950
951TEST(DocumentWithException) {
952 v8::HandleScope scope;
953 LocalContext env;
954
955 CompileRun(
956 "this.__defineGetter__(\"document\", function() { throw new Error(); })");
957 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000958 v8::HeapProfiler::TakeSnapshot(v8_str("document"));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000959 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
960 CHECK_NE(NULL, global);
961 CHECK_EQ("Object",
962 const_cast<i::HeapEntry*>(
963 reinterpret_cast<const i::HeapEntry*>(global))->name());
964}
965
966
967TEST(DocumentURLWithException) {
968 v8::HandleScope scope;
969 LocalContext env;
970
971 CompileRun(
972 "function URLWithException() {}\n"
973 "URLWithException.prototype = { get URL() { throw new Error(); } };\n"
974 "document = { URL: new URLWithException() };");
975 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000976 v8::HeapProfiler::TakeSnapshot(v8_str("document"));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000977 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
978 CHECK_NE(NULL, global);
979 CHECK_EQ("Object",
980 const_cast<i::HeapEntry*>(
981 reinterpret_cast<const i::HeapEntry*>(global))->name());
982}
983
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000984
erikcorry0ad885c2011-11-21 13:51:57 +0000985TEST(NoHandleLeaks) {
986 v8::HandleScope scope;
987 LocalContext env;
988
989 CompileRun("document = { URL:\"abcdefgh\" };");
990
991 v8::Handle<v8::String> name(v8_str("leakz"));
992 int count_before = i::HandleScope::NumberOfHandles();
993 v8::HeapProfiler::TakeSnapshot(name);
994 int count_after = i::HandleScope::NumberOfHandles();
995 CHECK_EQ(count_before, count_after);
996}
997
998
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000999TEST(NodesIteration) {
1000 v8::HandleScope scope;
1001 LocalContext env;
1002 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001003 v8::HeapProfiler::TakeSnapshot(v8_str("iteration"));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001004 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1005 CHECK_NE(NULL, global);
1006 // Verify that we can find this object by iteration.
1007 const int nodes_count = snapshot->GetNodesCount();
1008 int count = 0;
1009 for (int i = 0; i < nodes_count; ++i) {
1010 if (snapshot->GetNode(i) == global)
1011 ++count;
1012 }
1013 CHECK_EQ(1, count);
1014}
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001015
1016
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001017TEST(GetHeapValue) {
1018 v8::HandleScope scope;
1019 LocalContext env;
1020
1021 CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };");
1022 const v8::HeapSnapshot* snapshot =
1023 v8::HeapProfiler::TakeSnapshot(v8_str("value"));
1024 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1025 CHECK(global->GetHeapValue()->IsObject());
1026 v8::Local<v8::Object> js_global =
1027 env->Global()->GetPrototype().As<v8::Object>();
1028 CHECK(js_global == global->GetHeapValue());
1029 const v8::HeapGraphNode* obj = GetProperty(
1030 global, v8::HeapGraphEdge::kShortcut, "a");
1031 CHECK(obj->GetHeapValue()->IsObject());
1032 v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
1033 CHECK(js_obj == obj->GetHeapValue());
1034 const v8::HeapGraphNode* s_prop =
1035 GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
1036 v8::Local<v8::String> js_s_prop =
1037 js_obj->Get(v8_str("s_prop")).As<v8::String>();
1038 CHECK(js_s_prop == s_prop->GetHeapValue());
1039 const v8::HeapGraphNode* n_prop =
1040 GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
1041 v8::Local<v8::Number> js_n_prop =
1042 js_obj->Get(v8_str("n_prop")).As<v8::Number>();
1043 CHECK(js_n_prop == n_prop->GetHeapValue());
1044}
1045
1046
1047TEST(GetHeapValueForDeletedObject) {
1048 v8::HandleScope scope;
1049 LocalContext env;
1050
1051 // It is impossible to delete a global property, so we are about to delete a
1052 // property of the "a" object. Also, the "p" object can't be an empty one
1053 // because the empty object is static and isn't actually deleted.
1054 CompileRun("a = { p: { r: {} } };");
1055 const v8::HeapSnapshot* snapshot =
1056 v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1057 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1058 const v8::HeapGraphNode* obj = GetProperty(
1059 global, v8::HeapGraphEdge::kShortcut, "a");
1060 const v8::HeapGraphNode* prop = GetProperty(
1061 obj, v8::HeapGraphEdge::kProperty, "p");
1062 {
1063 // Perform the check inside a nested local scope to avoid creating a
1064 // reference to the object we are deleting.
1065 v8::HandleScope scope;
1066 CHECK(prop->GetHeapValue()->IsObject());
1067 }
1068 CompileRun("delete a.p;");
1069 CHECK(prop->GetHeapValue()->IsUndefined());
1070}
1071
1072
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001073static int StringCmp(const char* ref, i::String* act) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001074 i::SmartArrayPointer<char> s_act = act->ToCString();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001075 int result = strcmp(ref, *s_act);
1076 if (result != 0)
1077 fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, *s_act);
1078 return result;
1079}
1080
1081
1082TEST(GetConstructorName) {
1083 v8::HandleScope scope;
1084 LocalContext env;
1085
1086 CompileRun(
1087 "function Constructor1() {};\n"
1088 "var obj1 = new Constructor1();\n"
1089 "var Constructor2 = function() {};\n"
1090 "var obj2 = new Constructor2();\n"
1091 "var obj3 = {};\n"
1092 "obj3.constructor = function Constructor3() {};\n"
1093 "var obj4 = {};\n"
1094 "// Slow properties\n"
1095 "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
1096 "obj4.constructor = function Constructor4() {};\n"
1097 "var obj5 = {};\n"
1098 "var obj6 = {};\n"
1099 "obj6.constructor = 6;");
1100 v8::Local<v8::Object> js_global =
1101 env->Global()->GetPrototype().As<v8::Object>();
1102 v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
1103 i::Handle<i::JSObject> js_obj1 = v8::Utils::OpenHandle(*obj1);
1104 CHECK_EQ(0, StringCmp(
1105 "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
1106 v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
1107 i::Handle<i::JSObject> js_obj2 = v8::Utils::OpenHandle(*obj2);
1108 CHECK_EQ(0, StringCmp(
1109 "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
1110 v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
1111 i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
1112 CHECK_EQ(0, StringCmp(
1113 "Constructor3", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
1114 v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
1115 i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
1116 CHECK_EQ(0, StringCmp(
1117 "Constructor4", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
1118 v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
1119 i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
1120 CHECK_EQ(0, StringCmp(
1121 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
1122 v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
1123 i::Handle<i::JSObject> js_obj6 = v8::Utils::OpenHandle(*obj6);
1124 CHECK_EQ(0, StringCmp(
1125 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1126}
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001127
erikcorry0ad885c2011-11-21 13:51:57 +00001128
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001129TEST(FastCaseGetter) {
1130 v8::HandleScope scope;
1131 LocalContext env;
1132
1133 CompileRun("var obj1 = {};\n"
1134 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1135 " return 42;\n"
1136 "});\n"
1137 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1138 " return this.value_ = value;\n"
1139 "});\n");
1140 const v8::HeapSnapshot* snapshot =
1141 v8::HeapProfiler::TakeSnapshot(v8_str("fastCaseGetter"));
1142
1143 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1144 CHECK_NE(NULL, global);
1145 const v8::HeapGraphNode* obj1 =
1146 GetProperty(global, v8::HeapGraphEdge::kShortcut, "obj1");
1147 CHECK_NE(NULL, obj1);
1148 const v8::HeapGraphNode* getterFunction =
1149 GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get-propWithGetter");
1150 CHECK_NE(NULL, getterFunction);
1151 const v8::HeapGraphNode* setterFunction =
1152 GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter");
1153 CHECK_NE(NULL, setterFunction);
1154}
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001155
1156
1157bool HasWeakEdge(const v8::HeapGraphNode* node) {
1158 for (int i = 0; i < node->GetChildrenCount(); ++i) {
1159 const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
1160 if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
1161 }
1162 return false;
1163}
1164
1165
1166bool HasWeakGlobalHandle() {
1167 const v8::HeapSnapshot* snapshot =
1168 v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
1169 const v8::HeapGraphNode* gc_roots = GetNode(
1170 snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1171 CHECK_NE(NULL, gc_roots);
1172 const v8::HeapGraphNode* global_handles = GetNode(
1173 gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
1174 CHECK_NE(NULL, global_handles);
1175 return HasWeakEdge(global_handles);
1176}
1177
1178
1179static void PersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
1180 handle.Dispose();
1181}
1182
1183
1184TEST(WeakGlobalHandle) {
1185 v8::HandleScope scope;
1186 LocalContext env;
1187
1188 CHECK(!HasWeakGlobalHandle());
1189
1190 v8::Persistent<v8::Object> handle =
1191 v8::Persistent<v8::Object>::New(v8::Object::New());
1192 handle.MakeWeak(NULL, PersistentHandleCallback);
1193
1194 CHECK(HasWeakGlobalHandle());
1195}
1196
1197
1198TEST(WeakGlobalContextRefs) {
1199 v8::HandleScope scope;
1200 LocalContext env;
1201
1202 const v8::HeapSnapshot* snapshot =
1203 v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
1204 const v8::HeapGraphNode* gc_roots = GetNode(
1205 snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1206 CHECK_NE(NULL, gc_roots);
1207 const v8::HeapGraphNode* global_handles = GetNode(
1208 gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
1209 CHECK_NE(NULL, global_handles);
1210 const v8::HeapGraphNode* global_context = GetNode(
1211 global_handles, v8::HeapGraphNode::kHidden, "system / GlobalContext");
1212 CHECK_NE(NULL, global_context);
1213 CHECK(HasWeakEdge(global_context));
1214}
1215
1216
1217TEST(SfiAndJsFunctionWeakRefs) {
1218 v8::HandleScope scope;
1219 LocalContext env;
1220
1221 CompileRun(
1222 "fun = (function (x) { return function () { return x + 1; } })(1);");
1223 const v8::HeapSnapshot* snapshot =
1224 v8::HeapProfiler::TakeSnapshot(v8_str("fun"));
1225 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1226 CHECK_NE(NULL, global);
1227 const v8::HeapGraphNode* fun =
1228 GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun");
1229 CHECK(HasWeakEdge(fun));
1230 const v8::HeapGraphNode* shared =
1231 GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
1232 CHECK(HasWeakEdge(shared));
1233}