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