blob: 8f9b4843912a2fe807bae69188f96bbc9b70e296 [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) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100893 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000894 v8::HandleScope scope(env->GetIsolate());
895 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100896
897#define STRING_LITERAL_FOR_TEST \
898 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
Ben Murdochf87a2032010-10-22 12:50:53 +0100899 CompileRun(
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100900 "function A(s) { this.s = s; }\n"
901 "function B(x) { this.x = x; }\n"
902 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
903 "var b = new B(a);");
904 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000905 heap_profiler->TakeHeapSnapshot(v8_str("json"));
906 CHECK(ValidateSnapshot(snapshot));
907
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100908 TestJSONStream stream;
909 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
910 CHECK_GT(stream.size(), 0);
911 CHECK_EQ(1, stream.eos_signaled());
912 i::ScopedVector<char> json(stream.size());
913 stream.WriteTo(json);
914
915 // Verify that snapshot string is valid JSON.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916 OneByteResource* json_res = new OneByteResource(json);
917 v8::Local<v8::String> json_string =
918 v8::String::NewExternal(env->GetIsolate(), json_res);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000919 env->Global()->Set(v8_str("json_snapshot"), json_string);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100920 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
921 "var parsed = JSON.parse(json_snapshot); true;");
922 CHECK(!snapshot_parse_result.IsEmpty());
923
924 // Verify that snapshot object has required fields.
925 v8::Local<v8::Object> parsed_snapshot =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000926 env->Global()->Get(v8_str("parsed"))->ToObject();
927 CHECK(parsed_snapshot->Has(v8_str("snapshot")));
928 CHECK(parsed_snapshot->Has(v8_str("nodes")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000929 CHECK(parsed_snapshot->Has(v8_str("edges")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000930 CHECK(parsed_snapshot->Has(v8_str("strings")));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100931
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100932 // Get node and edge "member" offsets.
933 v8::Local<v8::Value> meta_analysis_result = CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934 "var meta = parsed.snapshot.meta;\n"
935 "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n"
936 "var node_fields_count = meta.node_fields.length;\n"
937 "var edge_fields_count = meta.edge_fields.length;\n"
938 "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
939 "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n"
940 "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100941 "var property_type ="
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942 " meta.edge_types[edge_type_offset].indexOf('property');\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800943 "var shortcut_type ="
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 " meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
945 "var node_count = parsed.nodes.length / node_fields_count;\n"
946 "var first_edge_indexes = parsed.first_edge_indexes = [];\n"
947 "for (var i = 0, first_edge_index = 0; i < node_count; ++i) {\n"
948 " first_edge_indexes[i] = first_edge_index;\n"
949 " first_edge_index += edge_fields_count *\n"
950 " parsed.nodes[i * node_fields_count + edge_count_offset];\n"
951 "}\n"
952 "first_edge_indexes[node_count] = first_edge_index;\n");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100953 CHECK(!meta_analysis_result.IsEmpty());
954
955 // A helper function for processing encoded nodes.
956 CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800957 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100958 " var nodes = parsed.nodes;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 " var edges = parsed.edges;\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100960 " var strings = parsed.strings;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000961 " var node_ordinal = pos / node_fields_count;\n"
962 " for (var i = parsed.first_edge_indexes[node_ordinal],\n"
963 " count = parsed.first_edge_indexes[node_ordinal + 1];\n"
964 " i < count; i += edge_fields_count) {\n"
965 " if (edges[i + edge_type_offset] === prop_type\n"
966 " && strings[edges[i + edge_name_offset]] === prop_name)\n"
967 " return edges[i + edge_to_node_offset];\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100968 " }\n"
969 " return null;\n"
970 "}\n");
971 // Get the string index using the path: <root> -> <global>.b.x.s
972 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
973 "GetChildPosByProperty(\n"
974 " GetChildPosByProperty(\n"
975 " GetChildPosByProperty("
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 " parsed.edges[edge_fields_count + edge_to_node_offset],"
977 " \"b\", property_type),\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800978 " \"x\", property_type),"
979 " \"s\", property_type)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100980 CHECK(!string_obj_pos_val.IsEmpty());
981 int string_obj_pos =
982 static_cast<int>(string_obj_pos_val->ToNumber()->Value());
983 v8::Local<v8::Object> nodes_array =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000984 parsed_snapshot->Get(v8_str("nodes"))->ToObject();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100985 int string_index = static_cast<int>(
986 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
987 CHECK_GT(string_index, 0);
988 v8::Local<v8::Object> strings_array =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000989 parsed_snapshot->Get(v8_str("strings"))->ToObject();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100990 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
991 v8::Local<v8::String> ref_string =
992 CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
993#undef STRING_LITERAL_FOR_TEST
994 CHECK_EQ(*v8::String::Utf8Value(ref_string),
995 *v8::String::Utf8Value(string));
996}
997
998
999TEST(HeapSnapshotJSONSerializationAborting) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001000 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 v8::HandleScope scope(env->GetIsolate());
1002 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001003 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001004 heap_profiler->TakeHeapSnapshot(v8_str("abort"));
1005 CHECK(ValidateSnapshot(snapshot));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001006 TestJSONStream stream(5);
1007 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1008 CHECK_GT(stream.size(), 0);
1009 CHECK_EQ(0, stream.eos_signaled());
1010}
1011
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001012namespace {
1013
1014class TestStatsStream : public v8::OutputStream {
1015 public:
1016 TestStatsStream()
1017 : eos_signaled_(0),
1018 updates_written_(0),
1019 entries_count_(0),
1020 entries_size_(0),
1021 intervals_count_(0),
1022 first_interval_index_(-1) { }
1023 TestStatsStream(const TestStatsStream& stream)
1024 : v8::OutputStream(stream),
1025 eos_signaled_(stream.eos_signaled_),
1026 updates_written_(stream.updates_written_),
1027 entries_count_(stream.entries_count_),
1028 entries_size_(stream.entries_size_),
1029 intervals_count_(stream.intervals_count_),
1030 first_interval_index_(stream.first_interval_index_) { }
1031 virtual ~TestStatsStream() {}
1032 virtual void EndOfStream() { ++eos_signaled_; }
1033 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
1034 DCHECK(false);
1035 return kAbort;
1036 }
1037 virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
1038 int updates_written) {
1039 ++intervals_count_;
1040 DCHECK(updates_written);
1041 updates_written_ += updates_written;
1042 entries_count_ = 0;
1043 if (first_interval_index_ == -1 && updates_written != 0)
1044 first_interval_index_ = buffer[0].index;
1045 for (int i = 0; i < updates_written; ++i) {
1046 entries_count_ += buffer[i].count;
1047 entries_size_ += buffer[i].size;
1048 }
1049
1050 return kContinue;
1051 }
1052 int eos_signaled() { return eos_signaled_; }
1053 int updates_written() { return updates_written_; }
1054 uint32_t entries_count() const { return entries_count_; }
1055 uint32_t entries_size() const { return entries_size_; }
1056 int intervals_count() const { return intervals_count_; }
1057 int first_interval_index() const { return first_interval_index_; }
1058
1059 private:
1060 int eos_signaled_;
1061 int updates_written_;
1062 uint32_t entries_count_;
1063 uint32_t entries_size_;
1064 int intervals_count_;
1065 int first_interval_index_;
1066};
1067
1068} // namespace
1069
1070static TestStatsStream GetHeapStatsUpdate(
1071 v8::HeapProfiler* heap_profiler,
1072 v8::SnapshotObjectId* object_id = NULL) {
1073 TestStatsStream stream;
1074 v8::SnapshotObjectId last_seen_id = heap_profiler->GetHeapStats(&stream);
1075 if (object_id)
1076 *object_id = last_seen_id;
1077 CHECK_EQ(1, stream.eos_signaled());
1078 return stream;
1079}
1080
1081
1082TEST(HeapSnapshotObjectsStats) {
1083 LocalContext env;
1084 v8::HandleScope scope(env->GetIsolate());
1085 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1086
1087 heap_profiler->StartTrackingHeapObjects();
1088 // We have to call GC 6 times. In other case the garbage will be
1089 // the reason of flakiness.
1090 for (int i = 0; i < 6; ++i) {
1091 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
1092 }
1093
1094 v8::SnapshotObjectId initial_id;
1095 {
1096 // Single chunk of data expected in update. Initial data.
1097 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
1098 &initial_id);
1099 CHECK_EQ(1, stats_update.intervals_count());
1100 CHECK_EQ(1, stats_update.updates_written());
1101 CHECK_LT(0, stats_update.entries_size());
1102 CHECK_EQ(0, stats_update.first_interval_index());
1103 }
1104
1105 // No data expected in update because nothing has happened.
1106 v8::SnapshotObjectId same_id;
1107 CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &same_id).updates_written());
1108 CHECK_EQ_SNAPSHOT_OBJECT_ID(initial_id, same_id);
1109
1110 {
1111 v8::SnapshotObjectId additional_string_id;
1112 v8::HandleScope inner_scope_1(env->GetIsolate());
1113 v8_str("string1");
1114 {
1115 // Single chunk of data with one new entry expected in update.
1116 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
1117 &additional_string_id);
1118 CHECK_LT(same_id, additional_string_id);
1119 CHECK_EQ(1, stats_update.intervals_count());
1120 CHECK_EQ(1, stats_update.updates_written());
1121 CHECK_LT(0, stats_update.entries_size());
1122 CHECK_EQ(1, stats_update.entries_count());
1123 CHECK_EQ(2, stats_update.first_interval_index());
1124 }
1125
1126 // No data expected in update because nothing happened.
1127 v8::SnapshotObjectId last_id;
1128 CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &last_id).updates_written());
1129 CHECK_EQ_SNAPSHOT_OBJECT_ID(additional_string_id, last_id);
1130
1131 {
1132 v8::HandleScope inner_scope_2(env->GetIsolate());
1133 v8_str("string2");
1134
1135 uint32_t entries_size;
1136 {
1137 v8::HandleScope inner_scope_3(env->GetIsolate());
1138 v8_str("string3");
1139 v8_str("string4");
1140
1141 {
1142 // Single chunk of data with three new entries expected in update.
1143 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1144 CHECK_EQ(1, stats_update.intervals_count());
1145 CHECK_EQ(1, stats_update.updates_written());
1146 CHECK_LT(0, entries_size = stats_update.entries_size());
1147 CHECK_EQ(3, stats_update.entries_count());
1148 CHECK_EQ(4, stats_update.first_interval_index());
1149 }
1150 }
1151
1152 {
1153 // Single chunk of data with two left entries expected in update.
1154 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1155 CHECK_EQ(1, stats_update.intervals_count());
1156 CHECK_EQ(1, stats_update.updates_written());
1157 CHECK_GT(entries_size, stats_update.entries_size());
1158 CHECK_EQ(1, stats_update.entries_count());
1159 // Two strings from forth interval were released.
1160 CHECK_EQ(4, stats_update.first_interval_index());
1161 }
1162 }
1163
1164 {
1165 // Single chunk of data with 0 left entries expected in update.
1166 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1167 CHECK_EQ(1, stats_update.intervals_count());
1168 CHECK_EQ(1, stats_update.updates_written());
1169 CHECK_EQ(0, stats_update.entries_size());
1170 CHECK_EQ(0, stats_update.entries_count());
1171 // The last string from forth interval was released.
1172 CHECK_EQ(4, stats_update.first_interval_index());
1173 }
1174 }
1175 {
1176 // Single chunk of data with 0 left entries expected in update.
1177 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1178 CHECK_EQ(1, stats_update.intervals_count());
1179 CHECK_EQ(1, stats_update.updates_written());
1180 CHECK_EQ(0, stats_update.entries_size());
1181 CHECK_EQ(0, stats_update.entries_count());
1182 // The only string from the second interval was released.
1183 CHECK_EQ(2, stats_update.first_interval_index());
1184 }
1185
1186 v8::Local<v8::Array> array = v8::Array::New(env->GetIsolate());
1187 CHECK_EQ(0, array->Length());
1188 // Force array's buffer allocation.
1189 array->Set(2, v8_num(7));
1190
1191 uint32_t entries_size;
1192 {
1193 // Single chunk of data with 2 entries expected in update.
1194 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1195 CHECK_EQ(1, stats_update.intervals_count());
1196 CHECK_EQ(1, stats_update.updates_written());
1197 CHECK_LT(0, entries_size = stats_update.entries_size());
1198 // They are the array and its buffer.
1199 CHECK_EQ(2, stats_update.entries_count());
1200 CHECK_EQ(8, stats_update.first_interval_index());
1201 }
1202
1203 for (int i = 0; i < 100; ++i)
1204 array->Set(i, v8_num(i));
1205
1206 {
1207 // Single chunk of data with 1 entry expected in update.
1208 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1209 CHECK_EQ(1, stats_update.intervals_count());
1210 // The first interval was changed because old buffer was collected.
1211 // The second interval was changed because new buffer was allocated.
1212 CHECK_EQ(2, stats_update.updates_written());
1213 CHECK_LT(entries_size, stats_update.entries_size());
1214 CHECK_EQ(2, stats_update.entries_count());
1215 CHECK_EQ(8, stats_update.first_interval_index());
1216 }
1217
1218 heap_profiler->StopTrackingHeapObjects();
1219}
1220
1221
1222TEST(HeapObjectIds) {
1223 LocalContext env;
1224 v8::Isolate* isolate = env->GetIsolate();
1225 v8::HandleScope scope(isolate);
1226 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1227
1228 const int kLength = 10;
1229 v8::Handle<v8::Object> objects[kLength];
1230 v8::SnapshotObjectId ids[kLength];
1231
1232 heap_profiler->StartTrackingHeapObjects(false);
1233
1234 for (int i = 0; i < kLength; i++) {
1235 objects[i] = v8::Object::New(isolate);
1236 }
1237 GetHeapStatsUpdate(heap_profiler);
1238
1239 for (int i = 0; i < kLength; i++) {
1240 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1241 CHECK_NE(v8::HeapProfiler::kUnknownObjectId, static_cast<int>(id));
1242 ids[i] = id;
1243 }
1244
1245 heap_profiler->StopTrackingHeapObjects();
1246 CcTest::heap()->CollectAllAvailableGarbage();
1247
1248 for (int i = 0; i < kLength; i++) {
1249 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1250 CHECK_EQ(static_cast<int>(ids[i]), static_cast<int>(id));
1251 v8::Handle<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1252 CHECK_EQ(objects[i], obj);
1253 }
1254
1255 heap_profiler->ClearObjectIds();
1256 for (int i = 0; i < kLength; i++) {
1257 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1258 CHECK_EQ(v8::HeapProfiler::kUnknownObjectId, static_cast<int>(id));
1259 v8::Handle<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1260 CHECK(obj.IsEmpty());
1261 }
1262}
1263
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001264
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001265static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
1266 const v8::HeapGraphNode* node,
1267 int level, int max_level) {
1268 if (level > max_level) return;
1269 CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
1270 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
1271 const v8::HeapGraphEdge* prop = node->GetChild(i);
1272 const v8::HeapGraphNode* child =
1273 snapshot->GetNodeById(prop->GetToNode()->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001274 CHECK_EQ_SNAPSHOT_OBJECT_ID(prop->GetToNode()->GetId(), child->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001275 CHECK_EQ(prop->GetToNode(), child);
1276 CheckChildrenIds(snapshot, child, level + 1, max_level);
1277 }
1278}
1279
1280
Ben Murdochb0fe1622011-05-05 13:52:32 +01001281TEST(HeapSnapshotGetNodeById) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001282 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283 v8::HandleScope scope(env->GetIsolate());
1284 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001285
1286 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287 heap_profiler->TakeHeapSnapshot(v8_str("id"));
1288 CHECK(ValidateSnapshot(snapshot));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001289 const v8::HeapGraphNode* root = snapshot->GetRoot();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001290 CheckChildrenIds(snapshot, root, 0, 3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001291 // Check a big id, which should not exist yet.
1292 CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
1293}
1294
1295
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296TEST(HeapSnapshotGetSnapshotObjectId) {
1297 LocalContext env;
1298 v8::HandleScope scope(env->GetIsolate());
1299 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1300 CompileRun("globalObject = {};\n");
1301 const v8::HeapSnapshot* snapshot =
1302 heap_profiler->TakeHeapSnapshot(v8_str("get_snapshot_object_id"));
1303 CHECK(ValidateSnapshot(snapshot));
1304 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1305 const v8::HeapGraphNode* global_object =
1306 GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject");
1307 CHECK(global_object);
1308
1309 v8::Local<v8::Value> globalObjectHandle = env->Global()->Get(
1310 v8::String::NewFromUtf8(env->GetIsolate(), "globalObject"));
1311 CHECK(!globalObjectHandle.IsEmpty());
1312 CHECK(globalObjectHandle->IsObject());
1313
1314 v8::SnapshotObjectId id = heap_profiler->GetObjectId(globalObjectHandle);
1315 CHECK_NE(static_cast<int>(v8::HeapProfiler::kUnknownObjectId),
1316 id);
1317 CHECK_EQ(static_cast<int>(id), global_object->GetId());
1318}
1319
1320
1321TEST(HeapSnapshotUnknownSnapshotObjectId) {
1322 LocalContext env;
1323 v8::HandleScope scope(env->GetIsolate());
1324 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1325 CompileRun("globalObject = {};\n");
1326 const v8::HeapSnapshot* snapshot =
1327 heap_profiler->TakeHeapSnapshot(v8_str("unknown_object_id"));
1328 CHECK(ValidateSnapshot(snapshot));
1329 const v8::HeapGraphNode* node =
1330 snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId);
1331 CHECK_EQ(NULL, node);
1332}
1333
1334
Ben Murdochb0fe1622011-05-05 13:52:32 +01001335namespace {
1336
1337class TestActivityControl : public v8::ActivityControl {
1338 public:
1339 explicit TestActivityControl(int abort_count)
1340 : done_(0), total_(0), abort_count_(abort_count) {}
1341 ControlOption ReportProgressValue(int done, int total) {
1342 done_ = done;
1343 total_ = total;
1344 return --abort_count_ != 0 ? kContinue : kAbort;
1345 }
1346 int done() { return done_; }
1347 int total() { return total_; }
1348
1349 private:
1350 int done_;
1351 int total_;
1352 int abort_count_;
1353};
1354}
1355
Ben Murdochb0fe1622011-05-05 13:52:32 +01001356
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001357TEST(TakeHeapSnapshotAborting) {
1358 LocalContext env;
1359 v8::HandleScope scope(env->GetIsolate());
1360
1361 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1362 const int snapshots_count = heap_profiler->GetSnapshotCount();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001363 TestActivityControl aborting_control(1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001364 const v8::HeapSnapshot* no_snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365 heap_profiler->TakeHeapSnapshot(v8_str("abort"),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001366 &aborting_control);
1367 CHECK_EQ(NULL, no_snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368 CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001369 CHECK_GT(aborting_control.total(), aborting_control.done());
1370
1371 TestActivityControl control(-1); // Don't abort.
1372 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001373 heap_profiler->TakeHeapSnapshot(v8_str("full"),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001374 &control);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001375 CHECK(ValidateSnapshot(snapshot));
1376
Ben Murdochb0fe1622011-05-05 13:52:32 +01001377 CHECK_NE(NULL, snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 CHECK_EQ(snapshots_count + 1, heap_profiler->GetSnapshotCount());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001379 CHECK_EQ(control.total(), control.done());
1380 CHECK_GT(control.total(), 0);
1381}
1382
Steve Block44f0eee2011-05-26 01:26:41 +01001383
1384namespace {
1385
1386class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
1387 public:
1388 TestRetainedObjectInfo(int hash,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001389 const char* group_label,
Steve Block44f0eee2011-05-26 01:26:41 +01001390 const char* label,
1391 intptr_t element_count = -1,
1392 intptr_t size = -1)
1393 : disposed_(false),
1394 hash_(hash),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001395 group_label_(group_label),
Steve Block44f0eee2011-05-26 01:26:41 +01001396 label_(label),
1397 element_count_(element_count),
1398 size_(size) {
1399 instances.Add(this);
1400 }
1401 virtual ~TestRetainedObjectInfo() {}
1402 virtual void Dispose() {
1403 CHECK(!disposed_);
1404 disposed_ = true;
1405 }
1406 virtual bool IsEquivalent(RetainedObjectInfo* other) {
1407 return GetHash() == other->GetHash();
1408 }
1409 virtual intptr_t GetHash() { return hash_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001410 virtual const char* GetGroupLabel() { return group_label_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001411 virtual const char* GetLabel() { return label_; }
1412 virtual intptr_t GetElementCount() { return element_count_; }
1413 virtual intptr_t GetSizeInBytes() { return size_; }
1414 bool disposed() { return disposed_; }
1415
1416 static v8::RetainedObjectInfo* WrapperInfoCallback(
1417 uint16_t class_id, v8::Handle<v8::Value> wrapper) {
1418 if (class_id == 1) {
1419 if (wrapper->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001420 v8::String::Utf8Value utf8(wrapper);
1421 if (strcmp(*utf8, "AAA") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001422 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423 else if (strcmp(*utf8, "BBB") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001424 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
Steve Block44f0eee2011-05-26 01:26:41 +01001425 }
1426 } else if (class_id == 2) {
1427 if (wrapper->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001428 v8::String::Utf8Value utf8(wrapper);
1429 if (strcmp(*utf8, "CCC") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001430 return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
Steve Block44f0eee2011-05-26 01:26:41 +01001431 }
1432 }
1433 CHECK(false);
1434 return NULL;
1435 }
1436
1437 static i::List<TestRetainedObjectInfo*> instances;
1438
1439 private:
1440 bool disposed_;
Steve Block44f0eee2011-05-26 01:26:41 +01001441 int hash_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001442 const char* group_label_;
Steve Block44f0eee2011-05-26 01:26:41 +01001443 const char* label_;
1444 intptr_t element_count_;
1445 intptr_t size_;
1446};
1447
1448
1449i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
1450}
1451
1452
1453static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1454 v8::HeapGraphNode::Type type,
1455 const char* name) {
1456 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1457 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1458 if (node->GetType() == type && strcmp(name,
1459 const_cast<i::HeapEntry*>(
1460 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1461 return node;
1462 }
1463 }
1464 return NULL;
1465}
1466
1467
1468TEST(HeapSnapshotRetainedObjectInfo) {
Steve Block44f0eee2011-05-26 01:26:41 +01001469 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470 v8::Isolate* isolate = env->GetIsolate();
1471 v8::HandleScope scope(isolate);
1472 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001473
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001474 heap_profiler->SetWrapperClassInfoProvider(
Steve Block44f0eee2011-05-26 01:26:41 +01001475 1, TestRetainedObjectInfo::WrapperInfoCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 heap_profiler->SetWrapperClassInfoProvider(
Steve Block44f0eee2011-05-26 01:26:41 +01001477 2, TestRetainedObjectInfo::WrapperInfoCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 v8::Persistent<v8::String> p_AAA(isolate, v8_str("AAA"));
Steve Block44f0eee2011-05-26 01:26:41 +01001479 p_AAA.SetWrapperClassId(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 v8::Persistent<v8::String> p_BBB(isolate, v8_str("BBB"));
Steve Block44f0eee2011-05-26 01:26:41 +01001481 p_BBB.SetWrapperClassId(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001482 v8::Persistent<v8::String> p_CCC(isolate, v8_str("CCC"));
Steve Block44f0eee2011-05-26 01:26:41 +01001483 p_CCC.SetWrapperClassId(2);
1484 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
1485 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486 heap_profiler->TakeHeapSnapshot(v8_str("retained"));
1487 CHECK(ValidateSnapshot(snapshot));
Steve Block44f0eee2011-05-26 01:26:41 +01001488
1489 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1490 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1491 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1492 delete TestRetainedObjectInfo::instances[i];
1493 }
1494
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001495 const v8::HeapGraphNode* native_group_aaa = GetNode(
1496 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "aaa-group");
1497 CHECK_NE(NULL, native_group_aaa);
1498 CHECK_EQ(1, native_group_aaa->GetChildrenCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001499 const v8::HeapGraphNode* aaa = GetNode(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001500 native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
Steve Block44f0eee2011-05-26 01:26:41 +01001501 CHECK_NE(NULL, aaa);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001502 CHECK_EQ(2, aaa->GetChildrenCount());
1503
1504 const v8::HeapGraphNode* native_group_ccc = GetNode(
1505 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "ccc-group");
Steve Block44f0eee2011-05-26 01:26:41 +01001506 const v8::HeapGraphNode* ccc = GetNode(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001507 native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
Steve Block44f0eee2011-05-26 01:26:41 +01001508 CHECK_NE(NULL, ccc);
1509
Steve Block44f0eee2011-05-26 01:26:41 +01001510 const v8::HeapGraphNode* n_AAA = GetNode(
1511 aaa, v8::HeapGraphNode::kString, "AAA");
1512 CHECK_NE(NULL, n_AAA);
1513 const v8::HeapGraphNode* n_BBB = GetNode(
1514 aaa, v8::HeapGraphNode::kString, "BBB");
1515 CHECK_NE(NULL, n_BBB);
1516 CHECK_EQ(1, ccc->GetChildrenCount());
1517 const v8::HeapGraphNode* n_CCC = GetNode(
1518 ccc, v8::HeapGraphNode::kString, "CCC");
1519 CHECK_NE(NULL, n_CCC);
1520
Ben Murdoch8b112d22011-06-08 16:22:53 +01001521 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1522 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1523 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
Steve Block44f0eee2011-05-26 01:26:41 +01001524}
1525
1526
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001527class GraphWithImplicitRefs {
1528 public:
1529 static const int kObjectsCount = 4;
1530 explicit GraphWithImplicitRefs(LocalContext* env) {
1531 CHECK_EQ(NULL, instance_);
1532 instance_ = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001533 isolate_ = (*env)->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001534 for (int i = 0; i < kObjectsCount; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001535 objects_[i].Reset(isolate_, v8::Object::New(isolate_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001536 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 (*env)->Global()->Set(v8_str("root_object"),
1538 v8::Local<v8::Value>::New(isolate_, objects_[0]));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001539 }
1540 ~GraphWithImplicitRefs() {
1541 instance_ = NULL;
1542 }
1543
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001544 static void gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001545 instance_->AddImplicitReferences();
1546 }
1547
1548 private:
1549 void AddImplicitReferences() {
1550 // 0 -> 1
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001551 isolate_->SetObjectGroupId(objects_[0],
1552 v8::UniqueId(1));
1553 isolate_->SetReferenceFromGroup(
1554 v8::UniqueId(1), objects_[1]);
1555 // Adding two more references: 1 -> 2, 1 -> 3
1556 isolate_->SetReference(objects_[1].As<v8::Object>(),
1557 objects_[2]);
1558 isolate_->SetReference(objects_[1].As<v8::Object>(),
1559 objects_[3]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001560 }
1561
1562 v8::Persistent<v8::Value> objects_[kObjectsCount];
1563 static GraphWithImplicitRefs* instance_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001564 v8::Isolate* isolate_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001565};
1566
1567GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
1568
1569
1570TEST(HeapSnapshotImplicitReferences) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001571 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 v8::HandleScope scope(env->GetIsolate());
1573 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001574
1575 GraphWithImplicitRefs graph(&env);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001576 v8::V8::AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001577
1578 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001579 heap_profiler->TakeHeapSnapshot(v8_str("implicit_refs"));
1580 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001581
1582 const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001583 const v8::HeapGraphNode* obj0 = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 global_object, v8::HeapGraphEdge::kProperty, "root_object");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001585 CHECK(obj0);
1586 CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
1587 const v8::HeapGraphNode* obj1 = GetProperty(
1588 obj0, v8::HeapGraphEdge::kInternal, "native");
1589 CHECK(obj1);
1590 int implicit_targets_count = 0;
1591 for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
1592 const v8::HeapGraphEdge* prop = obj1->GetChild(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593 v8::String::Utf8Value prop_name(prop->GetName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001594 if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
1595 strcmp("native", *prop_name) == 0) {
1596 ++implicit_targets_count;
1597 }
1598 }
1599 CHECK_EQ(2, implicit_targets_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001600 v8::V8::RemoveGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001601}
1602
1603
Steve Block44f0eee2011-05-26 01:26:41 +01001604TEST(DeleteAllHeapSnapshots) {
Steve Block44f0eee2011-05-26 01:26:41 +01001605 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 v8::HandleScope scope(env->GetIsolate());
1607 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001608
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001609 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1610 heap_profiler->DeleteAllHeapSnapshots();
1611 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1612 CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1")));
1613 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1614 heap_profiler->DeleteAllHeapSnapshots();
1615 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1616 CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1")));
1617 CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("2")));
1618 CHECK_EQ(2, heap_profiler->GetSnapshotCount());
1619 heap_profiler->DeleteAllHeapSnapshots();
1620 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1621}
1622
1623
1624static const v8::HeapSnapshot* FindHeapSnapshot(v8::HeapProfiler* profiler,
1625 unsigned uid) {
1626 int length = profiler->GetSnapshotCount();
1627 for (int i = 0; i < length; i++) {
1628 const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i);
1629 if (snapshot->GetUid() == uid) {
1630 return snapshot;
1631 }
1632 }
1633 return NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001634}
1635
1636
1637TEST(DeleteHeapSnapshot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001638 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 v8::HandleScope scope(env->GetIsolate());
1640 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001641
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001642 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001643 const v8::HeapSnapshot* s1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001644 heap_profiler->TakeHeapSnapshot(v8_str("1"));
1645
Steve Block44f0eee2011-05-26 01:26:41 +01001646 CHECK_NE(NULL, s1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001647 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001648 unsigned uid1 = s1->GetUid();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 CHECK_EQ(s1, FindHeapSnapshot(heap_profiler, uid1));
Steve Block44f0eee2011-05-26 01:26:41 +01001650 const_cast<v8::HeapSnapshot*>(s1)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001651 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1652 CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid1));
Steve Block44f0eee2011-05-26 01:26:41 +01001653
1654 const v8::HeapSnapshot* s2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001655 heap_profiler->TakeHeapSnapshot(v8_str("2"));
Steve Block44f0eee2011-05-26 01:26:41 +01001656 CHECK_NE(NULL, s2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001657 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001658 unsigned uid2 = s2->GetUid();
1659 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001660 CHECK_EQ(s2, FindHeapSnapshot(heap_profiler, uid2));
Steve Block44f0eee2011-05-26 01:26:41 +01001661 const v8::HeapSnapshot* s3 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 heap_profiler->TakeHeapSnapshot(v8_str("3"));
Steve Block44f0eee2011-05-26 01:26:41 +01001663 CHECK_NE(NULL, s3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 CHECK_EQ(2, heap_profiler->GetSnapshotCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001665 unsigned uid3 = s3->GetUid();
1666 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001667 CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
Steve Block44f0eee2011-05-26 01:26:41 +01001668 const_cast<v8::HeapSnapshot*>(s2)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001669 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1670 CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid2));
1671 CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
Steve Block44f0eee2011-05-26 01:26:41 +01001672 const_cast<v8::HeapSnapshot*>(s3)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001673 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1674 CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid3));
Steve Block44f0eee2011-05-26 01:26:41 +01001675}
1676
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001677
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001678class NameResolver : public v8::HeapProfiler::ObjectNameResolver {
1679 public:
1680 virtual const char* GetName(v8::Handle<v8::Object> object) {
1681 return "Global object name";
1682 }
1683};
1684
1685
1686TEST(GlobalObjectName) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001687 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001688 v8::HandleScope scope(env->GetIsolate());
1689 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001690
1691 CompileRun("document = { URL:\"abcdefgh\" };");
1692
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001693 NameResolver name_resolver;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001694 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 heap_profiler->TakeHeapSnapshot(v8_str("document"),
1696 NULL,
1697 &name_resolver);
1698 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001699 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1700 CHECK_NE(NULL, global);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001701 CHECK_EQ("Object / Global object name" ,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001702 const_cast<i::HeapEntry*>(
1703 reinterpret_cast<const i::HeapEntry*>(global))->name());
1704}
1705
1706
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001707TEST(GlobalObjectFields) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001708 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001709 v8::HandleScope scope(env->GetIsolate());
1710 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1711 CompileRun("obj = {};");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001712 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001713 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1714 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001715 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001716 const v8::HeapGraphNode* builtins =
1717 GetProperty(global, v8::HeapGraphEdge::kInternal, "builtins");
1718 CHECK_NE(NULL, builtins);
1719 const v8::HeapGraphNode* native_context =
1720 GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
1721 CHECK_NE(NULL, native_context);
1722 const v8::HeapGraphNode* global_context =
1723 GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context");
1724 CHECK_NE(NULL, global_context);
1725 const v8::HeapGraphNode* global_proxy =
1726 GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
1727 CHECK_NE(NULL, global_proxy);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001728}
1729
1730
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001731TEST(NoHandleLeaks) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001732 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001733 v8::HandleScope scope(env->GetIsolate());
1734 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001735
1736 CompileRun("document = { URL:\"abcdefgh\" };");
1737
1738 v8::Handle<v8::String> name(v8_str("leakz"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001739 i::Isolate* isolate = CcTest::i_isolate();
1740 int count_before = i::HandleScope::NumberOfHandles(isolate);
1741 heap_profiler->TakeHeapSnapshot(name);
1742 int count_after = i::HandleScope::NumberOfHandles(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001743 CHECK_EQ(count_before, count_after);
1744}
1745
1746
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001747TEST(NodesIteration) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001748 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001749 v8::HandleScope scope(env->GetIsolate());
1750 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001751 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001752 heap_profiler->TakeHeapSnapshot(v8_str("iteration"));
1753 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001754 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1755 CHECK_NE(NULL, global);
1756 // Verify that we can find this object by iteration.
1757 const int nodes_count = snapshot->GetNodesCount();
1758 int count = 0;
1759 for (int i = 0; i < nodes_count; ++i) {
1760 if (snapshot->GetNode(i) == global)
1761 ++count;
1762 }
1763 CHECK_EQ(1, count);
1764}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001765
1766
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001767TEST(GetHeapValueForNode) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001768 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001769 v8::HandleScope scope(env->GetIsolate());
1770 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001771
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001772 CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001773 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001774 heap_profiler->TakeHeapSnapshot(v8_str("value"));
1775 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001776 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001777 CHECK(heap_profiler->FindObjectById(global->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001778 v8::Local<v8::Object> js_global =
1779 env->Global()->GetPrototype().As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001780 CHECK(js_global == heap_profiler->FindObjectById(global->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001781 const v8::HeapGraphNode* obj = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001782 global, v8::HeapGraphEdge::kProperty, "a");
1783 CHECK(heap_profiler->FindObjectById(obj->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001784 v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 CHECK(js_obj == heap_profiler->FindObjectById(obj->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001786 const v8::HeapGraphNode* s_prop =
1787 GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
1788 v8::Local<v8::String> js_s_prop =
1789 js_obj->Get(v8_str("s_prop")).As<v8::String>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001790 CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001791 const v8::HeapGraphNode* n_prop =
1792 GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001793 v8::Local<v8::String> js_n_prop =
1794 js_obj->Get(v8_str("n_prop")).As<v8::String>();
1795 CHECK(js_n_prop == heap_profiler->FindObjectById(n_prop->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001796}
1797
1798
1799TEST(GetHeapValueForDeletedObject) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001800 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801 v8::HandleScope scope(env->GetIsolate());
1802 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001803
1804 // It is impossible to delete a global property, so we are about to delete a
1805 // property of the "a" object. Also, the "p" object can't be an empty one
1806 // because the empty object is static and isn't actually deleted.
1807 CompileRun("a = { p: { r: {} } };");
1808 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001809 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1810 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001811 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1812 const v8::HeapGraphNode* obj = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001813 global, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001814 const v8::HeapGraphNode* prop = GetProperty(
1815 obj, v8::HeapGraphEdge::kProperty, "p");
1816 {
1817 // Perform the check inside a nested local scope to avoid creating a
1818 // reference to the object we are deleting.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 v8::HandleScope scope(env->GetIsolate());
1820 CHECK(heap_profiler->FindObjectById(prop->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001821 }
1822 CompileRun("delete a.p;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001823 CHECK(heap_profiler->FindObjectById(prop->GetId()).IsEmpty());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001824}
1825
1826
1827static int StringCmp(const char* ref, i::String* act) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001828 i::SmartArrayPointer<char> s_act = act->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001829 int result = strcmp(ref, s_act.get());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001830 if (result != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001831 fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, s_act.get());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001832 return result;
1833}
1834
1835
1836TEST(GetConstructorName) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001837 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001838 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001839
1840 CompileRun(
1841 "function Constructor1() {};\n"
1842 "var obj1 = new Constructor1();\n"
1843 "var Constructor2 = function() {};\n"
1844 "var obj2 = new Constructor2();\n"
1845 "var obj3 = {};\n"
1846 "obj3.constructor = function Constructor3() {};\n"
1847 "var obj4 = {};\n"
1848 "// Slow properties\n"
1849 "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
1850 "obj4.constructor = function Constructor4() {};\n"
1851 "var obj5 = {};\n"
1852 "var obj6 = {};\n"
1853 "obj6.constructor = 6;");
1854 v8::Local<v8::Object> js_global =
1855 env->Global()->GetPrototype().As<v8::Object>();
1856 v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
1857 i::Handle<i::JSObject> js_obj1 = v8::Utils::OpenHandle(*obj1);
1858 CHECK_EQ(0, StringCmp(
1859 "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
1860 v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
1861 i::Handle<i::JSObject> js_obj2 = v8::Utils::OpenHandle(*obj2);
1862 CHECK_EQ(0, StringCmp(
1863 "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
1864 v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
1865 i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001866 // TODO(verwaest): Restore to Constructor3 once supported by the
1867 // heap-snapshot-generator.
1868 CHECK_EQ(
1869 0, StringCmp("Object", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001870 v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
1871 i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001872 // TODO(verwaest): Restore to Constructor4 once supported by the
1873 // heap-snapshot-generator.
1874 CHECK_EQ(
1875 0, StringCmp("Object", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001876 v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
1877 i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
1878 CHECK_EQ(0, StringCmp(
1879 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
1880 v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
1881 i::Handle<i::JSObject> js_obj6 = v8::Utils::OpenHandle(*obj6);
1882 CHECK_EQ(0, StringCmp(
1883 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1884}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001885
1886
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001887TEST(FastCaseAccessors) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001888 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 v8::HandleScope scope(env->GetIsolate());
1890 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001891
1892 CompileRun("var obj1 = {};\n"
1893 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1894 " return 42;\n"
1895 "});\n"
1896 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1897 " return this.value_ = value;\n"
1898 "});\n");
1899 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
1901 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001902
1903 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1904 CHECK_NE(NULL, global);
1905 const v8::HeapGraphNode* obj1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001906 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001907 CHECK_NE(NULL, obj1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001908 const v8::HeapGraphNode* func;
1909 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
1910 CHECK_NE(NULL, func);
1911 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
1912 CHECK_EQ(NULL, func);
1913 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
1914 CHECK_NE(NULL, func);
1915 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
1916 CHECK_EQ(NULL, func);
1917}
1918
1919
1920TEST(SlowCaseAccessors) {
1921 LocalContext env;
1922 v8::HandleScope scope(env->GetIsolate());
1923 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1924
1925 CompileRun("var obj1 = {};\n"
1926 "for (var i = 0; i < 100; ++i) obj1['z' + i] = {};"
1927 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1928 " return 42;\n"
1929 "});\n"
1930 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1931 " return this.value_ = value;\n"
1932 "});\n");
1933 const v8::HeapSnapshot* snapshot =
1934 heap_profiler->TakeHeapSnapshot(v8_str("slowCaseAccessors"));
1935 CHECK(ValidateSnapshot(snapshot));
1936
1937 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1938 CHECK_NE(NULL, global);
1939 const v8::HeapGraphNode* obj1 =
1940 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
1941 CHECK_NE(NULL, obj1);
1942 const v8::HeapGraphNode* func;
1943 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
1944 CHECK_NE(NULL, func);
1945 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
1946 CHECK_EQ(NULL, func);
1947 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
1948 CHECK_NE(NULL, func);
1949 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
1950 CHECK_EQ(NULL, func);
1951}
1952
1953
1954TEST(HiddenPropertiesFastCase) {
1955 LocalContext env;
1956 v8::HandleScope scope(env->GetIsolate());
1957 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1958
1959 CompileRun(
1960 "function C(x) { this.a = this; this.b = x; }\n"
1961 "c = new C(2012);\n");
1962 const v8::HeapSnapshot* snapshot =
1963 heap_profiler->TakeHeapSnapshot(v8_str("HiddenPropertiesFastCase1"));
1964 CHECK(ValidateSnapshot(snapshot));
1965 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1966 const v8::HeapGraphNode* c =
1967 GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
1968 CHECK_NE(NULL, c);
1969 const v8::HeapGraphNode* hidden_props =
1970 GetProperty(c, v8::HeapGraphEdge::kInternal, "hidden_properties");
1971 CHECK_EQ(NULL, hidden_props);
1972
1973 v8::Handle<v8::Value> cHandle =
1974 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"));
1975 CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
1976 cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
1977
1978 snapshot = heap_profiler->TakeHeapSnapshot(
1979 v8_str("HiddenPropertiesFastCase2"));
1980 CHECK(ValidateSnapshot(snapshot));
1981 global = GetGlobalObject(snapshot);
1982 c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
1983 CHECK_NE(NULL, c);
1984 hidden_props = GetProperty(c, v8::HeapGraphEdge::kInternal,
1985 "hidden_properties");
1986 CHECK_NE(NULL, hidden_props);
1987}
1988
1989
1990TEST(AccessorInfo) {
1991 LocalContext env;
1992 v8::HandleScope scope(env->GetIsolate());
1993 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1994
1995 CompileRun("function foo(x) { }\n");
1996 const v8::HeapSnapshot* snapshot =
1997 heap_profiler->TakeHeapSnapshot(v8_str("AccessorInfoTest"));
1998 CHECK(ValidateSnapshot(snapshot));
1999 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2000 const v8::HeapGraphNode* foo =
2001 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2002 CHECK_NE(NULL, foo);
2003 const v8::HeapGraphNode* map =
2004 GetProperty(foo, v8::HeapGraphEdge::kInternal, "map");
2005 CHECK_NE(NULL, map);
2006 const v8::HeapGraphNode* descriptors =
2007 GetProperty(map, v8::HeapGraphEdge::kInternal, "descriptors");
2008 CHECK_NE(NULL, descriptors);
2009 const v8::HeapGraphNode* length_name =
2010 GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "2");
2011 CHECK_NE(NULL, length_name);
2012 CHECK_EQ("length", *v8::String::Utf8Value(length_name->GetName()));
2013 const v8::HeapGraphNode* length_accessor =
2014 GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "4");
2015 CHECK_NE(NULL, length_accessor);
2016 CHECK_EQ("system / ExecutableAccessorInfo",
2017 *v8::String::Utf8Value(length_accessor->GetName()));
2018 const v8::HeapGraphNode* name =
2019 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "name");
2020 CHECK_NE(NULL, name);
2021 const v8::HeapGraphNode* getter =
2022 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "getter");
2023 CHECK_NE(NULL, getter);
2024 const v8::HeapGraphNode* setter =
2025 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "setter");
2026 CHECK_NE(NULL, setter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002027}
2028
2029
2030bool HasWeakEdge(const v8::HeapGraphNode* node) {
2031 for (int i = 0; i < node->GetChildrenCount(); ++i) {
2032 const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
2033 if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
2034 }
2035 return false;
2036}
2037
2038
2039bool HasWeakGlobalHandle() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002040 v8::Isolate* isolate = CcTest::isolate();
2041 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002042 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002043 heap_profiler->TakeHeapSnapshot(v8_str("weaks"));
2044 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002045 const v8::HeapGraphNode* gc_roots = GetNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002046 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002047 CHECK_NE(NULL, gc_roots);
2048 const v8::HeapGraphNode* global_handles = GetNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002049 gc_roots, v8::HeapGraphNode::kSynthetic, "(Global handles)");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002050 CHECK_NE(NULL, global_handles);
2051 return HasWeakEdge(global_handles);
2052}
2053
2054
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002055static void PersistentHandleCallback(
2056 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
2057 data.GetParameter()->Reset();
2058 delete data.GetParameter();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002059}
2060
2061
2062TEST(WeakGlobalHandle) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002063 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002064 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002065
2066 CHECK(!HasWeakGlobalHandle());
2067
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002068 v8::Persistent<v8::Object> handle(env->GetIsolate(),
2069 v8::Object::New(env->GetIsolate()));
2070 handle.SetWeak(&handle, PersistentHandleCallback);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002071
2072 CHECK(HasWeakGlobalHandle());
2073}
2074
2075
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002076TEST(SfiAndJsFunctionWeakRefs) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002077 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002078 v8::HandleScope scope(env->GetIsolate());
2079 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002080
2081 CompileRun(
2082 "fun = (function (x) { return function () { return x + 1; } })(1);");
2083 const v8::HeapSnapshot* snapshot =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002084 heap_profiler->TakeHeapSnapshot(v8_str("fun"));
2085 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002086 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2087 CHECK_NE(NULL, global);
2088 const v8::HeapGraphNode* fun =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
2090 CHECK(!HasWeakEdge(fun));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002091 const v8::HeapGraphNode* shared =
2092 GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002093 CHECK(!HasWeakEdge(shared));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002094}
2095
2096
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002097TEST(NoDebugObjectInSnapshot) {
2098 LocalContext env;
2099 v8::HandleScope scope(env->GetIsolate());
2100 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2101
2102 CHECK(CcTest::i_isolate()->debug()->Load());
2103 CompileRun("foo = {};");
2104 const v8::HeapSnapshot* snapshot =
2105 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2106 CHECK(ValidateSnapshot(snapshot));
2107 const v8::HeapGraphNode* root = snapshot->GetRoot();
2108 int globals_count = 0;
2109 for (int i = 0; i < root->GetChildrenCount(); ++i) {
2110 const v8::HeapGraphEdge* edge = root->GetChild(i);
2111 if (edge->GetType() == v8::HeapGraphEdge::kShortcut) {
2112 ++globals_count;
2113 const v8::HeapGraphNode* global = edge->GetToNode();
2114 const v8::HeapGraphNode* foo =
2115 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2116 CHECK_NE(NULL, foo);
2117 }
2118 }
2119 CHECK_EQ(1, globals_count);
2120}
2121
2122
2123TEST(AllStrongGcRootsHaveNames) {
2124 LocalContext env;
2125 v8::HandleScope scope(env->GetIsolate());
2126 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2127
2128 CompileRun("foo = {};");
2129 const v8::HeapSnapshot* snapshot =
2130 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2131 CHECK(ValidateSnapshot(snapshot));
2132 const v8::HeapGraphNode* gc_roots = GetNode(
2133 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
2134 CHECK_NE(NULL, gc_roots);
2135 const v8::HeapGraphNode* strong_roots = GetNode(
2136 gc_roots, v8::HeapGraphNode::kSynthetic, "(Strong roots)");
2137 CHECK_NE(NULL, strong_roots);
2138 for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) {
2139 const v8::HeapGraphEdge* edge = strong_roots->GetChild(i);
2140 CHECK_EQ(v8::HeapGraphEdge::kInternal, edge->GetType());
2141 v8::String::Utf8Value name(edge->GetName());
2142 CHECK(isalpha(**name));
2143 }
2144}
2145
2146
2147TEST(NoRefsToNonEssentialEntries) {
2148 LocalContext env;
2149 v8::HandleScope scope(env->GetIsolate());
2150 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2151 CompileRun("global_object = {};\n");
2152 const v8::HeapSnapshot* snapshot =
2153 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2154 CHECK(ValidateSnapshot(snapshot));
2155 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2156 const v8::HeapGraphNode* global_object =
2157 GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object");
2158 CHECK_NE(NULL, global_object);
2159 const v8::HeapGraphNode* properties =
2160 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties");
2161 CHECK_EQ(NULL, properties);
2162 const v8::HeapGraphNode* elements =
2163 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements");
2164 CHECK_EQ(NULL, elements);
2165}
2166
2167
2168TEST(MapHasDescriptorsAndTransitions) {
2169 LocalContext env;
2170 v8::HandleScope scope(env->GetIsolate());
2171 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2172 CompileRun("obj = { a: 10 };\n");
2173 const v8::HeapSnapshot* snapshot =
2174 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2175 CHECK(ValidateSnapshot(snapshot));
2176 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2177 const v8::HeapGraphNode* global_object =
2178 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
2179 CHECK_NE(NULL, global_object);
2180
2181 const v8::HeapGraphNode* map =
2182 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "map");
2183 CHECK_NE(NULL, map);
2184 const v8::HeapGraphNode* own_descriptors = GetProperty(
2185 map, v8::HeapGraphEdge::kInternal, "descriptors");
2186 CHECK_NE(NULL, own_descriptors);
2187 const v8::HeapGraphNode* own_transitions = GetProperty(
2188 map, v8::HeapGraphEdge::kInternal, "transitions");
2189 CHECK_EQ(NULL, own_transitions);
2190}
2191
2192
2193TEST(ManyLocalsInSharedContext) {
2194 LocalContext env;
2195 v8::HandleScope scope(env->GetIsolate());
2196 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2197 int num_objects = 6000;
2198 CompileRun(
2199 "var n = 6000;"
2200 "var result = [];"
2201 "result.push('(function outer() {');"
2202 "for (var i = 0; i < n; i++) {"
2203 " var f = 'function f_' + i + '() { ';"
2204 " if (i > 0)"
2205 " f += 'f_' + (i - 1) + '();';"
2206 " f += ' }';"
2207 " result.push(f);"
2208 "}"
2209 "result.push('return f_' + (n - 1) + ';');"
2210 "result.push('})()');"
2211 "var ok = eval(result.join('\\n'));");
2212 const v8::HeapSnapshot* snapshot =
2213 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2214 CHECK(ValidateSnapshot(snapshot));
2215
2216 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2217 CHECK_NE(NULL, global);
2218 const v8::HeapGraphNode* ok_object =
2219 GetProperty(global, v8::HeapGraphEdge::kProperty, "ok");
2220 CHECK_NE(NULL, ok_object);
2221 const v8::HeapGraphNode* context_object =
2222 GetProperty(ok_object, v8::HeapGraphEdge::kInternal, "context");
2223 CHECK_NE(NULL, context_object);
2224 // Check the objects are not duplicated in the context.
2225 CHECK_EQ(v8::internal::Context::MIN_CONTEXT_SLOTS + num_objects - 1,
2226 context_object->GetChildrenCount());
2227 // Check all the objects have got their names.
2228 // ... well check just every 15th because otherwise it's too slow in debug.
2229 for (int i = 0; i < num_objects - 1; i += 15) {
2230 i::EmbeddedVector<char, 100> var_name;
2231 i::SNPrintF(var_name, "f_%d", i);
2232 const v8::HeapGraphNode* f_object = GetProperty(
2233 context_object, v8::HeapGraphEdge::kContextVariable, var_name.start());
2234 CHECK_NE(NULL, f_object);
2235 }
2236}
2237
2238
2239TEST(AllocationSitesAreVisible) {
2240 LocalContext env;
2241 v8::Isolate* isolate = env->GetIsolate();
2242 v8::HandleScope scope(isolate);
2243 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2244 CompileRun(
2245 "fun = function () { var a = [3, 2, 1]; return a; }\n"
2246 "fun();");
2247 const v8::HeapSnapshot* snapshot =
2248 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2249 CHECK(ValidateSnapshot(snapshot));
2250
2251 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2252 CHECK_NE(NULL, global);
2253 const v8::HeapGraphNode* fun_code =
2254 GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
2255 CHECK_NE(NULL, fun_code);
2256 const v8::HeapGraphNode* literals =
2257 GetProperty(fun_code, v8::HeapGraphEdge::kInternal, "literals");
2258 CHECK_NE(NULL, literals);
2259 CHECK_EQ(v8::HeapGraphNode::kArray, literals->GetType());
2260 CHECK_EQ(2, literals->GetChildrenCount());
2261
2262 // The second value in the literals array should be the boilerplate,
2263 // after an AllocationSite.
2264 const v8::HeapGraphEdge* prop = literals->GetChild(1);
2265 const v8::HeapGraphNode* allocation_site = prop->GetToNode();
2266 v8::String::Utf8Value name(allocation_site->GetName());
2267 CHECK_EQ("system / AllocationSite", *name);
2268 const v8::HeapGraphNode* transition_info =
2269 GetProperty(allocation_site, v8::HeapGraphEdge::kInternal,
2270 "transition_info");
2271 CHECK_NE(NULL, transition_info);
2272
2273 const v8::HeapGraphNode* elements =
2274 GetProperty(transition_info, v8::HeapGraphEdge::kInternal,
2275 "elements");
2276 CHECK_NE(NULL, elements);
2277 CHECK_EQ(v8::HeapGraphNode::kArray, elements->GetType());
2278 CHECK_EQ(v8::internal::FixedArray::SizeFor(3),
2279 static_cast<int>(elements->GetShallowSize()));
2280
2281 v8::Handle<v8::Value> array_val =
2282 heap_profiler->FindObjectById(transition_info->GetId());
2283 CHECK(array_val->IsArray());
2284 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(array_val);
2285 // Verify the array is "a" in the code above.
2286 CHECK_EQ(3, array->Length());
2287 CHECK_EQ(v8::Integer::New(isolate, 3),
2288 array->Get(v8::Integer::New(isolate, 0)));
2289 CHECK_EQ(v8::Integer::New(isolate, 2),
2290 array->Get(v8::Integer::New(isolate, 1)));
2291 CHECK_EQ(v8::Integer::New(isolate, 1),
2292 array->Get(v8::Integer::New(isolate, 2)));
2293}
2294
2295
2296TEST(JSFunctionHasCodeLink) {
2297 LocalContext env;
2298 v8::HandleScope scope(env->GetIsolate());
2299 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2300 CompileRun("function foo(x, y) { return x + y; }\n");
2301 const v8::HeapSnapshot* snapshot =
2302 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2303 CHECK(ValidateSnapshot(snapshot));
2304 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2305 const v8::HeapGraphNode* foo_func =
2306 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2307 CHECK_NE(NULL, foo_func);
2308 const v8::HeapGraphNode* code =
2309 GetProperty(foo_func, v8::HeapGraphEdge::kInternal, "code");
2310 CHECK_NE(NULL, code);
2311}
2312
2313
2314static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
2315 const char* path[],
2316 int depth) {
2317 const v8::HeapGraphNode* node = snapshot->GetRoot();
2318 for (int current_depth = 0; current_depth < depth; ++current_depth) {
2319 int i, count = node->GetChildrenCount();
2320 for (i = 0; i < count; ++i) {
2321 const v8::HeapGraphEdge* edge = node->GetChild(i);
2322 const v8::HeapGraphNode* to_node = edge->GetToNode();
2323 v8::String::Utf8Value edge_name(edge->GetName());
2324 v8::String::Utf8Value node_name(to_node->GetName());
2325 i::EmbeddedVector<char, 100> name;
2326 i::SNPrintF(name, "%s::%s", *edge_name, *node_name);
2327 if (strstr(name.start(), path[current_depth])) {
2328 node = to_node;
2329 break;
2330 }
2331 }
2332 if (i == count) return NULL;
2333 }
2334 return node;
2335}
2336
2337
2338TEST(CheckCodeNames) {
2339 LocalContext env;
2340 v8::HandleScope scope(env->GetIsolate());
2341 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2342 CompileRun("var a = 1.1;");
2343 const v8::HeapSnapshot* snapshot =
2344 heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames"));
2345 CHECK(ValidateSnapshot(snapshot));
2346
2347 const char* stub_path[] = {
2348 "::(GC roots)",
2349 "::(Strong roots)",
2350 "code_stubs::",
2351 "::(ArraySingleArgumentConstructorStub code)"
2352 };
2353 const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
2354 stub_path, arraysize(stub_path));
2355 CHECK_NE(NULL, node);
2356
2357 const char* builtin_path1[] = {
2358 "::(GC roots)",
2359 "::(Builtins)",
2360 "::(KeyedLoadIC_Generic builtin)"
2361 };
2362 node = GetNodeByPath(snapshot, builtin_path1, arraysize(builtin_path1));
2363 CHECK_NE(NULL, node);
2364
2365 const char* builtin_path2[] = {"::(GC roots)", "::(Builtins)",
2366 "::(CompileLazy builtin)"};
2367 node = GetNodeByPath(snapshot, builtin_path2, arraysize(builtin_path2));
2368 CHECK_NE(NULL, node);
2369 v8::String::Utf8Value node_name(node->GetName());
2370 CHECK_EQ("(CompileLazy builtin)", *node_name);
2371}
2372
2373
2374static const char* record_trace_tree_source =
2375"var topFunctions = [];\n"
2376"var global = this;\n"
2377"function generateFunctions(width, depth) {\n"
2378" var script = [];\n"
2379" for (var i = 0; i < width; i++) {\n"
2380" for (var j = 0; j < depth; j++) {\n"
2381" script.push('function f_' + i + '_' + j + '(x) {\\n');\n"
2382" script.push(' try {\\n');\n"
2383" if (j < depth-2) {\n"
2384" script.push(' return f_' + i + '_' + (j+1) + '(x+1);\\n');\n"
2385" } else if (j == depth - 2) {\n"
2386" script.push(' return new f_' + i + '_' + (depth - 1) + '();\\n');\n"
2387" } else if (j == depth - 1) {\n"
2388" script.push(' this.ts = Date.now();\\n');\n"
2389" }\n"
2390" script.push(' } catch (e) {}\\n');\n"
2391" script.push('}\\n');\n"
2392" \n"
2393" }\n"
2394" }\n"
2395" var script = script.join('');\n"
2396" // throw script;\n"
2397" global.eval(script);\n"
2398" for (var i = 0; i < width; i++) {\n"
2399" topFunctions.push(this['f_' + i + '_0']);\n"
2400" }\n"
2401"}\n"
2402"\n"
2403"var width = 3;\n"
2404"var depth = 3;\n"
2405"generateFunctions(width, depth);\n"
2406"var instances = [];\n"
2407"function start() {\n"
2408" for (var i = 0; i < width; i++) {\n"
2409" instances.push(topFunctions[i](0));\n"
2410" }\n"
2411"}\n"
2412"\n"
2413"for (var i = 0; i < 100; i++) start();\n";
2414
2415
2416static AllocationTraceNode* FindNode(
2417 AllocationTracker* tracker, const Vector<const char*>& names) {
2418 AllocationTraceNode* node = tracker->trace_tree()->root();
2419 for (int i = 0; node != NULL && i < names.length(); i++) {
2420 const char* name = names[i];
2421 Vector<AllocationTraceNode*> children = node->children();
2422 node = NULL;
2423 for (int j = 0; j < children.length(); j++) {
2424 unsigned index = children[j]->function_info_index();
2425 AllocationTracker::FunctionInfo* info =
2426 tracker->function_info_list()[index];
2427 if (info && strcmp(info->name, name) == 0) {
2428 node = children[j];
2429 break;
2430 }
2431 }
2432 }
2433 return node;
2434}
2435
2436
2437TEST(ArrayGrowLeftTrim) {
2438 LocalContext env;
2439 v8::HandleScope scope(env->GetIsolate());
2440 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2441 heap_profiler->StartTrackingHeapObjects(true);
2442
2443 CompileRun(
2444 "var a = [];\n"
2445 "for (var i = 0; i < 5; ++i)\n"
2446 " a[i] = i;\n"
2447 "for (var i = 0; i < 3; ++i)\n"
2448 " a.shift();\n");
2449
2450 const char* names[] = {""};
2451 AllocationTracker* tracker =
2452 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2453 CHECK_NE(NULL, tracker);
2454 // Resolve all function locations.
2455 tracker->PrepareForSerialization();
2456 // Print for better diagnostics in case of failure.
2457 tracker->trace_tree()->Print(tracker);
2458
2459 AllocationTraceNode* node =
2460 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2461 CHECK_NE(NULL, node);
2462 CHECK_GE(node->allocation_count(), 2);
2463 CHECK_GE(node->allocation_size(), 4 * 5);
2464 heap_profiler->StopTrackingHeapObjects();
2465}
2466
2467
2468TEST(TrackHeapAllocations) {
2469 v8::HandleScope scope(v8::Isolate::GetCurrent());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002470 LocalContext env;
2471
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002472 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2473 heap_profiler->StartTrackingHeapObjects(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002474
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002475 CompileRun(record_trace_tree_source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002476
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002477 AllocationTracker* tracker =
2478 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2479 CHECK_NE(NULL, tracker);
2480 // Resolve all function locations.
2481 tracker->PrepareForSerialization();
2482 // Print for better diagnostics in case of failure.
2483 tracker->trace_tree()->Print(tracker);
2484
2485 const char* names[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"};
2486 AllocationTraceNode* node =
2487 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2488 CHECK_NE(NULL, node);
2489 CHECK_GE(node->allocation_count(), 100);
2490 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2491 heap_profiler->StopTrackingHeapObjects();
2492}
2493
2494
2495static const char* inline_heap_allocation_source =
2496"function f_0(x) {\n"
2497" return f_1(x+1);\n"
2498"}\n"
2499"%NeverOptimizeFunction(f_0);\n"
2500"function f_1(x) {\n"
2501" return new f_2(x+1);\n"
2502"}\n"
2503"function f_2(x) {\n"
2504" this.foo = x;\n"
2505"}\n"
2506"var instances = [];\n"
2507"function start() {\n"
2508" instances.push(f_0(0));\n"
2509"}\n"
2510"\n"
2511"for (var i = 0; i < 100; i++) start();\n";
2512
2513
2514TEST(TrackBumpPointerAllocations) {
2515 i::FLAG_allow_natives_syntax = true;
2516 v8::HandleScope scope(v8::Isolate::GetCurrent());
2517 LocalContext env;
2518
2519 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2520 const char* names[] = {"", "start", "f_0", "f_1"};
2521 // First check that normally all allocations are recorded.
2522 {
2523 heap_profiler->StartTrackingHeapObjects(true);
2524
2525 CompileRun(inline_heap_allocation_source);
2526
2527 AllocationTracker* tracker =
2528 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2529 CHECK_NE(NULL, tracker);
2530 // Resolve all function locations.
2531 tracker->PrepareForSerialization();
2532 // Print for better diagnostics in case of failure.
2533 tracker->trace_tree()->Print(tracker);
2534
2535 AllocationTraceNode* node =
2536 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2537 CHECK_NE(NULL, node);
2538 CHECK_GE(node->allocation_count(), 100);
2539 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2540 heap_profiler->StopTrackingHeapObjects();
2541 }
2542
2543 {
2544 heap_profiler->StartTrackingHeapObjects(true);
2545
2546 // Now check that not all allocations are tracked if we manually reenable
2547 // inline allocations.
2548 CHECK(CcTest::heap()->inline_allocation_disabled());
2549 CcTest::heap()->EnableInlineAllocation();
2550
2551 CompileRun(inline_heap_allocation_source);
2552
2553 AllocationTracker* tracker =
2554 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2555 CHECK_NE(NULL, tracker);
2556 // Resolve all function locations.
2557 tracker->PrepareForSerialization();
2558 // Print for better diagnostics in case of failure.
2559 tracker->trace_tree()->Print(tracker);
2560
2561 AllocationTraceNode* node =
2562 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2563 CHECK_NE(NULL, node);
2564 CHECK_LT(node->allocation_count(), 100);
2565
2566 CcTest::heap()->DisableInlineAllocation();
2567 heap_profiler->StopTrackingHeapObjects();
2568 }
2569}
2570
2571
2572TEST(TrackV8ApiAllocation) {
2573 v8::HandleScope scope(v8::Isolate::GetCurrent());
2574 LocalContext env;
2575
2576 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2577 const char* names[] = { "(V8 API)" };
2578 heap_profiler->StartTrackingHeapObjects(true);
2579
2580 v8::Handle<v8::Object> o1 = v8::Object::New(env->GetIsolate());
2581 o1->Clone();
2582
2583 AllocationTracker* tracker =
2584 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2585 CHECK_NE(NULL, tracker);
2586 // Resolve all function locations.
2587 tracker->PrepareForSerialization();
2588 // Print for better diagnostics in case of failure.
2589 tracker->trace_tree()->Print(tracker);
2590
2591 AllocationTraceNode* node =
2592 FindNode(tracker, Vector<const char*>(names, arraysize(names)));
2593 CHECK_NE(NULL, node);
2594 CHECK_GE(node->allocation_count(), 2);
2595 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2596 heap_profiler->StopTrackingHeapObjects();
2597}
2598
2599
2600TEST(ArrayBufferAndArrayBufferView) {
2601 LocalContext env;
2602 v8::HandleScope scope(env->GetIsolate());
2603 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2604 CompileRun("arr1 = new Uint32Array(100);\n");
2605 const v8::HeapSnapshot* snapshot =
2606 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2607 CHECK(ValidateSnapshot(snapshot));
2608 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2609 const v8::HeapGraphNode* arr1_obj =
2610 GetProperty(global, v8::HeapGraphEdge::kProperty, "arr1");
2611 CHECK_NE(NULL, arr1_obj);
2612 const v8::HeapGraphNode* arr1_buffer =
2613 GetProperty(arr1_obj, v8::HeapGraphEdge::kInternal, "buffer");
2614 CHECK_NE(NULL, arr1_buffer);
2615 const v8::HeapGraphNode* first_view =
2616 GetProperty(arr1_buffer, v8::HeapGraphEdge::kWeak, "weak_first_view");
2617 CHECK_NE(NULL, first_view);
2618 const v8::HeapGraphNode* backing_store =
2619 GetProperty(arr1_buffer, v8::HeapGraphEdge::kInternal, "backing_store");
2620 CHECK_NE(NULL, backing_store);
2621 CHECK_EQ(400, static_cast<int>(backing_store->GetShallowSize()));
2622}
2623
2624
2625static int GetRetainersCount(const v8::HeapSnapshot* snapshot,
2626 const v8::HeapGraphNode* node) {
2627 int count = 0;
2628 for (int i = 0, l = snapshot->GetNodesCount(); i < l; ++i) {
2629 const v8::HeapGraphNode* parent = snapshot->GetNode(i);
2630 for (int j = 0, l2 = parent->GetChildrenCount(); j < l2; ++j) {
2631 if (parent->GetChild(j)->GetToNode() == node) {
2632 ++count;
2633 }
2634 }
2635 }
2636 return count;
2637}
2638
2639
2640TEST(ArrayBufferSharedBackingStore) {
2641 LocalContext env;
2642 v8::Isolate* isolate = env->GetIsolate();
2643 v8::HandleScope handle_scope(isolate);
2644 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2645
2646 v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2647 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2648 CHECK(!ab->IsExternal());
2649 v8::ArrayBuffer::Contents ab_contents = ab->Externalize();
2650 CHECK(ab->IsExternal());
2651
2652 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2653 void* data = ab_contents.Data();
2654 DCHECK(data != NULL);
2655 v8::Local<v8::ArrayBuffer> ab2 =
2656 v8::ArrayBuffer::New(isolate, data, ab_contents.ByteLength());
2657 CHECK(ab2->IsExternal());
2658 env->Global()->Set(v8_str("ab1"), ab);
2659 env->Global()->Set(v8_str("ab2"), ab2);
2660
2661 v8::Handle<v8::Value> result = CompileRun("ab2.byteLength");
2662 CHECK_EQ(1024, result->Int32Value());
2663
2664 const v8::HeapSnapshot* snapshot =
2665 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2666 CHECK(ValidateSnapshot(snapshot));
2667 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2668 const v8::HeapGraphNode* ab1_node =
2669 GetProperty(global, v8::HeapGraphEdge::kProperty, "ab1");
2670 CHECK_NE(NULL, ab1_node);
2671 const v8::HeapGraphNode* ab1_data =
2672 GetProperty(ab1_node, v8::HeapGraphEdge::kInternal, "backing_store");
2673 CHECK_NE(NULL, ab1_data);
2674 const v8::HeapGraphNode* ab2_node =
2675 GetProperty(global, v8::HeapGraphEdge::kProperty, "ab2");
2676 CHECK_NE(NULL, ab2_node);
2677 const v8::HeapGraphNode* ab2_data =
2678 GetProperty(ab2_node, v8::HeapGraphEdge::kInternal, "backing_store");
2679 CHECK_NE(NULL, ab2_data);
2680 CHECK_EQ(ab1_data, ab2_data);
2681 CHECK_EQ(2, GetRetainersCount(snapshot, ab1_data));
2682 free(data);
2683}
2684
2685
2686TEST(BoxObject) {
2687 v8::Isolate* isolate = CcTest::isolate();
2688 v8::HandleScope scope(isolate);
2689 LocalContext env;
2690 v8::Handle<v8::Object> global_proxy = env->Global();
2691 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2692
2693 i::Factory* factory = CcTest::i_isolate()->factory();
2694 i::Handle<i::String> string = factory->NewStringFromStaticChars("string");
2695 i::Handle<i::Object> box = factory->NewBox(string);
2696 global->Set(0, v8::ToApiHandle<v8::Object>(box));
2697
2698 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2699 const v8::HeapSnapshot* snapshot =
2700 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2701 CHECK(ValidateSnapshot(snapshot));
2702 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
2703 const v8::HeapGraphNode* box_node =
2704 GetProperty(global_node, v8::HeapGraphEdge::kElement, "0");
2705 CHECK_NE(NULL, box_node);
2706 v8::String::Utf8Value box_node_name(box_node->GetName());
2707 CHECK_EQ("system / Box", *box_node_name);
2708 const v8::HeapGraphNode* box_value =
2709 GetProperty(box_node, v8::HeapGraphEdge::kInternal, "value");
2710 CHECK_NE(NULL, box_value);
2711}
2712
2713
2714TEST(WeakContainers) {
2715 i::FLAG_allow_natives_syntax = true;
2716 LocalContext env;
2717 v8::HandleScope scope(env->GetIsolate());
2718 if (!CcTest::i_isolate()->use_crankshaft()) return;
2719 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2720 CompileRun(
2721 "function foo(a) { return a.x; }\n"
2722 "obj = {x : 123};\n"
2723 "foo(obj);\n"
2724 "foo(obj);\n"
2725 "%OptimizeFunctionOnNextCall(foo);\n"
2726 "foo(obj);\n");
2727 const v8::HeapSnapshot* snapshot =
2728 heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2729 CHECK(ValidateSnapshot(snapshot));
2730 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2731 const v8::HeapGraphNode* obj =
2732 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
2733 CHECK_NE(NULL, obj);
2734 const v8::HeapGraphNode* map =
2735 GetProperty(obj, v8::HeapGraphEdge::kInternal, "map");
2736 CHECK_NE(NULL, map);
2737 const v8::HeapGraphNode* dependent_code =
2738 GetProperty(map, v8::HeapGraphEdge::kInternal, "dependent_code");
2739 if (!dependent_code) return;
2740 int count = dependent_code->GetChildrenCount();
2741 CHECK_NE(0, count);
2742 for (int i = 0; i < count; ++i) {
2743 const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
2744 CHECK_EQ(v8::HeapGraphEdge::kWeak, prop->GetType());
2745 }
2746}
2747
2748
2749static inline i::Address ToAddress(int n) {
2750 return reinterpret_cast<i::Address>(n);
2751}
2752
2753
2754TEST(AddressToTraceMap) {
2755 i::AddressToTraceMap map;
2756
2757 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(150)));
2758
2759 // [0x100, 0x200) -> 1
2760 map.AddRange(ToAddress(0x100), 0x100, 1U);
2761 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x50)));
2762 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x100)));
2763 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x150)));
2764 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x100 + 0x100)));
2765 CHECK_EQ(1, static_cast<int>(map.size()));
2766
2767 // [0x100, 0x200) -> 1, [0x200, 0x300) -> 2
2768 map.AddRange(ToAddress(0x200), 0x100, 2U);
2769 CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x2a0)));
2770 CHECK_EQ(2, static_cast<int>(map.size()));
2771
2772 // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2
2773 map.AddRange(ToAddress(0x180), 0x100, 3U);
2774 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
2775 CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
2776 CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
2777 CHECK_EQ(3, static_cast<int>(map.size()));
2778
2779 // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2,
2780 // [0x400, 0x500) -> 4
2781 map.AddRange(ToAddress(0x400), 0x100, 4U);
2782 CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
2783 CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
2784 CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
2785 CHECK_EQ(4, map.GetTraceNodeId(ToAddress(0x450)));
2786 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x500)));
2787 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x350)));
2788 CHECK_EQ(4, static_cast<int>(map.size()));
2789
2790 // [0x100, 0x180) -> 1, [0x180, 0x200) -> 3, [0x200, 0x600) -> 5
2791 map.AddRange(ToAddress(0x200), 0x400, 5U);
2792 CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
2793 CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x400)));
2794 CHECK_EQ(3, static_cast<int>(map.size()));
2795
2796 // [0x100, 0x180) -> 1, [0x180, 0x200) -> 7, [0x200, 0x600) ->5
2797 map.AddRange(ToAddress(0x180), 0x80, 6U);
2798 map.AddRange(ToAddress(0x180), 0x80, 7U);
2799 CHECK_EQ(7, map.GetTraceNodeId(ToAddress(0x180)));
2800 CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
2801 CHECK_EQ(3, static_cast<int>(map.size()));
2802
2803 map.Clear();
2804 CHECK_EQ(0, static_cast<int>(map.size()));
2805 CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x400)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002806}