| 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 209 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 291 void initialize() | 210 void initialize() |
| 292 { | 211 { |
| 293 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); | 212 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); |
| 294 state->checkThread(); | 213 state->checkThread(); |
| 295 m_prev = state->roots(); | 214 m_persistentNode = state->persistentRegion()->allocatePersistentNode(thi
s, TraceMethodDelegate<Persistent<T>, &Persistent<T>::trace>::trampoline); |
| 296 m_next = m_prev->m_next; | |
| 297 m_prev->m_next = this; | |
| 298 m_next->m_prev = this; | |
| 299 } | 215 } |
| 300 | 216 |
| 301 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 302 void uninitialize() | 217 void uninitialize() |
| 303 { | 218 { |
| 304 ASSERT(isHeapObjectAlive()); | 219 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); |
| 305 ASSERT(m_next->isHeapObjectAlive()); | 220 state->checkThread(); |
| 306 ASSERT(m_prev->isHeapObjectAlive()); | 221 state->persistentRegion()->freePersistentNode(m_persistentNode); |
| 307 m_next->m_prev = m_prev; | |
| 308 m_prev->m_next = m_next; | |
| 309 } | 222 } |
| 310 | 223 |
| 311 void checkPointer() | 224 void checkPointer() |
| 312 { | 225 { |
| 313 #if ENABLE(ASSERT) | 226 #if ENABLE(ASSERT) |
| 314 if (!m_raw) | 227 if (!m_raw) |
| 315 return; | 228 return; |
| 316 | 229 |
| 317 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable | 230 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable |
| 318 // object. In other words, it checks that the pointer is either of: | 231 // object. In other words, it checks that the pointer is either of: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 330 void recordBacktrace() | 243 void recordBacktrace() |
| 331 { | 244 { |
| 332 if (m_raw) | 245 if (m_raw) |
| 333 m_tracingName = Heap::createBacktraceString(); | 246 m_tracingName = Heap::createBacktraceString(); |
| 334 } | 247 } |
| 335 | 248 |
| 336 String m_tracingName; | 249 String m_tracingName; |
| 337 #else | 250 #else |
| 338 inline void recordBacktrace() const { } | 251 inline void recordBacktrace() const { } |
| 339 #endif | 252 #endif |
| 253 // m_raw is accessed most, so put it at the first field. |
| 340 T* m_raw; | 254 T* m_raw; |
| 255 PersistentNode* m_persistentNode; |
| 341 }; | 256 }; |
| 342 | 257 |
| 343 // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread | 258 // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread |
| 344 // different from the construction thread. | 259 // different from the construction thread. |
| 345 template<typename T> | 260 template<typename T> |
| 346 class CrossThreadPersistent : public PersistentNode { | 261 class CrossThreadPersistent final { |
| 347 public: | 262 public: |
| 348 CrossThreadPersistent() : PersistentNode(TraceMethodDelegate<CrossThreadPers
istent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(nullptr) | 263 CrossThreadPersistent() : m_raw(nullptr) |
| 349 { | 264 { |
| 350 initialize(); | 265 initialize(); |
| 351 } | 266 } |
| 352 | 267 |
| 353 CrossThreadPersistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<C
rossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(n
ullptr) | 268 CrossThreadPersistent(std::nullptr_t) : m_raw(nullptr) |
| 354 { | 269 { |
| 355 initialize(); | 270 initialize(); |
| 356 } | 271 } |
| 357 | 272 |
| 358 CrossThreadPersistent(T* raw) : PersistentNode(TraceMethodDelegate<CrossThre
adPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(raw) | 273 CrossThreadPersistent(T* raw) : m_raw(raw) |
| 359 { | 274 { |
| 360 initialize(); | 275 initialize(); |
| 361 checkPointer(); | 276 checkPointer(); |
| 362 recordBacktrace(); | 277 recordBacktrace(); |
| 363 } | 278 } |
| 364 | 279 |
| 365 CrossThreadPersistent(T& raw) : PersistentNode(TraceMethodDelegate<CrossThre
adPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(&raw) | 280 CrossThreadPersistent(T& raw) : m_raw(&raw) |
| 366 { | 281 { |
| 367 initialize(); | 282 initialize(); |
| 368 checkPointer(); | 283 checkPointer(); |
| 369 recordBacktrace(); | 284 recordBacktrace(); |
| 370 } | 285 } |
| 371 | 286 |
| 372 CrossThreadPersistent(const CrossThreadPersistent& other) : PersistentNode(T
raceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::
trampoline), m_raw(other) | 287 CrossThreadPersistent(const CrossThreadPersistent& other) : m_raw(other) |
| 373 { | 288 { |
| 374 initialize(); | 289 initialize(); |
| 375 checkPointer(); | 290 checkPointer(); |
| 376 recordBacktrace(); | 291 recordBacktrace(); |
| 377 } | 292 } |
| 378 | 293 |
| 379 template<typename U> | 294 template<typename U> |
| 380 CrossThreadPersistent(const CrossThreadPersistent<U>& other) : PersistentNod
e(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace
>::trampoline), m_raw(other) | 295 CrossThreadPersistent(const CrossThreadPersistent<U>& other) : m_raw(other) |
| 381 { | 296 { |
| 382 initialize(); | 297 initialize(); |
| 383 checkPointer(); | 298 checkPointer(); |
| 384 recordBacktrace(); | 299 recordBacktrace(); |
| 385 } | 300 } |
| 386 | 301 |
| 387 template<typename U> | 302 template<typename U> |
| 388 CrossThreadPersistent(const Member<U>& other) : PersistentNode(TraceMethodDe
legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline),
m_raw(other) | 303 CrossThreadPersistent(const Member<U>& other) : m_raw(other) |
| 389 { | 304 { |
| 390 initialize(); | 305 initialize(); |
| 391 checkPointer(); | 306 checkPointer(); |
| 392 recordBacktrace(); | 307 recordBacktrace(); |
| 393 } | 308 } |
| 394 | 309 |
| 395 template<typename U> | 310 template<typename U> |
| 396 CrossThreadPersistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDe
legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline),
m_raw(other.get()) | 311 CrossThreadPersistent(const RawPtr<U>& other) : m_raw(other.get()) |
| 397 { | 312 { |
| 398 initialize(); | 313 initialize(); |
| 399 checkPointer(); | 314 checkPointer(); |
| 400 recordBacktrace(); | 315 recordBacktrace(); |
| 401 } | 316 } |
| 402 | 317 |
| 403 void clear() { m_raw = nullptr; } | 318 void clear() { m_raw = nullptr; } |
| 404 | 319 |
| 405 ~CrossThreadPersistent() | 320 ~CrossThreadPersistent() |
| 406 { | 321 { |
| 407 uninitialize(); | 322 uninitialize(); |
| 408 m_raw = nullptr; | 323 m_raw = nullptr; |
| 409 m_trace = nullptr; | |
| 410 } | 324 } |
| 411 | 325 |
| 412 template<typename VisitorDispatcher> | 326 template<typename VisitorDispatcher> |
| 413 void trace(VisitorDispatcher visitor) | 327 void trace(VisitorDispatcher visitor) |
| 414 { | 328 { |
| 415 static_assert(sizeof(T), "T must be fully defined"); | 329 static_assert(sizeof(T), "T must be fully defined"); |
| 416 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); | 330 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); |
| 417 visitor->mark(m_raw); | 331 visitor->mark(m_raw); |
| 418 } | 332 } |
| 419 | 333 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 recordBacktrace(); | 396 recordBacktrace(); |
| 483 return *this; | 397 return *this; |
| 484 } | 398 } |
| 485 | 399 |
| 486 T* get() const { return m_raw; } | 400 T* get() const { return m_raw; } |
| 487 | 401 |
| 488 private: | 402 private: |
| 489 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 403 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 490 void initialize() | 404 void initialize() |
| 491 { | 405 { |
| 492 MutexLocker m_locker(ThreadState::globalRootsMutex()); | 406 m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePe
rsistentNode(this, TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPer
sistent<T>::trace>::trampoline); |
| 493 m_prev = &ThreadState::globalRoots(); | |
| 494 m_next = m_prev->m_next; | |
| 495 m_prev->m_next = this; | |
| 496 m_next->m_prev = this; | |
| 497 } | 407 } |
| 498 | 408 |
| 499 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 500 void uninitialize() | 409 void uninitialize() |
| 501 { | 410 { |
| 502 MutexLocker m_locker(ThreadState::globalRootsMutex()); | 411 ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persiste
ntNode); |
| 503 ASSERT(isHeapObjectAlive()); | |
| 504 ASSERT(m_next->isHeapObjectAlive()); | |
| 505 ASSERT(m_prev->isHeapObjectAlive()); | |
| 506 m_next->m_prev = m_prev; | |
| 507 m_prev->m_next = m_next; | |
| 508 } | 412 } |
| 509 | 413 |
| 510 void checkPointer() | 414 void checkPointer() |
| 511 { | 415 { |
| 512 #if ENABLE(ASSERT) | 416 #if ENABLE(ASSERT) |
| 513 if (!m_raw) | 417 if (!m_raw) |
| 514 return; | 418 return; |
| 515 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable | 419 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable |
| 516 // object. In other words, it checks that the pointer is either of: | 420 // object. In other words, it checks that the pointer is either of: |
| 517 // | 421 // |
| (...skipping 10 matching lines...) Expand all Loading... |
| 528 void recordBacktrace() | 432 void recordBacktrace() |
| 529 { | 433 { |
| 530 if (m_raw) | 434 if (m_raw) |
| 531 m_tracingName = Heap::createBacktraceString(); | 435 m_tracingName = Heap::createBacktraceString(); |
| 532 } | 436 } |
| 533 | 437 |
| 534 String m_tracingName; | 438 String m_tracingName; |
| 535 #else | 439 #else |
| 536 inline void recordBacktrace() const { } | 440 inline void recordBacktrace() const { } |
| 537 #endif | 441 #endif |
| 442 // m_raw is accessed most, so put it at the first field. |
| 538 T* m_raw; | 443 T* m_raw; |
| 444 PersistentNode* m_persistentNode; |
| 539 }; | 445 }; |
| 540 | 446 |
| 541 // PersistentNode must be the left-most class to let the | 447 // PersistentNode must be the left-most class to let the |
| 542 // visitor->trace(static_cast<Collection*>(this)) trace the correct position. | 448 // visitor->trace(static_cast<Collection*>(this)) trace the correct position. |
| 543 // FIXME: derive affinity based on the collection. | 449 // FIXME: derive affinity based on the collection. |
| 544 template<typename Collection> | 450 template<typename Collection> |
| 545 class PersistentHeapCollectionBase : public PersistentNode, public Collection { | 451 class PersistentHeapCollectionBase : public Collection { |
| 546 // We overload the various new and delete operators with using the WTF Defau
ltAllocator to ensure persistent | 452 // We overload the various new and delete operators with using the WTF Defau
ltAllocator to ensure persistent |
| 547 // heap collections are always allocated off-heap. This allows persistent co
llections to be used in | 453 // heap collections are always allocated off-heap. This allows persistent co
llections to be used in |
| 548 // DEFINE_STATIC_LOCAL et. al. | 454 // DEFINE_STATIC_LOCAL et. al. |
| 549 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); | 455 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); |
| 550 public: | 456 public: |
| 551 PersistentHeapCollectionBase() : PersistentNode(TraceMethodDelegate<Persiste
ntHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::tra
ce>::trampoline) | 457 PersistentHeapCollectionBase() |
| 552 { | 458 { |
| 553 initialize(); | 459 initialize(); |
| 554 } | 460 } |
| 555 | 461 |
| 556 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Pe
rsistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &Pers
istentHeapCollectionBase<Collection>::trace>::trampoline), Collection(other) | 462 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Co
llection(other) |
| 557 { | 463 { |
| 558 initialize(); | 464 initialize(); |
| 559 } | 465 } |
| 560 | 466 |
| 561 template<typename OtherCollection> | 467 template<typename OtherCollection> |
| 562 PersistentHeapCollectionBase(const OtherCollection& other) : PersistentNode(
TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeapCol
lectionBase<Collection>::trace>::trampoline), Collection(other) | 468 PersistentHeapCollectionBase(const OtherCollection& other) : Collection(othe
r) |
| 563 { | 469 { |
| 564 initialize(); | 470 initialize(); |
| 565 } | 471 } |
| 566 | 472 |
| 567 ~PersistentHeapCollectionBase() | 473 ~PersistentHeapCollectionBase() |
| 568 { | 474 { |
| 569 uninitialize(); | 475 uninitialize(); |
| 570 m_trace = nullptr; | |
| 571 } | 476 } |
| 572 | 477 |
| 573 template<typename VisitorDispatcher> | 478 template<typename VisitorDispatcher> |
| 574 void trace(VisitorDispatcher visitor) | 479 void trace(VisitorDispatcher visitor) |
| 575 { | 480 { |
| 576 static_assert(sizeof(Collection), "Collection must be fully defined"); | 481 static_assert(sizeof(Collection), "Collection must be fully defined"); |
| 577 visitor->trace(*static_cast<Collection*>(this)); | 482 visitor->trace(*static_cast<Collection*>(this)); |
| 578 } | 483 } |
| 579 | 484 |
| 580 private: | 485 private: |
| 581 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 486 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 582 void initialize() | 487 void initialize() |
| 583 { | 488 { |
| 584 ThreadState* state = ThreadState::current(); | 489 ThreadState* state = ThreadState::current(); |
| 585 m_prev = state->roots(); | 490 state->checkThread(); |
| 586 m_next = m_prev->m_next; | 491 m_persistentNode = state->persistentRegion()->allocatePersistentNode(thi
s, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentHeap
CollectionBase<Collection>::trace>::trampoline); |
| 587 m_prev->m_next = this; | |
| 588 m_next->m_prev = this; | |
| 589 } | 492 } |
| 590 | 493 |
| 591 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 592 void uninitialize() | 494 void uninitialize() |
| 593 { | 495 { |
| 594 ASSERT(isHeapObjectAlive()); | 496 ThreadState* state = ThreadState::current(); |
| 595 ASSERT(m_next->isHeapObjectAlive()); | 497 state->checkThread(); |
| 596 ASSERT(m_prev->isHeapObjectAlive()); | 498 state->persistentRegion()->freePersistentNode(m_persistentNode); |
| 597 m_next->m_prev = m_prev; | |
| 598 m_prev->m_next = m_next; | |
| 599 } | 499 } |
| 500 |
| 501 PersistentNode* m_persistentNode; |
| 600 }; | 502 }; |
| 601 | 503 |
| 602 template< | 504 template< |
| 603 typename KeyArg, | 505 typename KeyArg, |
| 604 typename MappedArg, | 506 typename MappedArg, |
| 605 typename HashArg = typename DefaultHash<KeyArg>::Hash, | 507 typename HashArg = typename DefaultHash<KeyArg>::Hash, |
| 606 typename KeyTraitsArg = HashTraits<KeyArg>, | 508 typename KeyTraitsArg = HashTraits<KeyArg>, |
| 607 typename MappedTraitsArg = HashTraits<MappedArg>> | 509 typename MappedTraitsArg = HashTraits<MappedArg>> |
| 608 class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<Ke
yArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { }; | 510 class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<Ke
yArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { }; |
| 609 | 511 |
| (...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1291 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin
k::IsGarbageCollectedType<T>::value> { | 1193 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin
k::IsGarbageCollectedType<T>::value> { |
| 1292 static_assert(sizeof(T), "T must be fully defined"); | 1194 static_assert(sizeof(T), "T must be fully defined"); |
| 1293 }; | 1195 }; |
| 1294 | 1196 |
| 1295 template<typename T> | 1197 template<typename T> |
| 1296 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; | 1198 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; |
| 1297 | 1199 |
| 1298 } // namespace WTF | 1200 } // namespace WTF |
| 1299 | 1201 |
| 1300 #endif | 1202 #endif |
| OLD | NEW |