| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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() | 61 virtual ~PersistentNode() |
| 62 { | 62 { |
| 63 ASSERT(isHeapObjectAlive()); | 63 ASSERT(isHeapObjectAlive()); |
| 64 m_trace = nullptr; | 64 m_trace = nullptr; |
| 65 } | 65 } |
| 66 | 66 |
| 67 // 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 |
| 69 // persistent handles. |
| 70 inline PersistentNode& operator=(const PersistentNode& otherref) { return *t
his; } |
| 71 |
| 72 private: |
| 67 // Ideally the trace method should be virtual and automatically dispatch | 73 // Ideally the trace method should be virtual and automatically dispatch |
| 68 // to the most specific implementation. However having a virtual method | 74 // to the most specific implementation. However having a virtual method |
| 69 // on PersistentNode leads to too eager template instantiation with MSVC | 75 // on PersistentNode leads to too eager template instantiation with MSVC |
| 70 // which leads to include cycles. | 76 // which leads to include cycles. |
| 71 // Instead we call the constructor with a TraceCallback which knows the | 77 // Instead we call the constructor with a TraceCallback which knows the |
| 72 // type of the most specific child and calls trace directly. See | 78 // type of the most specific child and calls trace directly. See |
| 73 // TraceMethodDelegate in Visitor.h for how this is done. | 79 // TraceMethodDelegate in Visitor.h for how this is done. |
| 74 void trace(Visitor* visitor) | 80 void tracePersistentNode(Visitor* visitor) |
| 75 { | 81 { |
| 76 m_trace(visitor, this); | 82 m_trace(visitor, this); |
| 77 } | 83 } |
| 78 | 84 |
| 79 protected: | |
| 80 TraceCallback m_trace; | 85 TraceCallback m_trace; |
| 81 | |
| 82 private: | |
| 83 PersistentNode* m_next; | 86 PersistentNode* m_next; |
| 84 PersistentNode* m_prev; | 87 PersistentNode* m_prev; |
| 85 | 88 |
| 86 template<typename RootsAccessor, typename Owner> friend class PersistentBase
; | 89 template<typename T> friend class CrossThreadPersistent; |
| 90 template<typename T> friend class Persistent; |
| 91 template<typename Collection> friend class PersistentHeapCollectionBase; |
| 87 friend class PersistentAnchor; | 92 friend class PersistentAnchor; |
| 88 friend class ThreadState; | 93 friend class ThreadState; |
| 89 }; | 94 }; |
| 90 | 95 |
| 91 // RootsAccessor for Persistent that provides access to thread-local list | |
| 92 // of persistent handles. Can only be used to create handles that | |
| 93 // are constructed and destructed on the same thread. | |
| 94 template<ThreadAffinity Affinity> | |
| 95 class ThreadLocalPersistents { | |
| 96 public: | |
| 97 static PersistentNode* roots() { return state()->roots(); } | |
| 98 | |
| 99 // No locking required. Just check that we are at the right thread. | |
| 100 class Lock { | |
| 101 public: | |
| 102 Lock() { state()->checkThread(); } | |
| 103 }; | |
| 104 | |
| 105 private: | |
| 106 static ThreadState* state() { return ThreadStateFor<Affinity>::state(); } | |
| 107 }; | |
| 108 | |
| 109 // RootsAccessor for Persistent that provides synchronized access to global | |
| 110 // list of persistent handles. Can be used for persistent handles that are | |
| 111 // passed between threads. | |
| 112 class GlobalPersistents { | |
| 113 public: | |
| 114 static PersistentNode* roots() { return &ThreadState::globalRoots(); } | |
| 115 | |
| 116 class Lock { | |
| 117 public: | |
| 118 Lock() : m_locker(ThreadState::globalRootsMutex()) { } | |
| 119 private: | |
| 120 MutexLocker m_locker; | |
| 121 }; | |
| 122 }; | |
| 123 | |
| 124 // Base class for persistent handles. RootsAccessor specifies which list to | |
| 125 // link resulting handle into. Owner specifies the class containing trace | |
| 126 // method. | |
| 127 template<typename RootsAccessor, typename Owner> | |
| 128 class PersistentBase : public PersistentNode { | |
| 129 public: | |
| 130 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 131 ~PersistentBase() | |
| 132 { | |
| 133 typename RootsAccessor::Lock lock; | |
| 134 ASSERT(m_roots == RootsAccessor::roots()); // Check that the thread is u
sing the same roots list. | |
| 135 ASSERT(isHeapObjectAlive()); | |
| 136 ASSERT(m_next->isHeapObjectAlive()); | |
| 137 ASSERT(m_prev->isHeapObjectAlive()); | |
| 138 m_next->m_prev = m_prev; | |
| 139 m_prev->m_next = m_next; | |
| 140 } | |
| 141 | |
| 142 protected: | |
| 143 inline PersistentBase() | |
| 144 : PersistentNode(TraceMethodDelegate<Owner, &Owner::trace>::trampoline) | |
| 145 #if ENABLE(ASSERT) | |
| 146 , m_roots(RootsAccessor::roots()) | |
| 147 #endif | |
| 148 { | |
| 149 // Persistent must belong to a thread that will GC it. | |
| 150 ASSERT(m_roots == GlobalPersistents::roots() || ThreadState::current()); | |
| 151 typename RootsAccessor::Lock lock; | |
| 152 m_prev = RootsAccessor::roots(); | |
| 153 m_next = m_prev->m_next; | |
| 154 m_prev->m_next = this; | |
| 155 m_next->m_prev = this; | |
| 156 } | |
| 157 | |
| 158 inline PersistentBase& operator=(const PersistentBase& otherref) { return *t
his; } | |
| 159 | |
| 160 #if ENABLE(ASSERT) | |
| 161 private: | |
| 162 PersistentNode* m_roots; | |
| 163 #endif | |
| 164 }; | |
| 165 | |
| 166 // A dummy Persistent handle that ensures the list of persistents is never null. | 96 // A dummy Persistent handle that ensures the list of persistents is never null. |
| 167 // This removes a test from a hot path. | 97 // This removes a test from a hot path. |
| 168 class PersistentAnchor : public PersistentNode { | 98 class PersistentAnchor : public PersistentNode { |
| 169 public: | 99 public: |
| 170 void trace(Visitor* visitor) | 100 void tracePersistentNodes(Visitor* visitor) |
| 171 { | 101 { |
| 172 for (PersistentNode* current = m_next; current != this; current = curren
t->m_next) | 102 for (PersistentNode* current = m_next; current != this; current = curren
t->m_next) |
| 173 current->trace(visitor); | 103 current->tracePersistentNode(visitor); |
| 174 } | 104 } |
| 175 | 105 |
| 176 int numberOfPersistents() | 106 int numberOfPersistents() |
| 177 { | 107 { |
| 178 int numberOfPersistents = 0; | 108 int numberOfPersistents = 0; |
| 179 for (PersistentNode* current = m_next; current != this; current = curren
t->m_next) | 109 for (PersistentNode* current = m_next; current != this; current = curren
t->m_next) |
| 180 ++numberOfPersistents; | 110 ++numberOfPersistents; |
| 181 return numberOfPersistents; | 111 return numberOfPersistents; |
| 182 } | 112 } |
| 183 | 113 |
| 184 virtual ~PersistentAnchor() | 114 virtual ~PersistentAnchor() |
| 185 { | 115 { |
| 186 // FIXME: oilpan: Ideally we should have no left-over persistents at thi
s point. However currently there is a | 116 // FIXME: oilpan: Ideally we should have no left-over persistents at thi
s point. However currently there is a |
| 187 // large number of objects leaked when we tear down the main thread. Sin
ce some of these might contain a | 117 // large number of objects leaked when we tear down the main thread. Sin
ce some of these might contain a |
| 188 // persistent or e.g. be RefCountedGarbageCollected we cannot guarantee
there are no remaining Persistents at | 118 // persistent or e.g. be RefCountedGarbageCollected we cannot guarantee
there are no remaining Persistents at |
| 189 // this point. | 119 // this point. |
| 190 } | 120 } |
| 191 | 121 |
| 122 template<typename VisitorDispatcher> |
| 123 void trace(VisitorDispatcher visitor) |
| 124 { |
| 125 ASSERT_NOT_REACHED(); |
| 126 } |
| 127 |
| 192 private: | 128 private: |
| 193 PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &P
ersistentAnchor::trace>::trampoline) | 129 PersistentAnchor() : PersistentNode(TraceMethodDelegate<PersistentAnchor, &P
ersistentAnchor::trace>::trampoline) |
| 194 { | 130 { |
| 195 m_next = this; | 131 m_next = this; |
| 196 m_prev = this; | 132 m_prev = this; |
| 197 } | 133 } |
| 198 | 134 |
| 199 friend class ThreadState; | 135 friend class ThreadState; |
| 200 }; | 136 }; |
| 201 | 137 |
| 202 template<typename T> | |
| 203 class CrossThreadPersistent; | |
| 204 | |
| 205 // Persistent handles are used to store pointers into the | 138 // Persistent handles are used to store pointers into the |
| 206 // managed heap. As long as the Persistent handle is alive | 139 // managed heap. As long as the Persistent handle is alive |
| 207 // the GC will keep the object pointed to alive. Persistent | 140 // the GC will keep the object pointed to alive. Persistent |
| 208 // handles can be stored in objects and they are not scoped. | 141 // handles can be stored in objects and they are not scoped. |
| 209 // Persistent handles must not be used to contain pointers | 142 // Persistent handles must not be used to contain pointers |
| 210 // between objects that are in the managed heap. They are only | 143 // between objects that are in the managed heap. They are only |
| 211 // meant to point to managed heap objects from variables/members | 144 // meant to point to managed heap objects from variables/members |
| 212 // outside the managed heap. | 145 // outside the managed heap. |
| 213 // | 146 // |
| 214 // A Persistent is always a GC root from the point of view of | 147 // A Persistent is always a GC root from the point of view of |
| 215 // the garbage collector. | 148 // the garbage collector. |
| 216 // | 149 // |
| 217 // We have to construct and destruct Persistent in the same thread. | 150 // We have to construct and destruct Persistent in the same thread. |
| 218 template<typename T> | 151 template<typename T> |
| 219 class Persistent : public PersistentBase<ThreadLocalPersistents<ThreadingTrait<T
>::Affinity>, Persistent<T>> { | 152 class Persistent : public PersistentNode { |
| 220 public: | 153 public: |
| 221 Persistent() : m_raw(nullptr) { } | 154 Persistent() : PersistentNode(TraceMethodDelegate<Persistent<T>, &Persistent
<T>::trace>::trampoline), m_raw(nullptr) |
| 155 { |
| 156 initialize(); |
| 157 } |
| 222 | 158 |
| 223 Persistent(std::nullptr_t) : m_raw(nullptr) { } | 159 Persistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<Persistent<T
>, &Persistent<T>::trace>::trampoline), m_raw(nullptr) |
| 160 { |
| 161 initialize(); |
| 162 } |
| 224 | 163 |
| 225 Persistent(T* raw) : m_raw(raw) | 164 Persistent(T* raw) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Pers
istent<T>::trace>::trampoline), m_raw(raw) |
| 226 { | 165 { |
| 166 initialize(); |
| 227 checkPointer(); | 167 checkPointer(); |
| 228 recordBacktrace(); | 168 recordBacktrace(); |
| 229 } | 169 } |
| 230 | 170 |
| 231 explicit Persistent(T& raw) : m_raw(&raw) | 171 Persistent(T& raw) : PersistentNode(TraceMethodDelegate<Persistent<T>, &Pers
istent<T>::trace>::trampoline), m_raw(&raw) |
| 232 { | 172 { |
| 173 initialize(); |
| 233 checkPointer(); | 174 checkPointer(); |
| 234 recordBacktrace(); | 175 recordBacktrace(); |
| 235 } | 176 } |
| 236 | 177 |
| 237 Persistent(const Persistent& other) : m_raw(other) | 178 Persistent(const Persistent& other) : PersistentNode(TraceMethodDelegate<Per
sistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other) |
| 238 { | 179 { |
| 180 initialize(); |
| 239 checkPointer(); | 181 checkPointer(); |
| 240 recordBacktrace(); | 182 recordBacktrace(); |
| 241 } | 183 } |
| 242 | 184 |
| 243 template<typename U> | 185 template<typename U> |
| 244 Persistent(const Persistent<U>& other) : m_raw(other) | 186 Persistent(const Persistent<U>& other) : PersistentNode(TraceMethodDelegate<
Persistent<T>, &Persistent<T>::trace>::trampoline), m_raw(other) |
| 245 { | 187 { |
| 188 initialize(); |
| 246 checkPointer(); | 189 checkPointer(); |
| 247 recordBacktrace(); | 190 recordBacktrace(); |
| 248 } | 191 } |
| 249 | 192 |
| 250 template<typename U> | 193 template<typename U> |
| 251 Persistent(const Member<U>& other) : m_raw(other) | 194 Persistent(const Member<U>& other) : PersistentNode(TraceMethodDelegate<Pers
istent<T>, &Persistent<T>::trace>::trampoline), m_raw(other) |
| 252 { | 195 { |
| 196 initialize(); |
| 253 checkPointer(); | 197 checkPointer(); |
| 254 recordBacktrace(); | 198 recordBacktrace(); |
| 255 } | 199 } |
| 256 | 200 |
| 257 template<typename U> | 201 template<typename U> |
| 258 Persistent(const RawPtr<U>& other) : m_raw(other.get()) | 202 Persistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDelegate<Pers
istent<T>, &Persistent<T>::trace>::trampoline), m_raw(other.get()) |
| 259 { | 203 { |
| 204 initialize(); |
| 260 checkPointer(); | 205 checkPointer(); |
| 261 recordBacktrace(); | 206 recordBacktrace(); |
| 262 } | 207 } |
| 263 | 208 |
| 264 void clear() { m_raw = nullptr; } | 209 void clear() { m_raw = nullptr; } |
| 265 | 210 |
| 266 virtual ~Persistent() | 211 virtual ~Persistent() |
| 267 { | 212 { |
| 213 uninitialize(); |
| 268 m_raw = nullptr; | 214 m_raw = nullptr; |
| 269 } | 215 } |
| 270 | 216 |
| 271 template<typename VisitorDispatcher> | 217 template<typename VisitorDispatcher> |
| 272 void trace(VisitorDispatcher visitor) | 218 void trace(VisitorDispatcher visitor) |
| 273 { | 219 { |
| 274 static_assert(sizeof(T), "T must be fully defined"); | 220 static_assert(sizeof(T), "T must be fully defined"); |
| 275 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); | 221 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); |
| 276 #if ENABLE(GC_PROFILING) | 222 #if ENABLE(GC_PROFILING) |
| 277 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tr
acingName); | 223 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tr
acingName); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 { | 287 { |
| 342 m_raw = other; | 288 m_raw = other; |
| 343 checkPointer(); | 289 checkPointer(); |
| 344 recordBacktrace(); | 290 recordBacktrace(); |
| 345 return *this; | 291 return *this; |
| 346 } | 292 } |
| 347 | 293 |
| 348 T* get() const { return m_raw; } | 294 T* get() const { return m_raw; } |
| 349 | 295 |
| 350 private: | 296 private: |
| 297 void initialize() |
| 298 { |
| 299 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(
); |
| 300 state->checkThread(); |
| 301 m_prev = state->roots(); |
| 302 m_next = m_prev->m_next; |
| 303 m_prev->m_next = this; |
| 304 m_next->m_prev = this; |
| 305 } |
| 306 |
| 307 void uninitialize() |
| 308 { |
| 309 ASSERT(isHeapObjectAlive()); |
| 310 ASSERT(m_next->isHeapObjectAlive()); |
| 311 ASSERT(m_prev->isHeapObjectAlive()); |
| 312 m_next->m_prev = m_prev; |
| 313 m_prev->m_next = m_next; |
| 314 } |
| 315 |
| 351 void checkPointer() | 316 void checkPointer() |
| 352 { | 317 { |
| 353 #if ENABLE(ASSERT) | 318 #if ENABLE(ASSERT) |
| 354 if (!m_raw) | 319 if (!m_raw) |
| 355 return; | 320 return; |
| 356 | 321 |
| 357 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable | 322 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable |
| 358 // object. In other words, it checks that the pointer is either of: | 323 // object. In other words, it checks that the pointer is either of: |
| 359 // | 324 // |
| 360 // (a) a pointer to the head of an on-heap object. | 325 // (a) a pointer to the head of an on-heap object. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 376 String m_tracingName; | 341 String m_tracingName; |
| 377 #else | 342 #else |
| 378 inline void recordBacktrace() const { } | 343 inline void recordBacktrace() const { } |
| 379 #endif | 344 #endif |
| 380 T* m_raw; | 345 T* m_raw; |
| 381 }; | 346 }; |
| 382 | 347 |
| 383 // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread | 348 // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread |
| 384 // different from the construction thread. | 349 // different from the construction thread. |
| 385 template<typename T> | 350 template<typename T> |
| 386 class CrossThreadPersistent : public PersistentBase<GlobalPersistents, CrossThre
adPersistent<T>> { | 351 class CrossThreadPersistent : public PersistentNode { |
| 387 public: | 352 public: |
| 388 CrossThreadPersistent() : m_raw(nullptr) { } | 353 CrossThreadPersistent() : PersistentNode(TraceMethodDelegate<CrossThreadPers
istent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(nullptr) |
| 354 { |
| 355 initialize(); |
| 356 } |
| 389 | 357 |
| 390 CrossThreadPersistent(std::nullptr_t) : m_raw(nullptr) { } | 358 CrossThreadPersistent(std::nullptr_t) : PersistentNode(TraceMethodDelegate<C
rossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(n
ullptr) |
| 359 { |
| 360 initialize(); |
| 361 } |
| 391 | 362 |
| 392 CrossThreadPersistent(T* raw) : m_raw(raw) | 363 CrossThreadPersistent(T* raw) : PersistentNode(TraceMethodDelegate<CrossThre
adPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(raw) |
| 393 { | 364 { |
| 365 initialize(); |
| 394 checkPointer(); | 366 checkPointer(); |
| 395 recordBacktrace(); | 367 recordBacktrace(); |
| 396 } | 368 } |
| 397 | 369 |
| 398 explicit CrossThreadPersistent(T& raw) : m_raw(&raw) | 370 CrossThreadPersistent(T& raw) : PersistentNode(TraceMethodDelegate<CrossThre
adPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline), m_raw(&raw) |
| 399 { | 371 { |
| 372 initialize(); |
| 400 checkPointer(); | 373 checkPointer(); |
| 401 recordBacktrace(); | 374 recordBacktrace(); |
| 402 } | 375 } |
| 403 | 376 |
| 404 CrossThreadPersistent(const CrossThreadPersistent& other) : m_raw(other) | 377 CrossThreadPersistent(const CrossThreadPersistent& other) : PersistentNode(T
raceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::
trampoline), m_raw(other) |
| 405 { | 378 { |
| 379 initialize(); |
| 406 checkPointer(); | 380 checkPointer(); |
| 407 recordBacktrace(); | 381 recordBacktrace(); |
| 408 } | 382 } |
| 409 | 383 |
| 410 template<typename U> | 384 template<typename U> |
| 411 CrossThreadPersistent(const CrossThreadPersistent<U>& other) : m_raw(other) | 385 CrossThreadPersistent(const CrossThreadPersistent<U>& other) : PersistentNod
e(TraceMethodDelegate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace
>::trampoline), m_raw(other) |
| 412 { | 386 { |
| 387 initialize(); |
| 413 checkPointer(); | 388 checkPointer(); |
| 414 recordBacktrace(); | 389 recordBacktrace(); |
| 415 } | 390 } |
| 416 | 391 |
| 417 template<typename U> | 392 template<typename U> |
| 418 CrossThreadPersistent(const Member<U>& other) : m_raw(other) | 393 CrossThreadPersistent(const Member<U>& other) : PersistentNode(TraceMethodDe
legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline),
m_raw(other) |
| 419 { | 394 { |
| 395 initialize(); |
| 420 checkPointer(); | 396 checkPointer(); |
| 421 recordBacktrace(); | 397 recordBacktrace(); |
| 422 } | 398 } |
| 423 | 399 |
| 424 template<typename U> | 400 template<typename U> |
| 425 CrossThreadPersistent(const RawPtr<U>& other) : m_raw(other.get()) | 401 CrossThreadPersistent(const RawPtr<U>& other) : PersistentNode(TraceMethodDe
legate<CrossThreadPersistent<T>, &CrossThreadPersistent<T>::trace>::trampoline),
m_raw(other.get()) |
| 426 { | 402 { |
| 403 initialize(); |
| 427 checkPointer(); | 404 checkPointer(); |
| 428 recordBacktrace(); | 405 recordBacktrace(); |
| 429 } | 406 } |
| 430 | 407 |
| 431 void clear() { m_raw = nullptr; } | 408 void clear() { m_raw = nullptr; } |
| 432 | 409 |
| 433 virtual ~CrossThreadPersistent() | 410 virtual ~CrossThreadPersistent() |
| 434 { | 411 { |
| 412 uninitialize(); |
| 435 m_raw = nullptr; | 413 m_raw = nullptr; |
| 436 } | 414 } |
| 437 | 415 |
| 438 template<typename VisitorDispatcher> | 416 template<typename VisitorDispatcher> |
| 439 void trace(VisitorDispatcher visitor) | 417 void trace(VisitorDispatcher visitor) |
| 440 { | 418 { |
| 441 static_assert(sizeof(T), "T must be fully defined"); | 419 static_assert(sizeof(T), "T must be fully defined"); |
| 442 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); | 420 static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage
collected object"); |
| 443 #if ENABLE(GC_PROFILING) | 421 #if ENABLE(GC_PROFILING) |
| 444 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "CrossThreadPersist
ent" : m_tracingName); | 422 visitor->setHostInfo(this, m_tracingName.isEmpty() ? "CrossThreadPersist
ent" : m_tracingName); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 { | 486 { |
| 509 m_raw = other; | 487 m_raw = other; |
| 510 checkPointer(); | 488 checkPointer(); |
| 511 recordBacktrace(); | 489 recordBacktrace(); |
| 512 return *this; | 490 return *this; |
| 513 } | 491 } |
| 514 | 492 |
| 515 T* get() const { return m_raw; } | 493 T* get() const { return m_raw; } |
| 516 | 494 |
| 517 private: | 495 private: |
| 496 void initialize() |
| 497 { |
| 498 MutexLocker m_locker(ThreadState::globalRootsMutex()); |
| 499 m_prev = &ThreadState::globalRoots(); |
| 500 m_next = m_prev->m_next; |
| 501 m_prev->m_next = this; |
| 502 m_next->m_prev = this; |
| 503 } |
| 504 |
| 505 void uninitialize() |
| 506 { |
| 507 MutexLocker m_locker(ThreadState::globalRootsMutex()); |
| 508 ASSERT(isHeapObjectAlive()); |
| 509 ASSERT(m_next->isHeapObjectAlive()); |
| 510 ASSERT(m_prev->isHeapObjectAlive()); |
| 511 m_next->m_prev = m_prev; |
| 512 m_prev->m_next = m_next; |
| 513 } |
| 514 |
| 518 void checkPointer() | 515 void checkPointer() |
| 519 { | 516 { |
| 520 #if ENABLE(ASSERT) | 517 #if ENABLE(ASSERT) |
| 521 if (!m_raw) | 518 if (!m_raw) |
| 522 return; | 519 return; |
| 523 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable | 520 // Heap::isHeapObjectAlive(m_raw) checks that m_raw is a traceable |
| 524 // object. In other words, it checks that the pointer is either of: | 521 // object. In other words, it checks that the pointer is either of: |
| 525 // | 522 // |
| 526 // (a) a pointer to the head of an on-heap object. | 523 // (a) a pointer to the head of an on-heap object. |
| 527 // (b) a pointer to the head of an on-heap mixin object. | 524 // (b) a pointer to the head of an on-heap mixin object. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 540 } | 537 } |
| 541 | 538 |
| 542 String m_tracingName; | 539 String m_tracingName; |
| 543 #else | 540 #else |
| 544 inline void recordBacktrace() const { } | 541 inline void recordBacktrace() const { } |
| 545 #endif | 542 #endif |
| 546 T* m_raw; | 543 T* m_raw; |
| 547 }; | 544 }; |
| 548 | 545 |
| 549 // FIXME: derive affinity based on the collection. | 546 // FIXME: derive affinity based on the collection. |
| 550 template<typename Collection, ThreadAffinity Affinity = AnyThread> | 547 template<typename Collection> |
| 551 class PersistentHeapCollectionBase | 548 class PersistentHeapCollectionBase : public Collection, public PersistentNode { |
| 552 : public Collection | |
| 553 , public PersistentBase<ThreadLocalPersistents<Affinity>, PersistentHeapColl
ectionBase<Collection, Affinity>> { | |
| 554 // We overload the various new and delete operators with using the WTF Defau
ltAllocator to ensure persistent | 549 // We overload the various new and delete operators with using the WTF Defau
ltAllocator to ensure persistent |
| 555 // heap collections are always allocated off-heap. This allows persistent co
llections to be used in | 550 // heap collections are always allocated off-heap. This allows persistent co
llections to be used in |
| 556 // DEFINE_STATIC_LOCAL et. al. | 551 // DEFINE_STATIC_LOCAL et. al. |
| 557 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); | 552 WTF_USE_ALLOCATOR(PersistentHeapCollectionBase, WTF::DefaultAllocator); |
| 558 public: | 553 public: |
| 559 PersistentHeapCollectionBase() { } | 554 PersistentHeapCollectionBase() : PersistentNode(TraceMethodDelegate<Persiste
ntHeapCollectionBase<Collection>, &PersistentHeapCollectionBase<Collection>::tra
ce>::trampoline) |
| 555 { |
| 556 initialize(); |
| 557 } |
| 560 | 558 |
| 561 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Co
llection(other) { } | 559 PersistentHeapCollectionBase(const PersistentHeapCollectionBase& other) : Co
llection(other), PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase
<Collection>, &PersistentHeapCollectionBase<Collection>::trace>::trampoline) |
| 560 { |
| 561 initialize(); |
| 562 } |
| 562 | 563 |
| 563 template<typename OtherCollection> | 564 template<typename OtherCollection> |
| 564 PersistentHeapCollectionBase(const OtherCollection& other) : Collection(othe
r) { } | 565 PersistentHeapCollectionBase(const OtherCollection& other) : Collection(othe
r), PersistentNode(TraceMethodDelegate<PersistentHeapCollectionBase<Collection>,
&PersistentHeapCollectionBase<Collection>::trace>::trampoline) |
| 566 { |
| 567 initialize(); |
| 568 } |
| 569 |
| 570 ~PersistentHeapCollectionBase() |
| 571 { |
| 572 uninitialize(); |
| 573 } |
| 565 | 574 |
| 566 template<typename VisitorDispatcher> | 575 template<typename VisitorDispatcher> |
| 567 void trace(VisitorDispatcher visitor) | 576 void trace(VisitorDispatcher visitor) |
| 568 { | 577 { |
| 569 static_assert(sizeof(Collection), "Collection must be fully defined"); | 578 static_assert(sizeof(Collection), "Collection must be fully defined"); |
| 570 #if ENABLE(GC_PROFILING) | 579 #if ENABLE(GC_PROFILING) |
| 571 visitor->setHostInfo(this, "PersistentHeapCollectionBase"); | 580 visitor->setHostInfo(this, "PersistentHeapCollectionBase"); |
| 572 #endif | 581 #endif |
| 573 visitor->trace(*static_cast<Collection*>(this)); | 582 visitor->trace(*static_cast<Collection*>(this)); |
| 574 } | 583 } |
| 584 |
| 585 private: |
| 586 void initialize() |
| 587 { |
| 588 ThreadState* state = ThreadState::current(); |
| 589 m_prev = state->roots(); |
| 590 m_next = m_prev->m_next; |
| 591 m_prev->m_next = this; |
| 592 m_next->m_prev = this; |
| 593 } |
| 594 |
| 595 void uninitialize() |
| 596 { |
| 597 ASSERT(isHeapObjectAlive()); |
| 598 ASSERT(m_next->isHeapObjectAlive()); |
| 599 ASSERT(m_prev->isHeapObjectAlive()); |
| 600 m_next->m_prev = m_prev; |
| 601 m_prev->m_next = m_next; |
| 602 } |
| 575 }; | 603 }; |
| 576 | 604 |
| 577 template< | 605 template< |
| 578 typename KeyArg, | 606 typename KeyArg, |
| 579 typename MappedArg, | 607 typename MappedArg, |
| 580 typename HashArg = typename DefaultHash<KeyArg>::Hash, | 608 typename HashArg = typename DefaultHash<KeyArg>::Hash, |
| 581 typename KeyTraitsArg = HashTraits<KeyArg>, | 609 typename KeyTraitsArg = HashTraits<KeyArg>, |
| 582 typename MappedTraitsArg = HashTraits<MappedArg>> | 610 typename MappedTraitsArg = HashTraits<MappedArg>> |
| 583 class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<Ke
yArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { }; | 611 class PersistentHeapHashMap : public PersistentHeapCollectionBase<HeapHashMap<Ke
yArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>> { }; |
| 584 | 612 |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1259 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin
k::IsGarbageCollectedType<T>::value> { | 1287 struct ParamStorageTraits<RawPtr<T>> : public PointerParamStorageTraits<T*, blin
k::IsGarbageCollectedType<T>::value> { |
| 1260 static_assert(sizeof(T), "T must be fully defined"); | 1288 static_assert(sizeof(T), "T must be fully defined"); |
| 1261 }; | 1289 }; |
| 1262 | 1290 |
| 1263 template<typename T> | 1291 template<typename T> |
| 1264 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; | 1292 PassRefPtr<T> adoptRef(blink::RefCountedGarbageCollected<T>*) = delete; |
| 1265 | 1293 |
| 1266 } // namespace WTF | 1294 } // namespace WTF |
| 1267 | 1295 |
| 1268 #endif | 1296 #endif |
| OLD | NEW |