blob: 94a5be47c197a3f0157ab8fa4a00bdb8071c3249 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Steve Blocka7e24c12009-10-30 11:49:00 +000027//
28// Tests for heap profiler
29
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include <ctype.h>
Ben Murdoch257744e2011-11-30 15:57:28 +000031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/v8.h"
33
34#include "include/v8-profiler.h"
35#include "src/allocation-tracker.h"
36#include "src/debug.h"
37#include "src/hashmap.h"
38#include "src/heap-profiler.h"
39#include "src/snapshot.h"
40#include "src/utils-inl.h"
41#include "test/cctest/cctest.h"
42
43using i::AllocationTraceNode;
44using i::AllocationTraceTree;
45using i::AllocationTracker;
46using i::HashMap;
47using i::Vector;
Steve Blocka7e24c12009-10-30 11:49:00 +000048
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010049namespace {
50
51class NamedEntriesDetector {
52 public:
53 NamedEntriesDetector()
Russell Brenner90bac252010-11-18 13:33:46 -080054 : has_A2(false), has_B2(false), has_C2(false) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010055 }
56
Ben Murdoch3ef787d2012-04-12 10:51:47 +010057 void CheckEntry(i::HeapEntry* entry) {
58 if (strcmp(entry->name(), "A2") == 0) has_A2 = true;
59 if (strcmp(entry->name(), "B2") == 0) has_B2 = true;
60 if (strcmp(entry->name(), "C2") == 0) has_C2 = true;
Iain Merrick75681382010-08-19 15:07:18 +010061 }
62
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 static bool AddressesMatch(void* key1, void* key2) {
64 return key1 == key2;
65 }
66
Ben Murdoch3ef787d2012-04-12 10:51:47 +010067 void CheckAllReachables(i::HeapEntry* root) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 i::HashMap visited(AddressesMatch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010069 i::List<i::HeapEntry*> list(10);
70 list.Add(root);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010071 CheckEntry(root);
72 while (!list.is_empty()) {
73 i::HeapEntry* entry = list.RemoveLast();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 i::Vector<i::HeapGraphEdge*> children = entry->children();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010075 for (int i = 0; i < children.length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076 if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue;
77 i::HeapEntry* child = children[i]->to();
78 i::HashMap::Entry* entry = visited.Lookup(
79 reinterpret_cast<void*>(child),
80 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child)),
81 true);
82 if (entry->value)
83 continue;
84 entry->value = reinterpret_cast<void*>(1);
85 list.Add(child);
86 CheckEntry(child);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010087 }
88 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010089 }
90
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010091 bool has_A2;
92 bool has_B2;
93 bool has_C2;
94};
95
96} // namespace
97
98
99static const v8::HeapGraphNode* GetGlobalObject(
100 const v8::HeapSnapshot* snapshot) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800101 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102 // The 0th-child is (GC Roots), 1st is the user root.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800103 const v8::HeapGraphNode* global_obj =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 snapshot->GetRoot()->GetChild(1)->GetToNode();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000105 CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
106 reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800107 return global_obj;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100108}
109
110
111static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
112 v8::HeapGraphEdge::Type type,
113 const char* name) {
114 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
115 const v8::HeapGraphEdge* prop = node->GetChild(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 v8::String::Utf8Value prop_name(prop->GetName());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100117 if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
118 return prop->GetToNode();
119 }
120 return NULL;
121}
122
123
124static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
125 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
126 const v8::HeapGraphEdge* prop = node->GetChild(i);
127 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100128 if (node->GetType() == v8::HeapGraphNode::kString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 v8::String::Utf8Value node_name(node->GetName());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100130 if (strcmp(contents, *node_name) == 0) return true;
131 }
132 }
133 return false;
134}
135
136
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137static bool AddressesMatch(void* key1, void* key2) {
138 return key1 == key2;
139}
140
141
142// Check that snapshot has no unretained entries except root.
143static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) {
144 i::HeapSnapshot* heap_snapshot = const_cast<i::HeapSnapshot*>(
145 reinterpret_cast<const i::HeapSnapshot*>(snapshot));
146
147 i::HashMap visited(AddressesMatch);
148 i::List<i::HeapGraphEdge>& edges = heap_snapshot->edges();
149 for (int i = 0; i < edges.length(); ++i) {
150 i::HashMap::Entry* entry = visited.Lookup(
151 reinterpret_cast<void*>(edges[i].to()),
152 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(edges[i].to())),
153 true);
154 uint32_t ref_count = static_cast<uint32_t>(
155 reinterpret_cast<uintptr_t>(entry->value));
156 entry->value = reinterpret_cast<void*>(ref_count + 1);
157 }
158 uint32_t unretained_entries_count = 0;
159 i::List<i::HeapEntry>& entries = heap_snapshot->entries();
160 for (int i = 0; i < entries.length(); ++i) {
161 i::HashMap::Entry* entry = visited.Lookup(
162 reinterpret_cast<void*>(&entries[i]),
163 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&entries[i])),
164 false);
165 if (!entry && entries[i].id() != 1) {
166 entries[i].Print("entry with no retainer", "", depth, 0);
167 ++unretained_entries_count;
168 }
169 }
170 return unretained_entries_count == 0;
171}
172
173
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100174TEST(HeapSnapshot) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100175 LocalContext env2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 v8::HandleScope scope(env2->GetIsolate());
177 v8::HeapProfiler* heap_profiler = env2->GetIsolate()->GetHeapProfiler();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100178
Ben Murdochf87a2032010-10-22 12:50:53 +0100179 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100180 "function A2() {}\n"
181 "function B2(x) { return function() { return typeof x; }; }\n"
182 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
183 "var a2 = new A2();\n"
184 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
185 "var c2 = new C2(a2);");
186 const v8::HeapSnapshot* snapshot_env2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 heap_profiler->TakeHeapSnapshot(v8_str("env2"));
188 CHECK(ValidateSnapshot(snapshot_env2));
Iain Merrick75681382010-08-19 15:07:18 +0100189 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
Iain Merrick75681382010-08-19 15:07:18 +0100190
Russell Brenner90bac252010-11-18 13:33:46 -0800191 // Verify, that JS global object of env2 has '..2' properties.
Iain Merrick75681382010-08-19 15:07:18 +0100192 const v8::HeapGraphNode* a2_node =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
Iain Merrick75681382010-08-19 15:07:18 +0100194 CHECK_NE(NULL, a2_node);
195 CHECK_NE(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1"));
Iain Merrick75681382010-08-19 15:07:18 +0100197 CHECK_NE(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2"));
199 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2"));
Iain Merrick75681382010-08-19 15:07:18 +0100200
Iain Merrick75681382010-08-19 15:07:18 +0100201 NamedEntriesDetector det;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100202 det.CheckAllReachables(const_cast<i::HeapEntry*>(
203 reinterpret_cast<const i::HeapEntry*>(global_env2)));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100204 CHECK(det.has_A2);
205 CHECK(det.has_B2);
206 CHECK(det.has_C2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100207}
208
209
Iain Merrick75681382010-08-19 15:07:18 +0100210TEST(HeapSnapshotObjectSizes) {
Iain Merrick75681382010-08-19 15:07:18 +0100211 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 v8::HandleScope scope(env->GetIsolate());
213 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Iain Merrick75681382010-08-19 15:07:18 +0100214
215 // -a-> X1 --a
216 // x -b-> X2 <-|
Ben Murdochf87a2032010-10-22 12:50:53 +0100217 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100218 "function X(a, b) { this.a = a; this.b = b; }\n"
219 "x = new X(new X(), new X());\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 "dummy = new X();\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800221 "(function() { x.a.a = x.b; })();");
Iain Merrick75681382010-08-19 15:07:18 +0100222 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 heap_profiler->TakeHeapSnapshot(v8_str("sizes"));
224 CHECK(ValidateSnapshot(snapshot));
Iain Merrick75681382010-08-19 15:07:18 +0100225 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
226 const v8::HeapGraphNode* x =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 GetProperty(global, v8::HeapGraphEdge::kProperty, "x");
Iain Merrick75681382010-08-19 15:07:18 +0100228 CHECK_NE(NULL, x);
Iain Merrick75681382010-08-19 15:07:18 +0100229 const v8::HeapGraphNode* x1 =
230 GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
231 CHECK_NE(NULL, x1);
232 const v8::HeapGraphNode* x2 =
233 GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
234 CHECK_NE(NULL, x2);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800235
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100236 // Test sizes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 CHECK_NE(0, static_cast<int>(x->GetShallowSize()));
238 CHECK_NE(0, static_cast<int>(x1->GetShallowSize()));
239 CHECK_NE(0, static_cast<int>(x2->GetShallowSize()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100240}
241
242
243TEST(BoundFunctionInSnapshot) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100244 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 v8::HandleScope scope(env->GetIsolate());
246 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100247 CompileRun(
248 "function myFunction(a, b) { this.a = a; this.b = b; }\n"
249 "function AAAAA() {}\n"
250 "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
251 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 heap_profiler->TakeHeapSnapshot(v8_str("sizes"));
253 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100254 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
255 const v8::HeapGraphNode* f =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000256 GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100257 CHECK(f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258 CHECK_EQ(v8::String::NewFromUtf8(env->GetIsolate(), "native_bind"),
259 f->GetName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100260 const v8::HeapGraphNode* bindings =
261 GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
262 CHECK_NE(NULL, bindings);
263 CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
264 CHECK_EQ(4, bindings->GetChildrenCount());
265
266 const v8::HeapGraphNode* bound_this = GetProperty(
267 f, v8::HeapGraphEdge::kShortcut, "bound_this");
268 CHECK(bound_this);
269 CHECK_EQ(v8::HeapGraphNode::kObject, bound_this->GetType());
270
271 const v8::HeapGraphNode* bound_function = GetProperty(
272 f, v8::HeapGraphEdge::kShortcut, "bound_function");
273 CHECK(bound_function);
274 CHECK_EQ(v8::HeapGraphNode::kClosure, bound_function->GetType());
275
276 const v8::HeapGraphNode* bound_argument = GetProperty(
277 f, v8::HeapGraphEdge::kShortcut, "bound_argument_1");
278 CHECK(bound_argument);
279 CHECK_EQ(v8::HeapGraphNode::kObject, bound_argument->GetType());
Iain Merrick75681382010-08-19 15:07:18 +0100280}
281
282
283TEST(HeapSnapshotEntryChildren) {
Iain Merrick75681382010-08-19 15:07:18 +0100284 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 v8::HandleScope scope(env->GetIsolate());
286 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Iain Merrick75681382010-08-19 15:07:18 +0100287
Ben Murdochf87a2032010-10-22 12:50:53 +0100288 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100289 "function A() { }\n"
290 "a = new A;");
291 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 heap_profiler->TakeHeapSnapshot(v8_str("children"));
293 CHECK(ValidateSnapshot(snapshot));
Iain Merrick75681382010-08-19 15:07:18 +0100294 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
295 for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
296 const v8::HeapGraphEdge* prop = global->GetChild(i);
297 CHECK_EQ(global, prop->GetFromNode());
298 }
299 const v8::HeapGraphNode* a =
300 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
301 CHECK_NE(NULL, a);
302 for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
303 const v8::HeapGraphEdge* prop = a->GetChild(i);
304 CHECK_EQ(a, prop->GetFromNode());
305 }
306}
307
308
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100309TEST(HeapSnapshotCodeObjects) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100310 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 v8::HandleScope scope(env->GetIsolate());
312 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100313
Ben Murdochf87a2032010-10-22 12:50:53 +0100314 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100315 "function lazy(x) { return x - 1; }\n"
316 "function compiled(x) { return x + 1; }\n"
Steve Block791712a2010-08-27 10:21:07 +0100317 "var anonymous = (function() { return function() { return 0; } })();\n"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100318 "compiled(1)");
319 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 heap_profiler->TakeHeapSnapshot(v8_str("code"));
321 CHECK(ValidateSnapshot(snapshot));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100322
323 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
324 const v8::HeapGraphNode* compiled =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100326 CHECK_NE(NULL, compiled);
Iain Merrick75681382010-08-19 15:07:18 +0100327 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100328 const v8::HeapGraphNode* lazy =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100330 CHECK_NE(NULL, lazy);
Iain Merrick75681382010-08-19 15:07:18 +0100331 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
Steve Block791712a2010-08-27 10:21:07 +0100332 const v8::HeapGraphNode* anonymous =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333 GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous");
Steve Block791712a2010-08-27 10:21:07 +0100334 CHECK_NE(NULL, anonymous);
335 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336 v8::String::Utf8Value anonymous_name(anonymous->GetName());
Ben Murdochf87a2032010-10-22 12:50:53 +0100337 CHECK_EQ("", *anonymous_name);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100338
339 // Find references to code.
340 const v8::HeapGraphNode* compiled_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100341 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100342 CHECK_NE(NULL, compiled_code);
343 const v8::HeapGraphNode* lazy_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100344 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100345 CHECK_NE(NULL, lazy_code);
346
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000347 // Check that there's no strong next_code_link. There might be a weak one
348 // but might be not, so we can't check that fact.
349 const v8::HeapGraphNode* code =
350 GetProperty(compiled_code, v8::HeapGraphEdge::kInternal, "code");
351 CHECK_NE(NULL, code);
352 const v8::HeapGraphNode* next_code_link =
353 GetProperty(code, v8::HeapGraphEdge::kInternal, "code");
354 CHECK_EQ(NULL, next_code_link);
355
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100356 // Verify that non-compiled code doesn't contain references to "x"
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100357 // literal, while compiled code does. The scope info is stored in FixedArray
358 // objects attached to the SharedFunctionInfo.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100359 bool compiled_references_x = false, lazy_references_x = false;
360 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
361 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
362 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100363 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100364 if (HasString(node, "x")) {
365 compiled_references_x = true;
366 break;
367 }
368 }
369 }
370 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
371 const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
372 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100373 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100374 if (HasString(node, "x")) {
375 lazy_references_x = true;
376 break;
377 }
378 }
379 }
380 CHECK(compiled_references_x);
381 CHECK(!lazy_references_x);
382}
383
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100384
Ben Murdochf87a2032010-10-22 12:50:53 +0100385TEST(HeapSnapshotHeapNumbers) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100386 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 v8::HandleScope scope(env->GetIsolate());
388 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdochf87a2032010-10-22 12:50:53 +0100389 CompileRun(
390 "a = 1; // a is Smi\n"
391 "b = 2.5; // b is HeapNumber");
392 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000393 heap_profiler->TakeHeapSnapshot(v8_str("numbers"));
394 CHECK(ValidateSnapshot(snapshot));
Ben Murdochf87a2032010-10-22 12:50:53 +0100395 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000396 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100397 const v8::HeapGraphNode* b =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000398 GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
Ben Murdochf87a2032010-10-22 12:50:53 +0100399 CHECK_NE(NULL, b);
400 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
401}
402
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000403
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100404TEST(HeapSnapshotSlicedString) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100405 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406 v8::HandleScope scope(env->GetIsolate());
407 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100408 CompileRun(
409 "parent_string = \"123456789.123456789.123456789.123456789.123456789."
410 "123456789.123456789.123456789.123456789.123456789."
411 "123456789.123456789.123456789.123456789.123456789."
412 "123456789.123456789.123456789.123456789.123456789.\";"
413 "child_string = parent_string.slice(100);");
414 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 heap_profiler->TakeHeapSnapshot(v8_str("strings"));
416 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100417 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
418 const v8::HeapGraphNode* parent_string =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419 GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100420 CHECK_NE(NULL, parent_string);
421 const v8::HeapGraphNode* child_string =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100423 CHECK_NE(NULL, child_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000424 CHECK_EQ(v8::HeapGraphNode::kSlicedString, child_string->GetType());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100425 const v8::HeapGraphNode* parent =
426 GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
427 CHECK_EQ(parent_string, parent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428 heap_profiler->DeleteAllHeapSnapshots();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100429}
Ben Murdochf87a2032010-10-22 12:50:53 +0100430
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431
432TEST(HeapSnapshotConsString) {
433 v8::Isolate* isolate = CcTest::isolate();
434 v8::HandleScope scope(isolate);
435 v8::Local<v8::ObjectTemplate> global_template =
436 v8::ObjectTemplate::New(isolate);
437 global_template->SetInternalFieldCount(1);
438 LocalContext env(NULL, global_template);
439 v8::Handle<v8::Object> global_proxy = env->Global();
440 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
441 CHECK_EQ(1, global->InternalFieldCount());
442
443 i::Factory* factory = CcTest::i_isolate()->factory();
444 i::Handle<i::String> first = factory->NewStringFromStaticChars("0123456789");
445 i::Handle<i::String> second = factory->NewStringFromStaticChars("0123456789");
446 i::Handle<i::String> cons_string =
447 factory->NewConsString(first, second).ToHandleChecked();
448
449 global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
450
451 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
452 const v8::HeapSnapshot* snapshot =
453 heap_profiler->TakeHeapSnapshot(v8_str("cons_strings"));
454 CHECK(ValidateSnapshot(snapshot));
455 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
456
457 const v8::HeapGraphNode* string_node =
458 GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0");
459 CHECK_NE(NULL, string_node);
460 CHECK_EQ(v8::HeapGraphNode::kConsString, string_node->GetType());
461
462 const v8::HeapGraphNode* first_node =
463 GetProperty(string_node, v8::HeapGraphEdge::kInternal, "first");
464 CHECK_EQ(v8::HeapGraphNode::kString, first_node->GetType());
465
466 const v8::HeapGraphNode* second_node =
467 GetProperty(string_node, v8::HeapGraphEdge::kInternal, "second");
468 CHECK_EQ(v8::HeapGraphNode::kString, second_node->GetType());
469
470 heap_profiler->DeleteAllHeapSnapshots();
471}
472
473
474TEST(HeapSnapshotSymbol) {
475 LocalContext env;
476 v8::HandleScope scope(env->GetIsolate());
477 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
478
479 CompileRun("a = Symbol('mySymbol');\n");
480 const v8::HeapSnapshot* snapshot =
481 heap_profiler->TakeHeapSnapshot(v8_str("Symbol"));
482 CHECK(ValidateSnapshot(snapshot));
483 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
484 const v8::HeapGraphNode* a =
485 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
486 CHECK_NE(NULL, a);
487 CHECK_EQ(a->GetType(), v8::HeapGraphNode::kSymbol);
488 CHECK_EQ(v8_str("symbol"), a->GetName());
489 const v8::HeapGraphNode* name =
490 GetProperty(a, v8::HeapGraphEdge::kInternal, "name");
491 CHECK_NE(NULL, name);
492 CHECK_EQ(v8_str("mySymbol"), name->GetName());
493}
494
495
496TEST(HeapSnapshotWeakCollection) {
497 LocalContext env;
498 v8::HandleScope scope(env->GetIsolate());
499 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
500
501 CompileRun(
502 "k = {}; v = {}; s = 'str';\n"
503 "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n"
504 "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n");
505 const v8::HeapSnapshot* snapshot =
506 heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections"));
507 CHECK(ValidateSnapshot(snapshot));
508 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
509 const v8::HeapGraphNode* k =
510 GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
511 CHECK_NE(NULL, k);
512 const v8::HeapGraphNode* v =
513 GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
514 CHECK_NE(NULL, v);
515 const v8::HeapGraphNode* s =
516 GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
517 CHECK_NE(NULL, s);
518
519 const v8::HeapGraphNode* ws =
520 GetProperty(global, v8::HeapGraphEdge::kProperty, "ws");
521 CHECK_NE(NULL, ws);
522 CHECK_EQ(v8::HeapGraphNode::kObject, ws->GetType());
523 CHECK_EQ(v8_str("WeakSet"), ws->GetName());
524
525 const v8::HeapGraphNode* ws_table =
526 GetProperty(ws, v8::HeapGraphEdge::kInternal, "table");
527 CHECK_EQ(v8::HeapGraphNode::kArray, ws_table->GetType());
528 CHECK_GT(ws_table->GetChildrenCount(), 0);
529 int weak_entries = 0;
530 for (int i = 0, count = ws_table->GetChildrenCount(); i < count; ++i) {
531 const v8::HeapGraphEdge* prop = ws_table->GetChild(i);
532 if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue;
533 if (k->GetId() == prop->GetToNode()->GetId()) {
534 ++weak_entries;
535 }
536 }
537 CHECK_EQ(1, weak_entries);
538 const v8::HeapGraphNode* ws_s =
539 GetProperty(ws, v8::HeapGraphEdge::kProperty, "str");
540 CHECK_NE(NULL, ws_s);
541 CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(ws_s->GetId()));
542
543 const v8::HeapGraphNode* wm =
544 GetProperty(global, v8::HeapGraphEdge::kProperty, "wm");
545 CHECK_NE(NULL, wm);
546 CHECK_EQ(v8::HeapGraphNode::kObject, wm->GetType());
547 CHECK_EQ(v8_str("WeakMap"), wm->GetName());
548
549 const v8::HeapGraphNode* wm_table =
550 GetProperty(wm, v8::HeapGraphEdge::kInternal, "table");
551 CHECK_EQ(v8::HeapGraphNode::kArray, wm_table->GetType());
552 CHECK_GT(wm_table->GetChildrenCount(), 0);
553 weak_entries = 0;
554 for (int i = 0, count = wm_table->GetChildrenCount(); i < count; ++i) {
555 const v8::HeapGraphEdge* prop = wm_table->GetChild(i);
556 if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue;
557 const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
558 if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
559 ++weak_entries;
560 }
561 }
562 CHECK_EQ(2, weak_entries);
563 const v8::HeapGraphNode* wm_s =
564 GetProperty(wm, v8::HeapGraphEdge::kProperty, "str");
565 CHECK_NE(NULL, wm_s);
566 CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(wm_s->GetId()));
567}
568
569
570TEST(HeapSnapshotCollection) {
571 LocalContext env;
572 v8::HandleScope scope(env->GetIsolate());
573 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
574
575 CompileRun(
576 "k = {}; v = {}; s = 'str';\n"
577 "set = new Set(); set.add(k); set.add(v); set[s] = s;\n"
578 "map = new Map(); map.set(k, v); map[s] = s;\n");
579 const v8::HeapSnapshot* snapshot =
580 heap_profiler->TakeHeapSnapshot(v8_str("Collections"));
581 CHECK(ValidateSnapshot(snapshot));
582 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
583 const v8::HeapGraphNode* k =
584 GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
585 CHECK_NE(NULL, k);
586 const v8::HeapGraphNode* v =
587 GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
588 CHECK_NE(NULL, v);
589 const v8::HeapGraphNode* s =
590 GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
591 CHECK_NE(NULL, s);
592
593 const v8::HeapGraphNode* set =
594 GetProperty(global, v8::HeapGraphEdge::kProperty, "set");
595 CHECK_NE(NULL, set);
596 CHECK_EQ(v8::HeapGraphNode::kObject, set->GetType());
597 CHECK_EQ(v8_str("Set"), set->GetName());
598
599 const v8::HeapGraphNode* set_table =
600 GetProperty(set, v8::HeapGraphEdge::kInternal, "table");
601 CHECK_EQ(v8::HeapGraphNode::kArray, set_table->GetType());
602 CHECK_GT(set_table->GetChildrenCount(), 0);
603 int entries = 0;
604 for (int i = 0, count = set_table->GetChildrenCount(); i < count; ++i) {
605 const v8::HeapGraphEdge* prop = set_table->GetChild(i);
606 const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
607 if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
608 ++entries;
609 }
610 }
611 CHECK_EQ(2, entries);
612 const v8::HeapGraphNode* set_s =
613 GetProperty(set, v8::HeapGraphEdge::kProperty, "str");
614 CHECK_NE(NULL, set_s);
615 CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(set_s->GetId()));
616
617 const v8::HeapGraphNode* map =
618 GetProperty(global, v8::HeapGraphEdge::kProperty, "map");
619 CHECK_NE(NULL, map);
620 CHECK_EQ(v8::HeapGraphNode::kObject, map->GetType());
621 CHECK_EQ(v8_str("Map"), map->GetName());
622
623 const v8::HeapGraphNode* map_table =
624 GetProperty(map, v8::HeapGraphEdge::kInternal, "table");
625 CHECK_EQ(v8::HeapGraphNode::kArray, map_table->GetType());
626 CHECK_GT(map_table->GetChildrenCount(), 0);
627 entries = 0;
628 for (int i = 0, count = map_table->GetChildrenCount(); i < count; ++i) {
629 const v8::HeapGraphEdge* prop = map_table->GetChild(i);
630 const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
631 if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
632 ++entries;
633 }
634 }
635 CHECK_EQ(2, entries);
636 const v8::HeapGraphNode* map_s =
637 GetProperty(map, v8::HeapGraphEdge::kProperty, "str");
638 CHECK_NE(NULL, map_s);
639 CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(map_s->GetId()));
640}
641
642
Ben Murdochf87a2032010-10-22 12:50:53 +0100643TEST(HeapSnapshotInternalReferences) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000644 v8::Isolate* isolate = CcTest::isolate();
645 v8::HandleScope scope(isolate);
646 v8::Local<v8::ObjectTemplate> global_template =
647 v8::ObjectTemplate::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +0100648 global_template->SetInternalFieldCount(2);
649 LocalContext env(NULL, global_template);
650 v8::Handle<v8::Object> global_proxy = env->Global();
651 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
652 CHECK_EQ(2, global->InternalFieldCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000653 v8::Local<v8::Object> obj = v8::Object::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +0100654 global->SetInternalField(0, v8_num(17));
655 global->SetInternalField(1, obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdochf87a2032010-10-22 12:50:53 +0100657 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000658 heap_profiler->TakeHeapSnapshot(v8_str("internals"));
659 CHECK(ValidateSnapshot(snapshot));
Ben Murdochf87a2032010-10-22 12:50:53 +0100660 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
661 // The first reference will not present, because it's a Smi.
662 CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
663 // The second reference is to an object.
664 CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
665}
666
667
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000668// Trying to introduce a check helper for uint32_t causes many
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100669// overloading ambiguities, so it seems easier just to cast
670// them to a signed type.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000671#define CHECK_EQ_SNAPSHOT_OBJECT_ID(a, b) \
672 CHECK_EQ(static_cast<int32_t>(a), static_cast<int32_t>(b))
673#define CHECK_NE_SNAPSHOT_OBJECT_ID(a, b) \
Iain Merrick75681382010-08-19 15:07:18 +0100674 CHECK((a) != (b)) // NOLINT
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100675
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000676TEST(HeapSnapshotAddressReuse) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100677 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000678 v8::HandleScope scope(env->GetIsolate());
679 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
680
681 CompileRun(
682 "function A() {}\n"
683 "var a = [];\n"
684 "for (var i = 0; i < 10000; ++i)\n"
685 " a[i] = new A();\n");
686 const v8::HeapSnapshot* snapshot1 =
687 heap_profiler->TakeHeapSnapshot(v8_str("snapshot1"));
688 CHECK(ValidateSnapshot(snapshot1));
689 v8::SnapshotObjectId maxId1 = snapshot1->GetMaxSnapshotJSObjectId();
690
691 CompileRun(
692 "for (var i = 0; i < 10000; ++i)\n"
693 " a[i] = new A();\n");
694 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
695
696 const v8::HeapSnapshot* snapshot2 =
697 heap_profiler->TakeHeapSnapshot(v8_str("snapshot2"));
698 CHECK(ValidateSnapshot(snapshot2));
699 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
700
701 const v8::HeapGraphNode* array_node =
702 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
703 CHECK_NE(NULL, array_node);
704 int wrong_count = 0;
705 for (int i = 0, count = array_node->GetChildrenCount(); i < count; ++i) {
706 const v8::HeapGraphEdge* prop = array_node->GetChild(i);
707 if (prop->GetType() != v8::HeapGraphEdge::kElement)
708 continue;
709 v8::SnapshotObjectId id = prop->GetToNode()->GetId();
710 if (id < maxId1)
711 ++wrong_count;
712 }
713 CHECK_EQ(0, wrong_count);
714}
715
716
717TEST(HeapEntryIdsAndArrayShift) {
718 LocalContext env;
719 v8::HandleScope scope(env->GetIsolate());
720 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100721
722 CompileRun(
723 "function AnObject() {\n"
724 " this.first = 'first';\n"
725 " this.second = 'second';\n"
726 "}\n"
727 "var a = new Array();\n"
728 "for (var i = 0; i < 10; ++i)\n"
729 " a.push(new AnObject());\n");
730 const v8::HeapSnapshot* snapshot1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000731 heap_profiler->TakeHeapSnapshot(v8_str("s1"));
732 CHECK(ValidateSnapshot(snapshot1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100733
734 CompileRun(
735 "for (var i = 0; i < 1; ++i)\n"
736 " a.shift();\n");
737
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100739
740 const v8::HeapSnapshot* snapshot2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000741 heap_profiler->TakeHeapSnapshot(v8_str("s2"));
742 CHECK(ValidateSnapshot(snapshot2));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100743
744 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
745 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746 CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId());
747 CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100748
749 const v8::HeapGraphNode* a1 =
750 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
751 CHECK_NE(NULL, a1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100752 const v8::HeapGraphNode* k1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000753 GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100754 CHECK_NE(NULL, k1);
755 const v8::HeapGraphNode* a2 =
756 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
757 CHECK_NE(NULL, a2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100758 const v8::HeapGraphNode* k2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100760 CHECK_NE(NULL, k2);
761
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000762 CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
763 CHECK_EQ_SNAPSHOT_OBJECT_ID(k1->GetId(), k2->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100764}
765
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000766
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100767TEST(HeapEntryIdsAndGC) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100768 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000769 v8::HandleScope scope(env->GetIsolate());
770 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100771
Ben Murdochf87a2032010-10-22 12:50:53 +0100772 CompileRun(
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100773 "function A() {}\n"
774 "function B(x) { this.x = x; }\n"
775 "var a = new A();\n"
776 "var b = new B(a);");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 v8::Local<v8::String> s1_str = v8_str("s1");
778 v8::Local<v8::String> s2_str = v8_str("s2");
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100779 const v8::HeapSnapshot* snapshot1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780 heap_profiler->TakeHeapSnapshot(s1_str);
781 CHECK(ValidateSnapshot(snapshot1));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100782
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100784
785 const v8::HeapSnapshot* snapshot2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 heap_profiler->TakeHeapSnapshot(s2_str);
787 CHECK(ValidateSnapshot(snapshot2));
788
789 CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000);
790 CHECK(snapshot1->GetMaxSnapshotJSObjectId() <=
791 snapshot2->GetMaxSnapshotJSObjectId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100792
793 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
794 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000795 CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId());
796 CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100797 const v8::HeapGraphNode* A1 =
Iain Merrick75681382010-08-19 15:07:18 +0100798 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
799 CHECK_NE(NULL, A1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100800 const v8::HeapGraphNode* A2 =
Iain Merrick75681382010-08-19 15:07:18 +0100801 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
802 CHECK_NE(NULL, A2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803 CHECK_NE_SNAPSHOT_OBJECT_ID(0, A1->GetId());
804 CHECK_EQ_SNAPSHOT_OBJECT_ID(A1->GetId(), A2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100805 const v8::HeapGraphNode* B1 =
Iain Merrick75681382010-08-19 15:07:18 +0100806 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
807 CHECK_NE(NULL, B1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100808 const v8::HeapGraphNode* B2 =
Iain Merrick75681382010-08-19 15:07:18 +0100809 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
810 CHECK_NE(NULL, B2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000811 CHECK_NE_SNAPSHOT_OBJECT_ID(0, B1->GetId());
812 CHECK_EQ_SNAPSHOT_OBJECT_ID(B1->GetId(), B2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100813 const v8::HeapGraphNode* a1 =
Iain Merrick75681382010-08-19 15:07:18 +0100814 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
815 CHECK_NE(NULL, a1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100816 const v8::HeapGraphNode* a2 =
Iain Merrick75681382010-08-19 15:07:18 +0100817 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
818 CHECK_NE(NULL, a2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000819 CHECK_NE_SNAPSHOT_OBJECT_ID(0, a1->GetId());
820 CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100821 const v8::HeapGraphNode* b1 =
Iain Merrick75681382010-08-19 15:07:18 +0100822 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
823 CHECK_NE(NULL, b1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100824 const v8::HeapGraphNode* b2 =
Iain Merrick75681382010-08-19 15:07:18 +0100825 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
826 CHECK_NE(NULL, b2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000827 CHECK_NE_SNAPSHOT_OBJECT_ID(0, b1->GetId());
828 CHECK_EQ_SNAPSHOT_OBJECT_ID(b1->GetId(), b2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100829}
830
831
Ben Murdochf87a2032010-10-22 12:50:53 +0100832TEST(HeapSnapshotRootPreservedAfterSorting) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100833 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000834 v8::HandleScope scope(env->GetIsolate());
835 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdochf87a2032010-10-22 12:50:53 +0100836 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 heap_profiler->TakeHeapSnapshot(v8_str("s"));
838 CHECK(ValidateSnapshot(snapshot));
Ben Murdochf87a2032010-10-22 12:50:53 +0100839 const v8::HeapGraphNode* root1 = snapshot->GetRoot();
840 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
841 snapshot))->GetSortedEntriesList();
842 const v8::HeapGraphNode* root2 = snapshot->GetRoot();
843 CHECK_EQ(root1, root2);
844}
845
846
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100847namespace {
848
849class TestJSONStream : public v8::OutputStream {
850 public:
851 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
852 explicit TestJSONStream(int abort_countdown)
853 : eos_signaled_(0), abort_countdown_(abort_countdown) {}
854 virtual ~TestJSONStream() {}
855 virtual void EndOfStream() { ++eos_signaled_; }
856 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
857 if (abort_countdown_ > 0) --abort_countdown_;
858 if (abort_countdown_ == 0) return kAbort;
859 CHECK_GT(chars_written, 0);
860 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861 i::MemCopy(chunk.start(), buffer, chars_written);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100862 return kContinue;
863 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000864 virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
865 DCHECK(false);
866 return kAbort;
867 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100868 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
869 int eos_signaled() { return eos_signaled_; }
870 int size() { return buffer_.size(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100872 private:
873 i::Collector<char> buffer_;
874 int eos_signaled_;
875 int abort_countdown_;
876};
877
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878class OneByteResource : public v8::String::ExternalOneByteStringResource {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100879 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 explicit OneByteResource(i::Vector<char> string) : data_(string.start()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100881 length_ = string.length();
882 }
883 virtual const char* data() const { return data_; }
884 virtual size_t length() const { return length_; }
885 private:
886 const char* data_;
887 size_t length_;
888};
889
890} // namespace
891
892TEST(HeapSnapshotJSONSerialization) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400893 v8::Isolate* isolate = CcTest::isolate();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100894 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400895 v8::HandleScope scope(isolate);
896 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100897
898#define STRING_LITERAL_FOR_TEST \
899 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
Ben Murdochf87a2032010-10-22 12:50:53 +0100900 CompileRun(
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100901 "function A(s) { this.s = s; }\n"
902 "function B(x) { this.x = x; }\n"
903 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
904 "var b = new B(a);");
905 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 heap_profiler->TakeHeapSnapshot(v8_str("json"));
907 CHECK(ValidateSnapshot(snapshot));
908
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100909 TestJSONStream stream;
910 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
911 CHECK_GT(stream.size(), 0);
912 CHECK_EQ(1, stream.eos_signaled());
913 i::ScopedVector<char> json(stream.size());
914 stream.WriteTo(json);
915
916 // Verify that snapshot string is valid JSON.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000917 OneByteResource* json_res = new OneByteResource(json);
918 v8::Local<v8::String> json_string =
919 v8::String::NewExternal(env->GetIsolate(), json_res);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000920 env->Global()->Set(v8_str("json_snapshot"), json_string);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100921 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
922 "var parsed = JSON.parse(json_snapshot); true;");
923 CHECK(!snapshot_parse_result.IsEmpty());
924
925 // Verify that snapshot object has required fields.
926 v8::Local<v8::Object> parsed_snapshot =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400927 env->Global()->Get(v8_str("parsed"))->ToObject(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000928 CHECK(parsed_snapshot->Has(v8_str("snapshot")));
929 CHECK(parsed_snapshot->Has(v8_str("nodes")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000930 CHECK(parsed_snapshot->Has(v8_str("edges")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000931 CHECK(parsed_snapshot->Has(v8_str("strings")));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100932
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100933 // Get node and edge "member" offsets.
934 v8::Local<v8::Value> meta_analysis_result = CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935 "var meta = parsed.snapshot.meta;\n"
936 "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n"
937 "var node_fields_count = meta.node_fields.length;\n"
938 "var edge_fields_count = meta.edge_fields.length;\n"
939 "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
940 "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n"
941 "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100942 "var property_type ="
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943 " meta.edge_types[edge_type_offset].indexOf('property');\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800944 "var shortcut_type ="
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000945 " meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
946 "var node_count = parsed.nodes.length / node_fields_count;\n"
947 "var first_edge_indexes = parsed.first_edge_indexes = [];\n"
948 "for (var i = 0, first_edge_index = 0; i < node_count; ++i) {\n"
949 " first_edge_indexes[i] = first_edge_index;\n"
950 " first_edge_index += edge_fields_count *\n"
951 " parsed.nodes[i * node_fields_count + edge_count_offset];\n"
952 "}\n"
953 "first_edge_indexes[node_count] = first_edge_index;\n");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100954 CHECK(!meta_analysis_result.IsEmpty());
955
956 // A helper function for processing encoded nodes.
957 CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800958 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100959 " var nodes = parsed.nodes;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000960 " var edges = parsed.edges;\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100961 " var strings = parsed.strings;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962 " var node_ordinal = pos / node_fields_count;\n"
963 " for (var i = parsed.first_edge_indexes[node_ordinal],\n"
964 " count = parsed.first_edge_indexes[node_ordinal + 1];\n"
965 " i < count; i += edge_fields_count) {\n"
966 " if (edges[i + edge_type_offset] === prop_type\n"
967 " && strings[edges[i + edge_name_offset]] === prop_name)\n"
968 " return edges[i + edge_to_node_offset];\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100969 " }\n"
970 " return null;\n"
971 "}\n");
972 // Get the string index using the path: <root> -> <global>.b.x.s
973 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
974 "GetChildPosByProperty(\n"
975 " GetChildPosByProperty(\n"
976 " GetChildPosByProperty("
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000977 " parsed.edges[edge_fields_count + edge_to_node_offset],"
978 " \"b\", property_type),\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800979 " \"x\", property_type),"
980 " \"s\", property_type)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100981 CHECK(!string_obj_pos_val.IsEmpty());
982 int string_obj_pos =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400983 static_cast<int>(string_obj_pos_val->ToNumber(isolate)->Value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100984 v8::Local<v8::Object> nodes_array =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400985 parsed_snapshot->Get(v8_str("nodes"))->ToObject(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100986 int string_index = static_cast<int>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400987 nodes_array->Get(string_obj_pos + 1)->ToNumber(isolate)->Value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100988 CHECK_GT(string_index, 0);
989 v8::Local<v8::Object> strings_array =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400990 parsed_snapshot->Get(v8_str("strings"))->ToObject(isolate);
991 v8::Local<v8::String> string =
992 strings_array->Get(string_index)->ToString(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100993 v8::Local<v8::String> ref_string =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400994 CompileRun(STRING_LITERAL_FOR_TEST)->ToString(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100995#undef STRING_LITERAL_FOR_TEST
996 CHECK_EQ(*v8::String::Utf8Value(ref_string),
997 *v8::String::Utf8Value(string));
998}
999
1000
1001TEST(HeapSnapshotJSONSerializationAborting) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001002 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001003 v8::HandleScope scope(env->GetIsolate());
1004 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001005 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006 heap_profiler->TakeHeapSnapshot(v8_str("abort"));
1007 CHECK(ValidateSnapshot(snapshot));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001008 TestJSONStream stream(5);
1009 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1010 CHECK_GT(stream.size(), 0);
1011 CHECK_EQ(0, stream.eos_signaled());
1012}
1013
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014namespace {
1015
1016class TestStatsStream : public v8::OutputStream {
1017 public:
1018 TestStatsStream()
1019 : eos_signaled_(0),
1020 updates_written_(0),
1021 entries_count_(0),
1022 entries_size_(0),
1023 intervals_count_(0),
1024 first_interval_index_(-1) { }
1025 TestStatsStream(const TestStatsStream& stream)
1026 : v8::OutputStream(stream),
1027 eos_signaled_(stream.eos_signaled_),
1028 updates_written_(stream.updates_written_),
1029 entries_count_(stream.entries_count_),
1030 entries_size_(stream.entries_size_),
1031 intervals_count_(stream.intervals_count_),
1032 first_interval_index_(stream.first_interval_index_) { }
1033 virtual ~TestStatsStream() {}
1034 virtual void EndOfStream() { ++eos_signaled_; }
1035 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
1036 DCHECK(false);
1037 return kAbort;
1038 }
1039 virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
1040 int updates_written) {
1041 ++intervals_count_;
1042 DCHECK(updates_written);
1043 updates_written_ += updates_written;
1044 entries_count_ = 0;
1045 if (first_interval_index_ == -1 && updates_written != 0)
1046 first_interval_index_ = buffer[0].index;
1047 for (int i = 0; i < updates_written; ++i) {
1048 entries_count_ += buffer[i].count;
1049 entries_size_ += buffer[i].size;
1050 }
1051
1052 return kContinue;
1053 }
1054 int eos_signaled() { return eos_signaled_; }
1055 int updates_written() { return updates_written_; }
1056 uint32_t entries_count() const { return entries_count_; }
1057 uint32_t entries_size() const { return entries_size_; }
1058 int intervals_count() const { return intervals_count_; }
1059 int first_interval_index() const { return first_interval_index_; }
1060
1061 private:
1062 int eos_signaled_;
1063 int updates_written_;
1064 uint32_t entries_count_;
1065 uint32_t entries_size_;
1066 int intervals_count_;
1067 int first_interval_index_;
1068};
1069
1070} // namespace
1071
1072static TestStatsStream GetHeapStatsUpdate(
1073 v8::HeapProfiler* heap_profiler,
1074 v8::SnapshotObjectId* object_id = NULL) {
1075 TestStatsStream stream;
1076 v8::SnapshotObjectId last_seen_id = heap_profiler->GetHeapStats(&stream);
1077 if (object_id)
1078 *object_id = last_seen_id;
1079 CHECK_EQ(1, stream.eos_signaled());
1080 return stream;
1081}
1082
1083
1084TEST(HeapSnapshotObjectsStats) {
1085 LocalContext env;
1086 v8::HandleScope scope(env->GetIsolate());
1087 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1088
1089 heap_profiler->StartTrackingHeapObjects();
1090 // We have to call GC 6 times. In other case the garbage will be
1091 // the reason of flakiness.
1092 for (int i = 0; i < 6; ++i) {
1093 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
1094 }
1095
1096 v8::SnapshotObjectId initial_id;
1097 {
1098 // Single chunk of data expected in update. Initial data.
1099 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
1100 &initial_id);
1101 CHECK_EQ(1, stats_update.intervals_count());
1102 CHECK_EQ(1, stats_update.updates_written());
1103 CHECK_LT(0, stats_update.entries_size());
1104 CHECK_EQ(0, stats_update.first_interval_index());
1105 }
1106
1107 // No data expected in update because nothing has happened.
1108 v8::SnapshotObjectId same_id;
1109 CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &same_id).updates_written());
1110 CHECK_EQ_SNAPSHOT_OBJECT_ID(initial_id, same_id);
1111
1112 {
1113 v8::SnapshotObjectId additional_string_id;
1114 v8::HandleScope inner_scope_1(env->GetIsolate());
1115 v8_str("string1");
1116 {
1117 // Single chunk of data with one new entry expected in update.
1118 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
1119 &additional_string_id);
1120 CHECK_LT(same_id, additional_string_id);
1121 CHECK_EQ(1, stats_update.intervals_count());
1122 CHECK_EQ(1, stats_update.updates_written());
1123 CHECK_LT(0, stats_update.entries_size());
1124 CHECK_EQ(1, stats_update.entries_count());
1125 CHECK_EQ(2, stats_update.first_interval_index());
1126 }
1127
1128 // No data expected in update because nothing happened.
1129 v8::SnapshotObjectId last_id;
1130 CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &last_id).updates_written());
1131 CHECK_EQ_SNAPSHOT_OBJECT_ID(additional_string_id, last_id);
1132
1133 {
1134 v8::HandleScope inner_scope_2(env->GetIsolate());
1135 v8_str("string2");
1136
1137 uint32_t entries_size;
1138 {
1139 v8::HandleScope inner_scope_3(env->GetIsolate());
1140 v8_str("string3");
1141 v8_str("string4");
1142
1143 {
1144 // Single chunk of data with three new entries expected in update.
1145 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1146 CHECK_EQ(1, stats_update.intervals_count());
1147 CHECK_EQ(1, stats_update.updates_written());
1148 CHECK_LT(0, entries_size = stats_update.entries_size());
1149 CHECK_EQ(3, stats_update.entries_count());
1150 CHECK_EQ(4, stats_update.first_interval_index());
1151 }
1152 }
1153
1154 {
1155 // Single chunk of data with two left entries expected in update.
1156 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1157 CHECK_EQ(1, stats_update.intervals_count());
1158 CHECK_EQ(1, stats_update.updates_written());
1159 CHECK_GT(entries_size, stats_update.entries_size());
1160 CHECK_EQ(1, stats_update.entries_count());
1161 // Two strings from forth interval were released.
1162 CHECK_EQ(4, stats_update.first_interval_index());
1163 }
1164 }
1165
1166 {
1167 // Single chunk of data with 0 left entries expected in update.
1168 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1169 CHECK_EQ(1, stats_update.intervals_count());
1170 CHECK_EQ(1, stats_update.updates_written());
1171 CHECK_EQ(0, stats_update.entries_size());
1172 CHECK_EQ(0, stats_update.entries_count());
1173 // The last string from forth interval was released.
1174 CHECK_EQ(4, stats_update.first_interval_index());
1175 }
1176 }
1177 {
1178 // Single chunk of data with 0 left entries expected in update.
1179 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1180 CHECK_EQ(1, stats_update.intervals_count());
1181 CHECK_EQ(1, stats_update.updates_written());
1182 CHECK_EQ(0, stats_update.entries_size());
1183 CHECK_EQ(0, stats_update.entries_count());
1184 // The only string from the second interval was released.
1185 CHECK_EQ(2, stats_update.first_interval_index());
1186 }
1187
1188 v8::Local<v8::Array> array = v8::Array::New(env->GetIsolate());
1189 CHECK_EQ(0, array->Length());
1190 // Force array's buffer allocation.
1191 array->Set(2, v8_num(7));
1192
1193 uint32_t entries_size;
1194 {
1195 // Single chunk of data with 2 entries expected in update.
1196 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1197 CHECK_EQ(1, stats_update.intervals_count());
1198 CHECK_EQ(1, stats_update.updates_written());
1199 CHECK_LT(0, entries_size = stats_update.entries_size());
1200 // They are the array and its buffer.
1201 CHECK_EQ(2, stats_update.entries_count());
1202 CHECK_EQ(8, stats_update.first_interval_index());
1203 }
1204
1205 for (int i = 0; i < 100; ++i)
1206 array->Set(i, v8_num(i));
1207
1208 {
1209 // Single chunk of data with 1 entry expected in update.
1210 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1211 CHECK_EQ(1, stats_update.intervals_count());
1212 // The first interval was changed because old buffer was collected.
1213 // The second interval was changed because new buffer was allocated.
1214 CHECK_EQ(2, stats_update.updates_written());
1215 CHECK_LT(entries_size, stats_update.entries_size());
1216 CHECK_EQ(2, stats_update.entries_count());
1217 CHECK_EQ(8, stats_update.first_interval_index());
1218 }
1219
1220 heap_profiler->StopTrackingHeapObjects();
1221}
1222
1223
1224TEST(HeapObjectIds) {
1225 LocalContext env;
1226 v8::Isolate* isolate = env->GetIsolate();
1227 v8::HandleScope scope(isolate);
1228 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1229
1230 const int kLength = 10;
1231 v8::Handle<v8::Object> objects[kLength];
1232 v8::SnapshotObjectId ids[kLength];
1233
1234 heap_profiler->StartTrackingHeapObjects(false);
1235
1236 for (int i = 0; i < kLength; i++) {
1237 objects[i] = v8::Object::New(isolate);
1238 }
1239 GetHeapStatsUpdate(heap_profiler);
1240
1241 for (int i = 0; i < kLength; i++) {
1242 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1243 CHECK_NE(v8::HeapProfiler::kUnknownObjectId, static_cast<int>(id));
1244 ids[i] = id;
1245 }
1246
1247 heap_profiler->StopTrackingHeapObjects();
1248 CcTest::heap()->CollectAllAvailableGarbage();
1249
1250 for (int i = 0; i < kLength; i++) {
1251 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1252 CHECK_EQ(static_cast<int>(ids[i]), static_cast<int>(id));
1253 v8::Handle<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1254 CHECK_EQ(objects[i], obj);
1255 }
1256
1257 heap_profiler->ClearObjectIds();
1258 for (int i = 0; i < kLength; i++) {
1259 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1260 CHECK_EQ(v8::HeapProfiler::kUnknownObjectId, static_cast<int>(id));
1261 v8::Handle<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1262 CHECK(obj.IsEmpty());
1263 }
1264}
1265
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001266
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001267static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
1268 const v8::HeapGraphNode* node,
1269 int level, int max_level) {
1270 if (level > max_level) return;
1271 CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
1272 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
1273 const v8::HeapGraphEdge* prop = node->GetChild(i);
1274 const v8::HeapGraphNode* child =
1275 snapshot->GetNodeById(prop->GetToNode()->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276 CHECK_EQ_SNAPSHOT_OBJECT_ID(prop->GetToNode()->GetId(), child->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001277 CHECK_EQ(prop->GetToNode(), child);
1278 CheckChildrenIds(snapshot, child, level + 1, max_level);
1279 }
1280}
1281
1282
Ben Murdochb0fe1622011-05-05 13:52:32 +01001283TEST(HeapSnapshotGetNodeById) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001284 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001285 v8::HandleScope scope(env->GetIsolate());
1286 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001287
1288 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001289 heap_profiler->TakeHeapSnapshot(v8_str("id"));
1290 CHECK(ValidateSnapshot(snapshot));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001291 const v8::HeapGraphNode* root = snapshot->GetRoot();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001292 CheckChildrenIds(snapshot, root, 0, 3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001293 // Check a big id, which should not exist yet.
1294 CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
1295}
1296
1297
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001298TEST(HeapSnapshotGetSnapshotObjectId) {
1299 LocalContext env;
1300 v8::HandleScope scope(env->GetIsolate());
1301 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1302 CompileRun("globalObject = {};\n");
1303 const v8::HeapSnapshot* snapshot =
1304 heap_profiler->TakeHeapSnapshot(v8_str("get_snapshot_object_id"));
1305 CHECK(ValidateSnapshot(snapshot));
1306 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1307 const v8::HeapGraphNode* global_object =
1308 GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject");
1309 CHECK(global_object);
1310
1311 v8::Local<v8::Value> globalObjectHandle = env->Global()->Get(
1312 v8::String::NewFromUtf8(env->GetIsolate(), "globalObject"));
1313 CHECK(!globalObjectHandle.IsEmpty());
1314 CHECK(globalObjectHandle->IsObject());
1315
1316 v8::SnapshotObjectId id = heap_profiler->GetObjectId(globalObjectHandle);
1317 CHECK_NE(static_cast<int>(v8::HeapProfiler::kUnknownObjectId),
1318 id);
1319 CHECK_EQ(static_cast<int>(id), global_object->GetId());
1320}
1321
1322
1323TEST(HeapSnapshotUnknownSnapshotObjectId) {
1324 LocalContext env;
1325 v8::HandleScope scope(env->GetIsolate());
1326 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1327 CompileRun("globalObject = {};\n");
1328 const v8::HeapSnapshot* snapshot =
1329 heap_profiler->TakeHeapSnapshot(v8_str("unknown_object_id"));
1330 CHECK(ValidateSnapshot(snapshot));
1331 const v8::HeapGraphNode* node =
1332 snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId);
1333 CHECK_EQ(NULL, node);
1334}
1335
1336
Ben Murdochb0fe1622011-05-05 13:52:32 +01001337namespace {
1338
1339class TestActivityControl : public v8::ActivityControl {
1340 public:
1341 explicit TestActivityControl(int abort_count)
1342 : done_(0), total_(0), abort_count_(abort_count) {}
1343 ControlOption ReportProgressValue(int done, int total) {
1344 done_ = done;
1345 total_ = total;
1346 return --abort_count_ != 0 ? kContinue : kAbort;
1347 }
1348 int done() { return done_; }
1349 int total() { return total_; }
1350
1351 private:
1352 int done_;
1353 int total_;
1354 int abort_count_;
1355};
1356}
1357
Ben Murdochb0fe1622011-05-05 13:52:32 +01001358
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001359TEST(TakeHeapSnapshotAborting) {
1360 LocalContext env;
1361 v8::HandleScope scope(env->GetIsolate());
1362
1363 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1364 const int snapshots_count = heap_profiler->GetSnapshotCount();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001365 TestActivityControl aborting_control(1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001366 const v8::HeapSnapshot* no_snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001367 heap_profiler->TakeHeapSnapshot(v8_str("abort"),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001368 &aborting_control);
1369 CHECK_EQ(NULL, no_snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001371 CHECK_GT(aborting_control.total(), aborting_control.done());
1372
1373 TestActivityControl control(-1); // Don't abort.
1374 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001375 heap_profiler->TakeHeapSnapshot(v8_str("full"),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001376 &control);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377 CHECK(ValidateSnapshot(snapshot));
1378
Ben Murdochb0fe1622011-05-05 13:52:32 +01001379 CHECK_NE(NULL, snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380 CHECK_EQ(snapshots_count + 1, heap_profiler->GetSnapshotCount());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001381 CHECK_EQ(control.total(), control.done());
1382 CHECK_GT(control.total(), 0);
1383}
1384
Steve Block44f0eee2011-05-26 01:26:41 +01001385
1386namespace {
1387
1388class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
1389 public:
1390 TestRetainedObjectInfo(int hash,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001391 const char* group_label,
Steve Block44f0eee2011-05-26 01:26:41 +01001392 const char* label,
1393 intptr_t element_count = -1,
1394 intptr_t size = -1)
1395 : disposed_(false),
1396 hash_(hash),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001397 group_label_(group_label),
Steve Block44f0eee2011-05-26 01:26:41 +01001398 label_(label),
1399 element_count_(element_count),
1400 size_(size) {
1401 instances.Add(this);
1402 }
1403 virtual ~TestRetainedObjectInfo() {}
1404 virtual void Dispose() {
1405 CHECK(!disposed_);
1406 disposed_ = true;
1407 }
1408 virtual bool IsEquivalent(RetainedObjectInfo* other) {
1409 return GetHash() == other->GetHash();
1410 }
1411 virtual intptr_t GetHash() { return hash_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001412 virtual const char* GetGroupLabel() { return group_label_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001413 virtual const char* GetLabel() { return label_; }
1414 virtual intptr_t GetElementCount() { return element_count_; }
1415 virtual intptr_t GetSizeInBytes() { return size_; }
1416 bool disposed() { return disposed_; }
1417
1418 static v8::RetainedObjectInfo* WrapperInfoCallback(
1419 uint16_t class_id, v8::Handle<v8::Value> wrapper) {
1420 if (class_id == 1) {
1421 if (wrapper->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422 v8::String::Utf8Value utf8(wrapper);
1423 if (strcmp(*utf8, "AAA") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001424 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425 else if (strcmp(*utf8, "BBB") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001426 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
Steve Block44f0eee2011-05-26 01:26:41 +01001427 }
1428 } else if (class_id == 2) {
1429 if (wrapper->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430 v8::String::Utf8Value utf8(wrapper);
1431 if (strcmp(*utf8, "CCC") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001432 return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
Steve Block44f0eee2011-05-26 01:26:41 +01001433 }
1434 }
1435 CHECK(false);
1436 return NULL;
1437 }
1438
1439 static i::List<TestRetainedObjectInfo*> instances;
1440
1441 private:
1442 bool disposed_;
Steve Block44f0eee2011-05-26 01:26:41 +01001443 int hash_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001444 const char* group_label_;
Steve Block44f0eee2011-05-26 01:26:41 +01001445 const char* label_;
1446 intptr_t element_count_;
1447 intptr_t size_;
1448};
1449
1450
1451i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
1452}
1453
1454
1455static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1456 v8::HeapGraphNode::Type type,
1457 const char* name) {
1458 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1459 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1460 if (node->GetType() == type && strcmp(name,
1461 const_cast<i::HeapEntry*>(
1462 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1463 return node;
1464 }
1465 }
1466 return NULL;
1467}
1468
1469
1470TEST(HeapSnapshotRetainedObjectInfo) {
Steve Block44f0eee2011-05-26 01:26:41 +01001471 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472 v8::Isolate* isolate = env->GetIsolate();
1473 v8::HandleScope scope(isolate);
1474 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001475
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 heap_profiler->SetWrapperClassInfoProvider(
Steve Block44f0eee2011-05-26 01:26:41 +01001477 1, TestRetainedObjectInfo::WrapperInfoCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 heap_profiler->SetWrapperClassInfoProvider(
Steve Block44f0eee2011-05-26 01:26:41 +01001479 2, TestRetainedObjectInfo::WrapperInfoCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 v8::Persistent<v8::String> p_AAA(isolate, v8_str("AAA"));
Steve Block44f0eee2011-05-26 01:26:41 +01001481 p_AAA.SetWrapperClassId(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001482 v8::Persistent<v8::String> p_BBB(isolate, v8_str("BBB"));
Steve Block44f0eee2011-05-26 01:26:41 +01001483 p_BBB.SetWrapperClassId(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 v8::Persistent<v8::String> p_CCC(isolate, v8_str("CCC"));
Steve Block44f0eee2011-05-26 01:26:41 +01001485 p_CCC.SetWrapperClassId(2);
1486 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
1487 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488 heap_profiler->TakeHeapSnapshot(v8_str("retained"));
1489 CHECK(ValidateSnapshot(snapshot));
Steve Block44f0eee2011-05-26 01:26:41 +01001490
1491 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1492 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1493 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1494 delete TestRetainedObjectInfo::instances[i];
1495 }
1496
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001497 const v8::HeapGraphNode* native_group_aaa = GetNode(
1498 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "aaa-group");
1499 CHECK_NE(NULL, native_group_aaa);
1500 CHECK_EQ(1, native_group_aaa->GetChildrenCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001501 const v8::HeapGraphNode* aaa = GetNode(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001502 native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
Steve Block44f0eee2011-05-26 01:26:41 +01001503 CHECK_NE(NULL, aaa);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001504 CHECK_EQ(2, aaa->GetChildrenCount());
1505
1506 const v8::HeapGraphNode* native_group_ccc = GetNode(
1507 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "ccc-group");
Steve Block44f0eee2011-05-26 01:26:41 +01001508 const v8::HeapGraphNode* ccc = GetNode(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001509 native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
Steve Block44f0eee2011-05-26 01:26:41 +01001510 CHECK_NE(NULL, ccc);
1511
Steve Block44f0eee2011-05-26 01:26:41 +01001512 const v8::HeapGraphNode* n_AAA = GetNode(
1513 aaa, v8::HeapGraphNode::kString, "AAA");
1514 CHECK_NE(NULL, n_AAA);
1515 const v8::HeapGraphNode* n_BBB = GetNode(
1516 aaa, v8::HeapGraphNode::kString, "BBB");
1517 CHECK_NE(NULL, n_BBB);
1518 CHECK_EQ(1, ccc->GetChildrenCount());
1519 const v8::HeapGraphNode* n_CCC = GetNode(
1520 ccc, v8::HeapGraphNode::kString, "CCC");
1521 CHECK_NE(NULL, n_CCC);
1522
Ben Murdoch8b112d22011-06-08 16:22:53 +01001523 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1524 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1525 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
Steve Block44f0eee2011-05-26 01:26:41 +01001526}
1527
1528
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001529class GraphWithImplicitRefs {
1530 public:
1531 static const int kObjectsCount = 4;
1532 explicit GraphWithImplicitRefs(LocalContext* env) {
1533 CHECK_EQ(NULL, instance_);
1534 instance_ = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001535 isolate_ = (*env)->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001536 for (int i = 0; i < kObjectsCount; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 objects_[i].Reset(isolate_, v8::Object::New(isolate_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001538 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001539 (*env)->Global()->Set(v8_str("root_object"),
1540 v8::Local<v8::Value>::New(isolate_, objects_[0]));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001541 }
1542 ~GraphWithImplicitRefs() {
1543 instance_ = NULL;
1544 }
1545
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001546 static void gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001547 instance_->AddImplicitReferences();
1548 }
1549
1550 private:
1551 void AddImplicitReferences() {
1552 // 0 -> 1
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001553 isolate_->SetObjectGroupId(objects_[0],
1554 v8::UniqueId(1));
1555 isolate_->SetReferenceFromGroup(
1556 v8::UniqueId(1), objects_[1]);
1557 // Adding two more references: 1 -> 2, 1 -> 3
1558 isolate_->SetReference(objects_[1].As<v8::Object>(),
1559 objects_[2]);
1560 isolate_->SetReference(objects_[1].As<v8::Object>(),
1561 objects_[3]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001562 }
1563
1564 v8::Persistent<v8::Value> objects_[kObjectsCount];
1565 static GraphWithImplicitRefs* instance_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001566 v8::Isolate* isolate_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001567};
1568
1569GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
1570
1571
1572TEST(HeapSnapshotImplicitReferences) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001573 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001574 v8::HandleScope scope(env->GetIsolate());
1575 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001576
1577 GraphWithImplicitRefs graph(&env);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001578 v8::V8::AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001579
1580 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 heap_profiler->TakeHeapSnapshot(v8_str("implicit_refs"));
1582 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001583
1584 const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001585 const v8::HeapGraphNode* obj0 = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001586 global_object, v8::HeapGraphEdge::kProperty, "root_object");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001587 CHECK(obj0);
1588 CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
1589 const v8::HeapGraphNode* obj1 = GetProperty(
1590 obj0, v8::HeapGraphEdge::kInternal, "native");
1591 CHECK(obj1);
1592 int implicit_targets_count = 0;
1593 for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
1594 const v8::HeapGraphEdge* prop = obj1->GetChild(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001595 v8::String::Utf8Value prop_name(prop->GetName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001596 if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
1597 strcmp("native", *prop_name) == 0) {
1598 ++implicit_targets_count;
1599 }
1600 }
1601 CHECK_EQ(2, implicit_targets_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001602 v8::V8::RemoveGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001603}
1604
1605
Steve Block44f0eee2011-05-26 01:26:41 +01001606TEST(DeleteAllHeapSnapshots) {
Steve Block44f0eee2011-05-26 01:26:41 +01001607 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001608 v8::HandleScope scope(env->GetIsolate());
1609 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001610
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001611 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1612 heap_profiler->DeleteAllHeapSnapshots();
1613 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1614 CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1")));
1615 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1616 heap_profiler->DeleteAllHeapSnapshots();
1617 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1618 CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1")));
1619 CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("2")));
1620 CHECK_EQ(2, heap_profiler->GetSnapshotCount());
1621 heap_profiler->DeleteAllHeapSnapshots();
1622 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1623}
1624
1625
1626static const v8::HeapSnapshot* FindHeapSnapshot(v8::HeapProfiler* profiler,
1627 unsigned uid) {
1628 int length = profiler->GetSnapshotCount();
1629 for (int i = 0; i < length; i++) {
1630 const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i);
1631 if (snapshot->GetUid() == uid) {
1632 return snapshot;
1633 }
1634 }
1635 return NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001636}
1637
1638
1639TEST(DeleteHeapSnapshot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001640 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001641 v8::HandleScope scope(env->GetIsolate());
1642 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001643
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001644 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001645 const v8::HeapSnapshot* s1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001646 heap_profiler->TakeHeapSnapshot(v8_str("1"));
1647
Steve Block44f0eee2011-05-26 01:26:41 +01001648 CHECK_NE(NULL, s1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001650 unsigned uid1 = s1->GetUid();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001651 CHECK_EQ(s1, FindHeapSnapshot(heap_profiler, uid1));
Steve Block44f0eee2011-05-26 01:26:41 +01001652 const_cast<v8::HeapSnapshot*>(s1)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1654 CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid1));
Steve Block44f0eee2011-05-26 01:26:41 +01001655
1656 const v8::HeapSnapshot* s2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001657 heap_profiler->TakeHeapSnapshot(v8_str("2"));
Steve Block44f0eee2011-05-26 01:26:41 +01001658 CHECK_NE(NULL, s2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001659 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001660 unsigned uid2 = s2->GetUid();
1661 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 CHECK_EQ(s2, FindHeapSnapshot(heap_profiler, uid2));
Steve Block44f0eee2011-05-26 01:26:41 +01001663 const v8::HeapSnapshot* s3 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 heap_profiler->TakeHeapSnapshot(v8_str("3"));
Steve Block44f0eee2011-05-26 01:26:41 +01001665 CHECK_NE(NULL, s3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 CHECK_EQ(2, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001667 unsigned uid3 = s3->GetUid();
1668 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001669 CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
Steve Block44f0eee2011-05-26 01:26:41 +01001670 const_cast<v8::HeapSnapshot*>(s2)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1672 CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid2));
1673 CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
Steve Block44f0eee2011-05-26 01:26:41 +01001674 const_cast<v8::HeapSnapshot*>(s3)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1676 CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid3));
Steve Block44f0eee2011-05-26 01:26:41 +01001677}
1678
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001679
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680class NameResolver : public v8::HeapProfiler::ObjectNameResolver {
1681 public:
1682 virtual const char* GetName(v8::Handle<v8::Object> object) {
1683 return "Global object name";
1684 }
1685};
1686
1687
1688TEST(GlobalObjectName) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001689 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001690 v8::HandleScope scope(env->GetIsolate());
1691 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001692
1693 CompileRun("document = { URL:\"abcdefgh\" };");
1694
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 NameResolver name_resolver;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001696 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001697 heap_profiler->TakeHeapSnapshot(v8_str("document"),
1698 NULL,
1699 &name_resolver);
1700 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001701 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1702 CHECK_NE(NULL, global);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001703 CHECK_EQ("Object / Global object name" ,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001704 const_cast<i::HeapEntry*>(
1705 reinterpret_cast<const i::HeapEntry*>(global))->name());
1706}
1707
1708
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001709TEST(GlobalObjectFields) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001710 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001711 v8::HandleScope scope(env->GetIsolate());
1712 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1713 CompileRun("obj = {};");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001714 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001715 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1716 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001717 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001718 const v8::HeapGraphNode* builtins =
1719 GetProperty(global, v8::HeapGraphEdge::kInternal, "builtins");
1720 CHECK_NE(NULL, builtins);
1721 const v8::HeapGraphNode* native_context =
1722 GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
1723 CHECK_NE(NULL, native_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001724 const v8::HeapGraphNode* global_proxy =
1725 GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
1726 CHECK_NE(NULL, global_proxy);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001727}
1728
1729
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001730TEST(NoHandleLeaks) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001731 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001732 v8::HandleScope scope(env->GetIsolate());
1733 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001734
1735 CompileRun("document = { URL:\"abcdefgh\" };");
1736
1737 v8::Handle<v8::String> name(v8_str("leakz"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001738 i::Isolate* isolate = CcTest::i_isolate();
1739 int count_before = i::HandleScope::NumberOfHandles(isolate);
1740 heap_profiler->TakeHeapSnapshot(name);
1741 int count_after = i::HandleScope::NumberOfHandles(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001742 CHECK_EQ(count_before, count_after);
1743}
1744
1745
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001746TEST(NodesIteration) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001747 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001748 v8::HandleScope scope(env->GetIsolate());
1749 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001750 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001751 heap_profiler->TakeHeapSnapshot(v8_str("iteration"));
1752 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001753 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1754 CHECK_NE(NULL, global);
1755 // Verify that we can find this object by iteration.
1756 const int nodes_count = snapshot->GetNodesCount();
1757 int count = 0;
1758 for (int i = 0; i < nodes_count; ++i) {
1759 if (snapshot->GetNode(i) == global)
1760 ++count;
1761 }
1762 CHECK_EQ(1, count);
1763}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001764
1765
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766TEST(GetHeapValueForNode) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001767 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001768 v8::HandleScope scope(env->GetIsolate());
1769 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001772 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 heap_profiler->TakeHeapSnapshot(v8_str("value"));
1774 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001775 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001776 CHECK(heap_profiler->FindObjectById(global->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001777 v8::Local<v8::Object> js_global =
1778 env->Global()->GetPrototype().As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001779 CHECK(js_global == heap_profiler->FindObjectById(global->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001780 const v8::HeapGraphNode* obj = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001781 global, v8::HeapGraphEdge::kProperty, "a");
1782 CHECK(heap_profiler->FindObjectById(obj->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001783 v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001784 CHECK(js_obj == heap_profiler->FindObjectById(obj->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001785 const v8::HeapGraphNode* s_prop =
1786 GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
1787 v8::Local<v8::String> js_s_prop =
1788 js_obj->Get(v8_str("s_prop")).As<v8::String>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001789 CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001790 const v8::HeapGraphNode* n_prop =
1791 GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001792 v8::Local<v8::String> js_n_prop =
1793 js_obj->Get(v8_str("n_prop")).As<v8::String>();
1794 CHECK(js_n_prop == heap_profiler->FindObjectById(n_prop->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001795}
1796
1797
1798TEST(GetHeapValueForDeletedObject) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001799 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001800 v8::HandleScope scope(env->GetIsolate());
1801 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001802
1803 // It is impossible to delete a global property, so we are about to delete a
1804 // property of the "a" object. Also, the "p" object can't be an empty one
1805 // because the empty object is static and isn't actually deleted.
1806 CompileRun("a = { p: { r: {} } };");
1807 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001808 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1809 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001810 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1811 const v8::HeapGraphNode* obj = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001812 global, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001813 const v8::HeapGraphNode* prop = GetProperty(
1814 obj, v8::HeapGraphEdge::kProperty, "p");
1815 {
1816 // Perform the check inside a nested local scope to avoid creating a
1817 // reference to the object we are deleting.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001818 v8::HandleScope scope(env->GetIsolate());
1819 CHECK(heap_profiler->FindObjectById(prop->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001820 }
1821 CompileRun("delete a.p;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001822 CHECK(heap_profiler->FindObjectById(prop->GetId()).IsEmpty());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001823}
1824
1825
1826static int StringCmp(const char* ref, i::String* act) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001827 i::SmartArrayPointer<char> s_act = act->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001828 int result = strcmp(ref, s_act.get());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001829 if (result != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001830 fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, s_act.get());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001831 return result;
1832}
1833
1834
1835TEST(GetConstructorName) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001836 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001837 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001838
1839 CompileRun(
1840 "function Constructor1() {};\n"
1841 "var obj1 = new Constructor1();\n"
1842 "var Constructor2 = function() {};\n"
1843 "var obj2 = new Constructor2();\n"
1844 "var obj3 = {};\n"
1845 "obj3.constructor = function Constructor3() {};\n"
1846 "var obj4 = {};\n"
1847 "// Slow properties\n"
1848 "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
1849 "obj4.constructor = function Constructor4() {};\n"
1850 "var obj5 = {};\n"
1851 "var obj6 = {};\n"
1852 "obj6.constructor = 6;");
1853 v8::Local<v8::Object> js_global =
1854 env->Global()->GetPrototype().As<v8::Object>();
1855 v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
1856 i::Handle<i::JSObject> js_obj1 = v8::Utils::OpenHandle(*obj1);
1857 CHECK_EQ(0, StringCmp(
1858 "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
1859 v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
1860 i::Handle<i::JSObject> js_obj2 = v8::Utils::OpenHandle(*obj2);
1861 CHECK_EQ(0, StringCmp(
1862 "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
1863 v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
1864 i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001865 // TODO(verwaest): Restore to Constructor3 once supported by the
1866 // heap-snapshot-generator.
1867 CHECK_EQ(
1868 0, StringCmp("Object", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001869 v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
1870 i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001871 // TODO(verwaest): Restore to Constructor4 once supported by the
1872 // heap-snapshot-generator.
1873 CHECK_EQ(
1874 0, StringCmp("Object", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001875 v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
1876 i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
1877 CHECK_EQ(0, StringCmp(
1878 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
1879 v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
1880 i::Handle<i::JSObject> js_obj6 = v8::Utils::OpenHandle(*obj6);
1881 CHECK_EQ(0, StringCmp(
1882 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1883}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001884
1885
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001886TEST(FastCaseAccessors) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001887 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001888 v8::HandleScope scope(env->GetIsolate());
1889 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001890
1891 CompileRun("var obj1 = {};\n"
1892 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1893 " return 42;\n"
1894 "});\n"
1895 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1896 " return this.value_ = value;\n"
1897 "});\n");
1898 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001899 heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
1900 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001901
1902 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1903 CHECK_NE(NULL, global);
1904 const v8::HeapGraphNode* obj1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001905 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001906 CHECK_NE(NULL, obj1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907 const v8::HeapGraphNode* func;
1908 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
1909 CHECK_NE(NULL, func);
1910 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
1911 CHECK_EQ(NULL, func);
1912 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
1913 CHECK_NE(NULL, func);
1914 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
1915 CHECK_EQ(NULL, func);
1916}
1917
1918
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001919TEST(FastCaseRedefinedAccessors) {
1920 LocalContext env;
1921 v8::HandleScope scope(env->GetIsolate());
1922 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1923
1924 CompileRun(
1925 "var obj1 = {};\n"
1926 "Object.defineProperty(obj1, 'prop', { "
1927 " get: function() { return 42; },\n"
1928 " set: function(value) { return this.prop_ = value; },\n"
1929 " configurable: true,\n"
1930 " enumerable: true,\n"
1931 "});\n"
1932 "Object.defineProperty(obj1, 'prop', { "
1933 " get: function() { return 153; },\n"
1934 " set: function(value) { return this.prop_ = value; },\n"
1935 " configurable: true,\n"
1936 " enumerable: true,\n"
1937 "});\n");
1938 v8::Local<v8::Object> js_global =
1939 env->Global()->GetPrototype().As<v8::Object>();
1940 i::Handle<i::JSObject> js_obj1 =
1941 v8::Utils::OpenHandle(*js_global->Get(v8_str("obj1")).As<v8::Object>());
1942 USE(js_obj1);
1943
1944 const v8::HeapSnapshot* snapshot =
1945 heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
1946 CHECK(ValidateSnapshot(snapshot));
1947 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1948 CHECK_NE(NULL, global);
1949 const v8::HeapGraphNode* obj1 =
1950 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
1951 CHECK_NE(NULL, obj1);
1952 const v8::HeapGraphNode* func;
1953 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get prop");
1954 CHECK_NE(NULL, func);
1955 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set prop");
1956 CHECK_NE(NULL, func);
1957}
1958
1959
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001960TEST(SlowCaseAccessors) {
1961 LocalContext env;
1962 v8::HandleScope scope(env->GetIsolate());
1963 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1964
1965 CompileRun("var obj1 = {};\n"
1966 "for (var i = 0; i < 100; ++i) obj1['z' + i] = {};"
1967 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1968 " return 42;\n"
1969 "});\n"
1970 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1971 " return this.value_ = value;\n"
1972 "});\n");
1973 const v8::HeapSnapshot* snapshot =
1974 heap_profiler->TakeHeapSnapshot(v8_str("slowCaseAccessors"));
1975 CHECK(ValidateSnapshot(snapshot));
1976
1977 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1978 CHECK_NE(NULL, global);
1979 const v8::HeapGraphNode* obj1 =
1980 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
1981 CHECK_NE(NULL, obj1);
1982 const v8::HeapGraphNode* func;
1983 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
1984 CHECK_NE(NULL, func);
1985 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
1986 CHECK_EQ(NULL, func);
1987 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
1988 CHECK_NE(NULL, func);
1989 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
1990 CHECK_EQ(NULL, func);
1991}
1992
1993
1994TEST(HiddenPropertiesFastCase) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001995 v8::Isolate* isolate = CcTest::isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001996 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001997 v8::HandleScope scope(isolate);
1998 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001999
2000 CompileRun(
2001 "function C(x) { this.a = this; this.b = x; }\n"
2002 "c = new C(2012);\n");
2003 const v8::HeapSnapshot* snapshot =
2004 heap_profiler->TakeHeapSnapshot(v8_str("HiddenPropertiesFastCase1"));
2005 CHECK(ValidateSnapshot(snapshot));
2006 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2007 const v8::HeapGraphNode* c =
2008 GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
2009 CHECK_NE(NULL, c);
2010 const v8::HeapGraphNode* hidden_props =
2011 GetProperty(c, v8::HeapGraphEdge::kInternal, "hidden_properties");
2012 CHECK_EQ(NULL, hidden_props);
2013
2014 v8::Handle<v8::Value> cHandle =
2015 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"));
2016 CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002017 cHandle->ToObject(isolate)->SetHiddenValue(v8_str("key"), v8_str("val"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002018
2019 snapshot = heap_profiler->TakeHeapSnapshot(
2020 v8_str("HiddenPropertiesFastCase2"));
2021 CHECK(ValidateSnapshot(snapshot));
2022 global = GetGlobalObject(snapshot);
2023 c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
2024 CHECK_NE(NULL, c);
2025 hidden_props = GetProperty(c, v8::HeapGraphEdge::kInternal,
2026 "hidden_properties");
2027 CHECK_NE(NULL, hidden_props);
2028}
2029
2030
2031TEST(AccessorInfo) {
2032 LocalContext env;
2033 v8::HandleScope scope(env->GetIsolate());
2034 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2035
2036 CompileRun("function foo(x) { }\n");
2037 const v8::HeapSnapshot* snapshot =
2038 heap_profiler->TakeHeapSnapshot(v8_str("AccessorInfoTest"));
2039 CHECK(ValidateSnapshot(snapshot));
2040 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2041 const v8::HeapGraphNode* foo =
2042 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2043 CHECK_NE(NULL, foo);
2044 const v8::HeapGraphNode* map =
2045 GetProperty(foo, v8::HeapGraphEdge::kInternal, "map");
2046 CHECK_NE(NULL, map);
2047 const v8::HeapGraphNode* descriptors =
2048 GetProperty(map, v8::HeapGraphEdge::kInternal, "descriptors");
2049 CHECK_NE(NULL, descriptors);
2050 const v8::HeapGraphNode* length_name =
2051 GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "2");
2052 CHECK_NE(NULL, length_name);
2053 CHECK_EQ("length", *v8::String::Utf8Value(length_name->GetName()));
2054 const v8::HeapGraphNode* length_accessor =
2055 GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "4");
2056 CHECK_NE(NULL, length_accessor);
2057 CHECK_EQ("system / ExecutableAccessorInfo",
2058 *v8::String::Utf8Value(length_accessor->GetName()));
2059 const v8::HeapGraphNode* name =
2060 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "name");
2061 CHECK_NE(NULL, name);
2062 const v8::HeapGraphNode* getter =
2063 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "getter");
2064 CHECK_NE(NULL, getter);
2065 const v8::HeapGraphNode* setter =
2066 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "setter");
2067 CHECK_NE(NULL, setter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002068}
2069
2070
2071bool HasWeakEdge(const v8::HeapGraphNode* node) {
2072 for (int i = 0; i < node->GetChildrenCount(); ++i) {
2073 const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
2074 if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
2075 }
2076 return false;
2077}
2078
2079
2080bool HasWeakGlobalHandle() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002081 v8::Isolate* isolate = CcTest::isolate();
2082 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002083 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002084 heap_profiler->TakeHeapSnapshot(v8_str("weaks"));
2085 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002086 const v8::HeapGraphNode* gc_roots = GetNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002087 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002088 CHECK_NE(NULL, gc_roots);
2089 const v8::HeapGraphNode* global_handles = GetNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002090 gc_roots, v8::HeapGraphNode::kSynthetic, "(Global handles)");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002091 CHECK_NE(NULL, global_handles);
2092 return HasWeakEdge(global_handles);
2093}
2094
2095
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002096static void PersistentHandleCallback(
2097 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
2098 data.GetParameter()->Reset();
2099 delete data.GetParameter();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002100}
2101
2102
2103TEST(WeakGlobalHandle) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002104 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002105 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002106
2107 CHECK(!HasWeakGlobalHandle());
2108
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002109 v8::Persistent<v8::Object> handle(env->GetIsolate(),
2110 v8::Object::New(env->GetIsolate()));
2111 handle.SetWeak(&handle, PersistentHandleCallback);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002112
2113 CHECK(HasWeakGlobalHandle());
2114}
2115
2116
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002117TEST(SfiAndJsFunctionWeakRefs) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002118 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002119 v8::HandleScope scope(env->GetIsolate());
2120 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002121
2122 CompileRun(
2123 "fun = (function (x) { return function () { return x + 1; } })(1);");
2124 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002125 heap_profiler->TakeHeapSnapshot(v8_str("fun"));
2126 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002127 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2128 CHECK_NE(NULL, global);
2129 const v8::HeapGraphNode* fun =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002130 GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
2131 CHECK(!HasWeakEdge(fun));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002132 const v8::HeapGraphNode* shared =
2133 GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002134 CHECK(!HasWeakEdge(shared));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002135}
2136
2137
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002138TEST(NoDebugObjectInSnapshot) {
2139 LocalContext env;
2140 v8::HandleScope scope(env->GetIsolate());
2141 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2142
2143 CHECK(CcTest::i_isolate()->debug()->Load());
2144 CompileRun("foo = {};");
2145 const v8::HeapSnapshot* snapshot =
2146 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2147 CHECK(ValidateSnapshot(snapshot));
2148 const v8::HeapGraphNode* root = snapshot->GetRoot();
2149 int globals_count = 0;
2150 for (int i = 0; i < root->GetChildrenCount(); ++i) {
2151 const v8::HeapGraphEdge* edge = root->GetChild(i);
2152 if (edge->GetType() == v8::HeapGraphEdge::kShortcut) {
2153 ++globals_count;
2154 const v8::HeapGraphNode* global = edge->GetToNode();
2155 const v8::HeapGraphNode* foo =
2156 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2157 CHECK_NE(NULL, foo);
2158 }
2159 }
2160 CHECK_EQ(1, globals_count);
2161}
2162
2163
2164TEST(AllStrongGcRootsHaveNames) {
2165 LocalContext env;
2166 v8::HandleScope scope(env->GetIsolate());
2167 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2168
2169 CompileRun("foo = {};");
2170 const v8::HeapSnapshot* snapshot =
2171 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2172 CHECK(ValidateSnapshot(snapshot));
2173 const v8::HeapGraphNode* gc_roots = GetNode(
2174 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
2175 CHECK_NE(NULL, gc_roots);
2176 const v8::HeapGraphNode* strong_roots = GetNode(
2177 gc_roots, v8::HeapGraphNode::kSynthetic, "(Strong roots)");
2178 CHECK_NE(NULL, strong_roots);
2179 for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) {
2180 const v8::HeapGraphEdge* edge = strong_roots->GetChild(i);
2181 CHECK_EQ(v8::HeapGraphEdge::kInternal, edge->GetType());
2182 v8::String::Utf8Value name(edge->GetName());
2183 CHECK(isalpha(**name));
2184 }
2185}
2186
2187
2188TEST(NoRefsToNonEssentialEntries) {
2189 LocalContext env;
2190 v8::HandleScope scope(env->GetIsolate());
2191 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2192 CompileRun("global_object = {};\n");
2193 const v8::HeapSnapshot* snapshot =
2194 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2195 CHECK(ValidateSnapshot(snapshot));
2196 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2197 const v8::HeapGraphNode* global_object =
2198 GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object");
2199 CHECK_NE(NULL, global_object);
2200 const v8::HeapGraphNode* properties =
2201 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties");
2202 CHECK_EQ(NULL, properties);
2203 const v8::HeapGraphNode* elements =
2204 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements");
2205 CHECK_EQ(NULL, elements);
2206}
2207
2208
2209TEST(MapHasDescriptorsAndTransitions) {
2210 LocalContext env;
2211 v8::HandleScope scope(env->GetIsolate());
2212 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2213 CompileRun("obj = { a: 10 };\n");
2214 const v8::HeapSnapshot* snapshot =
2215 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2216 CHECK(ValidateSnapshot(snapshot));
2217 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2218 const v8::HeapGraphNode* global_object =
2219 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
2220 CHECK_NE(NULL, global_object);
2221
2222 const v8::HeapGraphNode* map =
2223 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "map");
2224 CHECK_NE(NULL, map);
2225 const v8::HeapGraphNode* own_descriptors = GetProperty(
2226 map, v8::HeapGraphEdge::kInternal, "descriptors");
2227 CHECK_NE(NULL, own_descriptors);
2228 const v8::HeapGraphNode* own_transitions = GetProperty(
2229 map, v8::HeapGraphEdge::kInternal, "transitions");
2230 CHECK_EQ(NULL, own_transitions);
2231}
2232
2233
2234TEST(ManyLocalsInSharedContext) {
2235 LocalContext env;
2236 v8::HandleScope scope(env->GetIsolate());
2237 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2238 int num_objects = 6000;
2239 CompileRun(
2240 "var n = 6000;"
2241 "var result = [];"
2242 "result.push('(function outer() {');"
2243 "for (var i = 0; i < n; i++) {"
2244 " var f = 'function f_' + i + '() { ';"
2245 " if (i > 0)"
2246 " f += 'f_' + (i - 1) + '();';"
2247 " f += ' }';"
2248 " result.push(f);"
2249 "}"
2250 "result.push('return f_' + (n - 1) + ';');"
2251 "result.push('})()');"
2252 "var ok = eval(result.join('\\n'));");
2253 const v8::HeapSnapshot* snapshot =
2254 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2255 CHECK(ValidateSnapshot(snapshot));
2256
2257 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2258 CHECK_NE(NULL, global);
2259 const v8::HeapGraphNode* ok_object =
2260 GetProperty(global, v8::HeapGraphEdge::kProperty, "ok");
2261 CHECK_NE(NULL, ok_object);
2262 const v8::HeapGraphNode* context_object =
2263 GetProperty(ok_object, v8::HeapGraphEdge::kInternal, "context");
2264 CHECK_NE(NULL, context_object);
2265 // Check the objects are not duplicated in the context.
2266 CHECK_EQ(v8::internal::Context::MIN_CONTEXT_SLOTS + num_objects - 1,
2267 context_object->GetChildrenCount());
2268 // Check all the objects have got their names.
2269 // ... well check just every 15th because otherwise it's too slow in debug.
2270 for (int i = 0; i < num_objects - 1; i += 15) {
2271 i::EmbeddedVector<char, 100> var_name;
2272 i::SNPrintF(var_name, "f_%d", i);
2273 const v8::HeapGraphNode* f_object = GetProperty(
2274 context_object, v8::HeapGraphEdge::kContextVariable, var_name.start());
2275 CHECK_NE(NULL, f_object);
2276 }
2277}
2278
2279
2280TEST(AllocationSitesAreVisible) {
2281 LocalContext env;
2282 v8::Isolate* isolate = env->GetIsolate();
2283 v8::HandleScope scope(isolate);
2284 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2285 CompileRun(
2286 "fun = function () { var a = [3, 2, 1]; return a; }\n"
2287 "fun();");
2288 const v8::HeapSnapshot* snapshot =
2289 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2290 CHECK(ValidateSnapshot(snapshot));
2291
2292 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2293 CHECK_NE(NULL, global);
2294 const v8::HeapGraphNode* fun_code =
2295 GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
2296 CHECK_NE(NULL, fun_code);
2297 const v8::HeapGraphNode* literals =
2298 GetProperty(fun_code, v8::HeapGraphEdge::kInternal, "literals");
2299 CHECK_NE(NULL, literals);
2300 CHECK_EQ(v8::HeapGraphNode::kArray, literals->GetType());
2301 CHECK_EQ(2, literals->GetChildrenCount());
2302
2303 // The second value in the literals array should be the boilerplate,
2304 // after an AllocationSite.
2305 const v8::HeapGraphEdge* prop = literals->GetChild(1);
2306 const v8::HeapGraphNode* allocation_site = prop->GetToNode();
2307 v8::String::Utf8Value name(allocation_site->GetName());
2308 CHECK_EQ("system / AllocationSite", *name);
2309 const v8::HeapGraphNode* transition_info =
2310 GetProperty(allocation_site, v8::HeapGraphEdge::kInternal,
2311 "transition_info");
2312 CHECK_NE(NULL, transition_info);
2313
2314 const v8::HeapGraphNode* elements =
2315 GetProperty(transition_info, v8::HeapGraphEdge::kInternal,
2316 "elements");
2317 CHECK_NE(NULL, elements);
2318 CHECK_EQ(v8::HeapGraphNode::kArray, elements->GetType());
2319 CHECK_EQ(v8::internal::FixedArray::SizeFor(3),
2320 static_cast<int>(elements->GetShallowSize()));
2321
2322 v8::Handle<v8::Value> array_val =
2323 heap_profiler->FindObjectById(transition_info->GetId());
2324 CHECK(array_val->IsArray());
2325 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(array_val);
2326 // Verify the array is "a" in the code above.
2327 CHECK_EQ(3, array->Length());
2328 CHECK_EQ(v8::Integer::New(isolate, 3),
2329 array->Get(v8::Integer::New(isolate, 0)));
2330 CHECK_EQ(v8::Integer::New(isolate, 2),
2331 array->Get(v8::Integer::New(isolate, 1)));
2332 CHECK_EQ(v8::Integer::New(isolate, 1),
2333 array->Get(v8::Integer::New(isolate, 2)));
2334}
2335
2336
2337TEST(JSFunctionHasCodeLink) {
2338 LocalContext env;
2339 v8::HandleScope scope(env->GetIsolate());
2340 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2341 CompileRun("function foo(x, y) { return x + y; }\n");
2342 const v8::HeapSnapshot* snapshot =
2343 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2344 CHECK(ValidateSnapshot(snapshot));
2345 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2346 const v8::HeapGraphNode* foo_func =
2347 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2348 CHECK_NE(NULL, foo_func);
2349 const v8::HeapGraphNode* code =
2350 GetProperty(foo_func, v8::HeapGraphEdge::kInternal, "code");
2351 CHECK_NE(NULL, code);
2352}
2353
2354
2355static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
2356 const char* path[],
2357 int depth) {
2358 const v8::HeapGraphNode* node = snapshot->GetRoot();
2359 for (int current_depth = 0; current_depth < depth; ++current_depth) {
2360 int i, count = node->GetChildrenCount();
2361 for (i = 0; i < count; ++i) {
2362 const v8::HeapGraphEdge* edge = node->GetChild(i);
2363 const v8::HeapGraphNode* to_node = edge->GetToNode();
2364 v8::String::Utf8Value edge_name(edge->GetName());
2365 v8::String::Utf8Value node_name(to_node->GetName());
2366 i::EmbeddedVector<char, 100> name;
2367 i::SNPrintF(name, "%s::%s", *edge_name, *node_name);
2368 if (strstr(name.start(), path[current_depth])) {
2369 node = to_node;
2370 break;
2371 }
2372 }
2373 if (i == count) return NULL;
2374 }
2375 return node;
2376}
2377
2378
2379TEST(CheckCodeNames) {
2380 LocalContext env;
2381 v8::HandleScope scope(env->GetIsolate());
2382 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2383 CompileRun("var a = 1.1;");
2384 const v8::HeapSnapshot* snapshot =
2385 heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames"));
2386 CHECK(ValidateSnapshot(snapshot));
2387
2388 const char* stub_path[] = {
2389 "::(GC roots)",
2390 "::(Strong roots)",
2391 "code_stubs::",
2392 "::(ArraySingleArgumentConstructorStub code)"
2393 };
2394 const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
2395 stub_path, arraysize(stub_path));
2396 CHECK_NE(NULL, node);
2397
2398 const char* builtin_path1[] = {
2399 "::(GC roots)",
2400 "::(Builtins)",
2401 "::(KeyedLoadIC_Generic builtin)"
2402 };
2403 node = GetNodeByPath(snapshot, builtin_path1, arraysize(builtin_path1));
2404 CHECK_NE(NULL, node);
2405
2406 const char* builtin_path2[] = {"::(GC roots)", "::(Builtins)",
2407 "::(CompileLazy builtin)"};
2408 node = GetNodeByPath(snapshot, builtin_path2, arraysize(builtin_path2));
2409 CHECK_NE(NULL, node);
2410 v8::String::Utf8Value node_name(node->GetName());
2411 CHECK_EQ("(CompileLazy builtin)", *node_name);
2412}
2413
2414
2415static const char* record_trace_tree_source =
2416"var topFunctions = [];\n"
2417"var global = this;\n"
2418"function generateFunctions(width, depth) {\n"
2419" var script = [];\n"
2420" for (var i = 0; i < width; i++) {\n"
2421" for (var j = 0; j < depth; j++) {\n"
2422" script.push('function f_' + i + '_' + j + '(x) {\\n');\n"
2423" script.push(' try {\\n');\n"
2424" if (j < depth-2) {\n"
2425" script.push(' return f_' + i + '_' + (j+1) + '(x+1);\\n');\n"
2426" } else if (j == depth - 2) {\n"
2427" script.push(' return new f_' + i + '_' + (depth - 1) + '();\\n');\n"
2428" } else if (j == depth - 1) {\n"
2429" script.push(' this.ts = Date.now();\\n');\n"
2430" }\n"
2431" script.push(' } catch (e) {}\\n');\n"
2432" script.push('}\\n');\n"
2433" \n"
2434" }\n"
2435" }\n"
2436" var script = script.join('');\n"
2437" // throw script;\n"
2438" global.eval(script);\n"
2439" for (var i = 0; i < width; i++) {\n"
2440" topFunctions.push(this['f_' + i + '_0']);\n"
2441" }\n"
2442"}\n"
2443"\n"
2444"var width = 3;\n"
2445"var depth = 3;\n"
2446"generateFunctions(width, depth);\n"
2447"var instances = [];\n"
2448"function start() {\n"
2449" for (var i = 0; i < width; i++) {\n"
2450" instances.push(topFunctions[i](0));\n"
2451" }\n"
2452"}\n"
2453"\n"
2454"for (var i = 0; i < 100; i++) start();\n";
2455
2456
2457static AllocationTraceNode* FindNode(
2458 AllocationTracker* tracker, const Vector<const char*>& names) {
2459 AllocationTraceNode* node = tracker->trace_tree()->root();
2460 for (int i = 0; node != NULL && i < names.length(); i++) {
2461 const char* name = names[i];
2462 Vector<AllocationTraceNode*> children = node->children();
2463 node = NULL;
2464 for (int j = 0; j < children.length(); j++) {
2465 unsigned index = children[j]->function_info_index();
2466 AllocationTracker::FunctionInfo* info =
2467 tracker->function_info_list()[index];
2468 if (info && strcmp(info->name, name) == 0) {
2469 node = children[j];
2470 break;
2471 }
2472 }
2473 }
2474 return node;
2475}
2476
2477
2478TEST(ArrayGrowLeftTrim) {
2479 LocalContext env;
2480 v8::HandleScope scope(env->GetIsolate());
2481 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2482 heap_profiler->StartTrackingHeapObjects(true);
2483
2484 CompileRun(
2485 "var a = [];\n"
2486 "for (var i = 0; i < 5; ++i)\n"
2487 " a[i] = i;\n"
2488 "for (var i = 0; i < 3; ++i)\n"
2489 " a.shift();\n");
2490
2491 const char* names[] = {""};
2492 AllocationTracker* tracker =
2493 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2494 CHECK_NE(NULL, tracker);
2495 // Resolve all function locations.
2496 tracker->PrepareForSerialization();
2497 // Print for better diagnostics in case of failure.
2498 tracker->trace_tree()->Print(tracker);
2499
2500 AllocationTraceNode* node =
2501 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2502 CHECK_NE(NULL, node);
2503 CHECK_GE(node->allocation_count(), 2);
2504 CHECK_GE(node->allocation_size(), 4 * 5);
2505 heap_profiler->StopTrackingHeapObjects();
2506}
2507
2508
2509TEST(TrackHeapAllocations) {
2510 v8::HandleScope scope(v8::Isolate::GetCurrent());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002511 LocalContext env;
2512
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002513 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2514 heap_profiler->StartTrackingHeapObjects(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002515
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002516 CompileRun(record_trace_tree_source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002517
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002518 AllocationTracker* tracker =
2519 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2520 CHECK_NE(NULL, tracker);
2521 // Resolve all function locations.
2522 tracker->PrepareForSerialization();
2523 // Print for better diagnostics in case of failure.
2524 tracker->trace_tree()->Print(tracker);
2525
2526 const char* names[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"};
2527 AllocationTraceNode* node =
2528 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2529 CHECK_NE(NULL, node);
2530 CHECK_GE(node->allocation_count(), 100);
2531 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2532 heap_profiler->StopTrackingHeapObjects();
2533}
2534
2535
2536static const char* inline_heap_allocation_source =
2537"function f_0(x) {\n"
2538" return f_1(x+1);\n"
2539"}\n"
2540"%NeverOptimizeFunction(f_0);\n"
2541"function f_1(x) {\n"
2542" return new f_2(x+1);\n"
2543"}\n"
2544"function f_2(x) {\n"
2545" this.foo = x;\n"
2546"}\n"
2547"var instances = [];\n"
2548"function start() {\n"
2549" instances.push(f_0(0));\n"
2550"}\n"
2551"\n"
2552"for (var i = 0; i < 100; i++) start();\n";
2553
2554
2555TEST(TrackBumpPointerAllocations) {
2556 i::FLAG_allow_natives_syntax = true;
2557 v8::HandleScope scope(v8::Isolate::GetCurrent());
2558 LocalContext env;
2559
2560 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2561 const char* names[] = {"", "start", "f_0", "f_1"};
2562 // First check that normally all allocations are recorded.
2563 {
2564 heap_profiler->StartTrackingHeapObjects(true);
2565
2566 CompileRun(inline_heap_allocation_source);
2567
2568 AllocationTracker* tracker =
2569 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2570 CHECK_NE(NULL, tracker);
2571 // Resolve all function locations.
2572 tracker->PrepareForSerialization();
2573 // Print for better diagnostics in case of failure.
2574 tracker->trace_tree()->Print(tracker);
2575
2576 AllocationTraceNode* node =
2577 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2578 CHECK_NE(NULL, node);
2579 CHECK_GE(node->allocation_count(), 100);
2580 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2581 heap_profiler->StopTrackingHeapObjects();
2582 }
2583
2584 {
2585 heap_profiler->StartTrackingHeapObjects(true);
2586
2587 // Now check that not all allocations are tracked if we manually reenable
2588 // inline allocations.
2589 CHECK(CcTest::heap()->inline_allocation_disabled());
2590 CcTest::heap()->EnableInlineAllocation();
2591
2592 CompileRun(inline_heap_allocation_source);
2593
2594 AllocationTracker* tracker =
2595 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2596 CHECK_NE(NULL, tracker);
2597 // Resolve all function locations.
2598 tracker->PrepareForSerialization();
2599 // Print for better diagnostics in case of failure.
2600 tracker->trace_tree()->Print(tracker);
2601
2602 AllocationTraceNode* node =
2603 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2604 CHECK_NE(NULL, node);
2605 CHECK_LT(node->allocation_count(), 100);
2606
2607 CcTest::heap()->DisableInlineAllocation();
2608 heap_profiler->StopTrackingHeapObjects();
2609 }
2610}
2611
2612
2613TEST(TrackV8ApiAllocation) {
2614 v8::HandleScope scope(v8::Isolate::GetCurrent());
2615 LocalContext env;
2616
2617 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2618 const char* names[] = { "(V8 API)" };
2619 heap_profiler->StartTrackingHeapObjects(true);
2620
2621 v8::Handle<v8::Object> o1 = v8::Object::New(env->GetIsolate());
2622 o1->Clone();
2623
2624 AllocationTracker* tracker =
2625 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2626 CHECK_NE(NULL, tracker);
2627 // Resolve all function locations.
2628 tracker->PrepareForSerialization();
2629 // Print for better diagnostics in case of failure.
2630 tracker->trace_tree()->Print(tracker);
2631
2632 AllocationTraceNode* node =
2633 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2634 CHECK_NE(NULL, node);
2635 CHECK_GE(node->allocation_count(), 2);
2636 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2637 heap_profiler->StopTrackingHeapObjects();
2638}
2639
2640
2641TEST(ArrayBufferAndArrayBufferView) {
2642 LocalContext env;
2643 v8::HandleScope scope(env->GetIsolate());
2644 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2645 CompileRun("arr1 = new Uint32Array(100);\n");
2646 const v8::HeapSnapshot* snapshot =
2647 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2648 CHECK(ValidateSnapshot(snapshot));
2649 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2650 const v8::HeapGraphNode* arr1_obj =
2651 GetProperty(global, v8::HeapGraphEdge::kProperty, "arr1");
2652 CHECK_NE(NULL, arr1_obj);
2653 const v8::HeapGraphNode* arr1_buffer =
2654 GetProperty(arr1_obj, v8::HeapGraphEdge::kInternal, "buffer");
2655 CHECK_NE(NULL, arr1_buffer);
2656 const v8::HeapGraphNode* first_view =
2657 GetProperty(arr1_buffer, v8::HeapGraphEdge::kWeak, "weak_first_view");
2658 CHECK_NE(NULL, first_view);
2659 const v8::HeapGraphNode* backing_store =
2660 GetProperty(arr1_buffer, v8::HeapGraphEdge::kInternal, "backing_store");
2661 CHECK_NE(NULL, backing_store);
2662 CHECK_EQ(400, static_cast<int>(backing_store->GetShallowSize()));
2663}
2664
2665
2666static int GetRetainersCount(const v8::HeapSnapshot* snapshot,
2667 const v8::HeapGraphNode* node) {
2668 int count = 0;
2669 for (int i = 0, l = snapshot->GetNodesCount(); i < l; ++i) {
2670 const v8::HeapGraphNode* parent = snapshot->GetNode(i);
2671 for (int j = 0, l2 = parent->GetChildrenCount(); j < l2; ++j) {
2672 if (parent->GetChild(j)->GetToNode() == node) {
2673 ++count;
2674 }
2675 }
2676 }
2677 return count;
2678}
2679
2680
2681TEST(ArrayBufferSharedBackingStore) {
2682 LocalContext env;
2683 v8::Isolate* isolate = env->GetIsolate();
2684 v8::HandleScope handle_scope(isolate);
2685 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2686
2687 v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2688 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2689 CHECK(!ab->IsExternal());
2690 v8::ArrayBuffer::Contents ab_contents = ab->Externalize();
2691 CHECK(ab->IsExternal());
2692
2693 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2694 void* data = ab_contents.Data();
2695 DCHECK(data != NULL);
2696 v8::Local<v8::ArrayBuffer> ab2 =
2697 v8::ArrayBuffer::New(isolate, data, ab_contents.ByteLength());
2698 CHECK(ab2->IsExternal());
2699 env->Global()->Set(v8_str("ab1"), ab);
2700 env->Global()->Set(v8_str("ab2"), ab2);
2701
2702 v8::Handle<v8::Value> result = CompileRun("ab2.byteLength");
2703 CHECK_EQ(1024, result->Int32Value());
2704
2705 const v8::HeapSnapshot* snapshot =
2706 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2707 CHECK(ValidateSnapshot(snapshot));
2708 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2709 const v8::HeapGraphNode* ab1_node =
2710 GetProperty(global, v8::HeapGraphEdge::kProperty, "ab1");
2711 CHECK_NE(NULL, ab1_node);
2712 const v8::HeapGraphNode* ab1_data =
2713 GetProperty(ab1_node, v8::HeapGraphEdge::kInternal, "backing_store");
2714 CHECK_NE(NULL, ab1_data);
2715 const v8::HeapGraphNode* ab2_node =
2716 GetProperty(global, v8::HeapGraphEdge::kProperty, "ab2");
2717 CHECK_NE(NULL, ab2_node);
2718 const v8::HeapGraphNode* ab2_data =
2719 GetProperty(ab2_node, v8::HeapGraphEdge::kInternal, "backing_store");
2720 CHECK_NE(NULL, ab2_data);
2721 CHECK_EQ(ab1_data, ab2_data);
2722 CHECK_EQ(2, GetRetainersCount(snapshot, ab1_data));
2723 free(data);
2724}
2725
2726
2727TEST(BoxObject) {
2728 v8::Isolate* isolate = CcTest::isolate();
2729 v8::HandleScope scope(isolate);
2730 LocalContext env;
2731 v8::Handle<v8::Object> global_proxy = env->Global();
2732 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2733
2734 i::Factory* factory = CcTest::i_isolate()->factory();
2735 i::Handle<i::String> string = factory->NewStringFromStaticChars("string");
2736 i::Handle<i::Object> box = factory->NewBox(string);
2737 global->Set(0, v8::ToApiHandle<v8::Object>(box));
2738
2739 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2740 const v8::HeapSnapshot* snapshot =
2741 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2742 CHECK(ValidateSnapshot(snapshot));
2743 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
2744 const v8::HeapGraphNode* box_node =
2745 GetProperty(global_node, v8::HeapGraphEdge::kElement, "0");
2746 CHECK_NE(NULL, box_node);
2747 v8::String::Utf8Value box_node_name(box_node->GetName());
2748 CHECK_EQ("system / Box", *box_node_name);
2749 const v8::HeapGraphNode* box_value =
2750 GetProperty(box_node, v8::HeapGraphEdge::kInternal, "value");
2751 CHECK_NE(NULL, box_value);
2752}
2753
2754
2755TEST(WeakContainers) {
2756 i::FLAG_allow_natives_syntax = true;
2757 LocalContext env;
2758 v8::HandleScope scope(env->GetIsolate());
2759 if (!CcTest::i_isolate()->use_crankshaft()) return;
2760 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2761 CompileRun(
2762 "function foo(a) { return a.x; }\n"
2763 "obj = {x : 123};\n"
2764 "foo(obj);\n"
2765 "foo(obj);\n"
2766 "%OptimizeFunctionOnNextCall(foo);\n"
2767 "foo(obj);\n");
2768 const v8::HeapSnapshot* snapshot =
2769 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2770 CHECK(ValidateSnapshot(snapshot));
2771 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2772 const v8::HeapGraphNode* obj =
2773 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
2774 CHECK_NE(NULL, obj);
2775 const v8::HeapGraphNode* map =
2776 GetProperty(obj, v8::HeapGraphEdge::kInternal, "map");
2777 CHECK_NE(NULL, map);
2778 const v8::HeapGraphNode* dependent_code =
2779 GetProperty(map, v8::HeapGraphEdge::kInternal, "dependent_code");
2780 if (!dependent_code) return;
2781 int count = dependent_code->GetChildrenCount();
2782 CHECK_NE(0, count);
2783 for (int i = 0; i < count; ++i) {
2784 const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
2785 CHECK_EQ(v8::HeapGraphEdge::kWeak, prop->GetType());
2786 }
2787}
2788
2789
2790static inline i::Address ToAddress(int n) {
2791 return reinterpret_cast<i::Address>(n);
2792}
2793
2794
2795TEST(AddressToTraceMap) {
2796 i::AddressToTraceMap map;
2797
2798 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(150)));
2799
2800 // [0x100, 0x200) -> 1
2801 map.AddRange(ToAddress(0x100), 0x100, 1U);
2802 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x50)));
2803 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x100)));
2804 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x150)));
2805 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x100 + 0x100)));
2806 CHECK_EQ(1, static_cast<int>(map.size()));
2807
2808 // [0x100, 0x200) -> 1, [0x200, 0x300) -> 2
2809 map.AddRange(ToAddress(0x200), 0x100, 2U);
2810 CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x2a0)));
2811 CHECK_EQ(2, static_cast<int>(map.size()));
2812
2813 // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2
2814 map.AddRange(ToAddress(0x180), 0x100, 3U);
2815 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
2816 CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
2817 CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
2818 CHECK_EQ(3, static_cast<int>(map.size()));
2819
2820 // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2,
2821 // [0x400, 0x500) -> 4
2822 map.AddRange(ToAddress(0x400), 0x100, 4U);
2823 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
2824 CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
2825 CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
2826 CHECK_EQ(4, map.GetTraceNodeId(ToAddress(0x450)));
2827 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x500)));
2828 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x350)));
2829 CHECK_EQ(4, static_cast<int>(map.size()));
2830
2831 // [0x100, 0x180) -> 1, [0x180, 0x200) -> 3, [0x200, 0x600) -> 5
2832 map.AddRange(ToAddress(0x200), 0x400, 5U);
2833 CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
2834 CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x400)));
2835 CHECK_EQ(3, static_cast<int>(map.size()));
2836
2837 // [0x100, 0x180) -> 1, [0x180, 0x200) -> 7, [0x200, 0x600) ->5
2838 map.AddRange(ToAddress(0x180), 0x80, 6U);
2839 map.AddRange(ToAddress(0x180), 0x80, 7U);
2840 CHECK_EQ(7, map.GetTraceNodeId(ToAddress(0x180)));
2841 CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
2842 CHECK_EQ(3, static_cast<int>(map.size()));
2843
2844 map.Clear();
2845 CHECK_EQ(0, static_cast<int>(map.size()));
2846 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x400)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002847}