| 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 16 matching lines...) Expand all Loading... |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #ifndef Handle_h | 31 #ifndef Handle_h |
| 32 #define Handle_h | 32 #define Handle_h |
| 33 | 33 |
| 34 #include "platform/heap/Heap.h" | 34 #include "platform/heap/Heap.h" |
| 35 #include "platform/heap/HeapAllocator.h" | 35 #include "platform/heap/HeapAllocator.h" |
| 36 #include "platform/heap/InlinedGlobalMarkingVisitor.h" | 36 #include "platform/heap/InlinedGlobalMarkingVisitor.h" |
| 37 #include "platform/heap/PersistentNode.h" |
| 37 #include "platform/heap/ThreadState.h" | 38 #include "platform/heap/ThreadState.h" |
| 38 #include "platform/heap/TraceTraits.h" | 39 #include "platform/heap/TraceTraits.h" |
| 39 #include "platform/heap/Visitor.h" | 40 #include "platform/heap/Visitor.h" |
| 40 #include "wtf/Functional.h" | 41 #include "wtf/Functional.h" |
| 41 #include "wtf/HashFunctions.h" | 42 #include "wtf/HashFunctions.h" |
| 42 #include "wtf/Locker.h" | 43 #include "wtf/Locker.h" |
| 44 #include "wtf/MainThread.h" |
| 43 #include "wtf/RawPtr.h" | 45 #include "wtf/RawPtr.h" |
| 44 #include "wtf/RefCounted.h" | 46 #include "wtf/RefCounted.h" |
| 45 #include "wtf/TypeTraits.h" | 47 #include "wtf/TypeTraits.h" |
| 46 | 48 |
| 47 namespace blink { | 49 namespace blink { |
| 48 | 50 |
| 49 template<typename T> class HeapTerminatedArray; | 51 template<typename T> class HeapTerminatedArray; |
| 50 | 52 |
| 51 class PersistentNode { | |
| 52 public: | |
| 53 explicit PersistentNode(TraceCallback trace) | |
| 54 : m_trace(trace) | |
| 55 { | |
| 56 } | |
| 57 | |
| 58 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 59 bool isHeapObjectAlive() { return m_trace; } | |
| 60 | |
| 61 // This operator= is important. Without having the operator=, m_next and | |
| 62 // m_prev are inproperly copied and it breaks the link list of the | |
| 63 // persistent handles. | |
| 64 inline PersistentNode& operator=(const PersistentNode& otherref) { return *t
his; } | |
| 65 | |
| 66 private: | |
| 67 // Ideally the trace method should be virtual and automatically dispatch | |
| 68 // to the most specific implementation. However having a virtual method | |
| 69 // on PersistentNode leads to too eager template instantiation with MSVC | |
| 70 // which leads to include cycles. | |
| 71 // Instead we call the constructor with a TraceCallback which knows the | |
| 72 // type of the most specific child and calls trace directly. See | |
| 73 // TraceMethodDelegate in Visitor.h for how this is done. | |
| 74 void tracePersistentNode(Visitor* visitor) | |
| 75 { | |
| 76 m_trace(visitor, this); | |
| 77 } | |
| 78 | |
| 79 ~PersistentNode() | |
| 80 { | |
| 81 } | |
| 82 | |
| 83 TraceCallback m_trace; | |
| 84 PersistentNode* m_next; | |
| 85 PersistentNode* m_prev; | |
| 86 | |
| 87 template<typename T> friend class CrossThreadPersistent; | |
| 88 template<typename T> friend class Persistent; | |
| 89 template<typename Collection> friend class PersistentHeapCollectionBase; | |
| 90 friend class PersistentAnchor; | |
| 91 friend class ThreadState; | |
| 92 }; | |
| 93 | |
| 94 // A dummy Persistent handle that ensures the list of persistents is never null. | |
| 95 // This removes a test from a hot path. | |
| 96 class PersistentAnchor : public PersistentNode { | |
| 97 public: | |
| 98 void tracePersistentNodes(Visitor* visitor) | |
| 99 { | |
| 100 for (PersistentNode* current = m_next; current != this; current = curren
t->m_next) | |
| 101 current->tracePersistentNode(visitor); | |
| 102 } | |
| 103 | |
| 104 int numberOfPersistents() | |
| 105 { | |
| 106 int numberOfPersistents = 0; | |
| 107 for (PersistentNode* current = m_next; current != this; current = curren
t->m_next) | |
| 108 ++numberOfPersistents; | |
| 109 return numberOfPersistents; | |
| 110 } | |
| 111 | |
| 112 ~PersistentAnchor() | |
| 113 { | |
| 114 m_trace = nullptr; | |
| 115 } | |
| 116 | |
| 117 template<typename VisitorDispatcher> | |
| 118 void trace(VisitorDispatcher visitor) | |
| 119 { | |
| 120 ASSERT_NOT_REACHED(); | |
| 121 } | |
| 122 | |
| 123 private: | |
| 124 PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &P
ersistentAnchor::trace>::trampoline) | |
| 125 { | |
| 126 m_next = this; | |
| 127 m_prev = this; | |
| 128 } | |
| 129 | |
| 130 friend class ThreadState; | |
| 131 }; | |
| 132 | |
| 133 // Persistent handles are used to store pointers into the | 53 // Persistent handles are used to store pointers into the |
| 134 // managed heap. As long as the Persistent handle is alive | 54 // managed heap. As long as the Persistent handle is alive |
| 135 // the GC will keep the object pointed to alive. Persistent | 55 // the GC will keep the object pointed to alive. Persistent |
| 136 // handles can be stored in objects and they are not scoped. | 56 // handles can be stored in objects and they are not scoped. |
| 137 // Persistent handles must not be used to contain pointers | 57 // Persistent handles must not be used to contain pointers |
| 138 // between objects that are in the managed heap. They are only | 58 // between objects that are in the managed heap. They are only |
| 139 // meant to point to managed heap objects from variables/members | 59 // meant to point to managed heap objects from variables/members |
| 140 // outside the managed heap. | 60 // outside the managed heap. |
| 141 // | 61 // |
| 142 // A Persistent is always a GC root from the point of view of | 62 // A Persistent is always a GC root from the point of view of |
| 143 // the garbage collector. | 63 // the garbage collector. |
| 144 // | 64 // |
| 145 // We have to construct and destruct Persistent in the same thread. | 65 // We have to construct and destruct Persistent in the same thread. |
| 146 template<typename T> | 66 template<typename T> |
| 147 class Persistent : public PersistentNode { | 67 class Persistent final { |
| 148 public: | 68 public: |
| 149 Persistent() : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent
<T>::trace>::trampoline), m_raw(nullptr) | 69 Persistent() : m_raw(nullptr) |
| 150 { | 70 { |
| 151 initialize(); | 71 initialize(); |
| 152 } | 72 } |
| 153 | 73 |
| 154 Persistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<Persistent<T
>, &Persistent<T>::trace>::trampoline), m_raw(nullptr) | 74 Persistent(std::nullptr_t) : m_raw(nullptr) |
| 155 { | 75 { |
| 156 initialize(); | 76 initialize(); |
| 157 } | 77 } |
| 158 | 78 |
| 159 Persistent(T* raw) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Pers
istent<T>::trace>::trampoline), m_raw(raw) | 79 Persistent(T* raw) : m_raw(raw) |
| 160 { | 80 { |
| 161 initialize(); | 81 initialize(); |
| 162 checkPointer(); | 82 checkPointer(); |
| 163 recordBacktrace(); | 83 recordBacktrace(); |
| 164 } | 84 } |
| 165 | 85 |
| 166 Persistent(T& raw) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Pers
istent<T>::trace>::trampoline), m_raw(&raw) | 86 Persistent(T& raw) : m_raw(&raw) |
| 167 { | 87 { |
| 168 initialize(); | 88 initialize(); |
| 169 checkPointer(); | 89 checkPointer(); |
| 170 recordBacktrace(); | 90 recordBacktrace(); |
| 171 } | 91 } |
| 172 | 92 |
| 173 Persistent(const Persistent& other) : PersistentNode(TraceMethodDelegate<Per
sistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other) | 93 Persistent(const Persistent& other) : m_raw(other) |
| 174 { | 94 { |
| 175 initialize(); | 95 initialize(); |
| 176 checkPointer(); | 96 checkPointer(); |
| 177 recordBacktrace(); | 97 recordBacktrace(); |
| 178 } | 98 } |
| 179 | 99 |
| 180 template<typename U> | 100 template<typename U> |
| 181 Persistent(const Persistent<U>& other) : PersistentNode(TraceMethodDelegate<
Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other) | 101 Persistent(const Persistent<U>& other) : m_raw(other) |
| 182 { | 102 { |
| 183 initialize(); | 103 initialize(); |
| 184 checkPointer(); | 104 checkPointer(); |
| 185 recordBacktrace(); | 105 recordBacktrace(); |
| 186 } | 106 } |
| 187 | 107 |
| 188 template<typename U> | 108 template<typename U> |
| 189 Persistent(const Member<U>& other) : PersistentNode(TraceMethodDelegate<Pers
istent<T>, &Persistent<T>::trace>::trampoline), m_raw(other) | 109 Persistent(const Member<U>& other) : m_raw(other) |
| 190 { | 110 { |
| 191 initialize(); | 111 initialize(); |
| 192 checkPointer(); | 112 checkPointer(); |
| 193 recordBacktrace(); | 113 recordBacktrace(); |
| 194 } | 114 } |
| 195 | 115 |
| 196 template<typename U> | 116 template<typename U> |
| 197 Persistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDelegate<Pers
istent<T>, &Persistent<T>::trace>::trampoline), m_raw(other.get()) | 117 Persistent(const RawPtr<U>& other) : m_raw(other.get()) |
| 198 { | 118 { |
| 199 initialize(); | 119 initialize(); |
| 200 checkPointer(); | 120 checkPointer(); |
| 201 recordBacktrace(); | 121 recordBacktrace(); |
| 202 } | 122 } |
| 203 | 123 |
| 204 void clear() { m_raw = nullptr; } | 124 void clear() { m_raw = nullptr; } |
| 205 | 125 |
| 206 ~Persistent() | 126 ~Persistent() |
| 207 { | 127 { |
| 208 uninitialize(); | 128 uninitialize(); |
| 209 m_raw = nullptr; | 129 m_raw = nullptr; |
| 210 m_trace = nullptr; | |
| 211 } | 130 } |
| 212 | 131 |
| 213 template<typename VisitorDispatcher> | 132 template<typename VisitorDispatcher> |
| 214 void trace(VisitorDispatcher visitor) | 133 void trace(VisitorDispatcher visitor) |
| 215 { | 134 { |
| 216 static_assert(sizeof(T), "T must be fully defined"); | 135 static_assert(sizeof(T), "T must be fully defined"); |
| 217 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); | 136 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); |
| 218 visitor->mark(m_raw); | 137 visitor->mark(m_raw); |
| 219 } | 138 } |
| 220 | 139 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 return *this; | 203 return *this; |
| 285 } | 204 } |
| 286 | 205 |
| 287 T* get() const { return m_raw; } | 206 T* get() const { return m_raw; } |
| 288 | 207 |
| 289 private: | 208 private: |
| 290 void initialize() | 209 void initialize() |
| 291 { | 210 { |
| 292 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); | 211 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); |
| 293 state->checkThread(); | 212 state->checkThread(); |
| 294 m_prev = state->roots(); | 213 m_persistentNode = state->persistentRegion()->allocatePersistentNode(thi
s, TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline); |
| 295 m_next = m_prev->m_next; | |
| 296 m_prev->m_next = this; | |
| 297 m_next->m_prev = this; | |
| 298 } | 214 } |
| 299 | 215 |
| 300 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 301 void uninitialize() | 216 void uninitialize() |
| 302 { | 217 { |
| 303 ASSERT(isHeapObjectAlive()); | 218 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); |
| 304 ASSERT(m_next->isHeapObjectAlive()); | 219 state->checkThread(); |
| 305 ASSERT(m_prev->isHeapObjectAlive()); | 220 state->persistentRegion()->freePersistentNode(m_persistentNode); |
| 306 m_next->m_prev = m_prev; | |
| 307 m_prev->m_next = m_next; | |
| 308 } | 221 } |
| 309 | 222 |
| 310 void checkPointer() | 223 void checkPointer() |
| 311 { | 224 { |
| 312 #if ENABLE(ASSERT) | 225 #if ENABLE(ASSERT) |
| 313 if (!m_raw) | 226 if (!m_raw) |
| 314 return; | 227 return; |
| 315 | 228 |
| 316 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable | 229 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable |
| 317 // object. In other words, it checks that the pointer is either of: | 230 // object. In other words, it checks that the pointer is either of: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 329 void recordBacktrace() | 242 void recordBacktrace() |
| 330 { | 243 { |
| 331 if (m_raw) | 244 if (m_raw) |
| 332 m_tracingName = Heap::createBacktraceString(); | 245 m_tracingName = Heap::createBacktraceString(); |
| 333 } | 246 } |
| 334 | 247 |
| 335 String m_tracingName; | 248 String m_tracingName; |
| 336 #else | 249 #else |
| 337 inline void recordBacktrace() const { } | 250 inline void recordBacktrace() const { } |
| 338 #endif | 251 #endif |
| 252 // m_raw is accessed most, so put it at the first field. |
| 339 T* m_raw; | 253 T* m_raw; |
| 254 PersistentNode* m_persistentNode; |
| 340 }; | 255 }; |
| 341 | 256 |
| 342 // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread | 257 // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread |
| 343 // different from the construction thread. | 258 // different from the construction thread. |
| 344 template<typename T> | 259 template<typename T> |
| 345 class CrossThreadPersistent : public PersistentNode { | 260 class CrossThreadPersistent final { |
| 346 public: | 261 public: |
| 347 CrossThreadPersistent() : PersistentNode(TraceMethodDelegate<CrossThreadPers
istent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(nullptr) | 262 CrossThreadPersistent() : m_raw(nullptr) |
| 348 { | 263 { |
| 349 initialize(); | 264 initialize(); |
| 350 } | 265 } |
| 351 | 266 |
| 352 CrossThreadPersistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<C
rossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(n
ullptr) | 267 CrossThreadPersistent(std::nullptr_t) : m_raw(nullptr) |
| 353 { | 268 { |
| 354 initialize(); | 269 initialize(); |
| 355 } | 270 } |
| 356 | 271 |
| 357 CrossThreadPersistent(T* raw) : PersistentNode(TraceMethodDelegate<CrossThre
adPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(raw) | 272 CrossThreadPersistent(T* raw) : m_raw(raw) |
| 358 { | 273 { |
| 359 initialize(); | 274 initialize(); |
| 360 checkPointer(); | 275 checkPointer(); |
| 361 recordBacktrace(); | 276 recordBacktrace(); |
| 362 } | 277 } |
| 363 | 278 |
| 364 CrossThreadPersistent(T& raw) : PersistentNode(TraceMethodDelegate<CrossThre
adPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(&raw) | 279 CrossThreadPersistent(T& raw) : m_raw(&raw) |
| 365 { | 280 { |
| 366 initialize(); | 281 initialize(); |
| 367 checkPointer(); | 282 checkPointer(); |
| 368 recordBacktrace(); | 283 recordBacktrace(); |
| 369 } | 284 } |
| 370 | 285 |
| 371 CrossThreadPersistent(const CrossThreadPersistent& other) : PersistentNode(T
raceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::
trampoline), m_raw(other) | 286 CrossThreadPersistent(const CrossThreadPersistent& other) : m_raw(other) |
| 372 { | 287 { |
| 373 initialize(); | 288 initialize(); |
| 374 checkPointer(); | 289 checkPointer(); |
| 375 recordBacktrace(); | 290 recordBacktrace(); |
| 376 } | 291 } |
| 377 | 292 |
| 378 template<typename U> | 293 template<typename U> |
| 379 CrossThreadPersistent(const CrossThreadPersistent<U>& other) : PersistentNod
e(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace
>::trampoline), m_raw(other) | 294 CrossThreadPersistent(const CrossThreadPersistent<U>& other) : m_raw(other) |
| 380 { | 295 { |
| 381 initialize(); | 296 initialize(); |
| 382 checkPointer(); | 297 checkPointer(); |
| 383 recordBacktrace(); | 298 recordBacktrace(); |
| 384 } | 299 } |
| 385 | 300 |
| 386 template<typename U> | 301 template<typename U> |
| 387 CrossThreadPersistent(const Member<U>& other) : PersistentNode(TraceMethodDe
legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline),
m_raw(other) | 302 CrossThreadPersistent(const Member<U>& other) : m_raw(other) |
| 388 { | 303 { |
| 389 initialize(); | 304 initialize(); |
| 390 checkPointer(); | 305 checkPointer(); |
| 391 recordBacktrace(); | 306 recordBacktrace(); |
| 392 } | 307 } |
| 393 | 308 |
| 394 template<typename U> | 309 template<typename U> |
| 395 CrossThreadPersistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDe
legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline),
m_raw(other.get()) | 310 CrossThreadPersistent(const RawPtr<U>& other) : m_raw(other.get()) |
| 396 { | 311 { |
| 397 initialize(); | 312 initialize(); |
| 398 checkPointer(); | 313 checkPointer(); |
| 399 recordBacktrace(); | 314 recordBacktrace(); |
| 400 } | 315 } |
| 401 | 316 |
| 402 void clear() { m_raw = nullptr; } | 317 void clear() { m_raw = nullptr; } |
| 403 | 318 |
| 404 ~CrossThreadPersistent() | 319 ~CrossThreadPersistent() |
| 405 { | 320 { |
| 406 uninitialize(); | 321 uninitialize(); |
| 407 m_raw = nullptr; | 322 m_raw = nullptr; |
| 408 m_trace = nullptr; | |
| 409 } | 323 } |
| 410 | 324 |
| 411 template<typename VisitorDispatcher> | 325 template<typename VisitorDispatcher> |
| 412 void trace(VisitorDispatcher visitor) | 326 void trace(VisitorDispatcher visitor) |
| 413 { | 327 { |
| 414 static_assert(sizeof(T), "T must be fully defined"); | 328 static_assert(sizeof(T), "T must be fully defined"); |
| 415 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); | 329 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); |
| 416 visitor->mark(m_raw); | 330 visitor->mark(m_raw); |
| 417 } | 331 } |
| 418 | 332 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 checkPointer(); | 394 checkPointer(); |
| 481 recordBacktrace(); | 395 recordBacktrace(); |
| 482 return *this; | 396 return *this; |
| 483 } | 397 } |
| 484 | 398 |
| 485 T* get() const { return m_raw; } | 399 T* get() const { return m_raw; } |
| 486 | 400 |
| 487 private: | 401 private: |
| 488 void initialize() | 402 void initialize() |
| 489 { | 403 { |
| 490 MutexLocker m_locker(ThreadState::globalRootsMutex()); | 404 m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePe
rsistentNode(this, TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPer
sistent<T>::trace>::trampoline); |
| 491 m_prev = &ThreadState::globalRoots(); | |
| 492 m_next = m_prev->m_next; | |
| 493 m_prev->m_next = this; | |
| 494 m_next->m_prev = this; | |
| 495 } | 405 } |
| 496 | 406 |
| 497 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 498 void uninitialize() | 407 void uninitialize() |
| 499 { | 408 { |
| 500 MutexLocker m_locker(ThreadState::globalRootsMutex()); | 409 ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persiste
ntNode); |
| 501 ASSERT(isHeapObjectAlive()); | |
| 502 ASSERT(m_next->isHeapObjectAlive()); | |
| 503 ASSERT(m_prev->isHeapObjectAlive()); | |
| 504 m_next->m_prev = m_prev; | |
| 505 m_prev->m_next = m_next; | |
| 506 } | 410 } |
| 507 | 411 |
| 508 void checkPointer() | 412 void checkPointer() |
| 509 { | 413 { |
| 510 #if ENABLE(ASSERT) | 414 #if ENABLE(ASSERT) |
| 511 if (!m_raw) | 415 if (!m_raw) |
| 512 return; | 416 return; |
| 513 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable | 417 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable |
| 514 // object. In other words, it checks that the pointer is either of: | 418 // object. In other words, it checks that the pointer is either of: |
| 515 // | 419 // |
| (...skipping 10 matching lines...) Expand all Loading... |
| 526 void recordBacktrace() | 430 void recordBacktrace() |
| 527 { | 431 { |
| 528 if (m_raw) | 432 if (m_raw) |
| 529 m_tracingName = Heap::createBacktraceString(); | 433 m_tracingName = Heap::createBacktraceString(); |
| 530 } | 434 } |
| 531 | 435 |
| 532 String m_tracingName; | 436 String m_tracingName; |
| 533 #else | 437 #else |
| 534 inline void recordBacktrace() const { } | 438 inline void recordBacktrace() const { } |
| 535 #endif | 439 #endif |
| 440 // m_raw is accessed most, so put it at the first field. |
| 536 T* m_raw; | 441 T* m_raw; |
| 442 PersistentNode* m_persistentNode; |
| 537 }; | 443 }; |
| 538 | 444 |
| 539 // PersistentNode must be the left-most class to let the | 445 // PersistentNode must be the left-most class to let the |
| 540 // visitor->trace(static_cast<Collection*>(this)) trace the correct position. | 446 // visitor->trace(static_cast<Collection*>(this)) trace the correct position. |
| 541 // FIXME: derive affinity based on the collection. | 447 // FIXME: derive affinity based on the collection. |
| 542 template<typename Collection> | 448 template<typename Collection> |
| 543 class PersistentHeapCollectionBase : public PersistentNode, public Collection { | 449 class PersistentHeapCollectionBase : public Collection { |
| 544 // We overload the various new and delete operators with using the WTF Defau
ltAllocator to ensure persistent | 450 // We overload the various new and delete operators with using the WTF Defau
ltAllocator to ensure persistent |
| 545 // heap collections are always allocated off-heap. This allows persistent co
llections to be used in | 451 // heap collections are always allocated off-heap. This allows persistent co
llections to be used in |
| 546 // DEFINE_STATIC_LOCAL et. al. | 452 // DEFINE_STATIC_LOCAL et. al. |
| 547 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); | 453 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); |
| 548 public: | 454 public: |
| 549 PersistentHeapCollectionBase() : PersistentNode(TraceMethodDelegate<Persiste
ntHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::tra
ce>::trampoline) | 455 PersistentHeapCollectionBase() |
| 550 { | 456 { |
| 551 initialize(); | 457 initialize(); |
| 552 } | 458 } |
| 553 | 459 |
| 554 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Pe
rsistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &Pers
istentHeapCollectionBase<Collection>::trace>::trampoline), Collection(other) | 460 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Co
llection(other) |
| 555 { | 461 { |
| 556 initialize(); | 462 initialize(); |
| 557 } | 463 } |
| 558 | 464 |
| 559 template<typename OtherCollection> | 465 template<typename OtherCollection> |
| 560 PersistentHeapCollectionBase(const OtherCollection& other) : PersistentNode(
TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCol
lectionBase<Collection>::trace>::trampoline), Collection(other) | 466 PersistentHeapCollectionBase(const OtherCollection& other) : Collection(othe
r) |
| 561 { | 467 { |
| 562 initialize(); | 468 initialize(); |
| 563 } | 469 } |
| 564 | 470 |
| 565 ~PersistentHeapCollectionBase() | 471 ~PersistentHeapCollectionBase() |
| 566 { | 472 { |
| 567 uninitialize(); | 473 uninitialize(); |
| 568 m_trace = nullptr; | |
| 569 } | 474 } |
| 570 | 475 |
| 571 template<typename VisitorDispatcher> | 476 template<typename VisitorDispatcher> |
| 572 void trace(VisitorDispatcher visitor) | 477 void trace(VisitorDispatcher visitor) |
| 573 { | 478 { |
| 574 static_assert(sizeof(Collection), "Collection must be fully defined"); | 479 static_assert(sizeof(Collection), "Collection must be fully defined"); |
| 575 visitor->trace(*static_cast<Collection*>(this)); | 480 visitor->trace(*static_cast<Collection*>(this)); |
| 576 } | 481 } |
| 577 | 482 |
| 578 private: | 483 private: |
| 579 void initialize() | 484 void initialize() |
| 580 { | 485 { |
| 581 ThreadState* state = ThreadState::current(); | 486 ThreadState* state = ThreadState::current(); |
| 582 m_prev = state->roots(); | 487 state->checkThread(); |
| 583 m_next = m_prev->m_next; | 488 m_persistentNode = state->persistentRegion()->allocatePersistentNode(thi
s, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeap
CollectionBase<Collection>::trace>::trampoline); |
| 584 m_prev->m_next = this; | |
| 585 m_next->m_prev = this; | |
| 586 } | 489 } |
| 587 | 490 |
| 588 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 589 void uninitialize() | 491 void uninitialize() |
| 590 { | 492 { |
| 591 ASSERT(isHeapObjectAlive()); | 493 ThreadState* state = ThreadState::current(); |
| 592 ASSERT(m_next->isHeapObjectAlive()); | 494 state->checkThread(); |
| 593 ASSERT(m_prev->isHeapObjectAlive()); | 495 state->persistentRegion()->freePersistentNode(m_persistentNode); |
| 594 m_next->m_prev = m_prev; | |
| 595 m_prev->m_next = m_next; | |
| 596 } | 496 } |
| 497 |
| 498 PersistentNode* m_persistentNode; |
| 597 }; | 499 }; |
| 598 | 500 |
| 599 template< | 501 template< |
| 600 typename KeyArg, | 502 typename KeyArg, |
| 601 typename MappedArg, | 503 typename MappedArg, |
| 602 typename HashArg = typename DefaultHash<KeyArg>::Hash, | 504 typename HashArg = typename DefaultHash<KeyArg>::Hash, |
| 603 typename KeyTraitsArg = HashTraits<KeyArg>, | 505 typename KeyTraitsArg = HashTraits<KeyArg>, |
| 604 typename MappedTraitsArg = HashTraits<MappedArg>> | 506 typename MappedTraitsArg = HashTraits<MappedArg>> |
| 605 class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<Ke
yArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { }; | 507 class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<Ke
yArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { }; |
| 606 | 508 |
| (...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1287 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin
k::IsGarbageCollectedType<T>::value> { | 1189 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin
k::IsGarbageCollectedType<T>::value> { |
| 1288 static_assert(sizeof(T), "T must be fully defined"); | 1190 static_assert(sizeof(T), "T must be fully defined"); |
| 1289 }; | 1191 }; |
| 1290 | 1192 |
| 1291 template<typename T> | 1193 template<typename T> |
| 1292 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; | 1194 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; |
| 1293 | 1195 |
| 1294 } // namespace WTF | 1196 } // namespace WTF |
| 1295 | 1197 |
| 1296 #endif | 1198 #endif |
| OLD | NEW |