Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2014 Google Inc. All rights reserved. | 2 * Copyright (C) 2014 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 class PersistentNode { | 51 class PersistentNode { |
| 52 public: | 52 public: |
| 53 explicit PersistentNode(TraceCallback trace) | 53 explicit PersistentNode(TraceCallback trace) |
| 54 : m_trace(trace) | 54 : m_trace(trace) |
| 55 { | 55 { |
| 56 } | 56 } |
| 57 | 57 |
| 58 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 58 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 59 bool isHeapObjectAlive() { return m_trace; } | 59 bool isHeapObjectAlive() { return m_trace; } |
| 60 | 60 |
| 61 virtual ~PersistentNode() | |
| 62 { | |
| 63 ASSERT(isHeapObjectAlive()); | |
| 64 m_trace = nullptr; | |
| 65 } | |
| 66 | |
| 67 // This operator= is important. Without having the operator=, m_next and | 61 // This operator= is important. Without having the operator=, m_next and |
| 68 // m_prev are inproperly copied and it breaks the link list of the | 62 // m_prev are inproperly copied and it breaks the link list of the |
| 69 // persistent handles. | 63 // persistent handles. |
| 70 inline PersistentNode& operator=(const PersistentNode& otherref) { return *t his; } | 64 inline PersistentNode& operator=(const PersistentNode& otherref) { return *t his; } |
| 71 | 65 |
| 72 private: | 66 private: |
| 73 // Ideally the trace method should be virtual and automatically dispatch | 67 // Ideally the trace method should be virtual and automatically dispatch |
| 74 // to the most specific implementation. However having a virtual method | 68 // to the most specific implementation. However having a virtual method |
| 75 // on PersistentNode leads to too eager template instantiation with MSVC | 69 // on PersistentNode leads to too eager template instantiation with MSVC |
| 76 // which leads to include cycles. | 70 // which leads to include cycles. |
| 77 // Instead we call the constructor with a TraceCallback which knows the | 71 // Instead we call the constructor with a TraceCallback which knows the |
| 78 // type of the most specific child and calls trace directly. See | 72 // type of the most specific child and calls trace directly. See |
| 79 // TraceMethodDelegate in Visitor.h for how this is done. | 73 // TraceMethodDelegate in Visitor.h for how this is done. |
| 80 void tracePersistentNode(Visitor* visitor) | 74 void tracePersistentNode(Visitor* visitor) |
| 81 { | 75 { |
| 82 m_trace(visitor, this); | 76 m_trace(visitor, this); |
| 83 } | 77 } |
| 84 | 78 |
| 79 ~PersistentNode() | |
| 80 { | |
| 81 } | |
| 82 | |
| 85 TraceCallback m_trace; | 83 TraceCallback m_trace; |
| 86 PersistentNode* m_next; | 84 PersistentNode* m_next; |
| 87 PersistentNode* m_prev; | 85 PersistentNode* m_prev; |
| 88 | 86 |
| 89 template<typename T> friend class CrossThreadPersistent; | 87 template<typename T> friend class CrossThreadPersistent; |
| 90 template<typename T> friend class Persistent; | 88 template<typename T> friend class Persistent; |
| 91 template<typename Collection> friend class PersistentHeapCollectionBase; | 89 template<typename Collection> friend class PersistentHeapCollectionBase; |
| 92 friend class PersistentAnchor; | 90 friend class PersistentAnchor; |
| 93 friend class ThreadState; | 91 friend class ThreadState; |
| 94 }; | 92 }; |
| 95 | 93 |
| 96 // A dummy Persistent handle that ensures the list of persistents is never null. | 94 // A dummy Persistent handle that ensures the list of persistents is never null. |
| 97 // This removes a test from a hot path. | 95 // This removes a test from a hot path. |
| 98 class PersistentAnchor : public PersistentNode { | 96 class PersistentAnchor : public PersistentNode { |
| 99 public: | 97 public: |
| 100 void tracePersistentNodes(Visitor* visitor) | 98 void tracePersistentNodes(Visitor* visitor) |
| 101 { | 99 { |
| 102 for (PersistentNode* current = m_next; current != this; current = curren t->m_next) | 100 for (PersistentNode* current = m_next; current != this; current = curren t->m_next) |
| 103 current->tracePersistentNode(visitor); | 101 current->tracePersistentNode(visitor); |
| 104 } | 102 } |
| 105 | 103 |
| 106 int numberOfPersistents() | 104 int numberOfPersistents() |
| 107 { | 105 { |
| 108 int numberOfPersistents = 0; | 106 int numberOfPersistents = 0; |
| 109 for (PersistentNode* current = m_next; current != this; current = curren t->m_next) | 107 for (PersistentNode* current = m_next; current != this; current = curren t->m_next) |
| 110 ++numberOfPersistents; | 108 ++numberOfPersistents; |
| 111 return numberOfPersistents; | 109 return numberOfPersistents; |
| 112 } | 110 } |
| 113 | 111 |
| 114 virtual ~PersistentAnchor() | 112 ~PersistentAnchor() |
| 115 { | 113 { |
| 116 // FIXME: oilpan: Ideally we should have no left-over persistents at thi s point. However currently there is a | 114 m_trace = nullptr; |
| 117 // large number of objects leaked when we tear down the main thread. Sin ce some of these might contain a | |
| 118 // persistent or e.g. be RefCountedGarbageCollected we cannot guarantee there are no remaining Persistents at | |
| 119 // this point. | |
|
haraken
2015/06/09 08:58:42
Removed this FIXME because it is not realistic to
| |
| 120 } | 115 } |
| 121 | 116 |
| 122 template<typename VisitorDispatcher> | 117 template<typename VisitorDispatcher> |
| 123 void trace(VisitorDispatcher visitor) | 118 void trace(VisitorDispatcher visitor) |
| 124 { | 119 { |
| 125 ASSERT_NOT_REACHED(); | 120 ASSERT_NOT_REACHED(); |
| 126 } | 121 } |
| 127 | 122 |
| 128 private: | 123 private: |
| 129 PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &P ersistentAnchor::trace>::trampoline) | 124 PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &P ersistentAnchor::trace>::trampoline) |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 template<typename U> | 196 template<typename U> |
| 202 Persistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDelegate<Pers istent<T>, &Persistent<T>::trace>::trampoline), m_raw(other.get()) | 197 Persistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDelegate<Pers istent<T>, &Persistent<T>::trace>::trampoline), m_raw(other.get()) |
| 203 { | 198 { |
| 204 initialize(); | 199 initialize(); |
| 205 checkPointer(); | 200 checkPointer(); |
| 206 recordBacktrace(); | 201 recordBacktrace(); |
| 207 } | 202 } |
| 208 | 203 |
| 209 void clear() { m_raw = nullptr; } | 204 void clear() { m_raw = nullptr; } |
| 210 | 205 |
| 211 virtual ~Persistent() | 206 ~Persistent() |
| 212 { | 207 { |
| 213 uninitialize(); | 208 uninitialize(); |
| 214 m_raw = nullptr; | 209 m_raw = nullptr; |
| 210 m_trace = nullptr; | |
| 215 } | 211 } |
| 216 | 212 |
| 217 template<typename VisitorDispatcher> | 213 template<typename VisitorDispatcher> |
| 218 void trace(VisitorDispatcher visitor) | 214 void trace(VisitorDispatcher visitor) |
| 219 { | 215 { |
| 220 static_assert(sizeof(T), "T must be fully defined"); | 216 static_assert(sizeof(T), "T must be fully defined"); |
| 221 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); | 217 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); |
| 222 #if ENABLE(GC_PROFILING) | 218 #if ENABLE(GC_PROFILING) |
| 223 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tr acingName); | 219 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tr acingName); |
| 224 #endif | 220 #endif |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 401 template<typename U> | 397 template<typename U> |
| 402 CrossThreadPersistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDe legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(other.get()) | 398 CrossThreadPersistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDe legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(other.get()) |
| 403 { | 399 { |
| 404 initialize(); | 400 initialize(); |
| 405 checkPointer(); | 401 checkPointer(); |
| 406 recordBacktrace(); | 402 recordBacktrace(); |
| 407 } | 403 } |
| 408 | 404 |
| 409 void clear() { m_raw = nullptr; } | 405 void clear() { m_raw = nullptr; } |
| 410 | 406 |
| 411 virtual ~CrossThreadPersistent() | 407 ~CrossThreadPersistent() |
| 412 { | 408 { |
| 413 uninitialize(); | 409 uninitialize(); |
| 414 m_raw = nullptr; | 410 m_raw = nullptr; |
| 411 m_trace = nullptr; | |
| 415 } | 412 } |
| 416 | 413 |
| 417 template<typename VisitorDispatcher> | 414 template<typename VisitorDispatcher> |
| 418 void trace(VisitorDispatcher visitor) | 415 void trace(VisitorDispatcher visitor) |
| 419 { | 416 { |
| 420 static_assert(sizeof(T), "T must be fully defined"); | 417 static_assert(sizeof(T), "T must be fully defined"); |
| 421 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); | 418 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); |
| 422 #if ENABLE(GC_PROFILING) | 419 #if ENABLE(GC_PROFILING) |
| 423 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "CrossThreadPersist ent" : m_tracingName); | 420 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "CrossThreadPersist ent" : m_tracingName); |
| 424 #endif | 421 #endif |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 538 m_tracingName = Heap::createBacktraceString(); | 535 m_tracingName = Heap::createBacktraceString(); |
| 539 } | 536 } |
| 540 | 537 |
| 541 String m_tracingName; | 538 String m_tracingName; |
| 542 #else | 539 #else |
| 543 inline void recordBacktrace() const { } | 540 inline void recordBacktrace() const { } |
| 544 #endif | 541 #endif |
| 545 T* m_raw; | 542 T* m_raw; |
| 546 }; | 543 }; |
| 547 | 544 |
| 545 // PersistentNode must be the left-most class to let the | |
| 546 // visitor->trace(static_cast<Collection*>(this)) trace the correct position. | |
|
haraken
2015/06/09 08:58:42
It took me a couple of hours to notice this... Bef
| |
| 548 // FIXME: derive affinity based on the collection. | 547 // FIXME: derive affinity based on the collection. |
| 549 template<typename Collection> | 548 template<typename Collection> |
| 550 class PersistentHeapCollectionBase : public Collection, public PersistentNode { | 549 class PersistentHeapCollectionBase : public PersistentNode, public Collection { |
| 551 // We overload the various new and delete operators with using the WTF Defau ltAllocator to ensure persistent | 550 // We overload the various new and delete operators with using the WTF Defau ltAllocator to ensure persistent |
| 552 // heap collections are always allocated off-heap. This allows persistent co llections to be used in | 551 // heap collections are always allocated off-heap. This allows persistent co llections to be used in |
| 553 // DEFINE_STATIC_LOCAL et. al. | 552 // DEFINE_STATIC_LOCAL et. al. |
| 554 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); | 553 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); |
| 555 public: | 554 public: |
| 556 PersistentHeapCollectionBase() : PersistentNode(TraceMethodDelegate<Persiste ntHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::tra ce>::trampoline) | 555 PersistentHeapCollectionBase() : PersistentNode(TraceMethodDelegate<Persiste ntHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::tra ce>::trampoline) |
| 557 { | 556 { |
| 558 initialize(); | 557 initialize(); |
| 559 } | 558 } |
| 560 | 559 |
| 561 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Co llection(other), PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase <Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline) | 560 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Pe rsistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &Pers istentHeapCollectionBase<Collection>::trace>::trampoline), Collection(other) |
| 562 { | 561 { |
| 563 initialize(); | 562 initialize(); |
| 564 } | 563 } |
| 565 | 564 |
| 566 template<typename OtherCollection> | 565 template<typename OtherCollection> |
| 567 PersistentHeapCollectionBase(const OtherCollection& other) : Collection(othe r), PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline) | 566 PersistentHeapCollectionBase(const OtherCollection& other) : PersistentNode( TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCol lectionBase<Collection>::trace>::trampoline), Collection(other) |
| 568 { | 567 { |
| 569 initialize(); | 568 initialize(); |
| 570 } | 569 } |
| 571 | 570 |
| 572 ~PersistentHeapCollectionBase() | 571 ~PersistentHeapCollectionBase() |
| 573 { | 572 { |
| 574 uninitialize(); | 573 uninitialize(); |
| 574 m_trace = nullptr; | |
| 575 } | 575 } |
| 576 | 576 |
| 577 template<typename VisitorDispatcher> | 577 template<typename VisitorDispatcher> |
| 578 void trace(VisitorDispatcher visitor) | 578 void trace(VisitorDispatcher visitor) |
| 579 { | 579 { |
| 580 static_assert(sizeof(Collection), "Collection must be fully defined"); | 580 static_assert(sizeof(Collection), "Collection must be fully defined"); |
| 581 #if ENABLE(GC_PROFILING) | 581 #if ENABLE(GC_PROFILING) |
| 582 visitor->setHostInfo(this, "PersistentHeapCollectionBase"); | 582 visitor->setHostInfo(this, "PersistentHeapCollectionBase"); |
| 583 #endif | 583 #endif |
| 584 visitor->trace(*static_cast<Collection*>(this)); | 584 visitor->trace(*static_cast<Collection*>(this)); |
| (...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1290 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin k::IsGarbageCollectedType<T>::value> { | 1290 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin k::IsGarbageCollectedType<T>::value> { |
| 1291 static_assert(sizeof(T), "T must be fully defined"); | 1291 static_assert(sizeof(T), "T must be fully defined"); |
| 1292 }; | 1292 }; |
| 1293 | 1293 |
| 1294 template<typename T> | 1294 template<typename T> |
| 1295 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; | 1295 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; |
| 1296 | 1296 |
| 1297 } // namespace WTF | 1297 } // namespace WTF |
| 1298 | 1298 |
| 1299 #endif | 1299 #endif |
| OLD | NEW |