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 |