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 Persistent_h | 5 #ifndef Persistent_h |
6 #define Persistent_h | 6 #define Persistent_h |
7 | 7 |
8 #include "platform/heap/Heap.h" | 8 #include "platform/heap/Heap.h" |
9 #include "platform/heap/Member.h" | 9 #include "platform/heap/Member.h" |
10 #include "platform/heap/PersistentNode.h" | 10 #include "platform/heap/PersistentNode.h" |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 // Register the persistent node as a 'static reference', | 149 // Register the persistent node as a 'static reference', |
150 // belonging to the current thread and a persistent that must | 150 // belonging to the current thread and a persistent that must |
151 // be cleared when the ThreadState itself is cleared out and | 151 // be cleared when the ThreadState itself is cleared out and |
152 // destructed. | 152 // destructed. |
153 // | 153 // |
154 // Static singletons arrange for this to happen, either to ensure | 154 // Static singletons arrange for this to happen, either to ensure |
155 // clean LSan leak reports or to register a thread-local persistent | 155 // clean LSan leak reports or to register a thread-local persistent |
156 // needing to be cleared out before the thread is terminated. | 156 // needing to be cleared out before the thread is terminated. |
157 PersistentBase* registerAsStaticReference() { | 157 PersistentBase* registerAsStaticReference() { |
158 if (m_persistentNode) { | 158 if (m_persistentNode) { |
159 ASSERT(ThreadState::current()); | 159 DCHECK(ThreadState::current()); |
160 ThreadState::current()->registerStaticPersistentNode(m_persistentNode, | 160 ThreadState::current()->registerStaticPersistentNode(m_persistentNode, |
161 nullptr); | 161 nullptr); |
162 LEAK_SANITIZER_IGNORE_OBJECT(this); | 162 LEAK_SANITIZER_IGNORE_OBJECT(this); |
163 } | 163 } |
164 return this; | 164 return this; |
165 } | 165 } |
166 | 166 |
167 protected: | 167 protected: |
168 NO_SANITIZE_ADDRESS | 168 NO_SANITIZE_ADDRESS |
169 T* atomicGet() { | 169 T* atomicGet() { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 handleWeakPersistent); | 202 handleWeakPersistent); |
203 else | 203 else |
204 visitor->registerWeakMembers(this, m_raw, handleWeakPersistent); | 204 visitor->registerWeakMembers(this, m_raw, handleWeakPersistent); |
205 } else { | 205 } else { |
206 visitor->mark(m_raw); | 206 visitor->mark(m_raw); |
207 } | 207 } |
208 } | 208 } |
209 | 209 |
210 NO_SANITIZE_ADDRESS | 210 NO_SANITIZE_ADDRESS |
211 void initialize() { | 211 void initialize() { |
212 ASSERT(!m_persistentNode); | 212 DCHECK(!m_persistentNode); |
213 if (!m_raw || isHashTableDeletedValue()) | 213 if (!m_raw || isHashTableDeletedValue()) |
214 return; | 214 return; |
215 | 215 |
216 TraceCallback traceCallback = | 216 TraceCallback traceCallback = |
217 TraceMethodDelegate<PersistentBase, | 217 TraceMethodDelegate<PersistentBase, |
218 &PersistentBase::tracePersistent>::trampoline; | 218 &PersistentBase::tracePersistent>::trampoline; |
219 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { | 219 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { |
220 ProcessHeap::crossThreadPersistentRegion().allocatePersistentNode( | 220 ProcessHeap::crossThreadPersistentRegion().allocatePersistentNode( |
221 m_persistentNode, this, traceCallback); | 221 m_persistentNode, this, traceCallback); |
222 return; | 222 return; |
223 } | 223 } |
224 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); | 224 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); |
225 ASSERT(state->checkThread()); | 225 DCHECK(state->checkThread()); |
226 m_persistentNode = state->getPersistentRegion()->allocatePersistentNode( | 226 m_persistentNode = state->getPersistentRegion()->allocatePersistentNode( |
227 this, traceCallback); | 227 this, traceCallback); |
228 #if ENABLE(ASSERT) | 228 #if DCHECK_IS_ON() |
229 m_state = state; | 229 m_state = state; |
230 #endif | 230 #endif |
231 } | 231 } |
232 | 232 |
233 void uninitialize() { | 233 void uninitialize() { |
234 // TODO(haraken): This is a short-term hack to prevent use-after-frees | 234 // TODO(haraken): This is a short-term hack to prevent use-after-frees |
235 // during a shutdown sequence. | 235 // during a shutdown sequence. |
236 // 1) blink::shutdown() frees the underlying storage for persistent nodes. | 236 // 1) blink::shutdown() frees the underlying storage for persistent nodes. |
237 // 2) ~MessageLoop() destructs some Chromium-side objects that hold | 237 // 2) ~MessageLoop() destructs some Chromium-side objects that hold |
238 // Persistent. It touches the underlying storage and crashes. | 238 // Persistent. It touches the underlying storage and crashes. |
239 if (WTF::isShutdown()) | 239 if (WTF::isShutdown()) |
240 return; | 240 return; |
241 | 241 |
242 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { | 242 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { |
243 if (acquireLoad(reinterpret_cast<void* volatile*>(&m_persistentNode))) | 243 if (acquireLoad(reinterpret_cast<void* volatile*>(&m_persistentNode))) |
244 ProcessHeap::crossThreadPersistentRegion().freePersistentNode( | 244 ProcessHeap::crossThreadPersistentRegion().freePersistentNode( |
245 m_persistentNode); | 245 m_persistentNode); |
246 return; | 246 return; |
247 } | 247 } |
248 | 248 |
249 if (!m_persistentNode) | 249 if (!m_persistentNode) |
250 return; | 250 return; |
251 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); | 251 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); |
252 ASSERT(state->checkThread()); | 252 DCHECK(state->checkThread()); |
253 // Persistent handle must be created and destructed in the same thread. | 253 // Persistent handle must be created and destructed in the same thread. |
254 ASSERT(m_state == state); | 254 DCHECK(m_state == state); |
255 state->freePersistentNode(m_persistentNode); | 255 state->freePersistentNode(m_persistentNode); |
256 m_persistentNode = nullptr; | 256 m_persistentNode = nullptr; |
257 } | 257 } |
258 | 258 |
259 void checkPointer() { | 259 void checkPointer() { |
260 #if DCHECK_IS_ON() | 260 #if DCHECK_IS_ON() |
261 if (!m_raw || isHashTableDeletedValue()) | 261 if (!m_raw || isHashTableDeletedValue()) |
262 return; | 262 return; |
263 | 263 |
264 if (crossThreadnessConfiguration != CrossThreadPersistentConfiguration) { | 264 if (crossThreadnessConfiguration != CrossThreadPersistentConfiguration) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 weaknessConfiguration, crossThreadnessConfiguration>; | 307 weaknessConfiguration, crossThreadnessConfiguration>; |
308 Base* persistent = reinterpret_cast<Base*>(persistentPointer); | 308 Base* persistent = reinterpret_cast<Base*>(persistentPointer); |
309 T* object = persistent->get(); | 309 T* object = persistent->get(); |
310 if (object && !ObjectAliveTrait<T>::isHeapObjectAlive(object)) | 310 if (object && !ObjectAliveTrait<T>::isHeapObjectAlive(object)) |
311 persistent->clear(); | 311 persistent->clear(); |
312 } | 312 } |
313 | 313 |
314 // m_raw is accessed most, so put it at the first field. | 314 // m_raw is accessed most, so put it at the first field. |
315 T* m_raw; | 315 T* m_raw; |
316 PersistentNode* m_persistentNode = nullptr; | 316 PersistentNode* m_persistentNode = nullptr; |
317 #if ENABLE(ASSERT) | 317 #if DCHECK_IS_ON() |
318 ThreadState* m_state = nullptr; | 318 ThreadState* m_state = nullptr; |
319 #endif | 319 #endif |
320 #if DCHECK_IS_ON() | 320 #if DCHECK_IS_ON() |
321 const ThreadState* m_creationThreadState; | 321 const ThreadState* m_creationThreadState; |
322 #endif | 322 #endif |
323 }; | 323 }; |
324 | 324 |
325 // Persistent is a way to create a strong pointer from an off-heap object | 325 // Persistent is a way to create a strong pointer from an off-heap object |
326 // to another on-heap object. As long as the Persistent handle is alive | 326 // to another on-heap object. As long as the Persistent handle is alive |
327 // the GC will keep the object pointed to alive. The Persistent handle is | 327 // the GC will keep the object pointed to alive. The Persistent handle is |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 PersistentHeapCollectionBase(const OtherCollection& other) | 575 PersistentHeapCollectionBase(const OtherCollection& other) |
576 : Collection(other) { | 576 : Collection(other) { |
577 initialize(); | 577 initialize(); |
578 } | 578 } |
579 | 579 |
580 ~PersistentHeapCollectionBase() { uninitialize(); } | 580 ~PersistentHeapCollectionBase() { uninitialize(); } |
581 | 581 |
582 // See PersistentBase::registerAsStaticReference() comment. | 582 // See PersistentBase::registerAsStaticReference() comment. |
583 PersistentHeapCollectionBase* registerAsStaticReference() { | 583 PersistentHeapCollectionBase* registerAsStaticReference() { |
584 if (m_persistentNode) { | 584 if (m_persistentNode) { |
585 ASSERT(ThreadState::current()); | 585 DCHECK(ThreadState::current()); |
586 ThreadState::current()->registerStaticPersistentNode( | 586 ThreadState::current()->registerStaticPersistentNode( |
587 m_persistentNode, | 587 m_persistentNode, |
588 &PersistentHeapCollectionBase<Collection>::clearPersistentNode); | 588 &PersistentHeapCollectionBase<Collection>::clearPersistentNode); |
589 LEAK_SANITIZER_IGNORE_OBJECT(this); | 589 LEAK_SANITIZER_IGNORE_OBJECT(this); |
590 } | 590 } |
591 return this; | 591 return this; |
592 } | 592 } |
593 | 593 |
594 private: | 594 private: |
595 template <typename VisitorDispatcher> | 595 template <typename VisitorDispatcher> |
596 void tracePersistent(VisitorDispatcher visitor) { | 596 void tracePersistent(VisitorDispatcher visitor) { |
597 static_assert(sizeof(Collection), "Collection must be fully defined"); | 597 static_assert(sizeof(Collection), "Collection must be fully defined"); |
598 visitor->trace(*static_cast<Collection*>(this)); | 598 visitor->trace(*static_cast<Collection*>(this)); |
599 } | 599 } |
600 | 600 |
601 // Used when the registered PersistentNode of this object is | 601 // Used when the registered PersistentNode of this object is |
602 // released during ThreadState shutdown, clearing the association. | 602 // released during ThreadState shutdown, clearing the association. |
603 static void clearPersistentNode(void* self) { | 603 static void clearPersistentNode(void* self) { |
604 PersistentHeapCollectionBase<Collection>* collection = | 604 PersistentHeapCollectionBase<Collection>* collection = |
605 (reinterpret_cast<PersistentHeapCollectionBase<Collection>*>(self)); | 605 (reinterpret_cast<PersistentHeapCollectionBase<Collection>*>(self)); |
606 collection->uninitialize(); | 606 collection->uninitialize(); |
607 collection->clear(); | 607 collection->clear(); |
608 } | 608 } |
609 | 609 |
610 NO_SANITIZE_ADDRESS | 610 NO_SANITIZE_ADDRESS |
611 void initialize() { | 611 void initialize() { |
612 // FIXME: Derive affinity based on the collection. | 612 // FIXME: Derive affinity based on the collection. |
613 ThreadState* state = ThreadState::current(); | 613 ThreadState* state = ThreadState::current(); |
614 ASSERT(state->checkThread()); | 614 DCHECK(state->checkThread()); |
615 m_persistentNode = state->getPersistentRegion()->allocatePersistentNode( | 615 m_persistentNode = state->getPersistentRegion()->allocatePersistentNode( |
616 this, | 616 this, |
617 TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, | 617 TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, |
618 &PersistentHeapCollectionBase< | 618 &PersistentHeapCollectionBase< |
619 Collection>::tracePersistent>::trampoline); | 619 Collection>::tracePersistent>::trampoline); |
620 #if ENABLE(ASSERT) | 620 #if DCHECK_IS_ON() |
621 m_state = state; | 621 m_state = state; |
622 #endif | 622 #endif |
623 } | 623 } |
624 | 624 |
625 void uninitialize() { | 625 void uninitialize() { |
626 if (!m_persistentNode) | 626 if (!m_persistentNode) |
627 return; | 627 return; |
628 ThreadState* state = ThreadState::current(); | 628 ThreadState* state = ThreadState::current(); |
629 ASSERT(state->checkThread()); | 629 DCHECK(state->checkThread()); |
630 // Persistent handle must be created and destructed in the same thread. | 630 // Persistent handle must be created and destructed in the same thread. |
631 ASSERT(m_state == state); | 631 DCHECK(m_state == state); |
632 state->freePersistentNode(m_persistentNode); | 632 state->freePersistentNode(m_persistentNode); |
633 m_persistentNode = nullptr; | 633 m_persistentNode = nullptr; |
634 } | 634 } |
635 | 635 |
636 PersistentNode* m_persistentNode; | 636 PersistentNode* m_persistentNode; |
637 #if ENABLE(ASSERT) | 637 #if DCHECK_IS_ON() |
638 ThreadState* m_state; | 638 ThreadState* m_state; |
639 #endif | 639 #endif |
640 }; | 640 }; |
641 | 641 |
642 template <typename KeyArg, | 642 template <typename KeyArg, |
643 typename MappedArg, | 643 typename MappedArg, |
644 typename HashArg = typename DefaultHash<KeyArg>::Hash, | 644 typename HashArg = typename DefaultHash<KeyArg>::Hash, |
645 typename KeyTraitsArg = HashTraits<KeyArg>, | 645 typename KeyTraitsArg = HashTraits<KeyArg>, |
646 typename MappedTraitsArg = HashTraits<MappedArg>> | 646 typename MappedTraitsArg = HashTraits<MappedArg>> |
647 class PersistentHeapHashMap | 647 class PersistentHeapHashMap |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 static blink::CrossThreadPersistent<T> Unwrap( | 820 static blink::CrossThreadPersistent<T> Unwrap( |
821 const blink::CrossThreadWeakPersistent<T>& wrapped) { | 821 const blink::CrossThreadWeakPersistent<T>& wrapped) { |
822 blink::CrossThreadPersistentRegion::LockScope persistentLock( | 822 blink::CrossThreadPersistentRegion::LockScope persistentLock( |
823 blink::ProcessHeap::crossThreadPersistentRegion()); | 823 blink::ProcessHeap::crossThreadPersistentRegion()); |
824 return blink::CrossThreadPersistent<T>(wrapped.get()); | 824 return blink::CrossThreadPersistent<T>(wrapped.get()); |
825 } | 825 } |
826 }; | 826 }; |
827 } | 827 } |
828 | 828 |
829 #endif // Persistent_h | 829 #endif // Persistent_h |
OLD | NEW |