| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1745 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 const v8::HeapGraphNode* gc_roots = GetNode( | 1756 const v8::HeapGraphNode* gc_roots = GetNode( |
| 1757 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)"); | 1757 snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)"); |
| 1758 CHECK_NE(NULL, gc_roots); | 1758 CHECK_NE(NULL, gc_roots); |
| 1759 const v8::HeapGraphNode* global_handles = GetNode( | 1759 const v8::HeapGraphNode* global_handles = GetNode( |
| 1760 gc_roots, v8::HeapGraphNode::kSynthetic, "(Global handles)"); | 1760 gc_roots, v8::HeapGraphNode::kSynthetic, "(Global handles)"); |
| 1761 CHECK_NE(NULL, global_handles); | 1761 CHECK_NE(NULL, global_handles); |
| 1762 return HasWeakEdge(global_handles); | 1762 return HasWeakEdge(global_handles); |
| 1763 } | 1763 } |
| 1764 | 1764 |
| 1765 | 1765 |
| 1766 static void PersistentHandleCallback(v8::Isolate* isolate, | 1766 static void PersistentHandleCallback( |
| 1767 v8::Persistent<v8::Value>* handle, | 1767 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { |
| 1768 void*) { | 1768 data.GetParameter()->Reset(); |
| 1769 handle->Reset(); | 1769 delete data.GetParameter(); |
| 1770 } | 1770 } |
| 1771 | 1771 |
| 1772 | 1772 |
| 1773 TEST(WeakGlobalHandle) { | 1773 TEST(WeakGlobalHandle) { |
| 1774 LocalContext env; | 1774 LocalContext env; |
| 1775 v8::HandleScope scope(env->GetIsolate()); | 1775 v8::HandleScope scope(env->GetIsolate()); |
| 1776 | 1776 |
| 1777 CHECK(!HasWeakGlobalHandle()); | 1777 CHECK(!HasWeakGlobalHandle()); |
| 1778 | 1778 |
| 1779 v8::Persistent<v8::Object> handle(env->GetIsolate(), v8::Object::New()); | 1779 v8::Persistent<v8::Object>* handle = |
| 1780 handle.MakeWeak<v8::Value, void>(NULL, PersistentHandleCallback); | 1780 new v8::Persistent<v8::Object>(env->GetIsolate(), v8::Object::New()); |
| 1781 handle->SetWeak(handle, PersistentHandleCallback); |
| 1781 | 1782 |
| 1782 CHECK(HasWeakGlobalHandle()); | 1783 CHECK(HasWeakGlobalHandle()); |
| 1783 } | 1784 } |
| 1784 | 1785 |
| 1785 | 1786 |
| 1786 TEST(SfiAndJsFunctionWeakRefs) { | 1787 TEST(SfiAndJsFunctionWeakRefs) { |
| 1787 LocalContext env; | 1788 LocalContext env; |
| 1788 v8::HandleScope scope(env->GetIsolate()); | 1789 v8::HandleScope scope(env->GetIsolate()); |
| 1789 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); | 1790 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 1790 | 1791 |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2048 CHECK(false); | 2049 CHECK(false); |
| 2049 return v8::Handle<v8::FunctionTemplate>(); | 2050 return v8::Handle<v8::FunctionTemplate>(); |
| 2050 } | 2051 } |
| 2051 } | 2052 } |
| 2052 | 2053 |
| 2053 | 2054 |
| 2054 void HeapProfilerExtension::FindUntrackedObjects( | 2055 void HeapProfilerExtension::FindUntrackedObjects( |
| 2055 const v8::FunctionCallbackInfo<v8::Value>& args) { | 2056 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 2056 i::HeapProfiler* heap_profiler = | 2057 i::HeapProfiler* heap_profiler = |
| 2057 reinterpret_cast<i::HeapProfiler*>(args.GetIsolate()->GetHeapProfiler()); | 2058 reinterpret_cast<i::HeapProfiler*>(args.GetIsolate()->GetHeapProfiler()); |
| 2058 int untracked_objects = heap_profiler->FindUntrackedObjects(); | 2059 int untracked_objects = |
| 2060 heap_profiler->heap_object_map()->FindUntrackedObjects(); |
| 2059 args.GetReturnValue().Set(untracked_objects); | 2061 args.GetReturnValue().Set(untracked_objects); |
| 2060 CHECK_EQ(0, untracked_objects); | 2062 CHECK_EQ(0, untracked_objects); |
| 2061 } | 2063 } |
| 2062 | 2064 |
| 2063 | 2065 |
| 2064 static HeapProfilerExtension kHeapProfilerExtension; | 2066 static HeapProfilerExtension kHeapProfilerExtension; |
| 2065 v8::DeclareExtension kHeapProfilerExtensionDeclaration( | 2067 v8::DeclareExtension kHeapProfilerExtensionDeclaration( |
| 2066 &kHeapProfilerExtension); | 2068 &kHeapProfilerExtension); |
| 2067 | 2069 |
| 2068 | 2070 |
| 2069 // This is an example of using checking of JS allocations tracking in a test. | |
| 2070 TEST(HeapObjectsTracker) { | |
| 2071 const char* extensions[] = { HeapProfilerExtension::kName }; | |
| 2072 v8::ExtensionConfiguration config(1, extensions); | |
| 2073 LocalContext env(&config); | |
| 2074 v8::HandleScope scope(env->GetIsolate()); | |
| 2075 HeapObjectsTracker tracker; | |
| 2076 CompileRun("var a = 1.2"); | |
| 2077 CompileRun("var a = 1.2; var b = 1.0; var c = 1.0;"); | |
| 2078 CompileRun( | |
| 2079 "var a = [];\n" | |
| 2080 "for (var i = 0; i < 5; ++i)\n" | |
| 2081 " a[i] = i;\n" | |
| 2082 "findUntrackedObjects();\n" | |
| 2083 "for (var i = 0; i < 3; ++i)\n" | |
| 2084 " a.shift();\n" | |
| 2085 "findUntrackedObjects();\n"); | |
| 2086 } | |
| 2087 | |
| 2088 | |
| 2089 static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot, | 2071 static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot, |
| 2090 const char* path[], | 2072 const char* path[], |
| 2091 int depth) { | 2073 int depth) { |
| 2092 const v8::HeapGraphNode* node = snapshot->GetRoot(); | 2074 const v8::HeapGraphNode* node = snapshot->GetRoot(); |
| 2093 for (int current_depth = 0; current_depth < depth; ++current_depth) { | 2075 for (int current_depth = 0; current_depth < depth; ++current_depth) { |
| 2094 int i, count = node->GetChildrenCount(); | 2076 int i, count = node->GetChildrenCount(); |
| 2095 for (i = 0; i < count; ++i) { | 2077 for (i = 0; i < count; ++i) { |
| 2096 const v8::HeapGraphEdge* edge = node->GetChild(i); | 2078 const v8::HeapGraphEdge* edge = node->GetChild(i); |
| 2097 const v8::HeapGraphNode* to_node = edge->GetToNode(); | 2079 const v8::HeapGraphNode* to_node = edge->GetToNode(); |
| 2098 v8::String::Utf8Value edge_name(edge->GetName()); | 2080 v8::String::Utf8Value edge_name(edge->GetName()); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2174 "var instances = [];\n" | 2156 "var instances = [];\n" |
| 2175 "function start() {\n" | 2157 "function start() {\n" |
| 2176 " for (var i = 0; i < width; i++) {\n" | 2158 " for (var i = 0; i < width; i++) {\n" |
| 2177 " instances.push(topFunctions[i](0));\n" | 2159 " instances.push(topFunctions[i](0));\n" |
| 2178 " }\n" | 2160 " }\n" |
| 2179 "}\n" | 2161 "}\n" |
| 2180 "\n" | 2162 "\n" |
| 2181 "for (var i = 0; i < 100; i++) start();\n"; | 2163 "for (var i = 0; i < 100; i++) start();\n"; |
| 2182 | 2164 |
| 2183 | 2165 |
| 2184 static i::HeapSnapshot* ToInternal(const v8::HeapSnapshot* snapshot) { | |
| 2185 return const_cast<i::HeapSnapshot*>( | |
| 2186 reinterpret_cast<const i::HeapSnapshot*>(snapshot)); | |
| 2187 } | |
| 2188 | |
| 2189 | |
| 2190 static AllocationTraceNode* FindNode( | 2166 static AllocationTraceNode* FindNode( |
| 2191 AllocationTracker* tracker, const Vector<const char*>& names) { | 2167 AllocationTracker* tracker, const Vector<const char*>& names) { |
| 2192 AllocationTraceNode* node = tracker->trace_tree()->root(); | 2168 AllocationTraceNode* node = tracker->trace_tree()->root(); |
| 2193 for (int i = 0; node != NULL && i < names.length(); i++) { | 2169 for (int i = 0; node != NULL && i < names.length(); i++) { |
| 2194 const char* name = names[i]; | 2170 const char* name = names[i]; |
| 2195 Vector<AllocationTraceNode*> children = node->children(); | 2171 Vector<AllocationTraceNode*> children = node->children(); |
| 2196 node = NULL; | 2172 node = NULL; |
| 2197 for (int j = 0; j < children.length(); j++) { | 2173 for (int j = 0; j < children.length(); j++) { |
| 2198 v8::SnapshotObjectId id = children[j]->function_id(); | 2174 v8::SnapshotObjectId id = children[j]->function_id(); |
| 2199 AllocationTracker::FunctionInfo* info = tracker->GetFunctionInfo(id); | 2175 AllocationTracker::FunctionInfo* info = tracker->GetFunctionInfo(id); |
| 2200 if (info && strcmp(info->name, name) == 0) { | 2176 if (info && strcmp(info->name, name) == 0) { |
| 2201 node = children[j]; | 2177 node = children[j]; |
| 2202 break; | 2178 break; |
| 2203 } | 2179 } |
| 2204 } | 2180 } |
| 2205 } | 2181 } |
| 2206 return node; | 2182 return node; |
| 2207 } | 2183 } |
| 2208 | 2184 |
| 2209 | 2185 |
| 2186 TEST(ArrayGrowLeftTrim) { |
| 2187 LocalContext env; |
| 2188 v8::HandleScope scope(env->GetIsolate()); |
| 2189 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 2190 heap_profiler->StartTrackingHeapObjects(true); |
| 2191 |
| 2192 CompileRun( |
| 2193 "var a = [];\n" |
| 2194 "for (var i = 0; i < 5; ++i)\n" |
| 2195 " a[i] = i;\n" |
| 2196 "for (var i = 0; i < 3; ++i)\n" |
| 2197 " a.shift();\n"); |
| 2198 |
| 2199 const char* names[] = { "(anonymous function)" }; |
| 2200 AllocationTracker* tracker = |
| 2201 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker(); |
| 2202 CHECK_NE(NULL, tracker); |
| 2203 // Resolve all function locations. |
| 2204 tracker->PrepareForSerialization(); |
| 2205 // Print for better diagnostics in case of failure. |
| 2206 tracker->trace_tree()->Print(tracker); |
| 2207 |
| 2208 AllocationTraceNode* node = |
| 2209 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); |
| 2210 CHECK_NE(NULL, node); |
| 2211 CHECK_GE(node->allocation_count(), 2); |
| 2212 CHECK_GE(node->allocation_size(), 4 * 5); |
| 2213 heap_profiler->StopTrackingHeapObjects(); |
| 2214 } |
| 2215 |
| 2216 |
| 2210 TEST(TrackHeapAllocations) { | 2217 TEST(TrackHeapAllocations) { |
| 2211 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 2218 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
| 2212 LocalContext env; | 2219 LocalContext env; |
| 2213 | 2220 |
| 2214 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); | 2221 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 2215 heap_profiler->StartRecordingHeapAllocations(); | 2222 heap_profiler->StartTrackingHeapObjects(true); |
| 2216 | 2223 |
| 2217 CompileRun(record_trace_tree_source); | 2224 CompileRun(record_trace_tree_source); |
| 2218 | 2225 |
| 2219 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot( | 2226 AllocationTracker* tracker = |
| 2220 v8::String::NewFromUtf8(env->GetIsolate(), "Test")); | 2227 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker(); |
| 2221 i::HeapSnapshotsCollection* collection = ToInternal(snapshot)->collection(); | |
| 2222 AllocationTracker* tracker = collection->allocation_tracker(); | |
| 2223 CHECK_NE(NULL, tracker); | 2228 CHECK_NE(NULL, tracker); |
| 2224 // Resolve all function locations. | 2229 // Resolve all function locations. |
| 2225 tracker->PrepareForSerialization(); | 2230 tracker->PrepareForSerialization(); |
| 2226 // Print for better diagnostics in case of failure. | 2231 // Print for better diagnostics in case of failure. |
| 2227 tracker->trace_tree()->Print(tracker); | 2232 tracker->trace_tree()->Print(tracker); |
| 2228 | 2233 |
| 2229 const char* names[] = | 2234 const char* names[] = |
| 2230 { "(anonymous function)", "start", "f_0_0", "f_0_1", "f_0_2" }; | 2235 { "(anonymous function)", "start", "f_0_0", "f_0_1", "f_0_2" }; |
| 2231 AllocationTraceNode* node = | 2236 AllocationTraceNode* node = |
| 2232 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); | 2237 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); |
| 2233 CHECK_NE(NULL, node); | 2238 CHECK_NE(NULL, node); |
| 2234 CHECK_GE(node->allocation_count(), 100); | 2239 CHECK_GE(node->allocation_count(), 100); |
| 2235 CHECK_GE(node->allocation_size(), 4 * node->allocation_count()); | 2240 CHECK_GE(node->allocation_size(), 4 * node->allocation_count()); |
| 2236 heap_profiler->StopRecordingHeapAllocations(); | 2241 heap_profiler->StopTrackingHeapObjects(); |
| 2237 } | 2242 } |
| 2238 | 2243 |
| 2239 | 2244 |
| 2240 static const char* inline_heap_allocation_source = | 2245 static const char* inline_heap_allocation_source = |
| 2241 "function f_0(x) {\n" | 2246 "function f_0(x) {\n" |
| 2242 " return f_1(x+1);\n" | 2247 " return f_1(x+1);\n" |
| 2243 "}\n" | 2248 "}\n" |
| 2244 "%NeverOptimizeFunction(f_0);\n" | 2249 "%NeverOptimizeFunction(f_0);\n" |
| 2245 "function f_1(x) {\n" | 2250 "function f_1(x) {\n" |
| 2246 " return new f_2(x+1);\n" | 2251 " return new f_2(x+1);\n" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2258 | 2263 |
| 2259 TEST(TrackBumpPointerAllocations) { | 2264 TEST(TrackBumpPointerAllocations) { |
| 2260 i::FLAG_allow_natives_syntax = true; | 2265 i::FLAG_allow_natives_syntax = true; |
| 2261 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 2266 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
| 2262 LocalContext env; | 2267 LocalContext env; |
| 2263 | 2268 |
| 2264 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); | 2269 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 2265 const char* names[] = { "(anonymous function)", "start", "f_0", "f_1" }; | 2270 const char* names[] = { "(anonymous function)", "start", "f_0", "f_1" }; |
| 2266 // First check that normally all allocations are recorded. | 2271 // First check that normally all allocations are recorded. |
| 2267 { | 2272 { |
| 2268 heap_profiler->StartRecordingHeapAllocations(); | 2273 heap_profiler->StartTrackingHeapObjects(true); |
| 2269 | 2274 |
| 2270 CompileRun(inline_heap_allocation_source); | 2275 CompileRun(inline_heap_allocation_source); |
| 2271 | 2276 |
| 2272 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot( | 2277 AllocationTracker* tracker = |
| 2273 v8::String::NewFromUtf8(env->GetIsolate(), "Test2")); | 2278 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker(); |
| 2274 i::HeapSnapshotsCollection* collection = ToInternal(snapshot)->collection(); | |
| 2275 AllocationTracker* tracker = collection->allocation_tracker(); | |
| 2276 CHECK_NE(NULL, tracker); | 2279 CHECK_NE(NULL, tracker); |
| 2277 // Resolve all function locations. | 2280 // Resolve all function locations. |
| 2278 tracker->PrepareForSerialization(); | 2281 tracker->PrepareForSerialization(); |
| 2279 // Print for better diagnostics in case of failure. | 2282 // Print for better diagnostics in case of failure. |
| 2280 tracker->trace_tree()->Print(tracker); | 2283 tracker->trace_tree()->Print(tracker); |
| 2281 | 2284 |
| 2282 AllocationTraceNode* node = | 2285 AllocationTraceNode* node = |
| 2283 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); | 2286 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); |
| 2284 CHECK_NE(NULL, node); | 2287 CHECK_NE(NULL, node); |
| 2285 CHECK_GE(node->allocation_count(), 100); | 2288 CHECK_GE(node->allocation_count(), 100); |
| 2286 CHECK_GE(node->allocation_size(), 4 * node->allocation_count()); | 2289 CHECK_GE(node->allocation_size(), 4 * node->allocation_count()); |
| 2287 heap_profiler->StopRecordingHeapAllocations(); | 2290 heap_profiler->StopTrackingHeapObjects(); |
| 2288 } | 2291 } |
| 2289 | 2292 |
| 2290 { | 2293 { |
| 2291 heap_profiler->StartRecordingHeapAllocations(); | 2294 heap_profiler->StartTrackingHeapObjects(true); |
| 2292 | 2295 |
| 2293 // Now check that not all allocations are tracked if we manually reenable | 2296 // Now check that not all allocations are tracked if we manually reenable |
| 2294 // inline allocations. | 2297 // inline allocations. |
| 2295 CHECK(CcTest::heap()->inline_allocation_disabled()); | 2298 CHECK(CcTest::heap()->inline_allocation_disabled()); |
| 2296 CcTest::heap()->EnableInlineAllocation(); | 2299 CcTest::heap()->EnableInlineAllocation(); |
| 2297 | 2300 |
| 2298 CompileRun(inline_heap_allocation_source); | 2301 CompileRun(inline_heap_allocation_source); |
| 2299 | 2302 |
| 2300 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot( | 2303 AllocationTracker* tracker = |
| 2301 v8::String::NewFromUtf8(env->GetIsolate(), "Test1")); | 2304 reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker(); |
| 2302 i::HeapSnapshotsCollection* collection = ToInternal(snapshot)->collection(); | |
| 2303 AllocationTracker* tracker = collection->allocation_tracker(); | |
| 2304 CHECK_NE(NULL, tracker); | 2305 CHECK_NE(NULL, tracker); |
| 2305 // Resolve all function locations. | 2306 // Resolve all function locations. |
| 2306 tracker->PrepareForSerialization(); | 2307 tracker->PrepareForSerialization(); |
| 2307 // Print for better diagnostics in case of failure. | 2308 // Print for better diagnostics in case of failure. |
| 2308 tracker->trace_tree()->Print(tracker); | 2309 tracker->trace_tree()->Print(tracker); |
| 2309 | 2310 |
| 2310 AllocationTraceNode* node = | 2311 AllocationTraceNode* node = |
| 2311 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); | 2312 FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); |
| 2312 CHECK_NE(NULL, node); | 2313 CHECK_NE(NULL, node); |
| 2313 CHECK_LT(node->allocation_count(), 100); | 2314 CHECK_LT(node->allocation_count(), 100); |
| 2314 | 2315 |
| 2315 CcTest::heap()->DisableInlineAllocation(); | 2316 CcTest::heap()->DisableInlineAllocation(); |
| 2316 heap_profiler->StopRecordingHeapAllocations(); | 2317 heap_profiler->StopTrackingHeapObjects(); |
| 2317 } | 2318 } |
| 2318 } | 2319 } |
| OLD | NEW |