OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2009 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 #include "core/html/imports/HTMLImportsController.h" | 44 #include "core/html/imports/HTMLImportsController.h" |
45 #include "core/inspector/InspectorTraceEvents.h" | 45 #include "core/inspector/InspectorTraceEvents.h" |
46 #include "platform/Histogram.h" | 46 #include "platform/Histogram.h" |
47 #include "platform/RuntimeEnabledFeatures.h" | 47 #include "platform/RuntimeEnabledFeatures.h" |
48 #include "platform/instrumentation/tracing/TraceEvent.h" | 48 #include "platform/instrumentation/tracing/TraceEvent.h" |
49 #include "public/platform/BlameContext.h" | 49 #include "public/platform/BlameContext.h" |
50 #include "public/platform/Platform.h" | 50 #include "public/platform/Platform.h" |
51 #include "wtf/Vector.h" | 51 #include "wtf/Vector.h" |
52 #include "wtf/allocator/Partitions.h" | 52 #include "wtf/allocator/Partitions.h" |
53 #include <algorithm> | 53 #include <algorithm> |
| 54 #include <unordered_map> |
| 55 #include <unordered_set> |
54 | 56 |
55 namespace blink { | 57 namespace blink { |
56 | 58 |
57 // FIXME: This should use opaque GC roots. | 59 // FIXME: This should use opaque GC roots. |
58 static void addReferencesForNodeWithEventListeners( | 60 static void addReferencesForNodeWithEventListeners( |
59 v8::Isolate* isolate, | 61 v8::Isolate* isolate, |
60 Node* node, | 62 Node* node, |
61 const v8::Persistent<v8::Object>& wrapper) { | 63 const v8::Persistent<v8::Object>& wrapper) { |
62 ASSERT(node->hasEventListeners()); | 64 ASSERT(node->hasEventListeners()); |
63 | 65 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 v8::Persistent<v8::Object>::Cast(*value).MarkActive(); | 143 v8::Persistent<v8::Object>::Cast(*value).MarkActive(); |
142 return; | 144 return; |
143 } | 145 } |
144 } | 146 } |
145 } | 147 } |
146 | 148 |
147 private: | 149 private: |
148 v8::Isolate* m_isolate; | 150 v8::Isolate* m_isolate; |
149 }; | 151 }; |
150 | 152 |
| 153 class HeapSnaphotWrapperVisitor : public ScriptWrappableVisitor, |
| 154 public v8::PersistentHandleVisitor { |
| 155 public: |
| 156 explicit HeapSnaphotWrapperVisitor(v8::Isolate* isolate) |
| 157 : ScriptWrappableVisitor(isolate), |
| 158 m_currentParent(nullptr), |
| 159 m_onlyTraceSingleLevel(false), |
| 160 m_firstScriptWrappableTraced(false) {} |
| 161 |
| 162 // Collect interesting V8 roots for the heap snapshot. Currently these are |
| 163 // DOM nodes. |
| 164 void collectV8Roots() { m_isolate->VisitHandlesWithClassIds(this); } |
| 165 |
| 166 void VisitPersistentHandle(v8::Persistent<v8::Value>* value, |
| 167 uint16_t classId) override { |
| 168 if (classId != WrapperTypeInfo::NodeClassId) |
| 169 return; |
| 170 |
| 171 DCHECK(!value->IsIndependent()); |
| 172 v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New( |
| 173 m_isolate, v8::Persistent<v8::Object>::Cast(*value)); |
| 174 DCHECK(V8Node::hasInstance(wrapper, m_isolate)); |
| 175 Node* node = V8Node::toImpl(wrapper); |
| 176 Node* root = V8GCController::opaqueRootForGC(m_isolate, node); |
| 177 m_nodesRequiringTracing[root].push_back(node); |
| 178 } |
| 179 |
| 180 // Trace through the blink heap to find all V8 wrappers reachable from |
| 181 // ActiveScriptWrappables. Also collect retainer edges on the way. |
| 182 void tracePendingActivities() { |
| 183 CHECK(m_foundV8Wrappers.empty()); |
| 184 m_currentParent = nullptr; |
| 185 |
| 186 TracePrologue(); |
| 187 ActiveScriptWrappableBase::traceActiveScriptWrappables(m_isolate, this); |
| 188 AdvanceTracing( |
| 189 0, |
| 190 v8::EmbedderHeapTracer::AdvanceTracingActions( |
| 191 v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION)); |
| 192 // Abort instead of Epilogue as we want to finish synchronously. |
| 193 AbortTracing(); |
| 194 |
| 195 m_groups.push_back( |
| 196 std::make_pair(new SuspendableObjectsInfo(m_foundV8Wrappers.size()), |
| 197 std::move(m_foundV8Wrappers))); |
| 198 } |
| 199 |
| 200 // Trace through the blink heap to find all V8 wrappers reachable from any |
| 201 // of the collected roots. Also collect retainer edges on the way. |
| 202 void traceV8Roots() { |
| 203 for (auto& groupPair : m_nodesRequiringTracing) { |
| 204 v8::HeapProfiler::RetainerChildren groupChildren; |
| 205 for (auto& node : groupPair.second) { |
| 206 auto wrappers = findV8WrappersDirectlyReachableFrom(node); |
| 207 groupChildren.insert(wrappers.begin(), wrappers.end()); |
| 208 } |
| 209 m_groups.push_back(std::make_pair(new RetainedDOMInfo(groupPair.first), |
| 210 std::move(groupChildren))); |
| 211 } |
| 212 } |
| 213 |
| 214 v8::HeapProfiler::RetainerEdges edges() { return std::move(m_edges); } |
| 215 v8::HeapProfiler::RetainerGroups groups() { return std::move(m_groups); } |
| 216 |
| 217 void markWrapper(const v8::PersistentBase<v8::Value>* value) const override { |
| 218 if (m_currentParent && m_currentParent != value) |
| 219 m_edges.push_back(std::make_pair(m_currentParent, value)); |
| 220 m_foundV8Wrappers.insert(value); |
| 221 } |
| 222 |
| 223 void dispatchTraceWrappers(const TraceWrapperBase* traceable) const override { |
| 224 if (!m_onlyTraceSingleLevel || !traceable->isScriptWrappable() || |
| 225 !reinterpret_cast<const ScriptWrappable*>(traceable) |
| 226 ->containsWrapper() || |
| 227 !m_firstScriptWrappableTraced) { |
| 228 m_firstScriptWrappableTraced = true; |
| 229 traceable->traceWrappers(this); |
| 230 } |
| 231 } |
| 232 |
| 233 private: |
| 234 v8::HeapProfiler::RetainerChildren findV8WrappersDirectlyReachableFrom( |
| 235 Node* traceable) { |
| 236 CHECK(m_foundV8Wrappers.empty()); |
| 237 WTF::AutoReset<bool>(&m_onlyTraceSingleLevel, true); |
| 238 m_firstScriptWrappableTraced = false; |
| 239 m_currentParent = |
| 240 &v8::Persistent<v8::Value>::Cast(*traceable->rawMainWorldWrapper()); |
| 241 |
| 242 TracePrologue(); |
| 243 traceable->wrapperTypeInfo()->traceWrappers(this, traceable); |
| 244 AdvanceTracing( |
| 245 0, |
| 246 v8::EmbedderHeapTracer::AdvanceTracingActions( |
| 247 v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION)); |
| 248 // Abort instead of Epilogue as we want to finish synchronously. |
| 249 AbortTracing(); |
| 250 |
| 251 return std::move(m_foundV8Wrappers); |
| 252 } |
| 253 |
| 254 // Input obtained from |VisitPersistentHandle|. |
| 255 std::unordered_map<Node*, std::vector<Node*>> m_nodesRequiringTracing; |
| 256 |
| 257 // Temporaries used for tracing a single Node. |
| 258 const v8::PersistentBase<v8::Value>* m_currentParent; |
| 259 bool m_onlyTraceSingleLevel; |
| 260 mutable bool m_firstScriptWrappableTraced; |
| 261 mutable v8::HeapProfiler::RetainerChildren m_foundV8Wrappers; |
| 262 |
| 263 // Out variables |
| 264 mutable v8::HeapProfiler::RetainerEdges m_edges; |
| 265 mutable v8::HeapProfiler::RetainerGroups m_groups; |
| 266 }; |
| 267 |
| 268 // The function |getRetainerInfos| processing all handles on the blink heap, |
| 269 // logically grouping together DOM trees (attached and detached) and pending |
| 270 // activities, while at the same time finding parent to child relationships |
| 271 // for non-Node wrappers. Since we are processing *all* handles there is no |
| 272 // way we miss out on a handle. V8 will figure out the liveness information |
| 273 // for the provided information itself. |
| 274 v8::HeapProfiler::RetainerInfos V8GCController::getRetainerInfos( |
| 275 v8::Isolate* isolate) { |
| 276 std::unique_ptr<HeapSnaphotWrapperVisitor> tracer( |
| 277 new HeapSnaphotWrapperVisitor(isolate)); |
| 278 V8PerIsolateData::TemporaryScriptWrappableVisitorScope scope( |
| 279 isolate, std::move(tracer)); |
| 280 |
| 281 tracer->collectV8Roots(); |
| 282 tracer->traceV8Roots(); |
| 283 tracer->tracePendingActivities(); |
| 284 return v8::HeapProfiler::RetainerInfos{tracer->groups(), tracer->edges()}; |
| 285 } |
| 286 |
151 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { | 287 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { |
152 public: | 288 public: |
153 explicit MajorGCWrapperVisitor(v8::Isolate* isolate, | 289 explicit MajorGCWrapperVisitor(v8::Isolate* isolate, |
154 bool constructRetainedObjectInfos) | 290 bool constructRetainedObjectInfos) |
155 : m_isolate(isolate), | 291 : m_isolate(isolate), |
156 m_domObjectsWithPendingActivity(0), | 292 m_domObjectsWithPendingActivity(0), |
157 m_liveRootGroupIdSet(false), | 293 m_liveRootGroupIdSet(false), |
158 m_constructRetainedObjectInfos(constructRetainedObjectInfos) {} | 294 m_constructRetainedObjectInfos(constructRetainedObjectInfos) {} |
159 | 295 |
160 void VisitPersistentHandle(v8::Persistent<v8::Value>* value, | 296 void VisitPersistentHandle(v8::Persistent<v8::Value>* value, |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
544 double startTime = WTF::currentTimeMS(); | 680 double startTime = WTF::currentTimeMS(); |
545 v8::HandleScope scope(isolate); | 681 v8::HandleScope scope(isolate); |
546 PendingActivityVisitor visitor(isolate, executionContext); | 682 PendingActivityVisitor visitor(isolate, executionContext); |
547 toIsolate(executionContext)->VisitHandlesWithClassIds(&visitor); | 683 toIsolate(executionContext)->VisitHandlesWithClassIds(&visitor); |
548 scanPendingActivityHistogram.count( | 684 scanPendingActivityHistogram.count( |
549 static_cast<int>(WTF::currentTimeMS() - startTime)); | 685 static_cast<int>(WTF::currentTimeMS() - startTime)); |
550 return visitor.pendingActivityFound(); | 686 return visitor.pendingActivityFound(); |
551 } | 687 } |
552 | 688 |
553 } // namespace blink | 689 } // namespace blink |
OLD | NEW |