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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 | 143 |
144 private: | 144 private: |
145 PersistentNode* m_next; | 145 PersistentNode* m_next; |
146 PersistentNode* m_prev; | 146 PersistentNode* m_prev; |
147 | 147 |
148 template<typename RootsAccessor, typename Owner> friend class PersistentBase
; | 148 template<typename RootsAccessor, typename Owner> friend class PersistentBase
; |
149 friend class PersistentAnchor; | 149 friend class PersistentAnchor; |
150 friend class ThreadState; | 150 friend class ThreadState; |
151 }; | 151 }; |
152 | 152 |
| 153 |
| 154 const int wrapperPersistentsPerRegion = 256; |
| 155 const size_t wrapperPersistentOffsetMask = ~static_cast<size_t>(3); |
| 156 const size_t wrapperPersistentLiveBitMask = 1; |
| 157 |
| 158 class WrapperPersistentNode { |
| 159 ALLOW_ONLY_INLINE_ALLOCATION(); |
| 160 WTF_MAKE_NONCOPYABLE(WrapperPersistentNode); |
| 161 public: |
| 162 bool isAlive() { return m_regionOffset & wrapperPersistentLiveBitMask; } |
| 163 |
| 164 WrapperPersistentRegion* region() |
| 165 { |
| 166 return reinterpret_cast<WrapperPersistentRegion*>( |
| 167 reinterpret_cast<Address>(this) - regionOffset()); |
| 168 } |
| 169 |
| 170 virtual void trace(Visitor* visitor) { } |
| 171 |
| 172 static inline void destroy(const WrapperPersistentNode*); |
| 173 |
| 174 protected: |
| 175 WrapperPersistentNode() : m_raw(0), m_regionOffset(0) { } |
| 176 WrapperPersistentNode(void *raw, size_t regionOffset) : m_raw(raw), m_region
Offset(regionOffset) { } |
| 177 |
| 178 private: |
| 179 size_t regionOffset() { return m_regionOffset & wrapperPersistentOffsetMask;
} |
| 180 |
| 181 WrapperPersistentNode* takeSlot() |
| 182 { |
| 183 // The slot should not be alive at the point where it is allocated. |
| 184 ASSERT(!isAlive()); |
| 185 WrapperPersistentNode* nextFree = reinterpret_cast<WrapperPersistentNode
*>(m_raw); |
| 186 m_raw = 0; |
| 187 return nextFree; |
| 188 } |
| 189 |
| 190 WrapperPersistentNode* freeSlot(WrapperPersistentNode* nextFree) |
| 191 { |
| 192 m_regionOffset &= ~wrapperPersistentLiveBitMask; |
| 193 m_raw = nextFree; |
| 194 return this; |
| 195 } |
| 196 |
| 197 // Don't allow delete being called on wrapper persistent nodes. We |
| 198 // do use placement new to initialize the slot with the right vtable. See |
| 199 // WrapperPersistent<T> below. |
| 200 void operator delete(void*); |
| 201 |
| 202 protected: |
| 203 // m_raw is used both to point to the object when the WrapperPersistentNode
is used/alive |
| 204 // and to point to the next free wrapperPersistentNode in the region when th
e node is |
| 205 // unused/dead. |
| 206 void* m_raw; |
| 207 |
| 208 // The m_regionOffset field encodes liveness of the slot as well as being an |
| 209 // offset from this node to the base of the containing WrapperPersistentRegi
on. |
| 210 size_t m_regionOffset; |
| 211 |
| 212 friend class WrapperPersistentRegion; |
| 213 }; |
| 214 |
| 215 template<typename T> |
| 216 class WrapperPersistent FINAL : public WrapperPersistentNode { |
| 217 ALLOW_ONLY_INLINE_ALLOCATION(); |
| 218 public: |
| 219 static WrapperPersistent<T>* create(T* raw); |
| 220 |
| 221 virtual void trace(Visitor* visitor) OVERRIDE |
| 222 { |
| 223 ASSERT(isAlive()); |
| 224 visitor->mark(static_cast<T*>(m_raw)); |
| 225 } |
| 226 |
| 227 private: |
| 228 WrapperPersistent() { } |
| 229 |
| 230 // We need to use a constructor to initialize the allocated slot since it |
| 231 // has a vtable which must be set to the WrapperPersistent<T> type. |
| 232 WrapperPersistent(T* raw, size_t regionOffset) : WrapperPersistentNode(raw,
regionOffset) { } |
| 233 |
| 234 // Don't allow delete being called on wrapper persistents. |
| 235 void operator delete(void*); |
| 236 }; |
| 237 |
| 238 class PLATFORM_EXPORT WrapperPersistentRegion { |
| 239 WTF_MAKE_NONCOPYABLE(WrapperPersistentRegion); |
| 240 public: |
| 241 WrapperPersistentRegion() |
| 242 { |
| 243 WrapperPersistentNode* nextFree = 0; |
| 244 for (int i = wrapperPersistentsPerRegion - 1; i >= 0; --i) { |
| 245 size_t regionOffset = reinterpret_cast<Address>(&m_entries[i]) - rei
nterpret_cast<Address>(this); |
| 246 // Setup the free slot with an offset to the containing region's bas
e and a pointer to the next |
| 247 // free slot in the region. |
| 248 ASSERT(!(regionOffset & ~wrapperPersistentOffsetMask)); |
| 249 new (&m_entries[i]) WrapperPersistentNode(nextFree, regionOffset); |
| 250 nextFree = &m_entries[i]; |
| 251 } |
| 252 m_prev = 0; |
| 253 m_next = 0; |
| 254 m_freeHead = nextFree; |
| 255 m_count = 0; |
| 256 } |
| 257 |
| 258 Address allocate() |
| 259 { |
| 260 if (!m_freeHead) { |
| 261 ASSERT(m_count == wrapperPersistentsPerRegion); |
| 262 return 0; |
| 263 } |
| 264 // We have a free persistent slot in this region. |
| 265 WrapperPersistentNode* freeSlot = m_freeHead; |
| 266 // Take the slot and advance m_freeHead to the next free slot. |
| 267 m_freeHead = freeSlot->takeSlot(); |
| 268 ASSERT(m_count < wrapperPersistentsPerRegion); |
| 269 m_count++; |
| 270 return reinterpret_cast<Address>(freeSlot); |
| 271 } |
| 272 |
| 273 void free(WrapperPersistentNode* object) |
| 274 { |
| 275 ASSERT(object); |
| 276 m_freeHead = object->freeSlot(m_freeHead); |
| 277 ASSERT(m_count > 0); |
| 278 m_count--; |
| 279 if (!m_count) |
| 280 ThreadState::current()->freeWrapperPersistentRegion(this); |
| 281 } |
| 282 |
| 283 bool removeIfNotLast(WrapperPersistentRegion** headPtr); |
| 284 static void insertHead(WrapperPersistentRegion** headPtr, WrapperPersistentR
egion* newHead); |
| 285 static WrapperPersistentRegion* removeHead(WrapperPersistentRegion** headPtr
); |
| 286 static Address outOfLineAllocate(ThreadState*, WrapperPersistentRegion**); |
| 287 static void trace(WrapperPersistentRegion* head, Visitor* visitor) |
| 288 { |
| 289 for (WrapperPersistentRegion* current = head; current; current = current
->m_next) |
| 290 current->traceRegion(visitor); |
| 291 } |
| 292 |
| 293 private: |
| 294 void traceRegion(Visitor* visitor) |
| 295 { |
| 296 size_t live = 0; |
| 297 |
| 298 #ifdef NDEBUG |
| 299 for (int i = 0; i < wrapperPersistentsPerRegion && live < m_count; ++i)
{ |
| 300 #else |
| 301 // In DEBUG mode we scan all entries to validate we only have m_count |
| 302 // live entries. |
| 303 for (int i = 0; i < wrapperPersistentsPerRegion; ++i) { |
| 304 #endif |
| 305 if (m_entries[i].isAlive()) { |
| 306 m_entries[i].trace(visitor); |
| 307 live++; |
| 308 } |
| 309 } |
| 310 ASSERT(live == m_count); |
| 311 } |
| 312 |
| 313 WrapperPersistentRegion* m_prev; |
| 314 WrapperPersistentRegion* m_next; |
| 315 WrapperPersistentNode* m_freeHead; |
| 316 size_t m_count; |
| 317 WrapperPersistentNode m_entries[wrapperPersistentsPerRegion]; |
| 318 }; |
| 319 |
| 320 template<typename T> |
| 321 WrapperPersistent<T>* WrapperPersistent<T>::create(T* raw) |
| 322 { |
| 323 ThreadState* state = ThreadState::current(); |
| 324 WrapperPersistentRegion* region = state->wrapperRoots(); |
| 325 ASSERT(region); |
| 326 Address persistentSlot = region->allocate(); |
| 327 if (!persistentSlot) |
| 328 persistentSlot = WrapperPersistentRegion::outOfLineAllocate(state, ®i
on); |
| 329 ASSERT(persistentSlot); |
| 330 ASSERT(!reinterpret_cast<WrapperPersistentNode*>(persistentSlot)->isAlive())
; |
| 331 |
| 332 size_t regionOffset = persistentSlot - reinterpret_cast<Address>(region); |
| 333 regionOffset |= wrapperPersistentLiveBitMask; |
| 334 |
| 335 // We use placement new to call the constructor to ensure that we setup the |
| 336 // vtable correctly. |
| 337 return new (persistentSlot) WrapperPersistent<T>(raw, regionOffset); |
| 338 } |
| 339 |
| 340 void WrapperPersistentNode::destroy(const WrapperPersistentNode* node) |
| 341 { |
| 342 WrapperPersistentNode* persistent = const_cast<WrapperPersistentNode*>(node)
; |
| 343 persistent->region()->free(persistent); |
| 344 } |
| 345 |
153 // RootsAccessor for Persistent that provides access to thread-local list | 346 // RootsAccessor for Persistent that provides access to thread-local list |
154 // of persistent handles. Can only be used to create handles that | 347 // of persistent handles. Can only be used to create handles that |
155 // are constructed and destructed on the same thread. | 348 // are constructed and destructed on the same thread. |
156 template<ThreadAffinity Affinity> | 349 template<ThreadAffinity Affinity> |
157 class ThreadLocalPersistents { | 350 class ThreadLocalPersistents { |
158 public: | 351 public: |
159 static PersistentNode* roots() { return state()->roots(); } | 352 static PersistentNode* roots() { return state()->roots(); } |
160 | 353 |
161 // No locking required. Just check that we are at the right thread. | 354 // No locking required. Just check that we are at the right thread. |
162 class Lock { | 355 class Lock { |
(...skipping 1038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1201 struct ParamStorageTraits<T*> : public PointerParamStorageTraits<T*, blink::IsGa
rbageCollectedType<T>::value> { | 1394 struct ParamStorageTraits<T*> : public PointerParamStorageTraits<T*, blink::IsGa
rbageCollectedType<T>::value> { |
1202 }; | 1395 }; |
1203 | 1396 |
1204 template<typename T> | 1397 template<typename T> |
1205 struct ParamStorageTraits<RawPtr<T> > : public PointerParamStorageTraits<T*, bli
nk::IsGarbageCollectedType<T>::value> { | 1398 struct ParamStorageTraits<RawPtr<T> > : public PointerParamStorageTraits<T*, bli
nk::IsGarbageCollectedType<T>::value> { |
1206 }; | 1399 }; |
1207 | 1400 |
1208 } // namespace WTF | 1401 } // namespace WTF |
1209 | 1402 |
1210 #endif | 1403 #endif |
OLD | NEW |