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 WTF_MAKE_NONCOPYABLE(WrapperPersistentNode); | |
160 public: | |
161 bool isAlive() { return m_regionOffset & wrapperPersistentLiveBitMask; } | |
162 | |
163 WrapperPersistentRegion* region() | |
164 { | |
165 return reinterpret_cast<WrapperPersistentRegion*>( | |
166 reinterpret_cast<Address>(this) - (m_regionOffset & wrapperPersisten tOffsetMask)); | |
167 } | |
168 | |
169 virtual ~WrapperPersistentNode() | |
170 { | |
171 m_regionOffset &= ~wrapperPersistentLiveBitMask; | |
Fabrice (no longer in Chrome)
2014/09/05 18:37:32
From what I understand, isAlive returns false befo
| |
172 } | |
173 | |
174 virtual void trace(Visitor* visitor) { } | |
175 | |
176 protected: | |
177 WrapperPersistentNode() : m_raw(0), m_regionOffset(0) { } | |
178 | |
179 explicit WrapperPersistentNode(void* raw) | |
180 { | |
181 // When the constructor is called the slot should have been taken (takeS lot) | |
182 // as part of allocating the memory (via operator new). Hence the m_raw | |
183 // pointer should be 0. | |
Fabrice (no longer in Chrome)
2014/09/05 18:37:32
I take it from the above comment you are initializ
| |
184 ASSERT(!m_raw); | |
185 m_raw = raw; | |
186 // The m_regionOffset should always be set as an offset to the containin g | |
187 // region. However it should not have the live bit set when the construc tor | |
188 // is called. | |
189 ASSERT(m_regionOffset); | |
190 ASSERT(!isAlive()); | |
191 m_regionOffset |= wrapperPersistentLiveBitMask; | |
192 } | |
193 | |
194 private: | |
195 void initSlot(size_t regionOffset, WrapperPersistentNode* nextFree) | |
196 { | |
197 ASSERT(!m_raw); | |
198 ASSERT(!m_regionOffset); | |
199 ASSERT(!(regionOffset & ~wrapperPersistentOffsetMask)); | |
200 m_raw = nextFree; | |
201 m_regionOffset = regionOffset; | |
202 } | |
203 | |
204 WrapperPersistentNode* takeSlot() | |
205 { | |
206 // The slot should not be alive at the point where it is allocated. | |
207 ASSERT(!isAlive()); | |
208 WrapperPersistentNode* nextFree = reinterpret_cast<WrapperPersistentNode *>(m_raw); | |
209 m_raw = 0; | |
210 return nextFree; | |
211 } | |
212 | |
213 WrapperPersistentNode* freeSlot(WrapperPersistentNode* nextFree) | |
214 { | |
215 // When the slot is freed the destructor should already have cleared the live bit. | |
216 ASSERT(!isAlive()); | |
217 m_raw = nextFree; | |
218 return this; | |
219 } | |
220 | |
221 protected: | |
222 // m_raw is used both to point to the object when the WrapperPersistentNode is used/alive | |
223 // and to point to the next free wrapperPersistentNode in the region when th e node is | |
224 // unused/dead. | |
225 void* m_raw; | |
226 | |
227 // The m_regionOffset field is an offset from this node to the base of the c ontaining | |
228 // WrapperPersistentRegion. | |
229 size_t m_regionOffset; | |
230 | |
231 friend class WrapperPersistentRegion; | |
232 }; | |
233 | |
234 template<typename T> | |
235 class WrapperPersistent FINAL : public WrapperPersistentNode { | |
236 public: | |
237 WrapperPersistent() : WrapperPersistentNode(0) { } | |
238 WrapperPersistent(std::nullptr_t) : WrapperPersistentNode(0) { } | |
239 WrapperPersistent(T* raw) : WrapperPersistentNode(raw) { } | |
240 WrapperPersistent(T& raw) : WrapperPersistentNode(&raw) { } | |
241 | |
242 void* operator new(size_t); | |
243 void operator delete(void*); | |
244 | |
245 virtual void trace(Visitor* visitor) | |
246 { | |
247 ASSERT(isAlive()); | |
248 visitor->mark(static_cast<T*>(m_raw)); | |
249 } | |
250 }; | |
251 | |
252 class PLATFORM_EXPORT WrapperPersistentRegion { | |
253 WTF_MAKE_NONCOPYABLE(WrapperPersistentRegion); | |
254 public: | |
255 WrapperPersistentRegion() | |
256 { | |
257 WrapperPersistentNode* nextFree = 0; | |
258 for (int i = wrapperPersistentsPerRegion - 1; i >= 0; --i) { | |
259 size_t regionOffset = reinterpret_cast<Address>(&m_entries[i]) - rei nterpret_cast<Address>(this); | |
260 // Setup the free slot with an offset to the containing region's bas e and a pointer to the next | |
261 // free slot in the region. | |
262 m_entries[i].initSlot(regionOffset, nextFree); | |
263 nextFree = &m_entries[i]; | |
264 } | |
265 m_prev = 0; | |
266 m_next = 0; | |
267 m_freeHead = nextFree; | |
268 m_count = 0; | |
269 } | |
270 | |
271 void* allocate() | |
272 { | |
273 if (!m_freeHead) { | |
274 ASSERT(m_count == wrapperPersistentsPerRegion); | |
275 return 0; | |
276 } | |
277 // We have a free persistent slot in this region. | |
278 WrapperPersistentNode* freeSlot = m_freeHead; | |
279 // Take the slot and advance m_freeHead to the next free slot. | |
280 m_freeHead = freeSlot->takeSlot(); | |
281 ASSERT(m_count < wrapperPersistentsPerRegion); | |
282 m_count++; | |
283 return reinterpret_cast<void*>(freeSlot); | |
284 } | |
285 | |
286 void free(WrapperPersistentNode* object) | |
287 { | |
288 ASSERT(object); | |
289 ASSERT(!object->isAlive()); | |
Fabrice (no longer in Chrome)
2014/09/05 18:37:32
Per the above comment, you are calling this after
| |
290 m_freeHead = object->freeSlot(m_freeHead); | |
291 ASSERT(m_count > 0); | |
292 m_count--; | |
293 if (!m_count) | |
294 ThreadState::current()->freeWrapperPersistentRegion(this); | |
295 } | |
296 | |
297 bool removeIfNotLast(WrapperPersistentRegion** headPtr); | |
298 static void insertHead(WrapperPersistentRegion** headPtr, WrapperPersistentR egion* newHead); | |
299 static WrapperPersistentRegion* removeHead(WrapperPersistentRegion** headPtr ); | |
300 static void* outOfLineAllocate(ThreadState*, WrapperPersistentRegion*); | |
301 static void trace(WrapperPersistentRegion* head, Visitor* visitor) | |
302 { | |
303 for (WrapperPersistentRegion* current = head; current; current = current ->m_next) | |
304 current->traceRegion(visitor); | |
305 } | |
306 | |
307 private: | |
308 void traceRegion(Visitor* visitor) | |
309 { | |
310 size_t live = 0; | |
311 | |
312 #ifdef NDEBUG | |
313 for (int i = 0; i < wrapperPersistentsPerRegion && live < m_count; ++i) { | |
314 #else | |
315 // In DEBUG mode we scan all entries to validate we only have m_count | |
316 // live entries. | |
317 for (int i = 0; i < wrapperPersistentsPerRegion; ++i) { | |
318 #endif | |
319 if (m_entries[i].isAlive()) { | |
320 m_entries[i].trace(visitor); | |
321 live++; | |
322 } | |
323 } | |
324 ASSERT(live == m_count); | |
325 } | |
326 | |
327 WrapperPersistentRegion* m_prev; | |
328 WrapperPersistentRegion* m_next; | |
329 WrapperPersistentNode* m_freeHead; | |
330 size_t m_count; | |
331 WrapperPersistentNode m_entries[wrapperPersistentsPerRegion]; | |
332 }; | |
333 | |
334 template<typename T> | |
335 void* WrapperPersistent<T>::operator new(size_t size) | |
336 { | |
337 ASSERT(size == sizeof(WrapperPersistent<T>)); | |
338 ThreadState* state = ThreadState::current(); | |
339 WrapperPersistentRegion* region = state->wrapperRoots(); | |
340 ASSERT(region); | |
341 void* persistent = region->allocate(); | |
342 if (!persistent) | |
343 return WrapperPersistentRegion::outOfLineAllocate(state, region); | |
344 return persistent; | |
345 } | |
346 | |
347 template<typename T> | |
348 void WrapperPersistent<T>::operator delete(void* object) | |
349 { | |
350 WrapperPersistentNode* persistent = static_cast<WrapperPersistentNode*>(obje ct); | |
351 persistent->region()->free(persistent); | |
352 } | |
353 | |
153 // RootsAccessor for Persistent that provides access to thread-local list | 354 // RootsAccessor for Persistent that provides access to thread-local list |
154 // of persistent handles. Can only be used to create handles that | 355 // of persistent handles. Can only be used to create handles that |
155 // are constructed and destructed on the same thread. | 356 // are constructed and destructed on the same thread. |
156 template<ThreadAffinity Affinity> | 357 template<ThreadAffinity Affinity> |
157 class ThreadLocalPersistents { | 358 class ThreadLocalPersistents { |
158 public: | 359 public: |
159 static PersistentNode* roots() { return state()->roots(); } | 360 static PersistentNode* roots() { return state()->roots(); } |
160 | 361 |
161 // No locking required. Just check that we are at the right thread. | 362 // No locking required. Just check that we are at the right thread. |
162 class Lock { | 363 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> { | 1402 struct ParamStorageTraits<T*> : public PointerParamStorageTraits<T*, blink::IsGa rbageCollectedType<T>::value> { |
1202 }; | 1403 }; |
1203 | 1404 |
1204 template<typename T> | 1405 template<typename T> |
1205 struct ParamStorageTraits<RawPtr<T> > : public PointerParamStorageTraits<T*, bli nk::IsGarbageCollectedType<T>::value> { | 1406 struct ParamStorageTraits<RawPtr<T> > : public PointerParamStorageTraits<T*, bli nk::IsGarbageCollectedType<T>::value> { |
1206 }; | 1407 }; |
1207 | 1408 |
1208 } // namespace WTF | 1409 } // namespace WTF |
1209 | 1410 |
1210 #endif | 1411 #endif |
OLD | NEW |