Chromium Code Reviews| 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 |