| 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 |