blob: 7a227cdf9b273acc8b026eccabc337dae7062230 [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
ulan@chromium.org967e2702012-02-28 09:49:15 +000021 void CheckEntry(i::HeapEntry* entry) {
22 if (strcmp(entry->name(), "A2") == 0) has_A2 = true;
23 if (strcmp(entry->name(), "B2") == 0) has_B2 = true;
24 if (strcmp(entry->name(), "C2") == 0) has_C2 = true;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000025 }
26
ulan@chromium.org967e2702012-02-28 09:49:15 +000027 void CheckAllReachables(i::HeapEntry* root) {
28 i::List<i::HeapEntry*> list(10);
29 list.Add(root);
30 root->paint();
31 CheckEntry(root);
32 while (!list.is_empty()) {
33 i::HeapEntry* entry = list.RemoveLast();
34 i::Vector<i::HeapGraphEdge> children = entry->children();
35 for (int i = 0; i < children.length(); ++i) {
36 if (children[i].type() == i::HeapGraphEdge::kShortcut) continue;
37 i::HeapEntry* child = children[i].to();
38 if (!child->painted()) {
39 list.Add(child);
40 child->paint();
41 CheckEntry(child);
42 }
43 }
44 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000045 }
46
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000047 bool has_A2;
48 bool has_B2;
49 bool has_C2;
50};
51
52} // namespace
53
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000054
55static const v8::HeapGraphNode* GetGlobalObject(
56 const v8::HeapSnapshot* snapshot) {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +000057 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
58 const v8::HeapGraphNode* global_obj =
59 snapshot->GetRoot()->GetChild(0)->GetToNode();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000060 CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
61 reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +000062 return global_obj;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000063}
64
65
66static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
67 v8::HeapGraphEdge::Type type,
68 const char* name) {
69 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
70 const v8::HeapGraphEdge* prop = node->GetChild(i);
71 v8::String::AsciiValue prop_name(prop->GetName());
72 if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
73 return prop->GetToNode();
74 }
75 return NULL;
76}
77
78
79static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
80 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
81 const v8::HeapGraphEdge* prop = node->GetChild(i);
82 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000083 if (node->GetType() == v8::HeapGraphNode::kString) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000084 v8::String::AsciiValue node_name(node->GetName());
85 if (strcmp(contents, *node_name) == 0) return true;
86 }
87 }
88 return false;
89}
90
91
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000092TEST(HeapSnapshot) {
93 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +000094 LocalContext env2;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000095
vegorov@chromium.org42841962010-10-18 11:18:59 +000096 CompileRun(
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000097 "function A2() {}\n"
98 "function B2(x) { return function() { return typeof x; }; }\n"
99 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
100 "var a2 = new A2();\n"
101 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
102 "var c2 = new C2(a2);");
103 const v8::HeapSnapshot* snapshot_env2 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000104 v8::HeapProfiler::TakeSnapshot(v8_str("env2"));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000105 i::HeapSnapshot* i_snapshot_env2 =
106 const_cast<i::HeapSnapshot*>(
107 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000108 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000109
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000110 // Verify, that JS global object of env2 has '..2' properties.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000111 const v8::HeapGraphNode* a2_node =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000112 GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000113 CHECK_NE(NULL, a2_node);
114 CHECK_NE(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000115 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000116 CHECK_NE(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000117 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
118 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000119
ulan@chromium.org967e2702012-02-28 09:49:15 +0000120 // Paint all nodes reachable from global object.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000121 NamedEntriesDetector det;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000122 i_snapshot_env2->ClearPaint();
123 det.CheckAllReachables(const_cast<i::HeapEntry*>(
124 reinterpret_cast<const i::HeapEntry*>(global_env2)));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000125 CHECK(det.has_A2);
126 CHECK(det.has_B2);
127 CHECK(det.has_C2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000128}
129
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000130
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000131TEST(HeapSnapshotObjectSizes) {
132 v8::HandleScope scope;
133 LocalContext env;
134
135 // -a-> X1 --a
136 // x -b-> X2 <-|
vegorov@chromium.org42841962010-10-18 11:18:59 +0000137 CompileRun(
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000138 "function X(a, b) { this.a = a; this.b = b; }\n"
139 "x = new X(new X(), new X());\n"
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000140 "(function() { x.a.a = x.b; })();");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000141 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000142 v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000143 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
144 const v8::HeapGraphNode* x =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000145 GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000146 CHECK_NE(NULL, x);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000147 const v8::HeapGraphNode* x1 =
148 GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
149 CHECK_NE(NULL, x1);
150 const v8::HeapGraphNode* x2 =
151 GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
152 CHECK_NE(NULL, x2);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000153
ulan@chromium.org967e2702012-02-28 09:49:15 +0000154 // Test sizes.
155 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize());
156 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize());
157 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize());
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000158}
159
160
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000161TEST(BoundFunctionInSnapshot) {
162 v8::HandleScope scope;
163 LocalContext env;
164 CompileRun(
165 "function myFunction(a, b) { this.a = a; this.b = b; }\n"
166 "function AAAAA() {}\n"
167 "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
168 const v8::HeapSnapshot* snapshot =
169 v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
170 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
171 const v8::HeapGraphNode* f =
172 GetProperty(global, v8::HeapGraphEdge::kShortcut, "boundFunction");
173 CHECK(f);
174 CHECK_EQ(v8::String::New("native_bind"), f->GetName());
175 const v8::HeapGraphNode* bindings =
176 GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
177 CHECK_NE(NULL, bindings);
178 CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
179 CHECK_EQ(4, bindings->GetChildrenCount());
180
181 const v8::HeapGraphNode* bound_this = GetProperty(
182 f, v8::HeapGraphEdge::kShortcut, "bound_this");
183 CHECK(bound_this);
184 CHECK_EQ(v8::HeapGraphNode::kObject, bound_this->GetType());
185
186 const v8::HeapGraphNode* bound_function = GetProperty(
187 f, v8::HeapGraphEdge::kShortcut, "bound_function");
188 CHECK(bound_function);
189 CHECK_EQ(v8::HeapGraphNode::kClosure, bound_function->GetType());
190
191 const v8::HeapGraphNode* bound_argument = GetProperty(
192 f, v8::HeapGraphEdge::kShortcut, "bound_argument_1");
193 CHECK(bound_argument);
194 CHECK_EQ(v8::HeapGraphNode::kObject, bound_argument->GetType());
195}
196
197
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000198TEST(HeapSnapshotEntryChildren) {
199 v8::HandleScope scope;
200 LocalContext env;
201
vegorov@chromium.org42841962010-10-18 11:18:59 +0000202 CompileRun(
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000203 "function A() { }\n"
204 "a = new A;");
205 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000206 v8::HeapProfiler::TakeSnapshot(v8_str("children"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000207 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
208 for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
209 const v8::HeapGraphEdge* prop = global->GetChild(i);
210 CHECK_EQ(global, prop->GetFromNode());
211 }
212 const v8::HeapGraphNode* a =
213 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
214 CHECK_NE(NULL, a);
215 for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
216 const v8::HeapGraphEdge* prop = a->GetChild(i);
217 CHECK_EQ(a, prop->GetFromNode());
218 }
219}
220
221
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000222TEST(HeapSnapshotCodeObjects) {
223 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000224 LocalContext env;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000225
vegorov@chromium.org42841962010-10-18 11:18:59 +0000226 CompileRun(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000227 "function lazy(x) { return x - 1; }\n"
228 "function compiled(x) { return x + 1; }\n"
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000229 "var anonymous = (function() { return function() { return 0; } })();\n"
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000230 "compiled(1)");
231 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000232 v8::HeapProfiler::TakeSnapshot(v8_str("code"));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000233
234 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
235 const v8::HeapGraphNode* compiled =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000236 GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000237 CHECK_NE(NULL, compiled);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000238 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000239 const v8::HeapGraphNode* lazy =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000240 GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000241 CHECK_NE(NULL, lazy);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000242 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000243 const v8::HeapGraphNode* anonymous =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000244 GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000245 CHECK_NE(NULL, anonymous);
246 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
247 v8::String::AsciiValue anonymous_name(anonymous->GetName());
vegorov@chromium.org42841962010-10-18 11:18:59 +0000248 CHECK_EQ("", *anonymous_name);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000249
250 // Find references to code.
251 const v8::HeapGraphNode* compiled_code =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000252 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000253 CHECK_NE(NULL, compiled_code);
254 const v8::HeapGraphNode* lazy_code =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000255 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000256 CHECK_NE(NULL, lazy_code);
257
258 // Verify that non-compiled code doesn't contain references to "x"
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000259 // literal, while compiled code does. The scope info is stored in FixedArray
260 // objects attached to the SharedFunctionInfo.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000261 bool compiled_references_x = false, lazy_references_x = false;
262 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
263 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
264 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000265 if (node->GetType() == v8::HeapGraphNode::kArray) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000266 if (HasString(node, "x")) {
267 compiled_references_x = true;
268 break;
269 }
270 }
271 }
272 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
273 const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
274 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000275 if (node->GetType() == v8::HeapGraphNode::kArray) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000276 if (HasString(node, "x")) {
277 lazy_references_x = true;
278 break;
279 }
280 }
281 }
282 CHECK(compiled_references_x);
283 CHECK(!lazy_references_x);
284}
285
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000286
vegorov@chromium.org42841962010-10-18 11:18:59 +0000287TEST(HeapSnapshotHeapNumbers) {
288 v8::HandleScope scope;
289 LocalContext env;
290 CompileRun(
291 "a = 1; // a is Smi\n"
292 "b = 2.5; // b is HeapNumber");
293 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000294 v8::HeapProfiler::TakeSnapshot(v8_str("numbers"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000295 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000296 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000297 const v8::HeapGraphNode* b =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000298 GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
vegorov@chromium.org42841962010-10-18 11:18:59 +0000299 CHECK_NE(NULL, b);
300 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
301}
302
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000303TEST(HeapSnapshotSlicedString) {
304 v8::HandleScope scope;
305 LocalContext env;
306 CompileRun(
307 "parent_string = \"123456789.123456789.123456789.123456789.123456789."
308 "123456789.123456789.123456789.123456789.123456789."
309 "123456789.123456789.123456789.123456789.123456789."
310 "123456789.123456789.123456789.123456789.123456789.\";"
311 "child_string = parent_string.slice(100);");
312 const v8::HeapSnapshot* snapshot =
313 v8::HeapProfiler::TakeSnapshot(v8_str("strings"));
314 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
315 const v8::HeapGraphNode* parent_string =
316 GetProperty(global, v8::HeapGraphEdge::kShortcut, "parent_string");
317 CHECK_NE(NULL, parent_string);
318 const v8::HeapGraphNode* child_string =
319 GetProperty(global, v8::HeapGraphEdge::kShortcut, "child_string");
320 CHECK_NE(NULL, child_string);
321 const v8::HeapGraphNode* parent =
322 GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
323 CHECK_EQ(parent_string, parent);
324}
vegorov@chromium.org42841962010-10-18 11:18:59 +0000325
326TEST(HeapSnapshotInternalReferences) {
327 v8::HandleScope scope;
328 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
329 global_template->SetInternalFieldCount(2);
330 LocalContext env(NULL, global_template);
331 v8::Handle<v8::Object> global_proxy = env->Global();
332 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
333 CHECK_EQ(2, global->InternalFieldCount());
334 v8::Local<v8::Object> obj = v8::Object::New();
335 global->SetInternalField(0, v8_num(17));
336 global->SetInternalField(1, obj);
337 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000338 v8::HeapProfiler::TakeSnapshot(v8_str("internals"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000339 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
340 // The first reference will not present, because it's a Smi.
341 CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
342 // The second reference is to an object.
343 CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
344}
345
346
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000347// Trying to introduce a check helper for uint64_t causes many
348// overloading ambiguities, so it seems easier just to cast
349// them to a signed type.
350#define CHECK_EQ_UINT64_T(a, b) \
351 CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000352#define CHECK_NE_UINT64_T(a, b) \
353 CHECK((a) != (b)) // NOLINT
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000354
355TEST(HeapEntryIdsAndGC) {
356 v8::HandleScope scope;
357 LocalContext env;
358
vegorov@chromium.org42841962010-10-18 11:18:59 +0000359 CompileRun(
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000360 "function A() {}\n"
361 "function B(x) { this.x = x; }\n"
362 "var a = new A();\n"
363 "var b = new B(a);");
364 const v8::HeapSnapshot* snapshot1 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000365 v8::HeapProfiler::TakeSnapshot(v8_str("s1"));
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000366
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000368
369 const v8::HeapSnapshot* snapshot2 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000370 v8::HeapProfiler::TakeSnapshot(v8_str("s2"));
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000371
372 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
373 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
374 CHECK_NE_UINT64_T(0, global1->GetId());
375 CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
376 const v8::HeapGraphNode* A1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000377 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
378 CHECK_NE(NULL, A1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000379 const v8::HeapGraphNode* A2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000380 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
381 CHECK_NE(NULL, A2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000382 CHECK_NE_UINT64_T(0, A1->GetId());
383 CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
384 const v8::HeapGraphNode* B1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000385 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
386 CHECK_NE(NULL, B1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000387 const v8::HeapGraphNode* B2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000388 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
389 CHECK_NE(NULL, B2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000390 CHECK_NE_UINT64_T(0, B1->GetId());
391 CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
392 const v8::HeapGraphNode* a1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000393 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
394 CHECK_NE(NULL, a1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000395 const v8::HeapGraphNode* a2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000396 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
397 CHECK_NE(NULL, a2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000398 CHECK_NE_UINT64_T(0, a1->GetId());
399 CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
400 const v8::HeapGraphNode* b1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000401 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
402 CHECK_NE(NULL, b1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000403 const v8::HeapGraphNode* b2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000404 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
405 CHECK_NE(NULL, b2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000406 CHECK_NE_UINT64_T(0, b1->GetId());
407 CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
408}
409
410
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000411TEST(HeapSnapshotRootPreservedAfterSorting) {
412 v8::HandleScope scope;
413 LocalContext env;
414 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000415 v8::HeapProfiler::TakeSnapshot(v8_str("s"));
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000416 const v8::HeapGraphNode* root1 = snapshot->GetRoot();
417 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
418 snapshot))->GetSortedEntriesList();
419 const v8::HeapGraphNode* root2 = snapshot->GetRoot();
420 CHECK_EQ(root1, root2);
421}
422
423
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000424TEST(HeapEntryDominator) {
425 // The graph looks like this:
426 //
427 // -> node1
428 // a |^
429 // -> node5 ba
430 // a v|
431 // node6 -> node2
432 // b a |^
433 // -> node4 ba
434 // b v|
435 // -> node3
436 //
437 // The dominator for all nodes is node6.
438
439 v8::HandleScope scope;
440 LocalContext env;
441
442 CompileRun(
443 "function X(a, b) { this.a = a; this.b = b; }\n"
444 "node6 = new X(new X(new X()), new X(new X(),new X()));\n"
445 "(function(){\n"
446 "node6.a.a.b = node6.b.a; // node1 -> node2\n"
447 "node6.b.a.a = node6.a.a; // node2 -> node1\n"
448 "node6.b.a.b = node6.b.b; // node2 -> node3\n"
449 "node6.b.b.a = node6.b.a; // node3 -> node2\n"
450 "})();");
451
452 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000453 v8::HeapProfiler::TakeSnapshot(v8_str("dominators"));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000454
455 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
456 CHECK_NE(NULL, global);
457 const v8::HeapGraphNode* node6 =
458 GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
459 CHECK_NE(NULL, node6);
460 const v8::HeapGraphNode* node5 =
461 GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
462 CHECK_NE(NULL, node5);
463 const v8::HeapGraphNode* node4 =
464 GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
465 CHECK_NE(NULL, node4);
466 const v8::HeapGraphNode* node3 =
467 GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
468 CHECK_NE(NULL, node3);
469 const v8::HeapGraphNode* node2 =
470 GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
471 CHECK_NE(NULL, node2);
472 const v8::HeapGraphNode* node1 =
473 GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
474 CHECK_NE(NULL, node1);
475
476 CHECK_EQ(node6, node1->GetDominatorNode());
477 CHECK_EQ(node6, node2->GetDominatorNode());
478 CHECK_EQ(node6, node3->GetDominatorNode());
479 CHECK_EQ(node6, node4->GetDominatorNode());
480 CHECK_EQ(node6, node5->GetDominatorNode());
481}
482
483
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000484namespace {
485
486class TestJSONStream : public v8::OutputStream {
487 public:
488 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
489 explicit TestJSONStream(int abort_countdown)
490 : eos_signaled_(0), abort_countdown_(abort_countdown) {}
491 virtual ~TestJSONStream() {}
492 virtual void EndOfStream() { ++eos_signaled_; }
493 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
494 if (abort_countdown_ > 0) --abort_countdown_;
495 if (abort_countdown_ == 0) return kAbort;
496 CHECK_GT(chars_written, 0);
497 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
498 memcpy(chunk.start(), buffer, chars_written);
499 return kContinue;
500 }
501 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
502 int eos_signaled() { return eos_signaled_; }
503 int size() { return buffer_.size(); }
504 private:
505 i::Collector<char> buffer_;
506 int eos_signaled_;
507 int abort_countdown_;
508};
509
510class AsciiResource: public v8::String::ExternalAsciiStringResource {
511 public:
512 explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
513 length_ = string.length();
514 }
515 virtual const char* data() const { return data_; }
516 virtual size_t length() const { return length_; }
517 private:
518 const char* data_;
519 size_t length_;
520};
521
522} // namespace
523
524TEST(HeapSnapshotJSONSerialization) {
525 v8::HandleScope scope;
526 LocalContext env;
527
528#define STRING_LITERAL_FOR_TEST \
529 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
vegorov@chromium.org42841962010-10-18 11:18:59 +0000530 CompileRun(
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000531 "function A(s) { this.s = s; }\n"
532 "function B(x) { this.x = x; }\n"
533 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
534 "var b = new B(a);");
535 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000536 v8::HeapProfiler::TakeSnapshot(v8_str("json"));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000537 TestJSONStream stream;
538 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
539 CHECK_GT(stream.size(), 0);
540 CHECK_EQ(1, stream.eos_signaled());
541 i::ScopedVector<char> json(stream.size());
542 stream.WriteTo(json);
543
544 // Verify that snapshot string is valid JSON.
545 AsciiResource json_res(json);
546 v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000547 env->Global()->Set(v8_str("json_snapshot"), json_string);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000548 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
549 "var parsed = JSON.parse(json_snapshot); true;");
550 CHECK(!snapshot_parse_result.IsEmpty());
551
552 // Verify that snapshot object has required fields.
553 v8::Local<v8::Object> parsed_snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000554 env->Global()->Get(v8_str("parsed"))->ToObject();
555 CHECK(parsed_snapshot->Has(v8_str("snapshot")));
556 CHECK(parsed_snapshot->Has(v8_str("nodes")));
557 CHECK(parsed_snapshot->Has(v8_str("strings")));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000558
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000559 // Get node and edge "member" offsets.
560 v8::Local<v8::Value> meta_analysis_result = CompileRun(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000561 "var parsed_meta = parsed.nodes[0];\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000562 "var children_count_offset ="
563 " parsed_meta.fields.indexOf('children_count');\n"
564 "var children_offset ="
565 " parsed_meta.fields.indexOf('children');\n"
566 "var children_meta ="
567 " parsed_meta.types[children_offset];\n"
568 "var child_fields_count = children_meta.fields.length;\n"
569 "var child_type_offset ="
570 " children_meta.fields.indexOf('type');\n"
571 "var child_name_offset ="
572 " children_meta.fields.indexOf('name_or_index');\n"
573 "var child_to_node_offset ="
574 " children_meta.fields.indexOf('to_node');\n"
575 "var property_type ="
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000576 " children_meta.types[child_type_offset].indexOf('property');\n"
577 "var shortcut_type ="
578 " children_meta.types[child_type_offset].indexOf('shortcut');");
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000579 CHECK(!meta_analysis_result.IsEmpty());
580
581 // A helper function for processing encoded nodes.
582 CompileRun(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000583 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000584 " var nodes = parsed.nodes;\n"
585 " var strings = parsed.strings;\n"
586 " for (var i = 0,\n"
587 " count = nodes[pos + children_count_offset] * child_fields_count;\n"
588 " i < count; i += child_fields_count) {\n"
589 " var child_pos = pos + children_offset + i;\n"
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000590 " if (nodes[child_pos + child_type_offset] === prop_type\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000591 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
592 " return nodes[child_pos + child_to_node_offset];\n"
593 " }\n"
594 " return null;\n"
595 "}\n");
596 // Get the string index using the path: <root> -> <global>.b.x.s
597 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
598 "GetChildPosByProperty(\n"
599 " GetChildPosByProperty(\n"
600 " GetChildPosByProperty("
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000601 " parsed.nodes[1 + children_offset + child_to_node_offset],"
602 " \"b\",shortcut_type),\n"
603 " \"x\", property_type),"
604 " \"s\", property_type)");
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000605 CHECK(!string_obj_pos_val.IsEmpty());
606 int string_obj_pos =
607 static_cast<int>(string_obj_pos_val->ToNumber()->Value());
608 v8::Local<v8::Object> nodes_array =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000609 parsed_snapshot->Get(v8_str("nodes"))->ToObject();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000610 int string_index = static_cast<int>(
611 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
612 CHECK_GT(string_index, 0);
613 v8::Local<v8::Object> strings_array =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000614 parsed_snapshot->Get(v8_str("strings"))->ToObject();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000615 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
616 v8::Local<v8::String> ref_string =
617 CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
618#undef STRING_LITERAL_FOR_TEST
619 CHECK_EQ(*v8::String::Utf8Value(ref_string),
620 *v8::String::Utf8Value(string));
621}
622
623
624TEST(HeapSnapshotJSONSerializationAborting) {
625 v8::HandleScope scope;
626 LocalContext env;
627 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000628 v8::HeapProfiler::TakeSnapshot(v8_str("abort"));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000629 TestJSONStream stream(5);
630 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
631 CHECK_GT(stream.size(), 0);
632 CHECK_EQ(0, stream.eos_signaled());
633}
634
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000635
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000636static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
637 const v8::HeapGraphNode* node,
638 int level, int max_level) {
639 if (level > max_level) return;
640 CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
641 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
642 const v8::HeapGraphEdge* prop = node->GetChild(i);
643 const v8::HeapGraphNode* child =
644 snapshot->GetNodeById(prop->GetToNode()->GetId());
645 CHECK_EQ_UINT64_T(prop->GetToNode()->GetId(), child->GetId());
646 CHECK_EQ(prop->GetToNode(), child);
647 CheckChildrenIds(snapshot, child, level + 1, max_level);
648 }
649}
650
651
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000652TEST(HeapSnapshotGetNodeById) {
653 v8::HandleScope scope;
654 LocalContext env;
655
656 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000657 v8::HeapProfiler::TakeSnapshot(v8_str("id"));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000658 const v8::HeapGraphNode* root = snapshot->GetRoot();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000659 CheckChildrenIds(snapshot, root, 0, 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000660 // Check a big id, which should not exist yet.
661 CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
662}
663
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000664
665namespace {
666
667class TestActivityControl : public v8::ActivityControl {
668 public:
669 explicit TestActivityControl(int abort_count)
670 : done_(0), total_(0), abort_count_(abort_count) {}
671 ControlOption ReportProgressValue(int done, int total) {
672 done_ = done;
673 total_ = total;
674 return --abort_count_ != 0 ? kContinue : kAbort;
675 }
676 int done() { return done_; }
677 int total() { return total_; }
678
679 private:
680 int done_;
681 int total_;
682 int abort_count_;
683};
684}
685
686TEST(TakeHeapSnapshotAborting) {
687 v8::HandleScope scope;
688 LocalContext env;
689
690 const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000691 TestActivityControl aborting_control(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000692 const v8::HeapSnapshot* no_snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000693 v8::HeapProfiler::TakeSnapshot(v8_str("abort"),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000694 v8::HeapSnapshot::kFull,
695 &aborting_control);
696 CHECK_EQ(NULL, no_snapshot);
697 CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
698 CHECK_GT(aborting_control.total(), aborting_control.done());
699
700 TestActivityControl control(-1); // Don't abort.
701 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000702 v8::HeapProfiler::TakeSnapshot(v8_str("full"),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000703 v8::HeapSnapshot::kFull,
704 &control);
705 CHECK_NE(NULL, snapshot);
706 CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
707 CHECK_EQ(control.total(), control.done());
708 CHECK_GT(control.total(), 0);
709}
710
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000711
712namespace {
713
714class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
715 public:
716 TestRetainedObjectInfo(int hash,
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000717 const char* group_label,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000718 const char* label,
719 intptr_t element_count = -1,
720 intptr_t size = -1)
721 : disposed_(false),
722 hash_(hash),
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000723 group_label_(group_label),
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000724 label_(label),
725 element_count_(element_count),
726 size_(size) {
727 instances.Add(this);
728 }
729 virtual ~TestRetainedObjectInfo() {}
730 virtual void Dispose() {
731 CHECK(!disposed_);
732 disposed_ = true;
733 }
734 virtual bool IsEquivalent(RetainedObjectInfo* other) {
735 return GetHash() == other->GetHash();
736 }
737 virtual intptr_t GetHash() { return hash_; }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000738 virtual const char* GetGroupLabel() { return group_label_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000739 virtual const char* GetLabel() { return label_; }
740 virtual intptr_t GetElementCount() { return element_count_; }
741 virtual intptr_t GetSizeInBytes() { return size_; }
742 bool disposed() { return disposed_; }
743
744 static v8::RetainedObjectInfo* WrapperInfoCallback(
745 uint16_t class_id, v8::Handle<v8::Value> wrapper) {
746 if (class_id == 1) {
747 if (wrapper->IsString()) {
748 v8::String::AsciiValue ascii(wrapper);
749 if (strcmp(*ascii, "AAA") == 0)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000750 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000751 else if (strcmp(*ascii, "BBB") == 0)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000752 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000753 }
754 } else if (class_id == 2) {
755 if (wrapper->IsString()) {
756 v8::String::AsciiValue ascii(wrapper);
757 if (strcmp(*ascii, "CCC") == 0)
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000758 return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000759 }
760 }
761 CHECK(false);
762 return NULL;
763 }
764
765 static i::List<TestRetainedObjectInfo*> instances;
766
767 private:
768 bool disposed_;
769 int category_;
770 int hash_;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000771 const char* group_label_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000772 const char* label_;
773 intptr_t element_count_;
774 intptr_t size_;
775};
776
777
778i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
779}
780
781
782static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
783 v8::HeapGraphNode::Type type,
784 const char* name) {
785 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
786 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
787 if (node->GetType() == type && strcmp(name,
788 const_cast<i::HeapEntry*>(
789 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
790 return node;
791 }
792 }
793 return NULL;
794}
795
796
797TEST(HeapSnapshotRetainedObjectInfo) {
798 v8::HandleScope scope;
799 LocalContext env;
800
801 v8::HeapProfiler::DefineWrapperClass(
802 1, TestRetainedObjectInfo::WrapperInfoCallback);
803 v8::HeapProfiler::DefineWrapperClass(
804 2, TestRetainedObjectInfo::WrapperInfoCallback);
805 v8::Persistent<v8::String> p_AAA =
806 v8::Persistent<v8::String>::New(v8_str("AAA"));
807 p_AAA.SetWrapperClassId(1);
808 v8::Persistent<v8::String> p_BBB =
809 v8::Persistent<v8::String>::New(v8_str("BBB"));
810 p_BBB.SetWrapperClassId(1);
811 v8::Persistent<v8::String> p_CCC =
812 v8::Persistent<v8::String>::New(v8_str("CCC"));
813 p_CCC.SetWrapperClassId(2);
814 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
815 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000816 v8::HeapProfiler::TakeSnapshot(v8_str("retained"));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000817
818 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
819 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
820 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
821 delete TestRetainedObjectInfo::instances[i];
822 }
823
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000824 const v8::HeapGraphNode* native_group_aaa = GetNode(
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000825 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "aaa-group");
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000826 CHECK_NE(NULL, native_group_aaa);
827 CHECK_EQ(1, native_group_aaa->GetChildrenCount());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000828 const v8::HeapGraphNode* aaa = GetNode(
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000829 native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000830 CHECK_NE(NULL, aaa);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000831 CHECK_EQ(2, aaa->GetChildrenCount());
832
833 const v8::HeapGraphNode* native_group_ccc = GetNode(
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000834 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "ccc-group");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000835 const v8::HeapGraphNode* ccc = GetNode(
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000836 native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000837 CHECK_NE(NULL, ccc);
838
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000839 const v8::HeapGraphNode* n_AAA = GetNode(
840 aaa, v8::HeapGraphNode::kString, "AAA");
841 CHECK_NE(NULL, n_AAA);
842 const v8::HeapGraphNode* n_BBB = GetNode(
843 aaa, v8::HeapGraphNode::kString, "BBB");
844 CHECK_NE(NULL, n_BBB);
845 CHECK_EQ(1, ccc->GetChildrenCount());
846 const v8::HeapGraphNode* n_CCC = GetNode(
847 ccc, v8::HeapGraphNode::kString, "CCC");
848 CHECK_NE(NULL, n_CCC);
849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000850 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
851 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
852 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000853}
854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000856class GraphWithImplicitRefs {
857 public:
858 static const int kObjectsCount = 4;
859 explicit GraphWithImplicitRefs(LocalContext* env) {
860 CHECK_EQ(NULL, instance_);
861 instance_ = this;
862 for (int i = 0; i < kObjectsCount; i++) {
863 objects_[i] = v8::Persistent<v8::Object>::New(v8::Object::New());
864 }
865 (*env)->Global()->Set(v8_str("root_object"), objects_[0]);
866 }
867 ~GraphWithImplicitRefs() {
868 instance_ = NULL;
869 }
870
871 static void gcPrologue() {
872 instance_->AddImplicitReferences();
873 }
874
875 private:
876 void AddImplicitReferences() {
877 // 0 -> 1
878 v8::V8::AddImplicitReferences(
879 v8::Persistent<v8::Object>::Cast(objects_[0]), &objects_[1], 1);
880 // Adding two more references(note length=2 in params): 1 -> 2, 1 -> 3
881 v8::V8::AddImplicitReferences(
882 v8::Persistent<v8::Object>::Cast(objects_[1]), &objects_[2], 2);
883 }
884
885 v8::Persistent<v8::Value> objects_[kObjectsCount];
886 static GraphWithImplicitRefs* instance_;
887};
888
889GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
890
891
892TEST(HeapSnapshotImplicitReferences) {
893 v8::HandleScope scope;
894 LocalContext env;
895
896 GraphWithImplicitRefs graph(&env);
897 v8::V8::SetGlobalGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
898
899 const v8::HeapSnapshot* snapshot =
900 v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs"));
901
902 const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
903 // Use kShortcut type to skip intermediate JSGlobalPropertyCell
904 const v8::HeapGraphNode* obj0 = GetProperty(
905 global_object, v8::HeapGraphEdge::kShortcut, "root_object");
906 CHECK(obj0);
907 CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
908 const v8::HeapGraphNode* obj1 = GetProperty(
909 obj0, v8::HeapGraphEdge::kInternal, "native");
910 CHECK(obj1);
911 int implicit_targets_count = 0;
912 for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
913 const v8::HeapGraphEdge* prop = obj1->GetChild(i);
914 v8::String::AsciiValue prop_name(prop->GetName());
915 if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
916 strcmp("native", *prop_name) == 0) {
917 ++implicit_targets_count;
918 }
919 }
920 CHECK_EQ(2, implicit_targets_count);
921 v8::V8::SetGlobalGCPrologueCallback(NULL);
922}
923
924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925TEST(DeleteAllHeapSnapshots) {
926 v8::HandleScope scope;
927 LocalContext env;
928
929 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
930 v8::HeapProfiler::DeleteAllSnapshots();
931 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000932 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("1")));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
934 v8::HeapProfiler::DeleteAllSnapshots();
935 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000936 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("1")));
937 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("2")));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000938 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
939 v8::HeapProfiler::DeleteAllSnapshots();
940 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
941}
942
943
944TEST(DeleteHeapSnapshot) {
945 v8::HandleScope scope;
946 LocalContext env;
947
948 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
949 const v8::HeapSnapshot* s1 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000950 v8::HeapProfiler::TakeSnapshot(v8_str("1"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 CHECK_NE(NULL, s1);
952 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
953 unsigned uid1 = s1->GetUid();
954 CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1));
955 const_cast<v8::HeapSnapshot*>(s1)->Delete();
956 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
957 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1));
958
959 const v8::HeapSnapshot* s2 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000960 v8::HeapProfiler::TakeSnapshot(v8_str("2"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 CHECK_NE(NULL, s2);
962 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
963 unsigned uid2 = s2->GetUid();
964 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
965 CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2));
966 const v8::HeapSnapshot* s3 =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000967 v8::HeapProfiler::TakeSnapshot(v8_str("3"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 CHECK_NE(NULL, s3);
969 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
970 unsigned uid3 = s3->GetUid();
971 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
972 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
973 const_cast<v8::HeapSnapshot*>(s2)->Delete();
974 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
975 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2));
976 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
977 const_cast<v8::HeapSnapshot*>(s3)->Delete();
978 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
979 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
980}
981
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000982
983TEST(DocumentURL) {
984 v8::HandleScope scope;
985 LocalContext env;
986
987 CompileRun("document = { URL:\"abcdefgh\" };");
988
989 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000990 v8::HeapProfiler::TakeSnapshot(v8_str("document"));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000991 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
992 CHECK_NE(NULL, global);
993 CHECK_EQ("Object / abcdefgh",
994 const_cast<i::HeapEntry*>(
995 reinterpret_cast<const i::HeapEntry*>(global))->name());
996}
997
998
999TEST(DocumentWithException) {
1000 v8::HandleScope scope;
1001 LocalContext env;
1002
1003 CompileRun(
1004 "this.__defineGetter__(\"document\", function() { throw new Error(); })");
1005 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001006 v8::HeapProfiler::TakeSnapshot(v8_str("document"));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001007 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1008 CHECK_NE(NULL, global);
1009 CHECK_EQ("Object",
1010 const_cast<i::HeapEntry*>(
1011 reinterpret_cast<const i::HeapEntry*>(global))->name());
1012}
1013
1014
1015TEST(DocumentURLWithException) {
1016 v8::HandleScope scope;
1017 LocalContext env;
1018
1019 CompileRun(
1020 "function URLWithException() {}\n"
1021 "URLWithException.prototype = { get URL() { throw new Error(); } };\n"
1022 "document = { URL: new URLWithException() };");
1023 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001024 v8::HeapProfiler::TakeSnapshot(v8_str("document"));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001025 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1026 CHECK_NE(NULL, global);
1027 CHECK_EQ("Object",
1028 const_cast<i::HeapEntry*>(
1029 reinterpret_cast<const i::HeapEntry*>(global))->name());
1030}
1031
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001032
erikcorry0ad885c2011-11-21 13:51:57 +00001033TEST(NoHandleLeaks) {
1034 v8::HandleScope scope;
1035 LocalContext env;
1036
1037 CompileRun("document = { URL:\"abcdefgh\" };");
1038
1039 v8::Handle<v8::String> name(v8_str("leakz"));
1040 int count_before = i::HandleScope::NumberOfHandles();
1041 v8::HeapProfiler::TakeSnapshot(name);
1042 int count_after = i::HandleScope::NumberOfHandles();
1043 CHECK_EQ(count_before, count_after);
1044}
1045
1046
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001047TEST(NodesIteration) {
1048 v8::HandleScope scope;
1049 LocalContext env;
1050 const v8::HeapSnapshot* snapshot =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001051 v8::HeapProfiler::TakeSnapshot(v8_str("iteration"));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001052 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1053 CHECK_NE(NULL, global);
1054 // Verify that we can find this object by iteration.
1055 const int nodes_count = snapshot->GetNodesCount();
1056 int count = 0;
1057 for (int i = 0; i < nodes_count; ++i) {
1058 if (snapshot->GetNode(i) == global)
1059 ++count;
1060 }
1061 CHECK_EQ(1, count);
1062}
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001063
1064
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001065TEST(GetHeapValue) {
1066 v8::HandleScope scope;
1067 LocalContext env;
1068
1069 CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };");
1070 const v8::HeapSnapshot* snapshot =
1071 v8::HeapProfiler::TakeSnapshot(v8_str("value"));
1072 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1073 CHECK(global->GetHeapValue()->IsObject());
1074 v8::Local<v8::Object> js_global =
1075 env->Global()->GetPrototype().As<v8::Object>();
1076 CHECK(js_global == global->GetHeapValue());
1077 const v8::HeapGraphNode* obj = GetProperty(
1078 global, v8::HeapGraphEdge::kShortcut, "a");
1079 CHECK(obj->GetHeapValue()->IsObject());
1080 v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
1081 CHECK(js_obj == obj->GetHeapValue());
1082 const v8::HeapGraphNode* s_prop =
1083 GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
1084 v8::Local<v8::String> js_s_prop =
1085 js_obj->Get(v8_str("s_prop")).As<v8::String>();
1086 CHECK(js_s_prop == s_prop->GetHeapValue());
1087 const v8::HeapGraphNode* n_prop =
1088 GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
1089 v8::Local<v8::Number> js_n_prop =
1090 js_obj->Get(v8_str("n_prop")).As<v8::Number>();
1091 CHECK(js_n_prop == n_prop->GetHeapValue());
1092}
1093
1094
1095TEST(GetHeapValueForDeletedObject) {
1096 v8::HandleScope scope;
1097 LocalContext env;
1098
1099 // It is impossible to delete a global property, so we are about to delete a
1100 // property of the "a" object. Also, the "p" object can't be an empty one
1101 // because the empty object is static and isn't actually deleted.
1102 CompileRun("a = { p: { r: {} } };");
1103 const v8::HeapSnapshot* snapshot =
1104 v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1105 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1106 const v8::HeapGraphNode* obj = GetProperty(
1107 global, v8::HeapGraphEdge::kShortcut, "a");
1108 const v8::HeapGraphNode* prop = GetProperty(
1109 obj, v8::HeapGraphEdge::kProperty, "p");
1110 {
1111 // Perform the check inside a nested local scope to avoid creating a
1112 // reference to the object we are deleting.
1113 v8::HandleScope scope;
1114 CHECK(prop->GetHeapValue()->IsObject());
1115 }
1116 CompileRun("delete a.p;");
1117 CHECK(prop->GetHeapValue()->IsUndefined());
1118}
1119
1120
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001121static int StringCmp(const char* ref, i::String* act) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001122 i::SmartArrayPointer<char> s_act = act->ToCString();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001123 int result = strcmp(ref, *s_act);
1124 if (result != 0)
1125 fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, *s_act);
1126 return result;
1127}
1128
1129
1130TEST(GetConstructorName) {
1131 v8::HandleScope scope;
1132 LocalContext env;
1133
1134 CompileRun(
1135 "function Constructor1() {};\n"
1136 "var obj1 = new Constructor1();\n"
1137 "var Constructor2 = function() {};\n"
1138 "var obj2 = new Constructor2();\n"
1139 "var obj3 = {};\n"
1140 "obj3.constructor = function Constructor3() {};\n"
1141 "var obj4 = {};\n"
1142 "// Slow properties\n"
1143 "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
1144 "obj4.constructor = function Constructor4() {};\n"
1145 "var obj5 = {};\n"
1146 "var obj6 = {};\n"
1147 "obj6.constructor = 6;");
1148 v8::Local<v8::Object> js_global =
1149 env->Global()->GetPrototype().As<v8::Object>();
1150 v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
1151 i::Handle<i::JSObject> js_obj1 = v8::Utils::OpenHandle(*obj1);
1152 CHECK_EQ(0, StringCmp(
1153 "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
1154 v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
1155 i::Handle<i::JSObject> js_obj2 = v8::Utils::OpenHandle(*obj2);
1156 CHECK_EQ(0, StringCmp(
1157 "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
1158 v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
1159 i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
1160 CHECK_EQ(0, StringCmp(
1161 "Constructor3", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
1162 v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
1163 i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
1164 CHECK_EQ(0, StringCmp(
1165 "Constructor4", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
1166 v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
1167 i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
1168 CHECK_EQ(0, StringCmp(
1169 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
1170 v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
1171 i::Handle<i::JSObject> js_obj6 = v8::Utils::OpenHandle(*obj6);
1172 CHECK_EQ(0, StringCmp(
1173 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1174}
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001175
erikcorry0ad885c2011-11-21 13:51:57 +00001176
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001177TEST(FastCaseGetter) {
1178 v8::HandleScope scope;
1179 LocalContext env;
1180
1181 CompileRun("var obj1 = {};\n"
1182 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1183 " return 42;\n"
1184 "});\n"
1185 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1186 " return this.value_ = value;\n"
1187 "});\n");
1188 const v8::HeapSnapshot* snapshot =
1189 v8::HeapProfiler::TakeSnapshot(v8_str("fastCaseGetter"));
1190
1191 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1192 CHECK_NE(NULL, global);
1193 const v8::HeapGraphNode* obj1 =
1194 GetProperty(global, v8::HeapGraphEdge::kShortcut, "obj1");
1195 CHECK_NE(NULL, obj1);
1196 const v8::HeapGraphNode* getterFunction =
1197 GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get-propWithGetter");
1198 CHECK_NE(NULL, getterFunction);
1199 const v8::HeapGraphNode* setterFunction =
1200 GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter");
1201 CHECK_NE(NULL, setterFunction);
1202}
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001203
1204
1205bool HasWeakEdge(const v8::HeapGraphNode* node) {
1206 for (int i = 0; i < node->GetChildrenCount(); ++i) {
1207 const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
1208 if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
1209 }
1210 return false;
1211}
1212
1213
1214bool HasWeakGlobalHandle() {
1215 const v8::HeapSnapshot* snapshot =
1216 v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
1217 const v8::HeapGraphNode* gc_roots = GetNode(
1218 snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1219 CHECK_NE(NULL, gc_roots);
1220 const v8::HeapGraphNode* global_handles = GetNode(
1221 gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
1222 CHECK_NE(NULL, global_handles);
1223 return HasWeakEdge(global_handles);
1224}
1225
1226
1227static void PersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
1228 handle.Dispose();
1229}
1230
1231
1232TEST(WeakGlobalHandle) {
1233 v8::HandleScope scope;
1234 LocalContext env;
1235
1236 CHECK(!HasWeakGlobalHandle());
1237
1238 v8::Persistent<v8::Object> handle =
1239 v8::Persistent<v8::Object>::New(v8::Object::New());
1240 handle.MakeWeak(NULL, PersistentHandleCallback);
1241
1242 CHECK(HasWeakGlobalHandle());
1243}
1244
1245
1246TEST(WeakGlobalContextRefs) {
1247 v8::HandleScope scope;
1248 LocalContext env;
1249
1250 const v8::HeapSnapshot* snapshot =
1251 v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
1252 const v8::HeapGraphNode* gc_roots = GetNode(
1253 snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1254 CHECK_NE(NULL, gc_roots);
1255 const v8::HeapGraphNode* global_handles = GetNode(
1256 gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
1257 CHECK_NE(NULL, global_handles);
1258 const v8::HeapGraphNode* global_context = GetNode(
1259 global_handles, v8::HeapGraphNode::kHidden, "system / GlobalContext");
1260 CHECK_NE(NULL, global_context);
1261 CHECK(HasWeakEdge(global_context));
1262}
1263
1264
1265TEST(SfiAndJsFunctionWeakRefs) {
1266 v8::HandleScope scope;
1267 LocalContext env;
1268
1269 CompileRun(
1270 "fun = (function (x) { return function () { return x + 1; } })(1);");
1271 const v8::HeapSnapshot* snapshot =
1272 v8::HeapProfiler::TakeSnapshot(v8_str("fun"));
1273 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1274 CHECK_NE(NULL, global);
1275 const v8::HeapGraphNode* fun =
1276 GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun");
1277 CHECK(HasWeakEdge(fun));
1278 const v8::HeapGraphNode* shared =
1279 GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
1280 CHECK(HasWeakEdge(shared));
1281}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001282
1283
1284TEST(PersistentHandleCount) {
1285 v8::HandleScope scope;
1286 LocalContext env;
1287
1288 // V8 also uses global handles internally, so we can't test for an absolute
1289 // number.
1290 int global_handle_count = v8::HeapProfiler::GetPersistentHandleCount();
1291
1292 // Create some persistent handles.
1293 v8::Persistent<v8::String> p_AAA =
1294 v8::Persistent<v8::String>::New(v8_str("AAA"));
1295 CHECK_EQ(global_handle_count + 1,
1296 v8::HeapProfiler::GetPersistentHandleCount());
1297 v8::Persistent<v8::String> p_BBB =
1298 v8::Persistent<v8::String>::New(v8_str("BBB"));
1299 CHECK_EQ(global_handle_count + 2,
1300 v8::HeapProfiler::GetPersistentHandleCount());
1301 v8::Persistent<v8::String> p_CCC =
1302 v8::Persistent<v8::String>::New(v8_str("CCC"));
1303 CHECK_EQ(global_handle_count + 3,
1304 v8::HeapProfiler::GetPersistentHandleCount());
1305
1306 // Dipose the persistent handles in a different order.
1307 p_AAA.Dispose();
1308 CHECK_EQ(global_handle_count + 2,
1309 v8::HeapProfiler::GetPersistentHandleCount());
1310 p_CCC.Dispose();
1311 CHECK_EQ(global_handle_count + 1,
1312 v8::HeapProfiler::GetPersistentHandleCount());
1313 p_BBB.Dispose();
1314 CHECK_EQ(global_handle_count, v8::HeapProfiler::GetPersistentHandleCount());
1315}