OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef ScriptWrappableVisitor_h | 5 // This file has been moved to platform/bindings/ScriptWrappableVisitor.h. |
6 #define ScriptWrappableVisitor_h | 6 // TODO(adithyas): Remove this file. |
7 | 7 #include "platform/bindings/ScriptWrappableVisitor.h" |
8 #include "core/CoreExport.h" | |
9 #include "platform/RuntimeEnabledFeatures.h" | |
10 #include "platform/heap/HeapPage.h" | |
11 #include "platform/heap/VisitorImpl.h" | |
12 #include "platform/heap/WrapperVisitor.h" | |
13 #include "platform/wtf/Deque.h" | |
14 #include "platform/wtf/Vector.h" | |
15 #include "v8/include/v8.h" | |
16 | |
17 namespace blink { | |
18 | |
19 class HeapObjectHeader; | |
20 template <typename T> | |
21 class Member; | |
22 class ScriptWrappable; | |
23 template <typename T> | |
24 class TraceWrapperV8Reference; | |
25 | |
26 class WrapperMarkingData { | |
27 public: | |
28 WrapperMarkingData( | |
29 void (*trace_wrappers_callback)(const WrapperVisitor*, const void*), | |
30 HeapObjectHeader* (*heap_object_header_callback)(const void*), | |
31 const void* object) | |
32 : trace_wrappers_callback_(trace_wrappers_callback), | |
33 heap_object_header_callback_(heap_object_header_callback), | |
34 raw_object_pointer_(object) { | |
35 DCHECK(trace_wrappers_callback_); | |
36 DCHECK(heap_object_header_callback_); | |
37 DCHECK(raw_object_pointer_); | |
38 } | |
39 | |
40 inline void TraceWrappers(WrapperVisitor* visitor) { | |
41 if (raw_object_pointer_) { | |
42 trace_wrappers_callback_(visitor, raw_object_pointer_); | |
43 } | |
44 } | |
45 | |
46 // Returns true when object was marked. Ignores (returns true) invalidated | |
47 // objects. | |
48 inline bool IsWrapperHeaderMarked() { | |
49 return !raw_object_pointer_ || | |
50 GetHeapObjectHeader()->IsWrapperHeaderMarked(); | |
51 } | |
52 | |
53 inline const void* RawObjectPointer() { return raw_object_pointer_; } | |
54 | |
55 private: | |
56 inline bool ShouldBeInvalidated() { | |
57 return raw_object_pointer_ && !GetHeapObjectHeader()->IsMarked(); | |
58 } | |
59 | |
60 inline void Invalidate() { raw_object_pointer_ = nullptr; } | |
61 | |
62 inline const HeapObjectHeader* GetHeapObjectHeader() { | |
63 DCHECK(raw_object_pointer_); | |
64 return heap_object_header_callback_(raw_object_pointer_); | |
65 } | |
66 | |
67 void (*trace_wrappers_callback_)(const WrapperVisitor*, const void*); | |
68 HeapObjectHeader* (*heap_object_header_callback_)(const void*); | |
69 const void* raw_object_pointer_; | |
70 | |
71 friend class ScriptWrappableVisitor; | |
72 }; | |
73 | |
74 // ScriptWrappableVisitor is able to trace through the objects to get all | |
75 // wrappers. It is used during V8 garbage collection. When this visitor is | |
76 // set to the v8::Isolate as its embedder heap tracer, V8 will call it during | |
77 // its garbage collection. At the beginning, it will call TracePrologue, then | |
78 // repeatedly it will call AdvanceTracing, and at the end it will call | |
79 // TraceEpilogue. Everytime V8 finds new wrappers, it will let the tracer | |
80 // know using RegisterV8References. | |
81 class CORE_EXPORT ScriptWrappableVisitor : public v8::EmbedderHeapTracer, | |
82 public WrapperVisitor { | |
83 DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptWrappableVisitor); | |
84 | |
85 public: | |
86 ScriptWrappableVisitor(v8::Isolate* isolate) : isolate_(isolate){}; | |
87 ~ScriptWrappableVisitor() override; | |
88 | |
89 // Replace all dead objects in the marking deque with nullptr after oilpan | |
90 // gc. | |
91 static void InvalidateDeadObjectsInMarkingDeque(v8::Isolate*); | |
92 | |
93 // Immediately clean up all wrappers. | |
94 static void PerformCleanup(v8::Isolate*); | |
95 | |
96 void TracePrologue() override; | |
97 | |
98 static WrapperVisitor* CurrentVisitor(v8::Isolate*); | |
99 | |
100 static void WriteBarrier(v8::Isolate*, | |
101 const void*, | |
102 const TraceWrapperV8Reference<v8::Value>*); | |
103 | |
104 // TODO(mlippautz): Remove once ScriptWrappable is converted to | |
105 // TraceWrapperV8Reference. | |
106 static void WriteBarrier(v8::Isolate*, const v8::Persistent<v8::Object>*); | |
107 | |
108 template <typename T> | |
109 static void WriteBarrier(const void* object, const Member<T>& value) { | |
110 WriteBarrier(object, value.Get()); | |
111 } | |
112 | |
113 template <typename T> | |
114 static void WriteBarrier(const void* src_object, const T* dst_object) { | |
115 static_assert(!NeedsAdjustAndMark<T>::value, | |
116 "wrapper tracing is not supported within mixins"); | |
117 if (!src_object || !dst_object) { | |
118 return; | |
119 } | |
120 // We only require a write barrier if |srcObject| is already marked. Note | |
121 // that this implicitly disables the write barrier when the GC is not | |
122 // active as object will not be marked in this case. | |
123 if (!HeapObjectHeader::FromPayload(src_object)->IsWrapperHeaderMarked()) { | |
124 return; | |
125 } | |
126 | |
127 const ThreadState* thread_state = ThreadState::Current(); | |
128 DCHECK(thread_state); | |
129 // If the wrapper is already marked we can bail out here. | |
130 if (TraceTrait<T>::GetHeapObjectHeader(dst_object)->IsWrapperHeaderMarked()) | |
131 return; | |
132 // Otherwise, eagerly mark the wrapper header and put the object on the | |
133 // marking deque for further processing. | |
134 WrapperVisitor* const visitor = CurrentVisitor(thread_state->GetIsolate()); | |
135 visitor->MarkAndPushToMarkingDeque(dst_object); | |
136 } | |
137 | |
138 void RegisterV8References(const std::vector<std::pair<void*, void*>>& | |
139 internal_fields_of_potential_wrappers) override; | |
140 void RegisterV8Reference(const std::pair<void*, void*>& internal_fields); | |
141 bool AdvanceTracing(double deadline_in_ms, | |
142 v8::EmbedderHeapTracer::AdvanceTracingActions) override; | |
143 void TraceEpilogue() override; | |
144 void AbortTracing() override; | |
145 void EnterFinalPause() override; | |
146 size_t NumberOfWrappersToTrace() override; | |
147 | |
148 void DispatchTraceWrappers(const TraceWrapperBase*) const override; | |
149 | |
150 void TraceWrappers(const TraceWrapperV8Reference<v8::Value>&) const override; | |
151 void MarkWrapper(const v8::PersistentBase<v8::Value>*) const override; | |
152 | |
153 void InvalidateDeadObjectsInMarkingDeque(); | |
154 | |
155 bool MarkWrapperHeader(HeapObjectHeader*) const; | |
156 | |
157 // Mark wrappers in all worlds for the given script wrappable as alive in | |
158 // V8. | |
159 void MarkWrappersInAllWorlds(const ScriptWrappable*) const override; | |
160 | |
161 WTF::Deque<WrapperMarkingData>* GetMarkingDeque() { return &marking_deque_; } | |
162 WTF::Deque<WrapperMarkingData>* GetVerifierDeque() { | |
163 return &verifier_deque_; | |
164 } | |
165 WTF::Vector<HeapObjectHeader*>* GetHeadersToUnmark() { | |
166 return &headers_to_unmark_; | |
167 } | |
168 | |
169 // Immediately cleans up all wrappers if necessary. | |
170 void PerformCleanup(); | |
171 | |
172 protected: | |
173 bool PushToMarkingDeque( | |
174 void (*trace_wrappers_callback)(const WrapperVisitor*, const void*), | |
175 HeapObjectHeader* (*heap_object_header_callback)(const void*), | |
176 void (*missed_write_barrier_callback)(void), | |
177 const void* object) const override { | |
178 if (!tracing_in_progress_) | |
179 return false; | |
180 | |
181 marking_deque_.push_back(WrapperMarkingData( | |
182 trace_wrappers_callback, heap_object_header_callback, object)); | |
183 #if DCHECK_IS_ON() | |
184 if (!advancing_tracing_) { | |
185 verifier_deque_.push_back(WrapperMarkingData( | |
186 trace_wrappers_callback, heap_object_header_callback, object)); | |
187 } | |
188 #endif | |
189 return true; | |
190 } | |
191 | |
192 // Returns true if wrapper tracing is currently in progress, i.e., | |
193 // TracePrologue has been called, and TraceEpilogue has not yet been called. | |
194 bool tracing_in_progress_ = false; | |
195 | |
196 // Is AdvanceTracing currently running? If not, we know that all calls of | |
197 // pushToMarkingDeque are from V8 or new wrapper associations. And this | |
198 // information is used by the verifier feature. | |
199 bool advancing_tracing_ = false; | |
200 | |
201 // Indicates whether an idle task for a lazy cleanup has already been | |
202 // scheduled. The flag is used to avoid scheduling multiple idle tasks for | |
203 // cleaning up. | |
204 bool idle_cleanup_task_scheduled_ = false; | |
205 | |
206 // Indicates whether cleanup should currently happen. The flag is used to | |
207 // avoid cleaning up in the next GC cycle. | |
208 bool should_cleanup_ = false; | |
209 | |
210 // Schedule an idle task to perform a lazy (incremental) clean up of | |
211 // wrappers. | |
212 void ScheduleIdleLazyCleanup(); | |
213 void PerformLazyCleanup(double deadline_seconds); | |
214 | |
215 // Collection of objects we need to trace from. We assume it is safe to hold | |
216 // on to the raw pointers because: | |
217 // - oilpan object cannot move | |
218 // - oilpan gc will call invalidateDeadObjectsInMarkingDeque to delete all | |
219 // obsolete objects | |
220 mutable WTF::Deque<WrapperMarkingData> marking_deque_; | |
221 | |
222 // Collection of objects we started tracing from. We assume it is safe to | |
223 // hold on to the raw pointers because: | |
224 // - oilpan object cannot move | |
225 // - oilpan gc will call invalidateDeadObjectsInMarkingDeque to delete | |
226 // all obsolete objects | |
227 // | |
228 // These objects are used when TraceWrappablesVerifier feature is enabled to | |
229 // verify that all objects reachable in the atomic pause were marked | |
230 // incrementally. If not, there is one or multiple write barriers missing. | |
231 mutable WTF::Deque<WrapperMarkingData> verifier_deque_; | |
232 | |
233 // Collection of headers we need to unmark after the tracing finished. We | |
234 // assume it is safe to hold on to the headers because: | |
235 // - oilpan objects cannot move | |
236 // - objects this headers belong to are invalidated by the oilpan GC in | |
237 // invalidateDeadObjectsInMarkingDeque. | |
238 mutable WTF::Vector<HeapObjectHeader*> headers_to_unmark_; | |
239 v8::Isolate* isolate_; | |
240 }; | |
241 | |
242 } // namespace blink | |
243 | |
244 #endif // ScriptWrappableVisitor_h | |
OLD | NEW |