blob: 767c5cd4b4670d3231400ca268c5261eef401809 [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"
Ben Murdochda12d292016-06-02 14:46:10 +010035#include "src/collector.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036#include "src/debug/debug.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#include "src/hashmap.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038#include "src/profiler/allocation-tracker.h"
39#include "src/profiler/heap-profiler.h"
40#include "src/profiler/heap-snapshot-generator-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041#include "test/cctest/cctest.h"
42
43using i::AllocationTraceNode;
44using i::AllocationTraceTree;
45using i::AllocationTracker;
46using i::HashMap;
Ben Murdochc5610432016-08-08 18:44:38 +010047using i::ArrayVector;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048using i::Vector;
Steve Blocka7e24c12009-10-30 11:49:00 +000049
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010050namespace {
51
52class NamedEntriesDetector {
53 public:
54 NamedEntriesDetector()
Russell Brenner90bac252010-11-18 13:33:46 -080055 : has_A2(false), has_B2(false), has_C2(false) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010056 }
57
Ben Murdoch3ef787d2012-04-12 10:51:47 +010058 void CheckEntry(i::HeapEntry* entry) {
59 if (strcmp(entry->name(), "A2") == 0) has_A2 = true;
60 if (strcmp(entry->name(), "B2") == 0) has_B2 = true;
61 if (strcmp(entry->name(), "C2") == 0) has_C2 = true;
Iain Merrick75681382010-08-19 15:07:18 +010062 }
63
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 static bool AddressesMatch(void* key1, void* key2) {
65 return key1 == key2;
66 }
67
Ben Murdoch3ef787d2012-04-12 10:51:47 +010068 void CheckAllReachables(i::HeapEntry* root) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 i::HashMap visited(AddressesMatch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010070 i::List<i::HeapEntry*> list(10);
71 list.Add(root);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010072 CheckEntry(root);
73 while (!list.is_empty()) {
74 i::HeapEntry* entry = list.RemoveLast();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 i::Vector<i::HeapGraphEdge*> children = entry->children();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010076 for (int i = 0; i < children.length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue;
78 i::HeapEntry* child = children[i]->to();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 i::HashMap::Entry* entry = visited.LookupOrInsert(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 reinterpret_cast<void*>(child),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 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) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150 i::HashMap::Entry* entry = visited.LookupOrInsert(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151 reinterpret_cast<void*>(edges[i].to()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(edges[i].to())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 uint32_t ref_count = static_cast<uint32_t>(
154 reinterpret_cast<uintptr_t>(entry->value));
155 entry->value = reinterpret_cast<void*>(ref_count + 1);
156 }
157 uint32_t unretained_entries_count = 0;
158 i::List<i::HeapEntry>& entries = heap_snapshot->entries();
159 for (int i = 0; i < entries.length(); ++i) {
160 i::HashMap::Entry* entry = visited.Lookup(
161 reinterpret_cast<void*>(&entries[i]),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&entries[i])));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 if (!entry && entries[i].id() != 1) {
164 entries[i].Print("entry with no retainer", "", depth, 0);
165 ++unretained_entries_count;
166 }
167 }
168 return unretained_entries_count == 0;
169}
170
171
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100172TEST(HeapSnapshot) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100173 LocalContext env2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 v8::HandleScope scope(env2->GetIsolate());
175 v8::HeapProfiler* heap_profiler = env2->GetIsolate()->GetHeapProfiler();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100176
Ben Murdochf87a2032010-10-22 12:50:53 +0100177 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100178 "function A2() {}\n"
179 "function B2(x) { return function() { return typeof x; }; }\n"
180 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
181 "var a2 = new A2();\n"
182 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
183 "var c2 = new C2(a2);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 const v8::HeapSnapshot* snapshot_env2 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 CHECK(ValidateSnapshot(snapshot_env2));
Iain Merrick75681382010-08-19 15:07:18 +0100186 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
Iain Merrick75681382010-08-19 15:07:18 +0100187
Russell Brenner90bac252010-11-18 13:33:46 -0800188 // Verify, that JS global object of env2 has '..2' properties.
Iain Merrick75681382010-08-19 15:07:18 +0100189 const v8::HeapGraphNode* a2_node =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 CHECK(a2_node);
192 CHECK(GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1"));
193 CHECK(GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2"));
194 CHECK(GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2"));
Iain Merrick75681382010-08-19 15:07:18 +0100195
Iain Merrick75681382010-08-19 15:07:18 +0100196 NamedEntriesDetector det;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100197 det.CheckAllReachables(const_cast<i::HeapEntry*>(
198 reinterpret_cast<const i::HeapEntry*>(global_env2)));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100199 CHECK(det.has_A2);
200 CHECK(det.has_B2);
201 CHECK(det.has_C2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100202}
203
204
Iain Merrick75681382010-08-19 15:07:18 +0100205TEST(HeapSnapshotObjectSizes) {
Iain Merrick75681382010-08-19 15:07:18 +0100206 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 v8::HandleScope scope(env->GetIsolate());
208 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Iain Merrick75681382010-08-19 15:07:18 +0100209
210 // -a-> X1 --a
211 // x -b-> X2 <-|
Ben Murdochf87a2032010-10-22 12:50:53 +0100212 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100213 "function X(a, b) { this.a = a; this.b = b; }\n"
214 "x = new X(new X(), new X());\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 "dummy = new X();\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800216 "(function() { x.a.a = x.b; })();");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 CHECK(ValidateSnapshot(snapshot));
Iain Merrick75681382010-08-19 15:07:18 +0100219 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
220 const v8::HeapGraphNode* x =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 GetProperty(global, v8::HeapGraphEdge::kProperty, "x");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 CHECK(x);
Iain Merrick75681382010-08-19 15:07:18 +0100223 const v8::HeapGraphNode* x1 =
224 GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 CHECK(x1);
Iain Merrick75681382010-08-19 15:07:18 +0100226 const v8::HeapGraphNode* x2 =
227 GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 CHECK(x2);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800229
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 // Test sizes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 CHECK_NE(0, static_cast<int>(x->GetShallowSize()));
232 CHECK_NE(0, static_cast<int>(x1->GetShallowSize()));
233 CHECK_NE(0, static_cast<int>(x2->GetShallowSize()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100234}
235
236
237TEST(BoundFunctionInSnapshot) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100238 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 v8::HandleScope scope(env->GetIsolate());
240 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100241 CompileRun(
242 "function myFunction(a, b) { this.a = a; this.b = b; }\n"
243 "function AAAAA() {}\n"
244 "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100247 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
248 const v8::HeapGraphNode* f =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100250 CHECK(f);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 CHECK(v8_str("native_bind")->Equals(env.local(), f->GetName()).FromJust());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252 const v8::HeapGraphNode* bindings =
253 GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 CHECK(bindings);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100255 CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 CHECK_EQ(1, bindings->GetChildrenCount());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100257
258 const v8::HeapGraphNode* bound_this = GetProperty(
259 f, v8::HeapGraphEdge::kShortcut, "bound_this");
260 CHECK(bound_this);
261 CHECK_EQ(v8::HeapGraphNode::kObject, bound_this->GetType());
262
263 const v8::HeapGraphNode* bound_function = GetProperty(
264 f, v8::HeapGraphEdge::kShortcut, "bound_function");
265 CHECK(bound_function);
266 CHECK_EQ(v8::HeapGraphNode::kClosure, bound_function->GetType());
267
268 const v8::HeapGraphNode* bound_argument = GetProperty(
269 f, v8::HeapGraphEdge::kShortcut, "bound_argument_1");
270 CHECK(bound_argument);
271 CHECK_EQ(v8::HeapGraphNode::kObject, bound_argument->GetType());
Iain Merrick75681382010-08-19 15:07:18 +0100272}
273
274
275TEST(HeapSnapshotEntryChildren) {
Iain Merrick75681382010-08-19 15:07:18 +0100276 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 v8::HandleScope scope(env->GetIsolate());
278 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Iain Merrick75681382010-08-19 15:07:18 +0100279
Ben Murdochf87a2032010-10-22 12:50:53 +0100280 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100281 "function A() { }\n"
282 "a = new A;");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000283 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 CHECK(ValidateSnapshot(snapshot));
Iain Merrick75681382010-08-19 15:07:18 +0100285 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
286 for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
287 const v8::HeapGraphEdge* prop = global->GetChild(i);
288 CHECK_EQ(global, prop->GetFromNode());
289 }
290 const v8::HeapGraphNode* a =
291 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 CHECK(a);
Iain Merrick75681382010-08-19 15:07:18 +0100293 for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
294 const v8::HeapGraphEdge* prop = a->GetChild(i);
295 CHECK_EQ(a, prop->GetFromNode());
296 }
297}
298
299
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100300TEST(HeapSnapshotCodeObjects) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100301 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 v8::HandleScope scope(env->GetIsolate());
303 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100304
Ben Murdochf87a2032010-10-22 12:50:53 +0100305 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100306 "function lazy(x) { return x - 1; }\n"
307 "function compiled(x) { return x + 1; }\n"
Steve Block791712a2010-08-27 10:21:07 +0100308 "var anonymous = (function() { return function() { return 0; } })();\n"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100309 "compiled(1)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 CHECK(ValidateSnapshot(snapshot));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100312
313 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
314 const v8::HeapGraphNode* compiled =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 CHECK(compiled);
Iain Merrick75681382010-08-19 15:07:18 +0100317 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100318 const v8::HeapGraphNode* lazy =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 CHECK(lazy);
Iain Merrick75681382010-08-19 15:07:18 +0100321 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
Steve Block791712a2010-08-27 10:21:07 +0100322 const v8::HeapGraphNode* anonymous =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323 GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 CHECK(anonymous);
Steve Block791712a2010-08-27 10:21:07 +0100325 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 v8::String::Utf8Value anonymous_name(anonymous->GetName());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000327 CHECK_EQ(0, strcmp("", *anonymous_name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100328
329 // Find references to code.
330 const v8::HeapGraphNode* compiled_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100331 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 CHECK(compiled_code);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100333 const v8::HeapGraphNode* lazy_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100334 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335 CHECK(lazy_code);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100336
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 // Check that there's no strong next_code_link. There might be a weak one
338 // but might be not, so we can't check that fact.
339 const v8::HeapGraphNode* code =
340 GetProperty(compiled_code, v8::HeapGraphEdge::kInternal, "code");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 CHECK(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 const v8::HeapGraphNode* next_code_link =
343 GetProperty(code, v8::HeapGraphEdge::kInternal, "code");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 CHECK(!next_code_link);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100346 // Verify that non-compiled code doesn't contain references to "x"
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100347 // literal, while compiled code does. The scope info is stored in FixedArray
348 // objects attached to the SharedFunctionInfo.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100349 bool compiled_references_x = false, lazy_references_x = false;
350 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
351 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
352 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100353 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100354 if (HasString(node, "x")) {
355 compiled_references_x = true;
356 break;
357 }
358 }
359 }
360 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
361 const v8::HeapGraphEdge* prop = lazy_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 lazy_references_x = true;
366 break;
367 }
368 }
369 }
370 CHECK(compiled_references_x);
Ben Murdochda12d292016-06-02 14:46:10 +0100371 if (i::FLAG_lazy && !(i::FLAG_ignition && i::FLAG_ignition_eager)) {
372 CHECK(!lazy_references_x);
373 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100374}
375
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100376
Ben Murdochf87a2032010-10-22 12:50:53 +0100377TEST(HeapSnapshotHeapNumbers) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100378 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379 v8::HandleScope scope(env->GetIsolate());
380 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdochf87a2032010-10-22 12:50:53 +0100381 CompileRun(
382 "a = 1; // a is Smi\n"
383 "b = 2.5; // b is HeapNumber");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 CHECK(ValidateSnapshot(snapshot));
Ben Murdochf87a2032010-10-22 12:50:53 +0100386 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000387 CHECK(!GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100388 const v8::HeapGraphNode* b =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000389 GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 CHECK(b);
Ben Murdochf87a2032010-10-22 12:50:53 +0100391 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
392}
393
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100395TEST(HeapSnapshotSlicedString) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397 v8::HandleScope scope(env->GetIsolate());
398 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100399 CompileRun(
400 "parent_string = \"123456789.123456789.123456789.123456789.123456789."
401 "123456789.123456789.123456789.123456789.123456789."
402 "123456789.123456789.123456789.123456789.123456789."
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403 "123456789.123456789.123456789.123456789.123456789."
404 "123456789.123456789.123456789.123456789.123456789."
405 "123456789.123456789.123456789.123456789.123456789."
406 "123456789.123456789.123456789.123456789.123456789."
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100407 "123456789.123456789.123456789.123456789.123456789.\";"
408 "child_string = parent_string.slice(100);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100411 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
412 const v8::HeapGraphNode* parent_string =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413 GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 CHECK(parent_string);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100415 const v8::HeapGraphNode* child_string =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416 GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417 CHECK(child_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 CHECK_EQ(v8::HeapGraphNode::kSlicedString, child_string->GetType());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100419 const v8::HeapGraphNode* parent =
420 GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
421 CHECK_EQ(parent_string, parent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 heap_profiler->DeleteAllHeapSnapshots();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100423}
Ben Murdochf87a2032010-10-22 12:50:53 +0100424
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425
426TEST(HeapSnapshotConsString) {
427 v8::Isolate* isolate = CcTest::isolate();
428 v8::HandleScope scope(isolate);
429 v8::Local<v8::ObjectTemplate> global_template =
430 v8::ObjectTemplate::New(isolate);
431 global_template->SetInternalFieldCount(1);
432 LocalContext env(NULL, global_template);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433 v8::Local<v8::Object> global_proxy = env->Global();
434 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000435 CHECK_EQ(1, global->InternalFieldCount());
436
437 i::Factory* factory = CcTest::i_isolate()->factory();
438 i::Handle<i::String> first = factory->NewStringFromStaticChars("0123456789");
439 i::Handle<i::String> second = factory->NewStringFromStaticChars("0123456789");
440 i::Handle<i::String> cons_string =
441 factory->NewConsString(first, second).ToHandleChecked();
442
443 global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
444
445 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 CHECK(ValidateSnapshot(snapshot));
448 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
449
450 const v8::HeapGraphNode* string_node =
451 GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 CHECK(string_node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000453 CHECK_EQ(v8::HeapGraphNode::kConsString, string_node->GetType());
454
455 const v8::HeapGraphNode* first_node =
456 GetProperty(string_node, v8::HeapGraphEdge::kInternal, "first");
457 CHECK_EQ(v8::HeapGraphNode::kString, first_node->GetType());
458
459 const v8::HeapGraphNode* second_node =
460 GetProperty(string_node, v8::HeapGraphEdge::kInternal, "second");
461 CHECK_EQ(v8::HeapGraphNode::kString, second_node->GetType());
462
463 heap_profiler->DeleteAllHeapSnapshots();
464}
465
466
467TEST(HeapSnapshotSymbol) {
468 LocalContext env;
469 v8::HandleScope scope(env->GetIsolate());
470 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
471
472 CompileRun("a = Symbol('mySymbol');\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000474 CHECK(ValidateSnapshot(snapshot));
475 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
476 const v8::HeapGraphNode* a =
477 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 CHECK(a);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 CHECK_EQ(a->GetType(), v8::HeapGraphNode::kSymbol);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 CHECK(v8_str("symbol")->Equals(env.local(), a->GetName()).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 const v8::HeapGraphNode* name =
482 GetProperty(a, v8::HeapGraphEdge::kInternal, "name");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000483 CHECK(name);
484 CHECK(v8_str("mySymbol")->Equals(env.local(), name->GetName()).FromJust());
485}
486
487
488void CheckSimdSnapshot(const char* program, const char* var_name) {
489 i::FLAG_harmony_simd = true;
490 LocalContext env;
491 v8::HandleScope scope(env->GetIsolate());
492 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
493
494 CompileRun(program);
495 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
496 CHECK(ValidateSnapshot(snapshot));
497 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
498 const v8::HeapGraphNode* var =
499 GetProperty(global, v8::HeapGraphEdge::kProperty, var_name);
500 CHECK(var);
501 CHECK_EQ(var->GetType(), v8::HeapGraphNode::kSimdValue);
502}
503
504
505TEST(HeapSnapshotSimd) {
506 CheckSimdSnapshot("a = SIMD.Float32x4();\n", "a");
507 CheckSimdSnapshot("a = SIMD.Int32x4();\n", "a");
508 CheckSimdSnapshot("a = SIMD.Uint32x4();\n", "a");
509 CheckSimdSnapshot("a = SIMD.Bool32x4();\n", "a");
510 CheckSimdSnapshot("a = SIMD.Int16x8();\n", "a");
511 CheckSimdSnapshot("a = SIMD.Uint16x8();\n", "a");
512 CheckSimdSnapshot("a = SIMD.Bool16x8();\n", "a");
513 CheckSimdSnapshot("a = SIMD.Int8x16();\n", "a");
514 CheckSimdSnapshot("a = SIMD.Uint8x16();\n", "a");
515 CheckSimdSnapshot("a = SIMD.Bool8x16();\n", "a");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516}
517
518
519TEST(HeapSnapshotWeakCollection) {
520 LocalContext env;
521 v8::HandleScope scope(env->GetIsolate());
522 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
523
524 CompileRun(
525 "k = {}; v = {}; s = 'str';\n"
526 "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n"
527 "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 CHECK(ValidateSnapshot(snapshot));
530 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
531 const v8::HeapGraphNode* k =
532 GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 CHECK(k);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 const v8::HeapGraphNode* v =
535 GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 CHECK(v);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000537 const v8::HeapGraphNode* s =
538 GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539 CHECK(s);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000540
541 const v8::HeapGraphNode* ws =
542 GetProperty(global, v8::HeapGraphEdge::kProperty, "ws");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 CHECK(ws);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 CHECK_EQ(v8::HeapGraphNode::kObject, ws->GetType());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 CHECK(v8_str("WeakSet")->Equals(env.local(), ws->GetName()).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546
547 const v8::HeapGraphNode* ws_table =
548 GetProperty(ws, v8::HeapGraphEdge::kInternal, "table");
549 CHECK_EQ(v8::HeapGraphNode::kArray, ws_table->GetType());
550 CHECK_GT(ws_table->GetChildrenCount(), 0);
551 int weak_entries = 0;
552 for (int i = 0, count = ws_table->GetChildrenCount(); i < count; ++i) {
553 const v8::HeapGraphEdge* prop = ws_table->GetChild(i);
554 if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue;
555 if (k->GetId() == prop->GetToNode()->GetId()) {
556 ++weak_entries;
557 }
558 }
559 CHECK_EQ(1, weak_entries);
560 const v8::HeapGraphNode* ws_s =
561 GetProperty(ws, v8::HeapGraphEdge::kProperty, "str");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 CHECK(ws_s);
563 CHECK_EQ(s->GetId(), ws_s->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564
565 const v8::HeapGraphNode* wm =
566 GetProperty(global, v8::HeapGraphEdge::kProperty, "wm");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 CHECK(wm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000568 CHECK_EQ(v8::HeapGraphNode::kObject, wm->GetType());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 CHECK(v8_str("WeakMap")->Equals(env.local(), wm->GetName()).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570
571 const v8::HeapGraphNode* wm_table =
572 GetProperty(wm, v8::HeapGraphEdge::kInternal, "table");
573 CHECK_EQ(v8::HeapGraphNode::kArray, wm_table->GetType());
574 CHECK_GT(wm_table->GetChildrenCount(), 0);
575 weak_entries = 0;
576 for (int i = 0, count = wm_table->GetChildrenCount(); i < count; ++i) {
577 const v8::HeapGraphEdge* prop = wm_table->GetChild(i);
578 if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue;
579 const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
580 if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
581 ++weak_entries;
582 }
583 }
584 CHECK_EQ(2, weak_entries);
585 const v8::HeapGraphNode* wm_s =
586 GetProperty(wm, v8::HeapGraphEdge::kProperty, "str");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 CHECK(wm_s);
588 CHECK_EQ(s->GetId(), wm_s->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589}
590
591
592TEST(HeapSnapshotCollection) {
593 LocalContext env;
594 v8::HandleScope scope(env->GetIsolate());
595 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
596
597 CompileRun(
598 "k = {}; v = {}; s = 'str';\n"
599 "set = new Set(); set.add(k); set.add(v); set[s] = s;\n"
600 "map = new Map(); map.set(k, v); map[s] = s;\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 CHECK(ValidateSnapshot(snapshot));
603 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
604 const v8::HeapGraphNode* k =
605 GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000606 CHECK(k);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000607 const v8::HeapGraphNode* v =
608 GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 CHECK(v);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610 const v8::HeapGraphNode* s =
611 GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 CHECK(s);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613
614 const v8::HeapGraphNode* set =
615 GetProperty(global, v8::HeapGraphEdge::kProperty, "set");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616 CHECK(set);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000617 CHECK_EQ(v8::HeapGraphNode::kObject, set->GetType());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000618 CHECK(v8_str("Set")->Equals(env.local(), set->GetName()).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619
620 const v8::HeapGraphNode* set_table =
621 GetProperty(set, v8::HeapGraphEdge::kInternal, "table");
622 CHECK_EQ(v8::HeapGraphNode::kArray, set_table->GetType());
623 CHECK_GT(set_table->GetChildrenCount(), 0);
624 int entries = 0;
625 for (int i = 0, count = set_table->GetChildrenCount(); i < count; ++i) {
626 const v8::HeapGraphEdge* prop = set_table->GetChild(i);
627 const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
628 if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
629 ++entries;
630 }
631 }
632 CHECK_EQ(2, entries);
633 const v8::HeapGraphNode* set_s =
634 GetProperty(set, v8::HeapGraphEdge::kProperty, "str");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000635 CHECK(set_s);
636 CHECK_EQ(s->GetId(), set_s->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637
638 const v8::HeapGraphNode* map =
639 GetProperty(global, v8::HeapGraphEdge::kProperty, "map");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000640 CHECK(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641 CHECK_EQ(v8::HeapGraphNode::kObject, map->GetType());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642 CHECK(v8_str("Map")->Equals(env.local(), map->GetName()).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643
644 const v8::HeapGraphNode* map_table =
645 GetProperty(map, v8::HeapGraphEdge::kInternal, "table");
646 CHECK_EQ(v8::HeapGraphNode::kArray, map_table->GetType());
647 CHECK_GT(map_table->GetChildrenCount(), 0);
648 entries = 0;
649 for (int i = 0, count = map_table->GetChildrenCount(); i < count; ++i) {
650 const v8::HeapGraphEdge* prop = map_table->GetChild(i);
651 const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
652 if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
653 ++entries;
654 }
655 }
656 CHECK_EQ(2, entries);
657 const v8::HeapGraphNode* map_s =
658 GetProperty(map, v8::HeapGraphEdge::kProperty, "str");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659 CHECK(map_s);
660 CHECK_EQ(s->GetId(), map_s->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661}
662
663
Ben Murdochf87a2032010-10-22 12:50:53 +0100664TEST(HeapSnapshotInternalReferences) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 v8::Isolate* isolate = CcTest::isolate();
666 v8::HandleScope scope(isolate);
667 v8::Local<v8::ObjectTemplate> global_template =
668 v8::ObjectTemplate::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +0100669 global_template->SetInternalFieldCount(2);
670 LocalContext env(NULL, global_template);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 v8::Local<v8::Object> global_proxy = env->Global();
672 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
Ben Murdochf87a2032010-10-22 12:50:53 +0100673 CHECK_EQ(2, global->InternalFieldCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 v8::Local<v8::Object> obj = v8::Object::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +0100675 global->SetInternalField(0, v8_num(17));
676 global->SetInternalField(1, obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000678 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679 CHECK(ValidateSnapshot(snapshot));
Ben Murdochf87a2032010-10-22 12:50:53 +0100680 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
681 // The first reference will not present, because it's a Smi.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682 CHECK(!GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100683 // The second reference is to an object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000684 CHECK(GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100685}
686
687
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688TEST(HeapSnapshotAddressReuse) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100689 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 v8::HandleScope scope(env->GetIsolate());
691 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
692
693 CompileRun(
694 "function A() {}\n"
695 "var a = [];\n"
696 "for (var i = 0; i < 10000; ++i)\n"
697 " a[i] = new A();\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000699 CHECK(ValidateSnapshot(snapshot1));
700 v8::SnapshotObjectId maxId1 = snapshot1->GetMaxSnapshotJSObjectId();
701
702 CompileRun(
703 "for (var i = 0; i < 10000; ++i)\n"
704 " a[i] = new A();\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705 CcTest::heap()->CollectAllGarbage();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000707 const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708 CHECK(ValidateSnapshot(snapshot2));
709 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
710
711 const v8::HeapGraphNode* array_node =
712 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713 CHECK(array_node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000714 int wrong_count = 0;
715 for (int i = 0, count = array_node->GetChildrenCount(); i < count; ++i) {
716 const v8::HeapGraphEdge* prop = array_node->GetChild(i);
717 if (prop->GetType() != v8::HeapGraphEdge::kElement)
718 continue;
719 v8::SnapshotObjectId id = prop->GetToNode()->GetId();
720 if (id < maxId1)
721 ++wrong_count;
722 }
723 CHECK_EQ(0, wrong_count);
724}
725
726
727TEST(HeapEntryIdsAndArrayShift) {
728 LocalContext env;
729 v8::HandleScope scope(env->GetIsolate());
730 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100731
732 CompileRun(
733 "function AnObject() {\n"
734 " this.first = 'first';\n"
735 " this.second = 'second';\n"
736 "}\n"
737 "var a = new Array();\n"
738 "for (var i = 0; i < 10; ++i)\n"
739 " a.push(new AnObject());\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000740 const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000741 CHECK(ValidateSnapshot(snapshot1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100742
743 CompileRun(
744 "for (var i = 0; i < 1; ++i)\n"
745 " a.shift();\n");
746
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747 CcTest::heap()->CollectAllGarbage();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100748
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000750 CHECK(ValidateSnapshot(snapshot2));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100751
752 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
753 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 CHECK_NE(0u, global1->GetId());
755 CHECK_EQ(global1->GetId(), global2->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100756
757 const v8::HeapGraphNode* a1 =
758 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759 CHECK(a1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100760 const v8::HeapGraphNode* k1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000762 CHECK(k1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100763 const v8::HeapGraphNode* a2 =
764 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765 CHECK(a2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100766 const v8::HeapGraphNode* k2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767 GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 CHECK(k2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100769
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 CHECK_EQ(a1->GetId(), a2->GetId());
771 CHECK_EQ(k1->GetId(), k2->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100772}
773
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100775TEST(HeapEntryIdsAndGC) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100776 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 v8::HandleScope scope(env->GetIsolate());
778 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100779
Ben Murdochf87a2032010-10-22 12:50:53 +0100780 CompileRun(
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100781 "function A() {}\n"
782 "function B(x) { this.x = x; }\n"
783 "var a = new A();\n"
784 "var b = new B(a);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 CHECK(ValidateSnapshot(snapshot1));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100787
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 CcTest::heap()->CollectAllGarbage();
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100789
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790 const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000791 CHECK(ValidateSnapshot(snapshot2));
792
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794 CHECK(snapshot1->GetMaxSnapshotJSObjectId() <=
795 snapshot2->GetMaxSnapshotJSObjectId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100796
797 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
798 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000799 CHECK_NE(0u, global1->GetId());
800 CHECK_EQ(global1->GetId(), global2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100801 const v8::HeapGraphNode* A1 =
Iain Merrick75681382010-08-19 15:07:18 +0100802 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000803 CHECK(A1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100804 const v8::HeapGraphNode* A2 =
Iain Merrick75681382010-08-19 15:07:18 +0100805 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 CHECK(A2);
807 CHECK_NE(0u, A1->GetId());
808 CHECK_EQ(A1->GetId(), A2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100809 const v8::HeapGraphNode* B1 =
Iain Merrick75681382010-08-19 15:07:18 +0100810 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 CHECK(B1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100812 const v8::HeapGraphNode* B2 =
Iain Merrick75681382010-08-19 15:07:18 +0100813 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000814 CHECK(B2);
815 CHECK_NE(0u, B1->GetId());
816 CHECK_EQ(B1->GetId(), B2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100817 const v8::HeapGraphNode* a1 =
Iain Merrick75681382010-08-19 15:07:18 +0100818 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 CHECK(a1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100820 const v8::HeapGraphNode* a2 =
Iain Merrick75681382010-08-19 15:07:18 +0100821 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 CHECK(a2);
823 CHECK_NE(0u, a1->GetId());
824 CHECK_EQ(a1->GetId(), a2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100825 const v8::HeapGraphNode* b1 =
Iain Merrick75681382010-08-19 15:07:18 +0100826 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000827 CHECK(b1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100828 const v8::HeapGraphNode* b2 =
Iain Merrick75681382010-08-19 15:07:18 +0100829 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830 CHECK(b2);
831 CHECK_NE(0u, b1->GetId());
832 CHECK_EQ(b1->GetId(), b2->GetId());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100833}
834
835
Ben Murdochf87a2032010-10-22 12:50:53 +0100836TEST(HeapSnapshotRootPreservedAfterSorting) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100837 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838 v8::HandleScope scope(env->GetIsolate());
839 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000840 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000841 CHECK(ValidateSnapshot(snapshot));
Ben Murdochf87a2032010-10-22 12:50:53 +0100842 const v8::HeapGraphNode* root1 = snapshot->GetRoot();
843 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
844 snapshot))->GetSortedEntriesList();
845 const v8::HeapGraphNode* root2 = snapshot->GetRoot();
846 CHECK_EQ(root1, root2);
847}
848
849
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100850namespace {
851
852class TestJSONStream : public v8::OutputStream {
853 public:
854 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
855 explicit TestJSONStream(int abort_countdown)
856 : eos_signaled_(0), abort_countdown_(abort_countdown) {}
857 virtual ~TestJSONStream() {}
858 virtual void EndOfStream() { ++eos_signaled_; }
859 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
860 if (abort_countdown_ > 0) --abort_countdown_;
861 if (abort_countdown_ == 0) return kAbort;
862 CHECK_GT(chars_written, 0);
863 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000864 i::MemCopy(chunk.start(), buffer, chars_written);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100865 return kContinue;
866 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867 virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000868 CHECK(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869 return kAbort;
870 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100871 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
872 int eos_signaled() { return eos_signaled_; }
873 int size() { return buffer_.size(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100875 private:
876 i::Collector<char> buffer_;
877 int eos_signaled_;
878 int abort_countdown_;
879};
880
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000881class OneByteResource : public v8::String::ExternalOneByteStringResource {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100882 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000883 explicit OneByteResource(i::Vector<char> string) : data_(string.start()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100884 length_ = string.length();
885 }
886 virtual const char* data() const { return data_; }
887 virtual size_t length() const { return length_; }
888 private:
889 const char* data_;
890 size_t length_;
891};
892
893} // namespace
894
895TEST(HeapSnapshotJSONSerialization) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400896 v8::Isolate* isolate = CcTest::isolate();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100897 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400898 v8::HandleScope scope(isolate);
899 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100900
901#define STRING_LITERAL_FOR_TEST \
902 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
Ben Murdochf87a2032010-10-22 12:50:53 +0100903 CompileRun(
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100904 "function A(s) { this.s = s; }\n"
905 "function B(x) { this.x = x; }\n"
906 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
907 "var b = new B(a);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000909 CHECK(ValidateSnapshot(snapshot));
910
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100911 TestJSONStream stream;
912 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
913 CHECK_GT(stream.size(), 0);
914 CHECK_EQ(1, stream.eos_signaled());
915 i::ScopedVector<char> json(stream.size());
916 stream.WriteTo(json);
917
918 // Verify that snapshot string is valid JSON.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000919 OneByteResource* json_res = new OneByteResource(json);
920 v8::Local<v8::String> json_string =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921 v8::String::NewExternalOneByte(env->GetIsolate(), json_res)
922 .ToLocalChecked();
923 env->Global()
924 ->Set(env.local(), v8_str("json_snapshot"), json_string)
925 .FromJust();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100926 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
927 "var parsed = JSON.parse(json_snapshot); true;");
928 CHECK(!snapshot_parse_result.IsEmpty());
929
930 // Verify that snapshot object has required fields.
931 v8::Local<v8::Object> parsed_snapshot =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000932 env->Global()
933 ->Get(env.local(), v8_str("parsed"))
934 .ToLocalChecked()
935 ->ToObject(env.local())
936 .ToLocalChecked();
937 CHECK(parsed_snapshot->Has(env.local(), v8_str("snapshot")).FromJust());
938 CHECK(parsed_snapshot->Has(env.local(), v8_str("nodes")).FromJust());
939 CHECK(parsed_snapshot->Has(env.local(), v8_str("edges")).FromJust());
940 CHECK(parsed_snapshot->Has(env.local(), v8_str("strings")).FromJust());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100941
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100942 // Get node and edge "member" offsets.
943 v8::Local<v8::Value> meta_analysis_result = CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 "var meta = parsed.snapshot.meta;\n"
945 "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n"
946 "var node_fields_count = meta.node_fields.length;\n"
947 "var edge_fields_count = meta.edge_fields.length;\n"
948 "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
949 "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n"
950 "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100951 "var property_type ="
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952 " meta.edge_types[edge_type_offset].indexOf('property');\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800953 "var shortcut_type ="
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000954 " meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
955 "var node_count = parsed.nodes.length / node_fields_count;\n"
956 "var first_edge_indexes = parsed.first_edge_indexes = [];\n"
957 "for (var i = 0, first_edge_index = 0; i < node_count; ++i) {\n"
958 " first_edge_indexes[i] = first_edge_index;\n"
959 " first_edge_index += edge_fields_count *\n"
960 " parsed.nodes[i * node_fields_count + edge_count_offset];\n"
961 "}\n"
962 "first_edge_indexes[node_count] = first_edge_index;\n");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100963 CHECK(!meta_analysis_result.IsEmpty());
964
965 // A helper function for processing encoded nodes.
966 CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800967 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100968 " var nodes = parsed.nodes;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969 " var edges = parsed.edges;\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100970 " var strings = parsed.strings;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000971 " var node_ordinal = pos / node_fields_count;\n"
972 " for (var i = parsed.first_edge_indexes[node_ordinal],\n"
973 " count = parsed.first_edge_indexes[node_ordinal + 1];\n"
974 " i < count; i += edge_fields_count) {\n"
975 " if (edges[i + edge_type_offset] === prop_type\n"
976 " && strings[edges[i + edge_name_offset]] === prop_name)\n"
977 " return edges[i + edge_to_node_offset];\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100978 " }\n"
979 " return null;\n"
980 "}\n");
981 // Get the string index using the path: <root> -> <global>.b.x.s
982 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
983 "GetChildPosByProperty(\n"
984 " GetChildPosByProperty(\n"
985 " GetChildPosByProperty("
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986 " parsed.edges[edge_fields_count + edge_to_node_offset],"
987 " \"b\", property_type),\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800988 " \"x\", property_type),"
989 " \"s\", property_type)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100990 CHECK(!string_obj_pos_val.IsEmpty());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000991 int string_obj_pos = static_cast<int>(
992 string_obj_pos_val->ToNumber(env.local()).ToLocalChecked()->Value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100993 v8::Local<v8::Object> nodes_array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000994 parsed_snapshot->Get(env.local(), v8_str("nodes"))
995 .ToLocalChecked()
996 ->ToObject(env.local())
997 .ToLocalChecked();
998 int string_index =
999 static_cast<int>(nodes_array->Get(env.local(), string_obj_pos + 1)
1000 .ToLocalChecked()
1001 ->ToNumber(env.local())
1002 .ToLocalChecked()
1003 ->Value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001004 CHECK_GT(string_index, 0);
1005 v8::Local<v8::Object> strings_array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001006 parsed_snapshot->Get(env.local(), v8_str("strings"))
1007 .ToLocalChecked()
1008 ->ToObject(env.local())
1009 .ToLocalChecked();
1010 v8::Local<v8::String> string = strings_array->Get(env.local(), string_index)
1011 .ToLocalChecked()
1012 ->ToString(env.local())
1013 .ToLocalChecked();
1014 v8::Local<v8::String> ref_string = CompileRun(STRING_LITERAL_FOR_TEST)
1015 ->ToString(env.local())
1016 .ToLocalChecked();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001017#undef STRING_LITERAL_FOR_TEST
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(ref_string),
1019 *v8::String::Utf8Value(string)));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001020}
1021
1022
1023TEST(HeapSnapshotJSONSerializationAborting) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001024 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001025 v8::HandleScope scope(env->GetIsolate());
1026 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001027 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001028 CHECK(ValidateSnapshot(snapshot));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001029 TestJSONStream stream(5);
1030 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1031 CHECK_GT(stream.size(), 0);
1032 CHECK_EQ(0, stream.eos_signaled());
1033}
1034
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001035namespace {
1036
1037class TestStatsStream : public v8::OutputStream {
1038 public:
1039 TestStatsStream()
1040 : eos_signaled_(0),
1041 updates_written_(0),
1042 entries_count_(0),
1043 entries_size_(0),
1044 intervals_count_(0),
1045 first_interval_index_(-1) { }
1046 TestStatsStream(const TestStatsStream& stream)
1047 : v8::OutputStream(stream),
1048 eos_signaled_(stream.eos_signaled_),
1049 updates_written_(stream.updates_written_),
1050 entries_count_(stream.entries_count_),
1051 entries_size_(stream.entries_size_),
1052 intervals_count_(stream.intervals_count_),
1053 first_interval_index_(stream.first_interval_index_) { }
1054 virtual ~TestStatsStream() {}
1055 virtual void EndOfStream() { ++eos_signaled_; }
1056 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001057 CHECK(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001058 return kAbort;
1059 }
1060 virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
1061 int updates_written) {
1062 ++intervals_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063 CHECK(updates_written);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064 updates_written_ += updates_written;
1065 entries_count_ = 0;
1066 if (first_interval_index_ == -1 && updates_written != 0)
1067 first_interval_index_ = buffer[0].index;
1068 for (int i = 0; i < updates_written; ++i) {
1069 entries_count_ += buffer[i].count;
1070 entries_size_ += buffer[i].size;
1071 }
1072
1073 return kContinue;
1074 }
1075 int eos_signaled() { return eos_signaled_; }
1076 int updates_written() { return updates_written_; }
1077 uint32_t entries_count() const { return entries_count_; }
1078 uint32_t entries_size() const { return entries_size_; }
1079 int intervals_count() const { return intervals_count_; }
1080 int first_interval_index() const { return first_interval_index_; }
1081
1082 private:
1083 int eos_signaled_;
1084 int updates_written_;
1085 uint32_t entries_count_;
1086 uint32_t entries_size_;
1087 int intervals_count_;
1088 int first_interval_index_;
1089};
1090
1091} // namespace
1092
1093static TestStatsStream GetHeapStatsUpdate(
1094 v8::HeapProfiler* heap_profiler,
1095 v8::SnapshotObjectId* object_id = NULL) {
1096 TestStatsStream stream;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001097 int64_t timestamp = -1;
1098 v8::SnapshotObjectId last_seen_id =
1099 heap_profiler->GetHeapStats(&stream, &timestamp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001100 if (object_id)
1101 *object_id = last_seen_id;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102 CHECK_NE(-1, timestamp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 CHECK_EQ(1, stream.eos_signaled());
1104 return stream;
1105}
1106
1107
1108TEST(HeapSnapshotObjectsStats) {
1109 LocalContext env;
1110 v8::HandleScope scope(env->GetIsolate());
1111 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1112
1113 heap_profiler->StartTrackingHeapObjects();
1114 // We have to call GC 6 times. In other case the garbage will be
1115 // the reason of flakiness.
1116 for (int i = 0; i < 6; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001117 CcTest::heap()->CollectAllGarbage();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118 }
1119
1120 v8::SnapshotObjectId initial_id;
1121 {
1122 // Single chunk of data expected in update. Initial data.
1123 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
1124 &initial_id);
1125 CHECK_EQ(1, stats_update.intervals_count());
1126 CHECK_EQ(1, stats_update.updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001127 CHECK_LT(0u, stats_update.entries_size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001128 CHECK_EQ(0, stats_update.first_interval_index());
1129 }
1130
1131 // No data expected in update because nothing has happened.
1132 v8::SnapshotObjectId same_id;
1133 CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &same_id).updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001134 CHECK_EQ(initial_id, same_id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001135
1136 {
1137 v8::SnapshotObjectId additional_string_id;
1138 v8::HandleScope inner_scope_1(env->GetIsolate());
1139 v8_str("string1");
1140 {
1141 // Single chunk of data with one new entry expected in update.
1142 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
1143 &additional_string_id);
1144 CHECK_LT(same_id, additional_string_id);
1145 CHECK_EQ(1, stats_update.intervals_count());
1146 CHECK_EQ(1, stats_update.updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001147 CHECK_LT(0u, stats_update.entries_size());
1148 CHECK_EQ(1u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001149 CHECK_EQ(2, stats_update.first_interval_index());
1150 }
1151
1152 // No data expected in update because nothing happened.
1153 v8::SnapshotObjectId last_id;
1154 CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &last_id).updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155 CHECK_EQ(additional_string_id, last_id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156
1157 {
1158 v8::HandleScope inner_scope_2(env->GetIsolate());
1159 v8_str("string2");
1160
1161 uint32_t entries_size;
1162 {
1163 v8::HandleScope inner_scope_3(env->GetIsolate());
1164 v8_str("string3");
1165 v8_str("string4");
1166
1167 {
1168 // Single chunk of data with three new entries expected in update.
1169 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1170 CHECK_EQ(1, stats_update.intervals_count());
1171 CHECK_EQ(1, stats_update.updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001172 CHECK_LT(0u, entries_size = stats_update.entries_size());
1173 CHECK_EQ(3u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001174 CHECK_EQ(4, stats_update.first_interval_index());
1175 }
1176 }
1177
1178 {
1179 // Single chunk of data with two left entries expected in update.
1180 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1181 CHECK_EQ(1, stats_update.intervals_count());
1182 CHECK_EQ(1, stats_update.updates_written());
1183 CHECK_GT(entries_size, stats_update.entries_size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001184 CHECK_EQ(1u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001185 // Two strings from forth interval were released.
1186 CHECK_EQ(4, stats_update.first_interval_index());
1187 }
1188 }
1189
1190 {
1191 // Single chunk of data with 0 left entries expected in update.
1192 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1193 CHECK_EQ(1, stats_update.intervals_count());
1194 CHECK_EQ(1, stats_update.updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 CHECK_EQ(0u, stats_update.entries_size());
1196 CHECK_EQ(0u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001197 // The last string from forth interval was released.
1198 CHECK_EQ(4, stats_update.first_interval_index());
1199 }
1200 }
1201 {
1202 // Single chunk of data with 0 left entries expected in update.
1203 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1204 CHECK_EQ(1, stats_update.intervals_count());
1205 CHECK_EQ(1, stats_update.updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206 CHECK_EQ(0u, stats_update.entries_size());
1207 CHECK_EQ(0u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208 // The only string from the second interval was released.
1209 CHECK_EQ(2, stats_update.first_interval_index());
1210 }
1211
1212 v8::Local<v8::Array> array = v8::Array::New(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001213 CHECK_EQ(0u, array->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 // Force array's buffer allocation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001215 array->Set(env.local(), 2, v8_num(7)).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001216
1217 uint32_t entries_size;
1218 {
1219 // Single chunk of data with 2 entries expected in update.
1220 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1221 CHECK_EQ(1, stats_update.intervals_count());
1222 CHECK_EQ(1, stats_update.updates_written());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 CHECK_LT(0u, entries_size = stats_update.entries_size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001224 // They are the array and its buffer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001225 CHECK_EQ(2u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226 CHECK_EQ(8, stats_update.first_interval_index());
1227 }
1228
1229 for (int i = 0; i < 100; ++i)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230 array->Set(env.local(), i, v8_num(i)).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231
1232 {
1233 // Single chunk of data with 1 entry expected in update.
1234 TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1235 CHECK_EQ(1, stats_update.intervals_count());
1236 // The first interval was changed because old buffer was collected.
1237 // The second interval was changed because new buffer was allocated.
1238 CHECK_EQ(2, stats_update.updates_written());
1239 CHECK_LT(entries_size, stats_update.entries_size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 CHECK_EQ(2u, stats_update.entries_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241 CHECK_EQ(8, stats_update.first_interval_index());
1242 }
1243
1244 heap_profiler->StopTrackingHeapObjects();
1245}
1246
1247
1248TEST(HeapObjectIds) {
1249 LocalContext env;
1250 v8::Isolate* isolate = env->GetIsolate();
1251 v8::HandleScope scope(isolate);
1252 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1253
1254 const int kLength = 10;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255 v8::Local<v8::Object> objects[kLength];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256 v8::SnapshotObjectId ids[kLength];
1257
1258 heap_profiler->StartTrackingHeapObjects(false);
1259
1260 for (int i = 0; i < kLength; i++) {
1261 objects[i] = v8::Object::New(isolate);
1262 }
1263 GetHeapStatsUpdate(heap_profiler);
1264
1265 for (int i = 0; i < kLength; i++) {
1266 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001267 CHECK_NE(v8::HeapProfiler::kUnknownObjectId, id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268 ids[i] = id;
1269 }
1270
1271 heap_profiler->StopTrackingHeapObjects();
1272 CcTest::heap()->CollectAllAvailableGarbage();
1273
1274 for (int i = 0; i < kLength; i++) {
1275 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001276 CHECK_EQ(ids[i], id);
1277 v8::Local<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1278 CHECK(objects[i]->Equals(env.local(), obj).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001279 }
1280
1281 heap_profiler->ClearObjectIds();
1282 for (int i = 0; i < kLength; i++) {
1283 v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001284 CHECK_EQ(v8::HeapProfiler::kUnknownObjectId, id);
1285 v8::Local<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001286 CHECK(obj.IsEmpty());
1287 }
1288}
1289
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001290
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001291static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
1292 const v8::HeapGraphNode* node,
1293 int level, int max_level) {
1294 if (level > max_level) return;
1295 CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
1296 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
1297 const v8::HeapGraphEdge* prop = node->GetChild(i);
1298 const v8::HeapGraphNode* child =
1299 snapshot->GetNodeById(prop->GetToNode()->GetId());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001300 CHECK_EQ(prop->GetToNode()->GetId(), child->GetId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001301 CHECK_EQ(prop->GetToNode(), child);
1302 CheckChildrenIds(snapshot, child, level + 1, max_level);
1303 }
1304}
1305
1306
Ben Murdochb0fe1622011-05-05 13:52:32 +01001307TEST(HeapSnapshotGetNodeById) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001308 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001309 v8::HandleScope scope(env->GetIsolate());
1310 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001311
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001313 CHECK(ValidateSnapshot(snapshot));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001314 const v8::HeapGraphNode* root = snapshot->GetRoot();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001315 CheckChildrenIds(snapshot, root, 0, 3);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001316 // Check a big id, which should not exist yet.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001317 CHECK(!snapshot->GetNodeById(0x1000000UL));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001318}
1319
1320
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001321TEST(HeapSnapshotGetSnapshotObjectId) {
1322 LocalContext env;
1323 v8::HandleScope scope(env->GetIsolate());
1324 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1325 CompileRun("globalObject = {};\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 CHECK(ValidateSnapshot(snapshot));
1328 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1329 const v8::HeapGraphNode* global_object =
1330 GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject");
1331 CHECK(global_object);
1332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001333 v8::Local<v8::Value> globalObjectHandle =
1334 env->Global()->Get(env.local(), v8_str("globalObject")).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001335 CHECK(!globalObjectHandle.IsEmpty());
1336 CHECK(globalObjectHandle->IsObject());
1337
1338 v8::SnapshotObjectId id = heap_profiler->GetObjectId(globalObjectHandle);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001339 CHECK_NE(v8::HeapProfiler::kUnknownObjectId, id);
1340 CHECK_EQ(id, global_object->GetId());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341}
1342
1343
1344TEST(HeapSnapshotUnknownSnapshotObjectId) {
1345 LocalContext env;
1346 v8::HandleScope scope(env->GetIsolate());
1347 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1348 CompileRun("globalObject = {};\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 CHECK(ValidateSnapshot(snapshot));
1351 const v8::HeapGraphNode* node =
1352 snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 CHECK(!node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354}
1355
1356
Ben Murdochb0fe1622011-05-05 13:52:32 +01001357namespace {
1358
1359class TestActivityControl : public v8::ActivityControl {
1360 public:
1361 explicit TestActivityControl(int abort_count)
1362 : done_(0), total_(0), abort_count_(abort_count) {}
1363 ControlOption ReportProgressValue(int done, int total) {
1364 done_ = done;
1365 total_ = total;
1366 return --abort_count_ != 0 ? kContinue : kAbort;
1367 }
1368 int done() { return done_; }
1369 int total() { return total_; }
1370
1371 private:
1372 int done_;
1373 int total_;
1374 int abort_count_;
1375};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376
1377} // namespace
Ben Murdochb0fe1622011-05-05 13:52:32 +01001378
Ben Murdochb0fe1622011-05-05 13:52:32 +01001379
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380TEST(TakeHeapSnapshotAborting) {
1381 LocalContext env;
1382 v8::HandleScope scope(env->GetIsolate());
1383
1384 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1385 const int snapshots_count = heap_profiler->GetSnapshotCount();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001386 TestActivityControl aborting_control(1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001387 const v8::HeapSnapshot* no_snapshot =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 heap_profiler->TakeHeapSnapshot(&aborting_control);
1389 CHECK(!no_snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390 CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001391 CHECK_GT(aborting_control.total(), aborting_control.done());
1392
1393 TestActivityControl control(-1); // Don't abort.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(&control);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 CHECK(ValidateSnapshot(snapshot));
1396
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 CHECK(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 CHECK_EQ(snapshots_count + 1, heap_profiler->GetSnapshotCount());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001399 CHECK_EQ(control.total(), control.done());
1400 CHECK_GT(control.total(), 0);
1401}
1402
Steve Block44f0eee2011-05-26 01:26:41 +01001403
1404namespace {
1405
1406class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
1407 public:
1408 TestRetainedObjectInfo(int hash,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001409 const char* group_label,
Steve Block44f0eee2011-05-26 01:26:41 +01001410 const char* label,
1411 intptr_t element_count = -1,
1412 intptr_t size = -1)
1413 : disposed_(false),
1414 hash_(hash),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001415 group_label_(group_label),
Steve Block44f0eee2011-05-26 01:26:41 +01001416 label_(label),
1417 element_count_(element_count),
1418 size_(size) {
1419 instances.Add(this);
1420 }
1421 virtual ~TestRetainedObjectInfo() {}
1422 virtual void Dispose() {
1423 CHECK(!disposed_);
1424 disposed_ = true;
1425 }
1426 virtual bool IsEquivalent(RetainedObjectInfo* other) {
1427 return GetHash() == other->GetHash();
1428 }
1429 virtual intptr_t GetHash() { return hash_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001430 virtual const char* GetGroupLabel() { return group_label_; }
Steve Block44f0eee2011-05-26 01:26:41 +01001431 virtual const char* GetLabel() { return label_; }
1432 virtual intptr_t GetElementCount() { return element_count_; }
1433 virtual intptr_t GetSizeInBytes() { return size_; }
1434 bool disposed() { return disposed_; }
1435
1436 static v8::RetainedObjectInfo* WrapperInfoCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001437 uint16_t class_id, v8::Local<v8::Value> wrapper) {
Steve Block44f0eee2011-05-26 01:26:41 +01001438 if (class_id == 1) {
1439 if (wrapper->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440 v8::String::Utf8Value utf8(wrapper);
1441 if (strcmp(*utf8, "AAA") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001442 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 else if (strcmp(*utf8, "BBB") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001444 return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
Steve Block44f0eee2011-05-26 01:26:41 +01001445 }
1446 } else if (class_id == 2) {
1447 if (wrapper->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448 v8::String::Utf8Value utf8(wrapper);
1449 if (strcmp(*utf8, "CCC") == 0)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001450 return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
Steve Block44f0eee2011-05-26 01:26:41 +01001451 }
1452 }
1453 CHECK(false);
1454 return NULL;
1455 }
1456
1457 static i::List<TestRetainedObjectInfo*> instances;
1458
1459 private:
1460 bool disposed_;
Steve Block44f0eee2011-05-26 01:26:41 +01001461 int hash_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001462 const char* group_label_;
Steve Block44f0eee2011-05-26 01:26:41 +01001463 const char* label_;
1464 intptr_t element_count_;
1465 intptr_t size_;
1466};
1467
1468
1469i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001470
1471} // namespace
Steve Block44f0eee2011-05-26 01:26:41 +01001472
1473
1474static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1475 v8::HeapGraphNode::Type type,
1476 const char* name) {
1477 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1478 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1479 if (node->GetType() == type && strcmp(name,
1480 const_cast<i::HeapEntry*>(
1481 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1482 return node;
1483 }
1484 }
1485 return NULL;
1486}
1487
1488
1489TEST(HeapSnapshotRetainedObjectInfo) {
Steve Block44f0eee2011-05-26 01:26:41 +01001490 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491 v8::Isolate* isolate = env->GetIsolate();
1492 v8::HandleScope scope(isolate);
1493 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001494
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001495 heap_profiler->SetWrapperClassInfoProvider(
Steve Block44f0eee2011-05-26 01:26:41 +01001496 1, TestRetainedObjectInfo::WrapperInfoCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001497 heap_profiler->SetWrapperClassInfoProvider(
Steve Block44f0eee2011-05-26 01:26:41 +01001498 2, TestRetainedObjectInfo::WrapperInfoCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001499 v8::Persistent<v8::String> p_AAA(isolate, v8_str("AAA"));
Steve Block44f0eee2011-05-26 01:26:41 +01001500 p_AAA.SetWrapperClassId(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001501 v8::Persistent<v8::String> p_BBB(isolate, v8_str("BBB"));
Steve Block44f0eee2011-05-26 01:26:41 +01001502 p_BBB.SetWrapperClassId(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 v8::Persistent<v8::String> p_CCC(isolate, v8_str("CCC"));
Steve Block44f0eee2011-05-26 01:26:41 +01001504 p_CCC.SetWrapperClassId(2);
1505 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507 CHECK(ValidateSnapshot(snapshot));
Steve Block44f0eee2011-05-26 01:26:41 +01001508
1509 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1510 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1511 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1512 delete TestRetainedObjectInfo::instances[i];
1513 }
1514
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001515 const v8::HeapGraphNode* native_group_aaa = GetNode(
1516 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "aaa-group");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001517 CHECK(native_group_aaa);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001518 CHECK_EQ(1, native_group_aaa->GetChildrenCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001519 const v8::HeapGraphNode* aaa = GetNode(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001520 native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 CHECK(aaa);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001522 CHECK_EQ(2, aaa->GetChildrenCount());
1523
1524 const v8::HeapGraphNode* native_group_ccc = GetNode(
1525 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "ccc-group");
Steve Block44f0eee2011-05-26 01:26:41 +01001526 const v8::HeapGraphNode* ccc = GetNode(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001527 native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001528 CHECK(ccc);
Steve Block44f0eee2011-05-26 01:26:41 +01001529
Steve Block44f0eee2011-05-26 01:26:41 +01001530 const v8::HeapGraphNode* n_AAA = GetNode(
1531 aaa, v8::HeapGraphNode::kString, "AAA");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001532 CHECK(n_AAA);
Steve Block44f0eee2011-05-26 01:26:41 +01001533 const v8::HeapGraphNode* n_BBB = GetNode(
1534 aaa, v8::HeapGraphNode::kString, "BBB");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001535 CHECK(n_BBB);
Steve Block44f0eee2011-05-26 01:26:41 +01001536 CHECK_EQ(1, ccc->GetChildrenCount());
1537 const v8::HeapGraphNode* n_CCC = GetNode(
1538 ccc, v8::HeapGraphNode::kString, "CCC");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001539 CHECK(n_CCC);
Steve Block44f0eee2011-05-26 01:26:41 +01001540
Ben Murdoch8b112d22011-06-08 16:22:53 +01001541 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1542 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1543 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
Steve Block44f0eee2011-05-26 01:26:41 +01001544}
1545
1546
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001547class GraphWithImplicitRefs {
1548 public:
1549 static const int kObjectsCount = 4;
1550 explicit GraphWithImplicitRefs(LocalContext* env) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 CHECK(!instance_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001552 instance_ = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001553 isolate_ = (*env)->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001554 for (int i = 0; i < kObjectsCount; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555 objects_[i].Reset(isolate_, v8::Object::New(isolate_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001556 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557 (*env)
1558 ->Global()
1559 ->Set(isolate_->GetCurrentContext(), v8_str("root_object"),
1560 v8::Local<v8::Value>::New(isolate_, objects_[0]))
1561 .FromJust();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001562 }
1563 ~GraphWithImplicitRefs() {
1564 instance_ = NULL;
1565 }
1566
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001567 static void gcPrologue(v8::Isolate* isolate, v8::GCType type,
1568 v8::GCCallbackFlags flags) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001569 instance_->AddImplicitReferences();
1570 }
1571
1572 private:
1573 void AddImplicitReferences() {
1574 // 0 -> 1
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001575 isolate_->SetObjectGroupId(objects_[0],
1576 v8::UniqueId(1));
1577 isolate_->SetReferenceFromGroup(
1578 v8::UniqueId(1), objects_[1]);
1579 // Adding two more references: 1 -> 2, 1 -> 3
1580 isolate_->SetReference(objects_[1].As<v8::Object>(),
1581 objects_[2]);
1582 isolate_->SetReference(objects_[1].As<v8::Object>(),
1583 objects_[3]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001584 }
1585
1586 v8::Persistent<v8::Value> objects_[kObjectsCount];
1587 static GraphWithImplicitRefs* instance_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 v8::Isolate* isolate_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001589};
1590
1591GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
1592
1593
1594TEST(HeapSnapshotImplicitReferences) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001595 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001596 v8::HandleScope scope(env->GetIsolate());
1597 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001598
1599 GraphWithImplicitRefs graph(&env);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001600 env->GetIsolate()->AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001601
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001602 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001603 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001604
1605 const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001606 const v8::HeapGraphNode* obj0 = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 global_object, v8::HeapGraphEdge::kProperty, "root_object");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001608 CHECK(obj0);
1609 CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
1610 const v8::HeapGraphNode* obj1 = GetProperty(
1611 obj0, v8::HeapGraphEdge::kInternal, "native");
1612 CHECK(obj1);
1613 int implicit_targets_count = 0;
1614 for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
1615 const v8::HeapGraphEdge* prop = obj1->GetChild(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001616 v8::String::Utf8Value prop_name(prop->GetName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001617 if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
1618 strcmp("native", *prop_name) == 0) {
1619 ++implicit_targets_count;
1620 }
1621 }
1622 CHECK_EQ(2, implicit_targets_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001623 env->GetIsolate()->RemoveGCPrologueCallback(
1624 &GraphWithImplicitRefs::gcPrologue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001625}
1626
1627
Steve Block44f0eee2011-05-26 01:26:41 +01001628TEST(DeleteAllHeapSnapshots) {
Steve Block44f0eee2011-05-26 01:26:41 +01001629 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001630 v8::HandleScope scope(env->GetIsolate());
1631 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001632
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001633 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1634 heap_profiler->DeleteAllHeapSnapshots();
1635 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001636 CHECK(heap_profiler->TakeHeapSnapshot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001637 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1638 heap_profiler->DeleteAllHeapSnapshots();
1639 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 CHECK(heap_profiler->TakeHeapSnapshot());
1641 CHECK(heap_profiler->TakeHeapSnapshot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001642 CHECK_EQ(2, heap_profiler->GetSnapshotCount());
1643 heap_profiler->DeleteAllHeapSnapshots();
1644 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1645}
1646
1647
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648static bool FindHeapSnapshot(v8::HeapProfiler* profiler,
1649 const v8::HeapSnapshot* snapshot) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001650 int length = profiler->GetSnapshotCount();
1651 for (int i = 0; i < length; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 if (snapshot == profiler->GetHeapSnapshot(i)) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001654 return false;
Steve Block44f0eee2011-05-26 01:26:41 +01001655}
1656
1657
1658TEST(DeleteHeapSnapshot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001659 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001660 v8::HandleScope scope(env->GetIsolate());
1661 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +01001662
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001663 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001664 const v8::HeapSnapshot* s1 = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001666 CHECK(s1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001667 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001668 CHECK(FindHeapSnapshot(heap_profiler, s1));
Steve Block44f0eee2011-05-26 01:26:41 +01001669 const_cast<v8::HeapSnapshot*>(s1)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001670 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 CHECK(!FindHeapSnapshot(heap_profiler, s1));
Steve Block44f0eee2011-05-26 01:26:41 +01001672
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001673 const v8::HeapSnapshot* s2 = heap_profiler->TakeHeapSnapshot();
1674 CHECK(s2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001676 CHECK(FindHeapSnapshot(heap_profiler, s2));
1677 const v8::HeapSnapshot* s3 = heap_profiler->TakeHeapSnapshot();
1678 CHECK(s3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001679 CHECK_EQ(2, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001680 CHECK_NE(s2, s3);
1681 CHECK(FindHeapSnapshot(heap_profiler, s3));
Steve Block44f0eee2011-05-26 01:26:41 +01001682 const_cast<v8::HeapSnapshot*>(s2)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001683 CHECK_EQ(1, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 CHECK(!FindHeapSnapshot(heap_profiler, s2));
1685 CHECK(FindHeapSnapshot(heap_profiler, s3));
Steve Block44f0eee2011-05-26 01:26:41 +01001686 const_cast<v8::HeapSnapshot*>(s3)->Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 CHECK_EQ(0, heap_profiler->GetSnapshotCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 CHECK(!FindHeapSnapshot(heap_profiler, s3));
Steve Block44f0eee2011-05-26 01:26:41 +01001689}
1690
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001691
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692class NameResolver : public v8::HeapProfiler::ObjectNameResolver {
1693 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001694 virtual const char* GetName(v8::Local<v8::Object> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 return "Global object name";
1696 }
1697};
1698
1699
1700TEST(GlobalObjectName) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001701 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001702 v8::HandleScope scope(env->GetIsolate());
1703 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001704
1705 CompileRun("document = { URL:\"abcdefgh\" };");
1706
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001707 NameResolver name_resolver;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001708 const v8::HeapSnapshot* snapshot =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001709 heap_profiler->TakeHeapSnapshot(NULL, &name_resolver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001711 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001712 CHECK(global);
1713 CHECK_EQ(0,
1714 strcmp("Object / Global object name",
1715 const_cast<i::HeapEntry*>(
1716 reinterpret_cast<const i::HeapEntry*>(global))->name()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001717}
1718
1719
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720TEST(GlobalObjectFields) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001721 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001722 v8::HandleScope scope(env->GetIsolate());
1723 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1724 CompileRun("obj = {};");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001725 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001726 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001727 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001728 const v8::HeapGraphNode* native_context =
1729 GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001730 CHECK(native_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001731 const v8::HeapGraphNode* global_proxy =
1732 GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001733 CHECK(global_proxy);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001734}
1735
1736
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001737TEST(NoHandleLeaks) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001738 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001739 v8::HandleScope scope(env->GetIsolate());
1740 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001741
1742 CompileRun("document = { URL:\"abcdefgh\" };");
1743
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001744 i::Isolate* isolate = CcTest::i_isolate();
1745 int count_before = i::HandleScope::NumberOfHandles(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001746 heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001747 int count_after = i::HandleScope::NumberOfHandles(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001748 CHECK_EQ(count_before, count_after);
1749}
1750
1751
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001752TEST(NodesIteration) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001753 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001754 v8::HandleScope scope(env->GetIsolate());
1755 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001756 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001757 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001758 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001759 CHECK(global);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001760 // Verify that we can find this object by iteration.
1761 const int nodes_count = snapshot->GetNodesCount();
1762 int count = 0;
1763 for (int i = 0; i < nodes_count; ++i) {
1764 if (snapshot->GetNode(i) == global)
1765 ++count;
1766 }
1767 CHECK_EQ(1, count);
1768}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001769
1770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771TEST(GetHeapValueForNode) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001772 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 v8::HandleScope scope(env->GetIsolate());
1774 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001775
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001776 CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001777 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001778 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001779 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001780 CHECK(heap_profiler->FindObjectById(global->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001781 v8::Local<v8::Object> js_global =
1782 env->Global()->GetPrototype().As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001783 CHECK(js_global == heap_profiler->FindObjectById(global->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001784 const v8::HeapGraphNode* obj = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 global, v8::HeapGraphEdge::kProperty, "a");
1786 CHECK(heap_profiler->FindObjectById(obj->GetId())->IsObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001787 v8::Local<v8::Object> js_obj = js_global->Get(env.local(), v8_str("a"))
1788 .ToLocalChecked()
1789 .As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001790 CHECK(js_obj == heap_profiler->FindObjectById(obj->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001791 const v8::HeapGraphNode* s_prop =
1792 GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001793 v8::Local<v8::String> js_s_prop = js_obj->Get(env.local(), v8_str("s_prop"))
1794 .ToLocalChecked()
1795 .As<v8::String>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001796 CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001797 const v8::HeapGraphNode* n_prop =
1798 GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001799 v8::Local<v8::String> js_n_prop = js_obj->Get(env.local(), v8_str("n_prop"))
1800 .ToLocalChecked()
1801 .As<v8::String>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001802 CHECK(js_n_prop == heap_profiler->FindObjectById(n_prop->GetId()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001803}
1804
1805
1806TEST(GetHeapValueForDeletedObject) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001807 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001808 v8::HandleScope scope(env->GetIsolate());
1809 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001810
1811 // It is impossible to delete a global property, so we are about to delete a
1812 // property of the "a" object. Also, the "p" object can't be an empty one
1813 // because the empty object is static and isn't actually deleted.
1814 CompileRun("a = { p: { r: {} } };");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001815 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001816 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001817 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1818 const v8::HeapGraphNode* obj = GetProperty(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 global, v8::HeapGraphEdge::kProperty, "a");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001820 const v8::HeapGraphNode* prop = GetProperty(
1821 obj, v8::HeapGraphEdge::kProperty, "p");
1822 {
1823 // Perform the check inside a nested local scope to avoid creating a
1824 // reference to the object we are deleting.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001825 v8::HandleScope scope(env->GetIsolate());
1826 CHECK(heap_profiler->FindObjectById(prop->GetId())->IsObject());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001827 }
1828 CompileRun("delete a.p;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001829 CHECK(heap_profiler->FindObjectById(prop->GetId()).IsEmpty());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001830}
1831
1832
1833static int StringCmp(const char* ref, i::String* act) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001834 v8::base::SmartArrayPointer<char> s_act = act->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 int result = strcmp(ref, s_act.get());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001836 if (result != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001837 fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, s_act.get());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001838 return result;
1839}
1840
1841
1842TEST(GetConstructorName) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001843 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001845
1846 CompileRun(
1847 "function Constructor1() {};\n"
1848 "var obj1 = new Constructor1();\n"
1849 "var Constructor2 = function() {};\n"
1850 "var obj2 = new Constructor2();\n"
1851 "var obj3 = {};\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001852 "obj3.__proto__ = { constructor: function Constructor3() {} };\n"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001853 "var obj4 = {};\n"
1854 "// Slow properties\n"
1855 "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001856 "obj4.__proto__ = { constructor: function Constructor4() {} };\n"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001857 "var obj5 = {};\n"
1858 "var obj6 = {};\n"
1859 "obj6.constructor = 6;");
1860 v8::Local<v8::Object> js_global =
1861 env->Global()->GetPrototype().As<v8::Object>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001862 v8::Local<v8::Object> obj1 = js_global->Get(env.local(), v8_str("obj1"))
1863 .ToLocalChecked()
1864 .As<v8::Object>();
1865 i::Handle<i::JSObject> js_obj1 =
1866 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj1));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001867 CHECK_EQ(0, StringCmp(
1868 "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001869 v8::Local<v8::Object> obj2 = js_global->Get(env.local(), v8_str("obj2"))
1870 .ToLocalChecked()
1871 .As<v8::Object>();
1872 i::Handle<i::JSObject> js_obj2 =
1873 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj2));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001874 CHECK_EQ(0, StringCmp(
1875 "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001876 v8::Local<v8::Object> obj3 = js_global->Get(env.local(), v8_str("obj3"))
1877 .ToLocalChecked()
1878 .As<v8::Object>();
1879 i::Handle<i::JSObject> js_obj3 =
1880 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj3));
1881 CHECK_EQ(0, StringCmp("Constructor3",
1882 i::V8HeapExplorer::GetConstructorName(*js_obj3)));
1883 v8::Local<v8::Object> obj4 = js_global->Get(env.local(), v8_str("obj4"))
1884 .ToLocalChecked()
1885 .As<v8::Object>();
1886 i::Handle<i::JSObject> js_obj4 =
1887 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj4));
1888 CHECK_EQ(0, StringCmp("Constructor4",
1889 i::V8HeapExplorer::GetConstructorName(*js_obj4)));
1890 v8::Local<v8::Object> obj5 = js_global->Get(env.local(), v8_str("obj5"))
1891 .ToLocalChecked()
1892 .As<v8::Object>();
1893 i::Handle<i::JSObject> js_obj5 =
1894 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj5));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001895 CHECK_EQ(0, StringCmp(
1896 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001897 v8::Local<v8::Object> obj6 = js_global->Get(env.local(), v8_str("obj6"))
1898 .ToLocalChecked()
1899 .As<v8::Object>();
1900 i::Handle<i::JSObject> js_obj6 =
1901 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj6));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001902 CHECK_EQ(0, StringCmp(
1903 "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1904}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001905
1906
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907TEST(FastCaseAccessors) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001908 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 v8::HandleScope scope(env->GetIsolate());
1910 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001911
1912 CompileRun("var obj1 = {};\n"
1913 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1914 " return 42;\n"
1915 "});\n"
1916 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1917 " return this.value_ = value;\n"
1918 "});\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001919 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001921
1922 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001923 CHECK(global);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001924 const v8::HeapGraphNode* obj1 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001925 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001926 CHECK(obj1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001927 const v8::HeapGraphNode* func;
1928 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001929 CHECK(func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001930 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001931 CHECK(!func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001932 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001933 CHECK(func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001934 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001935 CHECK(!func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936}
1937
1938
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001939TEST(FastCaseRedefinedAccessors) {
1940 LocalContext env;
1941 v8::HandleScope scope(env->GetIsolate());
1942 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1943
1944 CompileRun(
1945 "var obj1 = {};\n"
1946 "Object.defineProperty(obj1, 'prop', { "
1947 " get: function() { return 42; },\n"
1948 " set: function(value) { return this.prop_ = value; },\n"
1949 " configurable: true,\n"
1950 " enumerable: true,\n"
1951 "});\n"
1952 "Object.defineProperty(obj1, 'prop', { "
1953 " get: function() { return 153; },\n"
1954 " set: function(value) { return this.prop_ = value; },\n"
1955 " configurable: true,\n"
1956 " enumerable: true,\n"
1957 "});\n");
1958 v8::Local<v8::Object> js_global =
1959 env->Global()->GetPrototype().As<v8::Object>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001960 i::Handle<i::JSReceiver> js_obj1 =
1961 v8::Utils::OpenHandle(*js_global->Get(env.local(), v8_str("obj1"))
1962 .ToLocalChecked()
1963 .As<v8::Object>());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001964 USE(js_obj1);
1965
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001966 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001967 CHECK(ValidateSnapshot(snapshot));
1968 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001969 CHECK(global);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001970 const v8::HeapGraphNode* obj1 =
1971 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001972 CHECK(obj1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001973 const v8::HeapGraphNode* func;
1974 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get prop");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001975 CHECK(func);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001976 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set prop");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001977 CHECK(func);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001978}
1979
1980
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981TEST(SlowCaseAccessors) {
1982 LocalContext env;
1983 v8::HandleScope scope(env->GetIsolate());
1984 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1985
1986 CompileRun("var obj1 = {};\n"
1987 "for (var i = 0; i < 100; ++i) obj1['z' + i] = {};"
1988 "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1989 " return 42;\n"
1990 "});\n"
1991 "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1992 " return this.value_ = value;\n"
1993 "});\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001994 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001995 CHECK(ValidateSnapshot(snapshot));
1996
1997 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998 CHECK(global);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001999 const v8::HeapGraphNode* obj1 =
2000 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002001 CHECK(obj1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002002 const v8::HeapGraphNode* func;
2003 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002004 CHECK(func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002005 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002006 CHECK(!func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002007 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008 CHECK(func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009 func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002010 CHECK(!func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002011}
2012
2013
2014TEST(HiddenPropertiesFastCase) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002015 v8::Isolate* isolate = CcTest::isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002016 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002017 v8::HandleScope scope(isolate);
2018 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002019
2020 CompileRun(
2021 "function C(x) { this.a = this; this.b = x; }\n"
2022 "c = new C(2012);\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002023 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002024 CHECK(ValidateSnapshot(snapshot));
2025 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2026 const v8::HeapGraphNode* c =
2027 GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002028 CHECK(c);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002029 const v8::HeapGraphNode* hidden_props =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002030 GetProperty(c, v8::HeapGraphEdge::kProperty, "<symbol>");
2031 CHECK(!hidden_props);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002033 v8::Local<v8::Value> cHandle =
2034 env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002035 CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002036 cHandle->ToObject(env.local())
2037 .ToLocalChecked()
2038 ->SetPrivate(env.local(),
2039 v8::Private::ForApi(env->GetIsolate(), v8_str("key")),
2040 v8_str("val"))
2041 .FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002042
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002043 snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002044 CHECK(ValidateSnapshot(snapshot));
2045 global = GetGlobalObject(snapshot);
2046 c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002047 CHECK(c);
2048 hidden_props = GetProperty(c, v8::HeapGraphEdge::kProperty, "<symbol>");
2049 CHECK(hidden_props);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002050}
2051
2052
2053TEST(AccessorInfo) {
2054 LocalContext env;
2055 v8::HandleScope scope(env->GetIsolate());
2056 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2057
2058 CompileRun("function foo(x) { }\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002059 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002060 CHECK(ValidateSnapshot(snapshot));
2061 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2062 const v8::HeapGraphNode* foo =
2063 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002064 CHECK(foo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002065 const v8::HeapGraphNode* map =
2066 GetProperty(foo, v8::HeapGraphEdge::kInternal, "map");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067 CHECK(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002068 const v8::HeapGraphNode* descriptors =
2069 GetProperty(map, v8::HeapGraphEdge::kInternal, "descriptors");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002070 CHECK(descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 const v8::HeapGraphNode* length_name =
2072 GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "2");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002073 CHECK(length_name);
2074 CHECK_EQ(0, strcmp("length", *v8::String::Utf8Value(length_name->GetName())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002075 const v8::HeapGraphNode* length_accessor =
2076 GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "4");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002077 CHECK(length_accessor);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002078 CHECK_EQ(0, strcmp("system / AccessorInfo",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002079 *v8::String::Utf8Value(length_accessor->GetName())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002080 const v8::HeapGraphNode* name =
2081 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "name");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002082 CHECK(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002083 const v8::HeapGraphNode* getter =
2084 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "getter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002085 CHECK(getter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002086 const v8::HeapGraphNode* setter =
2087 GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "setter");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002088 CHECK(setter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002089}
2090
2091
2092bool HasWeakEdge(const v8::HeapGraphNode* node) {
2093 for (int i = 0; i < node->GetChildrenCount(); ++i) {
2094 const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
2095 if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
2096 }
2097 return false;
2098}
2099
2100
2101bool HasWeakGlobalHandle() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002102 v8::Isolate* isolate = CcTest::isolate();
2103 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002104 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002105 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002106 const v8::HeapGraphNode* gc_roots = GetNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002107 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002108 CHECK(gc_roots);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002109 const v8::HeapGraphNode* global_handles = GetNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002110 gc_roots, v8::HeapGraphNode::kSynthetic, "(Global handles)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002111 CHECK(global_handles);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002112 return HasWeakEdge(global_handles);
2113}
2114
2115
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002116static void PersistentHandleCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002117 const v8::WeakCallbackInfo<v8::Persistent<v8::Object> >& data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002118 data.GetParameter()->Reset();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002119}
2120
2121
2122TEST(WeakGlobalHandle) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002123 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002124 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002125
2126 CHECK(!HasWeakGlobalHandle());
2127
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002128 v8::Persistent<v8::Object> handle(env->GetIsolate(),
2129 v8::Object::New(env->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002130 handle.SetWeak(&handle, PersistentHandleCallback,
2131 v8::WeakCallbackType::kParameter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002132
2133 CHECK(HasWeakGlobalHandle());
2134}
2135
2136
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002137TEST(SfiAndJsFunctionWeakRefs) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002138 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002139 v8::HandleScope scope(env->GetIsolate());
2140 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002141
2142 CompileRun(
2143 "fun = (function (x) { return function () { return x + 1; } })(1);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002144 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002145 CHECK(ValidateSnapshot(snapshot));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002146 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002147 CHECK(global);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002148 const v8::HeapGraphNode* fun =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002149 GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
2150 CHECK(!HasWeakEdge(fun));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002151 const v8::HeapGraphNode* shared =
2152 GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002153 CHECK(!HasWeakEdge(shared));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002154}
2155
2156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002157TEST(NoDebugObjectInSnapshot) {
2158 LocalContext env;
2159 v8::HandleScope scope(env->GetIsolate());
2160 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2161
2162 CHECK(CcTest::i_isolate()->debug()->Load());
2163 CompileRun("foo = {};");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002164 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002165 CHECK(ValidateSnapshot(snapshot));
2166 const v8::HeapGraphNode* root = snapshot->GetRoot();
2167 int globals_count = 0;
2168 for (int i = 0; i < root->GetChildrenCount(); ++i) {
2169 const v8::HeapGraphEdge* edge = root->GetChild(i);
2170 if (edge->GetType() == v8::HeapGraphEdge::kShortcut) {
2171 ++globals_count;
2172 const v8::HeapGraphNode* global = edge->GetToNode();
2173 const v8::HeapGraphNode* foo =
2174 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002175 CHECK(foo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002176 }
2177 }
2178 CHECK_EQ(1, globals_count);
2179}
2180
2181
2182TEST(AllStrongGcRootsHaveNames) {
2183 LocalContext env;
2184 v8::HandleScope scope(env->GetIsolate());
2185 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2186
2187 CompileRun("foo = {};");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002188 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002189 CHECK(ValidateSnapshot(snapshot));
2190 const v8::HeapGraphNode* gc_roots = GetNode(
2191 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002192 CHECK(gc_roots);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002193 const v8::HeapGraphNode* strong_roots = GetNode(
2194 gc_roots, v8::HeapGraphNode::kSynthetic, "(Strong roots)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002195 CHECK(strong_roots);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002196 for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) {
2197 const v8::HeapGraphEdge* edge = strong_roots->GetChild(i);
2198 CHECK_EQ(v8::HeapGraphEdge::kInternal, edge->GetType());
2199 v8::String::Utf8Value name(edge->GetName());
2200 CHECK(isalpha(**name));
2201 }
2202}
2203
2204
2205TEST(NoRefsToNonEssentialEntries) {
2206 LocalContext env;
2207 v8::HandleScope scope(env->GetIsolate());
2208 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2209 CompileRun("global_object = {};\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002210 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002211 CHECK(ValidateSnapshot(snapshot));
2212 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2213 const v8::HeapGraphNode* global_object =
2214 GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002215 CHECK(global_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002216 const v8::HeapGraphNode* properties =
2217 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002218 CHECK(!properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002219 const v8::HeapGraphNode* elements =
2220 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002221 CHECK(!elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222}
2223
2224
2225TEST(MapHasDescriptorsAndTransitions) {
2226 LocalContext env;
2227 v8::HandleScope scope(env->GetIsolate());
2228 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2229 CompileRun("obj = { a: 10 };\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002230 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002231 CHECK(ValidateSnapshot(snapshot));
2232 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2233 const v8::HeapGraphNode* global_object =
2234 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002235 CHECK(global_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002236
2237 const v8::HeapGraphNode* map =
2238 GetProperty(global_object, v8::HeapGraphEdge::kInternal, "map");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002239 CHECK(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002240 const v8::HeapGraphNode* own_descriptors = GetProperty(
2241 map, v8::HeapGraphEdge::kInternal, "descriptors");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002242 CHECK(own_descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002243 const v8::HeapGraphNode* own_transitions = GetProperty(
2244 map, v8::HeapGraphEdge::kInternal, "transitions");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002245 CHECK(!own_transitions);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002246}
2247
2248
2249TEST(ManyLocalsInSharedContext) {
2250 LocalContext env;
2251 v8::HandleScope scope(env->GetIsolate());
2252 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2253 int num_objects = 6000;
2254 CompileRun(
2255 "var n = 6000;"
2256 "var result = [];"
2257 "result.push('(function outer() {');"
2258 "for (var i = 0; i < n; i++) {"
2259 " var f = 'function f_' + i + '() { ';"
2260 " if (i > 0)"
2261 " f += 'f_' + (i - 1) + '();';"
2262 " f += ' }';"
2263 " result.push(f);"
2264 "}"
2265 "result.push('return f_' + (n - 1) + ';');"
2266 "result.push('})()');"
2267 "var ok = eval(result.join('\\n'));");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002268 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002269 CHECK(ValidateSnapshot(snapshot));
2270
2271 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002272 CHECK(global);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273 const v8::HeapGraphNode* ok_object =
2274 GetProperty(global, v8::HeapGraphEdge::kProperty, "ok");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002275 CHECK(ok_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 const v8::HeapGraphNode* context_object =
2277 GetProperty(ok_object, v8::HeapGraphEdge::kInternal, "context");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002278 CHECK(context_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002279 // Check the objects are not duplicated in the context.
2280 CHECK_EQ(v8::internal::Context::MIN_CONTEXT_SLOTS + num_objects - 1,
2281 context_object->GetChildrenCount());
2282 // Check all the objects have got their names.
2283 // ... well check just every 15th because otherwise it's too slow in debug.
2284 for (int i = 0; i < num_objects - 1; i += 15) {
2285 i::EmbeddedVector<char, 100> var_name;
2286 i::SNPrintF(var_name, "f_%d", i);
2287 const v8::HeapGraphNode* f_object = GetProperty(
2288 context_object, v8::HeapGraphEdge::kContextVariable, var_name.start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002289 CHECK(f_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002290 }
2291}
2292
2293
2294TEST(AllocationSitesAreVisible) {
2295 LocalContext env;
2296 v8::Isolate* isolate = env->GetIsolate();
2297 v8::HandleScope scope(isolate);
2298 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2299 CompileRun(
2300 "fun = function () { var a = [3, 2, 1]; return a; }\n"
2301 "fun();");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002302 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002303 CHECK(ValidateSnapshot(snapshot));
2304
2305 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002306 CHECK(global);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002307 const v8::HeapGraphNode* fun_code =
2308 GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002309 CHECK(fun_code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002310 const v8::HeapGraphNode* literals =
2311 GetProperty(fun_code, v8::HeapGraphEdge::kInternal, "literals");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002312 CHECK(literals);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002313 CHECK_EQ(v8::HeapGraphNode::kArray, literals->GetType());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002314 CHECK_EQ(1, literals->GetChildrenCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002315
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002316 // The first value in the literals array should be the boilerplate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002317 // after an AllocationSite.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002318 const v8::HeapGraphEdge* prop = literals->GetChild(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002319 const v8::HeapGraphNode* allocation_site = prop->GetToNode();
2320 v8::String::Utf8Value name(allocation_site->GetName());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002321 CHECK_EQ(0, strcmp("system / AllocationSite", *name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002322 const v8::HeapGraphNode* transition_info =
2323 GetProperty(allocation_site, v8::HeapGraphEdge::kInternal,
2324 "transition_info");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002325 CHECK(transition_info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002326
2327 const v8::HeapGraphNode* elements =
2328 GetProperty(transition_info, v8::HeapGraphEdge::kInternal,
2329 "elements");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002330 CHECK(elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002331 CHECK_EQ(v8::HeapGraphNode::kArray, elements->GetType());
2332 CHECK_EQ(v8::internal::FixedArray::SizeFor(3),
2333 static_cast<int>(elements->GetShallowSize()));
2334
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002335 v8::Local<v8::Value> array_val =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002336 heap_profiler->FindObjectById(transition_info->GetId());
2337 CHECK(array_val->IsArray());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002338 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(array_val);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002339 // Verify the array is "a" in the code above.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002340 CHECK_EQ(3u, array->Length());
2341 CHECK(v8::Integer::New(isolate, 3)
2342 ->Equals(env.local(),
2343 array->Get(env.local(), v8::Integer::New(isolate, 0))
2344 .ToLocalChecked())
2345 .FromJust());
2346 CHECK(v8::Integer::New(isolate, 2)
2347 ->Equals(env.local(),
2348 array->Get(env.local(), v8::Integer::New(isolate, 1))
2349 .ToLocalChecked())
2350 .FromJust());
2351 CHECK(v8::Integer::New(isolate, 1)
2352 ->Equals(env.local(),
2353 array->Get(env.local(), v8::Integer::New(isolate, 2))
2354 .ToLocalChecked())
2355 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002356}
2357
2358
2359TEST(JSFunctionHasCodeLink) {
2360 LocalContext env;
2361 v8::HandleScope scope(env->GetIsolate());
2362 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2363 CompileRun("function foo(x, y) { return x + y; }\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002364 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002365 CHECK(ValidateSnapshot(snapshot));
2366 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2367 const v8::HeapGraphNode* foo_func =
2368 GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002369 CHECK(foo_func);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002370 const v8::HeapGraphNode* code =
2371 GetProperty(foo_func, v8::HeapGraphEdge::kInternal, "code");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002372 CHECK(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002373}
2374
2375
2376static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
2377 const char* path[],
2378 int depth) {
2379 const v8::HeapGraphNode* node = snapshot->GetRoot();
2380 for (int current_depth = 0; current_depth < depth; ++current_depth) {
2381 int i, count = node->GetChildrenCount();
2382 for (i = 0; i < count; ++i) {
2383 const v8::HeapGraphEdge* edge = node->GetChild(i);
2384 const v8::HeapGraphNode* to_node = edge->GetToNode();
2385 v8::String::Utf8Value edge_name(edge->GetName());
2386 v8::String::Utf8Value node_name(to_node->GetName());
2387 i::EmbeddedVector<char, 100> name;
2388 i::SNPrintF(name, "%s::%s", *edge_name, *node_name);
2389 if (strstr(name.start(), path[current_depth])) {
2390 node = to_node;
2391 break;
2392 }
2393 }
2394 if (i == count) return NULL;
2395 }
2396 return node;
2397}
2398
2399
2400TEST(CheckCodeNames) {
2401 LocalContext env;
2402 v8::HandleScope scope(env->GetIsolate());
2403 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2404 CompileRun("var a = 1.1;");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002405 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002406 CHECK(ValidateSnapshot(snapshot));
2407
2408 const char* stub_path[] = {
2409 "::(GC roots)",
2410 "::(Strong roots)",
2411 "code_stubs::",
2412 "::(ArraySingleArgumentConstructorStub code)"
2413 };
2414 const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
2415 stub_path, arraysize(stub_path));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002416 CHECK(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002418 const char* builtin_path1[] = {"::(GC roots)", "::(Builtins)",
2419 "::(KeyedLoadIC_Megamorphic builtin)"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002420 node = GetNodeByPath(snapshot, builtin_path1, arraysize(builtin_path1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002421 CHECK(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002422
2423 const char* builtin_path2[] = {"::(GC roots)", "::(Builtins)",
2424 "::(CompileLazy builtin)"};
2425 node = GetNodeByPath(snapshot, builtin_path2, arraysize(builtin_path2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002426 CHECK(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002427 v8::String::Utf8Value node_name(node->GetName());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002428 CHECK_EQ(0, strcmp("(CompileLazy builtin)", *node_name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002429}
2430
2431
2432static const char* record_trace_tree_source =
2433"var topFunctions = [];\n"
2434"var global = this;\n"
2435"function generateFunctions(width, depth) {\n"
2436" var script = [];\n"
2437" for (var i = 0; i < width; i++) {\n"
2438" for (var j = 0; j < depth; j++) {\n"
2439" script.push('function f_' + i + '_' + j + '(x) {\\n');\n"
2440" script.push(' try {\\n');\n"
2441" if (j < depth-2) {\n"
2442" script.push(' return f_' + i + '_' + (j+1) + '(x+1);\\n');\n"
2443" } else if (j == depth - 2) {\n"
2444" script.push(' return new f_' + i + '_' + (depth - 1) + '();\\n');\n"
2445" } else if (j == depth - 1) {\n"
2446" script.push(' this.ts = Date.now();\\n');\n"
2447" }\n"
2448" script.push(' } catch (e) {}\\n');\n"
2449" script.push('}\\n');\n"
2450" \n"
2451" }\n"
2452" }\n"
2453" var script = script.join('');\n"
2454" // throw script;\n"
2455" global.eval(script);\n"
2456" for (var i = 0; i < width; i++) {\n"
2457" topFunctions.push(this['f_' + i + '_0']);\n"
2458" }\n"
2459"}\n"
2460"\n"
2461"var width = 3;\n"
2462"var depth = 3;\n"
2463"generateFunctions(width, depth);\n"
2464"var instances = [];\n"
2465"function start() {\n"
2466" for (var i = 0; i < width; i++) {\n"
2467" instances.push(topFunctions[i](0));\n"
2468" }\n"
2469"}\n"
2470"\n"
2471"for (var i = 0; i < 100; i++) start();\n";
2472
2473
2474static AllocationTraceNode* FindNode(
2475 AllocationTracker* tracker, const Vector<const char*>& names) {
2476 AllocationTraceNode* node = tracker->trace_tree()->root();
2477 for (int i = 0; node != NULL && i < names.length(); i++) {
2478 const char* name = names[i];
2479 Vector<AllocationTraceNode*> children = node->children();
2480 node = NULL;
2481 for (int j = 0; j < children.length(); j++) {
2482 unsigned index = children[j]->function_info_index();
2483 AllocationTracker::FunctionInfo* info =
2484 tracker->function_info_list()[index];
2485 if (info && strcmp(info->name, name) == 0) {
2486 node = children[j];
2487 break;
2488 }
2489 }
2490 }
2491 return node;
2492}
2493
2494
2495TEST(ArrayGrowLeftTrim) {
2496 LocalContext env;
2497 v8::HandleScope scope(env->GetIsolate());
2498 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2499 heap_profiler->StartTrackingHeapObjects(true);
2500
2501 CompileRun(
2502 "var a = [];\n"
2503 "for (var i = 0; i < 5; ++i)\n"
2504 " a[i] = i;\n"
2505 "for (var i = 0; i < 3; ++i)\n"
2506 " a.shift();\n");
2507
2508 const char* names[] = {""};
2509 AllocationTracker* tracker =
2510 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002511 CHECK(tracker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002512 // Resolve all function locations.
2513 tracker->PrepareForSerialization();
2514 // Print for better diagnostics in case of failure.
2515 tracker->trace_tree()->Print(tracker);
2516
Ben Murdochc5610432016-08-08 18:44:38 +01002517 AllocationTraceNode* node = FindNode(tracker, ArrayVector(names));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002518 CHECK(node);
2519 CHECK_GE(node->allocation_count(), 2u);
2520 CHECK_GE(node->allocation_size(), 4u * 5u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002521 heap_profiler->StopTrackingHeapObjects();
2522}
2523
2524
2525TEST(TrackHeapAllocations) {
2526 v8::HandleScope scope(v8::Isolate::GetCurrent());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002527 LocalContext env;
2528
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002529 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2530 heap_profiler->StartTrackingHeapObjects(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002531
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002532 CompileRun(record_trace_tree_source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002533
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002534 AllocationTracker* tracker =
2535 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002536 CHECK(tracker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002537 // Resolve all function locations.
2538 tracker->PrepareForSerialization();
2539 // Print for better diagnostics in case of failure.
2540 tracker->trace_tree()->Print(tracker);
2541
2542 const char* names[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"};
Ben Murdochc5610432016-08-08 18:44:38 +01002543 AllocationTraceNode* node = FindNode(tracker, ArrayVector(names));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002544 CHECK(node);
2545 CHECK_GE(node->allocation_count(), 100u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002546 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2547 heap_profiler->StopTrackingHeapObjects();
2548}
2549
2550
2551static const char* inline_heap_allocation_source =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002552 "function f_0(x) {\n"
2553 " return f_1(x+1);\n"
2554 "}\n"
2555 "%NeverOptimizeFunction(f_0);\n"
2556 "function f_1(x) {\n"
2557 " return new f_2(x+1);\n"
2558 "}\n"
2559 "%NeverOptimizeFunction(f_1);\n"
2560 "function f_2(x) {\n"
2561 " this.foo = x;\n"
2562 "}\n"
2563 "var instances = [];\n"
2564 "function start() {\n"
2565 " instances.push(f_0(0));\n"
2566 "}\n"
2567 "\n"
2568 "for (var i = 0; i < 100; i++) start();\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002569
2570
2571TEST(TrackBumpPointerAllocations) {
2572 i::FLAG_allow_natives_syntax = true;
2573 v8::HandleScope scope(v8::Isolate::GetCurrent());
2574 LocalContext env;
2575
2576 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2577 const char* names[] = {"", "start", "f_0", "f_1"};
2578 // First check that normally all allocations are recorded.
2579 {
2580 heap_profiler->StartTrackingHeapObjects(true);
2581
2582 CompileRun(inline_heap_allocation_source);
2583
2584 AllocationTracker* tracker =
2585 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002586 CHECK(tracker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002587 // Resolve all function locations.
2588 tracker->PrepareForSerialization();
2589 // Print for better diagnostics in case of failure.
2590 tracker->trace_tree()->Print(tracker);
2591
Ben Murdochc5610432016-08-08 18:44:38 +01002592 AllocationTraceNode* node = FindNode(tracker, ArrayVector(names));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002593 CHECK(node);
2594 CHECK_GE(node->allocation_count(), 100u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002595 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2596 heap_profiler->StopTrackingHeapObjects();
2597 }
2598
2599 {
2600 heap_profiler->StartTrackingHeapObjects(true);
2601
2602 // Now check that not all allocations are tracked if we manually reenable
2603 // inline allocations.
2604 CHECK(CcTest::heap()->inline_allocation_disabled());
2605 CcTest::heap()->EnableInlineAllocation();
2606
2607 CompileRun(inline_heap_allocation_source);
2608
2609 AllocationTracker* tracker =
2610 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002611 CHECK(tracker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002612 // Resolve all function locations.
2613 tracker->PrepareForSerialization();
2614 // Print for better diagnostics in case of failure.
2615 tracker->trace_tree()->Print(tracker);
2616
Ben Murdochc5610432016-08-08 18:44:38 +01002617 AllocationTraceNode* node = FindNode(tracker, ArrayVector(names));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002618 CHECK(node);
2619 CHECK_LT(node->allocation_count(), 100u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002620
2621 CcTest::heap()->DisableInlineAllocation();
2622 heap_profiler->StopTrackingHeapObjects();
2623 }
2624}
2625
2626
2627TEST(TrackV8ApiAllocation) {
2628 v8::HandleScope scope(v8::Isolate::GetCurrent());
2629 LocalContext env;
2630
2631 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2632 const char* names[] = { "(V8 API)" };
2633 heap_profiler->StartTrackingHeapObjects(true);
2634
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002635 v8::Local<v8::Object> o1 = v8::Object::New(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002636 o1->Clone();
2637
2638 AllocationTracker* tracker =
2639 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002640 CHECK(tracker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002641 // Resolve all function locations.
2642 tracker->PrepareForSerialization();
2643 // Print for better diagnostics in case of failure.
2644 tracker->trace_tree()->Print(tracker);
2645
Ben Murdochc5610432016-08-08 18:44:38 +01002646 AllocationTraceNode* node = FindNode(tracker, ArrayVector(names));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002647 CHECK(node);
2648 CHECK_GE(node->allocation_count(), 2u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002649 CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2650 heap_profiler->StopTrackingHeapObjects();
2651}
2652
2653
2654TEST(ArrayBufferAndArrayBufferView) {
2655 LocalContext env;
2656 v8::HandleScope scope(env->GetIsolate());
2657 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2658 CompileRun("arr1 = new Uint32Array(100);\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002659 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002660 CHECK(ValidateSnapshot(snapshot));
2661 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2662 const v8::HeapGraphNode* arr1_obj =
2663 GetProperty(global, v8::HeapGraphEdge::kProperty, "arr1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002664 CHECK(arr1_obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002665 const v8::HeapGraphNode* arr1_buffer =
2666 GetProperty(arr1_obj, v8::HeapGraphEdge::kInternal, "buffer");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002667 CHECK(arr1_buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002668 const v8::HeapGraphNode* backing_store =
2669 GetProperty(arr1_buffer, v8::HeapGraphEdge::kInternal, "backing_store");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002670 CHECK(backing_store);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002671 CHECK_EQ(400, static_cast<int>(backing_store->GetShallowSize()));
2672}
2673
2674
2675static int GetRetainersCount(const v8::HeapSnapshot* snapshot,
2676 const v8::HeapGraphNode* node) {
2677 int count = 0;
2678 for (int i = 0, l = snapshot->GetNodesCount(); i < l; ++i) {
2679 const v8::HeapGraphNode* parent = snapshot->GetNode(i);
2680 for (int j = 0, l2 = parent->GetChildrenCount(); j < l2; ++j) {
2681 if (parent->GetChild(j)->GetToNode() == node) {
2682 ++count;
2683 }
2684 }
2685 }
2686 return count;
2687}
2688
2689
2690TEST(ArrayBufferSharedBackingStore) {
2691 LocalContext env;
2692 v8::Isolate* isolate = env->GetIsolate();
2693 v8::HandleScope handle_scope(isolate);
2694 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2695
2696 v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2697 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2698 CHECK(!ab->IsExternal());
2699 v8::ArrayBuffer::Contents ab_contents = ab->Externalize();
2700 CHECK(ab->IsExternal());
2701
2702 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2703 void* data = ab_contents.Data();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002704 CHECK(data != NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002705 v8::Local<v8::ArrayBuffer> ab2 =
2706 v8::ArrayBuffer::New(isolate, data, ab_contents.ByteLength());
2707 CHECK(ab2->IsExternal());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002708 env->Global()->Set(env.local(), v8_str("ab1"), ab).FromJust();
2709 env->Global()->Set(env.local(), v8_str("ab2"), ab2).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002711 v8::Local<v8::Value> result = CompileRun("ab2.byteLength");
2712 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002713
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002714 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002715 CHECK(ValidateSnapshot(snapshot));
2716 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2717 const v8::HeapGraphNode* ab1_node =
2718 GetProperty(global, v8::HeapGraphEdge::kProperty, "ab1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002719 CHECK(ab1_node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002720 const v8::HeapGraphNode* ab1_data =
2721 GetProperty(ab1_node, v8::HeapGraphEdge::kInternal, "backing_store");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002722 CHECK(ab1_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002723 const v8::HeapGraphNode* ab2_node =
2724 GetProperty(global, v8::HeapGraphEdge::kProperty, "ab2");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002725 CHECK(ab2_node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002726 const v8::HeapGraphNode* ab2_data =
2727 GetProperty(ab2_node, v8::HeapGraphEdge::kInternal, "backing_store");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002728 CHECK(ab2_data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002729 CHECK_EQ(ab1_data, ab2_data);
2730 CHECK_EQ(2, GetRetainersCount(snapshot, ab1_data));
2731 free(data);
2732}
2733
2734
2735TEST(BoxObject) {
2736 v8::Isolate* isolate = CcTest::isolate();
2737 v8::HandleScope scope(isolate);
2738 LocalContext env;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002739 v8::Local<v8::Object> global_proxy = env->Global();
2740 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002741
2742 i::Factory* factory = CcTest::i_isolate()->factory();
2743 i::Handle<i::String> string = factory->NewStringFromStaticChars("string");
2744 i::Handle<i::Object> box = factory->NewBox(string);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002745 global->Set(env.local(), 0, v8::ToApiHandle<v8::Object>(box)).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002746
2747 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002748 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002749 CHECK(ValidateSnapshot(snapshot));
2750 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
2751 const v8::HeapGraphNode* box_node =
2752 GetProperty(global_node, v8::HeapGraphEdge::kElement, "0");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002753 CHECK(box_node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002754 v8::String::Utf8Value box_node_name(box_node->GetName());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002755 CHECK_EQ(0, strcmp("system / Box", *box_node_name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002756 const v8::HeapGraphNode* box_value =
2757 GetProperty(box_node, v8::HeapGraphEdge::kInternal, "value");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002758 CHECK(box_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002759}
2760
2761
2762TEST(WeakContainers) {
2763 i::FLAG_allow_natives_syntax = true;
2764 LocalContext env;
2765 v8::HandleScope scope(env->GetIsolate());
2766 if (!CcTest::i_isolate()->use_crankshaft()) return;
2767 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2768 CompileRun(
2769 "function foo(a) { return a.x; }\n"
2770 "obj = {x : 123};\n"
2771 "foo(obj);\n"
2772 "foo(obj);\n"
2773 "%OptimizeFunctionOnNextCall(foo);\n"
2774 "foo(obj);\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002775 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002776 CHECK(ValidateSnapshot(snapshot));
2777 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2778 const v8::HeapGraphNode* obj =
2779 GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002780 CHECK(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002781 const v8::HeapGraphNode* map =
2782 GetProperty(obj, v8::HeapGraphEdge::kInternal, "map");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002783 CHECK(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002784 const v8::HeapGraphNode* dependent_code =
2785 GetProperty(map, v8::HeapGraphEdge::kInternal, "dependent_code");
2786 if (!dependent_code) return;
2787 int count = dependent_code->GetChildrenCount();
2788 CHECK_NE(0, count);
2789 for (int i = 0; i < count; ++i) {
2790 const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
2791 CHECK_EQ(v8::HeapGraphEdge::kWeak, prop->GetType());
2792 }
2793}
2794
2795
2796static inline i::Address ToAddress(int n) {
2797 return reinterpret_cast<i::Address>(n);
2798}
2799
2800
2801TEST(AddressToTraceMap) {
2802 i::AddressToTraceMap map;
2803
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002804 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(150)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002805
2806 // [0x100, 0x200) -> 1
2807 map.AddRange(ToAddress(0x100), 0x100, 1U);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002808 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x50)));
2809 CHECK_EQ(1u, map.GetTraceNodeId(ToAddress(0x100)));
2810 CHECK_EQ(1u, map.GetTraceNodeId(ToAddress(0x150)));
2811 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x100 + 0x100)));
2812 CHECK_EQ(1u, map.size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002813
2814 // [0x100, 0x200) -> 1, [0x200, 0x300) -> 2
2815 map.AddRange(ToAddress(0x200), 0x100, 2U);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002816 CHECK_EQ(2u, map.GetTraceNodeId(ToAddress(0x2a0)));
2817 CHECK_EQ(2u, map.size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002818
2819 // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2
2820 map.AddRange(ToAddress(0x180), 0x100, 3U);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002821 CHECK_EQ(1u, map.GetTraceNodeId(ToAddress(0x17F)));
2822 CHECK_EQ(2u, map.GetTraceNodeId(ToAddress(0x280)));
2823 CHECK_EQ(3u, map.GetTraceNodeId(ToAddress(0x180)));
2824 CHECK_EQ(3u, map.size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002825
2826 // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2,
2827 // [0x400, 0x500) -> 4
2828 map.AddRange(ToAddress(0x400), 0x100, 4U);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002829 CHECK_EQ(1u, map.GetTraceNodeId(ToAddress(0x17F)));
2830 CHECK_EQ(2u, map.GetTraceNodeId(ToAddress(0x280)));
2831 CHECK_EQ(3u, map.GetTraceNodeId(ToAddress(0x180)));
2832 CHECK_EQ(4u, map.GetTraceNodeId(ToAddress(0x450)));
2833 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x500)));
2834 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x350)));
2835 CHECK_EQ(4u, map.size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002836
2837 // [0x100, 0x180) -> 1, [0x180, 0x200) -> 3, [0x200, 0x600) -> 5
2838 map.AddRange(ToAddress(0x200), 0x400, 5U);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002839 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x200)));
2840 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x400)));
2841 CHECK_EQ(3u, map.size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002842
2843 // [0x100, 0x180) -> 1, [0x180, 0x200) -> 7, [0x200, 0x600) ->5
2844 map.AddRange(ToAddress(0x180), 0x80, 6U);
2845 map.AddRange(ToAddress(0x180), 0x80, 7U);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002846 CHECK_EQ(7u, map.GetTraceNodeId(ToAddress(0x180)));
2847 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x200)));
2848 CHECK_EQ(3u, map.size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002849
2850 map.Clear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002851 CHECK_EQ(0u, map.size());
2852 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002853}
Ben Murdoch097c5b22016-05-18 11:27:45 +01002854
2855
2856static const v8::AllocationProfile::Node* FindAllocationProfileNode(
2857 v8::AllocationProfile& profile, const Vector<const char*>& names) {
2858 v8::AllocationProfile::Node* node = profile.GetRootNode();
2859 for (int i = 0; node != nullptr && i < names.length(); ++i) {
2860 const char* name = names[i];
2861 auto children = node->children;
2862 node = nullptr;
2863 for (v8::AllocationProfile::Node* child : children) {
2864 v8::String::Utf8Value child_name(child->name);
2865 if (strcmp(*child_name, name) == 0) {
2866 node = child;
2867 break;
2868 }
2869 }
2870 }
2871 return node;
2872}
2873
Ben Murdochc5610432016-08-08 18:44:38 +01002874static void CheckNoZeroCountNodes(v8::AllocationProfile::Node* node) {
2875 for (auto alloc : node->allocations) {
2876 CHECK_GT(alloc.count, 0u);
2877 }
2878 for (auto child : node->children) {
2879 CheckNoZeroCountNodes(child);
2880 }
2881}
2882
Ben Murdoch097c5b22016-05-18 11:27:45 +01002883TEST(SamplingHeapProfiler) {
2884 v8::HandleScope scope(v8::Isolate::GetCurrent());
2885 LocalContext env;
2886 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2887
2888 // Turn off always_opt. Inlining can cause stack traces to be shorter than
2889 // what we expect in this test.
2890 v8::internal::FLAG_always_opt = false;
2891
2892 // Suppress randomness to avoid flakiness in tests.
2893 v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true;
2894
2895 const char* script_source =
2896 "var A = [];\n"
2897 "function bar(size) { return new Array(size); }\n"
2898 "var foo = function() {\n"
2899 " for (var i = 0; i < 1024; ++i) {\n"
2900 " A[i] = bar(1024);\n"
2901 " }\n"
2902 "}\n"
2903 "foo();";
2904
2905 // Sample should be empty if requested before sampling has started.
2906 {
2907 v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile();
2908 CHECK(profile == nullptr);
2909 }
2910
2911 int count_1024 = 0;
2912 {
2913 heap_profiler->StartSamplingHeapProfiler(1024);
2914 CompileRun(script_source);
2915
2916 v8::base::SmartPointer<v8::AllocationProfile> profile(
2917 heap_profiler->GetAllocationProfile());
2918 CHECK(!profile.is_empty());
2919
2920 const char* names[] = {"", "foo", "bar"};
Ben Murdochc5610432016-08-08 18:44:38 +01002921 auto node_bar = FindAllocationProfileNode(*profile, ArrayVector(names));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002922 CHECK(node_bar);
2923
2924 // Count the number of allocations we sampled from bar.
2925 for (auto allocation : node_bar->allocations) {
2926 count_1024 += allocation.count;
2927 }
2928
2929 heap_profiler->StopSamplingHeapProfiler();
2930 }
2931
2932 // Samples should get cleared once sampling is stopped.
2933 {
2934 v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile();
2935 CHECK(profile == nullptr);
2936 }
2937
2938 // Sampling at a higher rate should give us similar numbers of objects.
2939 {
2940 heap_profiler->StartSamplingHeapProfiler(128);
2941 CompileRun(script_source);
2942
2943 v8::base::SmartPointer<v8::AllocationProfile> profile(
2944 heap_profiler->GetAllocationProfile());
2945 CHECK(!profile.is_empty());
2946
2947 const char* names[] = {"", "foo", "bar"};
Ben Murdochc5610432016-08-08 18:44:38 +01002948 auto node_bar = FindAllocationProfileNode(*profile, ArrayVector(names));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002949 CHECK(node_bar);
2950
2951 // Count the number of allocations we sampled from bar.
2952 int count_128 = 0;
2953 for (auto allocation : node_bar->allocations) {
2954 count_128 += allocation.count;
2955 }
2956
2957 // We should have similar unsampled counts of allocations. Though
2958 // we will sample different numbers of objects at different rates,
2959 // the unsampling process should produce similar final estimates
2960 // at the true number of allocations. However, the process to
2961 // determine these unsampled counts is probabilisitic so we need to
2962 // account for error.
2963 double max_count = std::max(count_128, count_1024);
2964 double min_count = std::min(count_128, count_1024);
2965 double percent_difference = (max_count - min_count) / min_count;
2966 CHECK_LT(percent_difference, 0.15);
2967
2968 heap_profiler->StopSamplingHeapProfiler();
2969 }
2970
2971 // A more complicated test cases with deeper call graph and dynamically
2972 // generated function names.
2973 {
2974 heap_profiler->StartSamplingHeapProfiler(64);
2975 CompileRun(record_trace_tree_source);
2976
2977 v8::base::SmartPointer<v8::AllocationProfile> profile(
2978 heap_profiler->GetAllocationProfile());
2979 CHECK(!profile.is_empty());
2980
2981 const char* names1[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"};
Ben Murdochc5610432016-08-08 18:44:38 +01002982 auto node1 = FindAllocationProfileNode(*profile, ArrayVector(names1));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002983 CHECK(node1);
2984
2985 const char* names2[] = {"", "generateFunctions"};
Ben Murdochc5610432016-08-08 18:44:38 +01002986 auto node2 = FindAllocationProfileNode(*profile, ArrayVector(names2));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002987 CHECK(node2);
2988
2989 heap_profiler->StopSamplingHeapProfiler();
2990 }
Ben Murdochda12d292016-06-02 14:46:10 +01002991
2992 // A test case with scripts unloaded before profile gathered
2993 {
2994 heap_profiler->StartSamplingHeapProfiler(64);
2995 CompileRun(
2996 "for (var i = 0; i < 1024; i++) {\n"
2997 " eval(\"new Array(100)\");\n"
2998 "}\n");
2999
3000 CcTest::heap()->CollectAllGarbage();
3001
3002 v8::base::SmartPointer<v8::AllocationProfile> profile(
3003 heap_profiler->GetAllocationProfile());
3004 CHECK(!profile.is_empty());
3005
Ben Murdochc5610432016-08-08 18:44:38 +01003006 CheckNoZeroCountNodes(profile->GetRootNode());
3007
Ben Murdochda12d292016-06-02 14:46:10 +01003008 heap_profiler->StopSamplingHeapProfiler();
3009 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01003010}
3011
3012
3013TEST(SamplingHeapProfilerApiAllocation) {
3014 v8::HandleScope scope(v8::Isolate::GetCurrent());
3015 LocalContext env;
3016 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
3017
3018 // Suppress randomness to avoid flakiness in tests.
3019 v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true;
3020
3021 heap_profiler->StartSamplingHeapProfiler(256);
3022
3023 for (int i = 0; i < 8 * 1024; ++i) v8::Object::New(env->GetIsolate());
3024
3025 v8::base::SmartPointer<v8::AllocationProfile> profile(
3026 heap_profiler->GetAllocationProfile());
3027 CHECK(!profile.is_empty());
3028 const char* names[] = {"(V8 API)"};
Ben Murdochc5610432016-08-08 18:44:38 +01003029 auto node = FindAllocationProfileNode(*profile, ArrayVector(names));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003030 CHECK(node);
3031
3032 heap_profiler->StopSamplingHeapProfiler();
3033}
3034
3035TEST(SamplingHeapProfilerLeftTrimming) {
3036 v8::HandleScope scope(v8::Isolate::GetCurrent());
3037 LocalContext env;
3038 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
3039
3040 // Suppress randomness to avoid flakiness in tests.
3041 v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true;
3042
3043 heap_profiler->StartSamplingHeapProfiler(64);
3044
3045 CompileRun(
3046 "for (var j = 0; j < 500; ++j) {\n"
3047 " var a = [];\n"
3048 " for (var i = 0; i < 5; ++i)\n"
3049 " a[i] = i;\n"
3050 " for (var i = 0; i < 3; ++i)\n"
3051 " a.shift();\n"
3052 "}\n");
3053
3054 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
3055 // Should not crash.
3056
3057 heap_profiler->StopSamplingHeapProfiler();
3058}