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_firstTracedScriptWrappable(false) { | |
161 m_nodesRequiringTracing.clear(); | |
162 } | |
163 | |
164 void VisitPersistentHandle(v8::Persistent<v8::Value>* value, | |
165 uint16_t classId) override { | |
166 if (classId != WrapperTypeInfo::NodeClassId) | |
167 return; | |
168 | |
169 DCHECK(!value->IsIndependent()); | |
170 v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New( | |
171 m_isolate, v8::Persistent<v8::Object>::Cast(*value)); | |
172 DCHECK(V8Node::hasInstance(wrapper, m_isolate)); | |
173 Node* node = V8Node::toImpl(wrapper); | |
174 Node* root = V8GCController::opaqueRootForGC(m_isolate, node); | |
175 m_nodesRequiringTracing[root].push_back(node); | |
haraken
2017/01/16 02:46:56
Why don't you need to push Nodes that are found du
Michael Lippautz
2017/01/16 10:45:06
VisitPersistentHandle visits all persistent handle
haraken
2017/01/16 12:48:13
What happens if there is a pending activity on a D
Michael Lippautz
2017/01/16 13:15:38
Then tracePendingActivities will catch it.
| |
176 } | |
177 | |
178 // Trace through the blink heap to find all V8 wrappers reachable from | |
179 // ActiveScriptWrappables. Also collect retainer edges on the way. | |
180 void tracePendingActivities() { | |
181 CHECK(m_tempFoundV8Wrappers.empty()); | |
182 m_currentParent = nullptr; | |
183 | |
184 TracePrologue(); | |
185 ActiveScriptWrappableBase::traceActiveScriptWrappables(m_isolate, this); | |
186 AdvanceTracing( | |
187 0, | |
188 v8::EmbedderHeapTracer::AdvanceTracingActions( | |
189 v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION)); | |
190 // Abort instead of Epilogue as we want to finish synchronously. | |
191 AbortTracing(); | |
haraken
2017/01/16 02:46:56
What's a difference between AbortTracing and Epilo
Michael Lippautz
2017/01/16 10:45:06
Since we finished the line before with FORE_COMPLE
haraken
2017/01/16 12:48:12
Yeah, that looks tidier. (You can address it in a
Michael Lippautz
2017/01/16 13:15:38
Acknowledged.
| |
192 | |
193 m_groups.push_back( | |
194 std::make_pair(new SuspendableObjectsInfo(m_tempFoundV8Wrappers.size()), | |
195 std::move(m_tempFoundV8Wrappers))); | |
196 } | |
197 | |
198 // Trace through the blink heap to find all V8 wrappers reachable from | |
199 // the nodes that require tracing. Also collect retainer edges on the way. | |
200 void traceNodesThatRequireTracing() { | |
haraken
2017/01/16 02:46:56
I'm not sure why we need the complexity of traceNo
Michael Lippautz
2017/01/16 10:45:06
We cannot do that, as we need a mapping from nodes
| |
201 for (auto& groupPair : m_nodesRequiringTracing) { | |
202 v8::HeapProfiler::RetainerChildren groupChildren; | |
203 for (auto& node : groupPair.second) { | |
204 auto wrappers = findV8WrappersDirectlyReachableFrom(node); | |
205 groupChildren.insert(wrappers.begin(), wrappers.end()); | |
206 } | |
207 m_groups.push_back(std::make_pair(new RetainedDOMInfo(groupPair.first), | |
208 std::move(groupChildren))); | |
209 } | |
210 } | |
211 | |
212 v8::HeapProfiler::RetainerEdges edges() { return std::move(m_edges); } | |
213 v8::HeapProfiler::RetainerGroups groups() { return std::move(m_groups); } | |
214 | |
215 void markWrapper(const v8::PersistentBase<v8::Value>* value) const override { | |
216 if (!m_tracingInProgress) | |
haraken
2017/01/16 02:46:56
Can this happen?
Michael Lippautz
2017/01/16 10:45:06
Removed as it cannot happen. This was copied over
| |
217 return; | |
218 if (m_currentParent && m_currentParent != value) | |
219 m_edges.push_back(std::make_pair(m_currentParent, value)); | |
220 m_tempFoundV8Wrappers.insert(value); | |
221 } | |
222 | |
223 void dispatchTraceWrappers(const TraceWrapperBase* traceable) const override { | |
224 if (!m_onlyTraceSingleLevel || !traceable->isScriptWrappable() || | |
225 m_firstTracedScriptWrappable) { | |
226 m_firstTracedScriptWrappable = false; | |
227 traceable->traceWrappers(this); | |
228 } | |
haraken
2017/01/16 02:46:56
Don't we need to reset m_firstTracedScriptWrappabl
Michael Lippautz
2017/01/16 10:45:06
Yes, that's the intention. It should find wrappers
haraken
2017/01/16 12:48:13
But what happens if there are multiple ScriptWrapp
Michael Lippautz
2017/01/16 13:15:38
They are traced and we insert edges from the v8 wr
haraken
2017/01/17 00:31:25
Imagine the following object graph:
Node --> Tr
Michael Lippautz
2017/01/17 09:15:32
Works, and here is why :)
My assumptions:
- Node
haraken
2017/01/17 09:22:41
Ah, I was missing this point.
| |
229 } | |
230 | |
231 private: | |
232 v8::HeapProfiler::RetainerChildren findV8WrappersDirectlyReachableFrom( | |
233 Node* traceable) { | |
234 CHECK(m_tempFoundV8Wrappers.empty()); | |
235 WTF::AutoReset<bool>(&m_onlyTraceSingleLevel, true); | |
236 m_firstTracedScriptWrappable = true; | |
haraken
2017/01/16 02:46:56
Maybe should we flip true/false?
Initially the fi
Michael Lippautz
2017/01/16 10:45:06
Done.
| |
237 m_currentParent = | |
238 &v8::Persistent<v8::Value>::Cast(*traceable->rawMainWorldWrapper()); | |
239 | |
240 TracePrologue(); | |
241 traceable->wrapperTypeInfo()->traceWrappers(this, traceable); | |
242 AdvanceTracing( | |
243 0, | |
244 v8::EmbedderHeapTracer::AdvanceTracingActions( | |
245 v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION)); | |
246 // Abort instead of Epilogue as we want to finish synchronously. | |
247 AbortTracing(); | |
248 | |
249 return std::move(m_tempFoundV8Wrappers); | |
250 } | |
251 | |
252 // Input obtained from |VisitPersistentHandle|. | |
253 std::unordered_map<Node*, std::vector<Node*>> m_nodesRequiringTracing; | |
254 | |
255 // Temporaries used for tracing a single Node. | |
256 const v8::PersistentBase<v8::Value>* m_currentParent; | |
257 bool m_onlyTraceSingleLevel; | |
258 mutable bool m_firstTracedScriptWrappable; | |
259 mutable v8::HeapProfiler::RetainerChildren m_tempFoundV8Wrappers; | |
haraken
2017/01/16 02:46:56
m_tempFoundV8Wrappers => m_foundV8Wrappers
Michael Lippautz
2017/01/16 10:45:06
Done.
| |
260 | |
261 // Out variables | |
262 mutable v8::HeapProfiler::RetainerEdges m_edges; | |
263 mutable v8::HeapProfiler::RetainerGroups m_groups; | |
264 }; | |
265 | |
266 // The function |getRetainerInfos| processing all handles on the blink heap, | |
267 // logically grouping together DOM trees (attached and detached) and pending | |
268 // activities, while at the same time finding parent to child relationships | |
269 // for non-Node wrappers. Since we are processing *all* handles there is no | |
270 // way we miss out on a handle. V8 will figure out the liveness information | |
271 // for the provided information itself. | |
272 v8::HeapProfiler::RetainerInfos V8GCController::getRetainerInfos( | |
273 v8::Isolate* isolate) { | |
274 HeapSnaphotWrapperVisitor tracer(isolate); | |
haraken
2017/01/16 02:46:56
I guess we should use:
std::unique_ptr<HeapSnap
Michael Lippautz
2017/01/16 10:45:06
Done.
| |
275 V8PerIsolateData::TemporaryScriptWrappableVisitorScope scope(isolate, | |
276 &tracer); | |
277 | |
278 // Collect which handles need to be processed. | |
279 isolate->VisitHandlesWithClassIds(&tracer); | |
haraken
2017/01/16 02:46:56
Nit: I'd prefer writing this as tracer->traceV8Roo
Michael Lippautz
2017/01/16 10:51:01
Done: collectV8Roots.
| |
280 | |
281 tracer.tracePendingActivities(); | |
282 tracer.traceNodesThatRequireTracing(); | |
haraken
2017/01/16 02:46:56
Nit: tracer->traceBlinkRoots().
Michael Lippautz
2017/01/16 10:51:01
This is now traceV8Roots, as it traces exactly wha
| |
283 | |
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 |