| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 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. | |
| 29 */ | |
| 30 | |
| 31 #ifndef Heap_h | |
| 32 #define Heap_h | |
| 33 | |
| 34 #include "platform/PlatformExport.h" | |
| 35 #include "platform/heap/AddressSanitizer.h" | |
| 36 #include "platform/heap/ThreadState.h" | |
| 37 #include "platform/heap/Visitor.h" | |
| 38 #include "public/platform/WebThread.h" | |
| 39 #include "wtf/Assertions.h" | |
| 40 #include "wtf/HashCountedSet.h" | |
| 41 #include "wtf/LinkedHashSet.h" | |
| 42 #include "wtf/ListHashSet.h" | |
| 43 #include "wtf/OwnPtr.h" | |
| 44 #include "wtf/PassRefPtr.h" | |
| 45 #include "wtf/ThreadSafeRefCounted.h" | |
| 46 | |
| 47 #include <stdint.h> | |
| 48 | |
| 49 namespace blink { | |
| 50 | |
| 51 const size_t blinkPageSizeLog2 = 17; | |
| 52 const size_t blinkPageSize = 1 << blinkPageSizeLog2; | |
| 53 const size_t blinkPageOffsetMask = blinkPageSize - 1; | |
| 54 const size_t blinkPageBaseMask = ~blinkPageOffsetMask; | |
| 55 | |
| 56 // We allocate pages at random addresses but in groups of | |
| 57 // blinkPagesPerRegion at a given random address. We group pages to | |
| 58 // not spread out too much over the address space which would blow | |
| 59 // away the page tables and lead to bad performance. | |
| 60 const size_t blinkPagesPerRegion = 10; | |
| 61 | |
| 62 // Double precision floats are more efficient when 8 byte aligned, so we 8 byte | |
| 63 // align all allocations even on 32 bit. | |
| 64 const size_t allocationGranularity = 8; | |
| 65 const size_t allocationMask = allocationGranularity - 1; | |
| 66 const size_t objectStartBitMapSize = (blinkPageSize + ((8 * allocationGranularit
y) - 1)) / (8 * allocationGranularity); | |
| 67 const size_t reservedForObjectBitMap = ((objectStartBitMapSize + allocationMask)
& ~allocationMask); | |
| 68 const size_t maxHeapObjectSizeLog2 = 27; | |
| 69 const size_t maxHeapObjectSize = 1 << maxHeapObjectSizeLog2; | |
| 70 | |
| 71 const size_t markBitMask = 1; | |
| 72 const size_t freeListMask = 2; | |
| 73 // The dead bit is used for objects that have gone through a GC marking, but did | |
| 74 // not get swept before a new GC started. In that case we set the dead bit on | |
| 75 // objects that were not marked in the previous GC to ensure we are not tracing | |
| 76 // them via a conservatively found pointer. Tracing dead objects could lead to | |
| 77 // tracing of already finalized objects in another thread's heap which is a | |
| 78 // use-after-free situation. | |
| 79 const size_t deadBitMask = 4; | |
| 80 // On free-list entries we reuse the dead bit to distinguish a normal free-list | |
| 81 // entry from one that has been promptly freed. | |
| 82 const size_t promptlyFreedMask = freeListMask | deadBitMask; | |
| 83 #if ENABLE(GC_PROFILE_HEAP) | |
| 84 const size_t heapObjectGenerations = 8; | |
| 85 const size_t maxHeapObjectAge = heapObjectGenerations - 1; | |
| 86 const size_t heapObjectAgeMask = ~(maxHeapObjectSize - 1); | |
| 87 const size_t sizeMask = ~heapObjectAgeMask & ~static_cast<size_t>(7); | |
| 88 #else | |
| 89 const size_t sizeMask = ~static_cast<size_t>(7); | |
| 90 #endif | |
| 91 const uint8_t freelistZapValue = 42; | |
| 92 const uint8_t finalizedZapValue = 24; | |
| 93 // The orphaned zap value must be zero in the lowest bits to allow for using | |
| 94 // the mark bit when tracing. | |
| 95 const uint8_t orphanedZapValue = 240; | |
| 96 | |
| 97 const int numberOfMarkingThreads = 2; | |
| 98 | |
| 99 const int numberOfPagesToConsiderForCoalescing = 100; | |
| 100 | |
| 101 enum CallbackInvocationMode { | |
| 102 GlobalMarking, | |
| 103 ThreadLocalMarking, | |
| 104 PostMarking, | |
| 105 WeaknessProcessing, | |
| 106 }; | |
| 107 | |
| 108 class HeapStats; | |
| 109 class PageMemory; | |
| 110 template<ThreadAffinity affinity> class ThreadLocalPersistents; | |
| 111 template<typename T, typename RootsAccessor = ThreadLocalPersistents<ThreadingTr
ait<T>::Affinity > > class Persistent; | |
| 112 | |
| 113 #if ENABLE(GC_PROFILE_HEAP) | |
| 114 class TracedValue; | |
| 115 #endif | |
| 116 | |
| 117 PLATFORM_EXPORT size_t osPageSize(); | |
| 118 | |
| 119 // Blink heap pages are set up with a guard page before and after the | |
| 120 // payload. | |
| 121 inline size_t blinkPagePayloadSize() | |
| 122 { | |
| 123 return blinkPageSize - 2 * osPageSize(); | |
| 124 } | |
| 125 | |
| 126 // Blink heap pages are aligned to the Blink heap page size. | |
| 127 // Therefore, the start of a Blink page can be obtained by | |
| 128 // rounding down to the Blink page size. | |
| 129 inline Address roundToBlinkPageStart(Address address) | |
| 130 { | |
| 131 return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address) & blin
kPageBaseMask); | |
| 132 } | |
| 133 | |
| 134 inline Address roundToBlinkPageEnd(Address address) | |
| 135 { | |
| 136 return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address - 1) &
blinkPageBaseMask) + blinkPageSize; | |
| 137 } | |
| 138 | |
| 139 // Compute the amount of padding we have to add to a header to make | |
| 140 // the size of the header plus the padding a multiple of 8 bytes. | |
| 141 template<typename Header> | |
| 142 inline size_t headerPadding() | |
| 143 { | |
| 144 return (allocationGranularity - (sizeof(Header) % allocationGranularity)) %
allocationGranularity; | |
| 145 } | |
| 146 | |
| 147 // Masks an address down to the enclosing blink page base address. | |
| 148 inline Address blinkPageAddress(Address address) | |
| 149 { | |
| 150 return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address) & blin
kPageBaseMask); | |
| 151 } | |
| 152 | |
| 153 #if ENABLE(ASSERT) | |
| 154 | |
| 155 // Sanity check for a page header address: the address of the page | |
| 156 // header should be OS page size away from being Blink page size | |
| 157 // aligned. | |
| 158 inline bool isPageHeaderAddress(Address address) | |
| 159 { | |
| 160 return !((reinterpret_cast<uintptr_t>(address) & blinkPageOffsetMask) - osPa
geSize()); | |
| 161 } | |
| 162 #endif | |
| 163 | |
| 164 // Mask an address down to the enclosing oilpan heap base page. | |
| 165 // All oilpan heap pages are aligned at blinkPageBase plus an OS page size. | |
| 166 // FIXME: Remove PLATFORM_EXPORT once we get a proper public interface to our ty
ped heaps. | |
| 167 // This is only exported to enable tests in HeapTest.cpp. | |
| 168 PLATFORM_EXPORT inline BaseHeapPage* pageHeaderFromObject(const void* object) | |
| 169 { | |
| 170 Address address = reinterpret_cast<Address>(const_cast<void*>(object)); | |
| 171 return reinterpret_cast<BaseHeapPage*>(blinkPageAddress(address) + osPageSiz
e()); | |
| 172 } | |
| 173 | |
| 174 // Large allocations are allocated as separate objects and linked in a | |
| 175 // list. | |
| 176 // | |
| 177 // In order to use the same memory allocation routines for everything | |
| 178 // allocated in the heap, large objects are considered heap pages | |
| 179 // containing only one object. | |
| 180 // | |
| 181 // The layout of a large heap object is as follows: | |
| 182 // | |
| 183 // | BaseHeapPage | next pointer | FinalizedHeapObjectHeader or HeapObjectHeader
| payload | | |
| 184 template<typename Header> | |
| 185 class LargeHeapObject : public BaseHeapPage { | |
| 186 public: | |
| 187 LargeHeapObject(PageMemory* storage, const GCInfo* gcInfo, ThreadState* stat
e) : BaseHeapPage(storage, gcInfo, state) | |
| 188 { | |
| 189 COMPILE_ASSERT(!(sizeof(LargeHeapObject<Header>) & allocationMask), larg
e_heap_object_header_misaligned); | |
| 190 } | |
| 191 | |
| 192 virtual void checkAndMarkPointer(Visitor*, Address) override; | |
| 193 virtual bool isLargeObject() override { return true; } | |
| 194 | |
| 195 #if ENABLE(GC_PROFILE_MARKING) | |
| 196 virtual const GCInfo* findGCInfo(Address address) | |
| 197 { | |
| 198 if (!objectContains(address)) | |
| 199 return 0; | |
| 200 return gcInfo(); | |
| 201 } | |
| 202 #endif | |
| 203 | |
| 204 #if ENABLE(GC_PROFILE_HEAP) | |
| 205 void snapshot(TracedValue*, ThreadState::SnapshotInfo*); | |
| 206 #endif | |
| 207 | |
| 208 void link(LargeHeapObject<Header>** previousNext) | |
| 209 { | |
| 210 m_next = *previousNext; | |
| 211 *previousNext = this; | |
| 212 } | |
| 213 | |
| 214 void unlink(LargeHeapObject<Header>** previousNext) | |
| 215 { | |
| 216 *previousNext = m_next; | |
| 217 } | |
| 218 | |
| 219 // The LargeHeapObject pseudo-page contains one actual object. Determine | |
| 220 // whether the pointer is within that object. | |
| 221 bool objectContains(Address object) | |
| 222 { | |
| 223 return (payload() <= object) && (object < address() + size()); | |
| 224 } | |
| 225 | |
| 226 // Returns true for any address that is on one of the pages that this | |
| 227 // large object uses. That ensures that we can use a negative result to | |
| 228 // populate the negative page cache. | |
| 229 virtual bool contains(Address object) override | |
| 230 { | |
| 231 return roundToBlinkPageStart(address()) <= object && object < roundToBli
nkPageEnd(address() + size()); | |
| 232 } | |
| 233 | |
| 234 LargeHeapObject<Header>* next() | |
| 235 { | |
| 236 return m_next; | |
| 237 } | |
| 238 | |
| 239 size_t size() | |
| 240 { | |
| 241 return heapObjectHeader()->size() + sizeof(LargeHeapObject<Header>) + he
aderPadding<Header>(); | |
| 242 } | |
| 243 | |
| 244 Address payload() { return heapObjectHeader()->payload(); } | |
| 245 size_t payloadSize() { return heapObjectHeader()->payloadSize(); } | |
| 246 | |
| 247 Header* heapObjectHeader() | |
| 248 { | |
| 249 Address headerAddress = address() + sizeof(LargeHeapObject<Header>) + he
aderPadding<Header>(); | |
| 250 return reinterpret_cast<Header*>(headerAddress); | |
| 251 } | |
| 252 | |
| 253 bool isMarked(); | |
| 254 void unmark(); | |
| 255 void getStats(HeapStats&); | |
| 256 void mark(Visitor*); | |
| 257 void finalize(); | |
| 258 void setDeadMark(); | |
| 259 virtual void markOrphaned() | |
| 260 { | |
| 261 // Zap the payload with a recognizable value to detect any incorrect | |
| 262 // cross thread pointer usage. | |
| 263 memset(payload(), orphanedZapValue, payloadSize()); | |
| 264 BaseHeapPage::markOrphaned(); | |
| 265 } | |
| 266 | |
| 267 private: | |
| 268 friend class ThreadHeap<Header>; | |
| 269 | |
| 270 LargeHeapObject<Header>* m_next; | |
| 271 }; | |
| 272 | |
| 273 // The BasicObjectHeader is the minimal object header. It is used when | |
| 274 // encountering heap space of size allocationGranularity to mark it as | |
| 275 // as freelist entry. | |
| 276 class PLATFORM_EXPORT BasicObjectHeader { | |
| 277 public: | |
| 278 NO_SANITIZE_ADDRESS | |
| 279 explicit BasicObjectHeader(size_t encodedSize) | |
| 280 : m_size(encodedSize) { } | |
| 281 | |
| 282 static size_t freeListEncodedSize(size_t size) { return size | freeListMask;
} | |
| 283 | |
| 284 NO_SANITIZE_ADDRESS | |
| 285 bool isFree() { return m_size & freeListMask; } | |
| 286 | |
| 287 NO_SANITIZE_ADDRESS | |
| 288 bool isPromptlyFreed() { return (m_size & promptlyFreedMask) == promptlyFree
dMask; } | |
| 289 | |
| 290 NO_SANITIZE_ADDRESS | |
| 291 void markPromptlyFreed() { m_size |= promptlyFreedMask; } | |
| 292 | |
| 293 NO_SANITIZE_ADDRESS | |
| 294 size_t size() const { return m_size & sizeMask; } | |
| 295 | |
| 296 #if ENABLE(GC_PROFILE_HEAP) | |
| 297 NO_SANITIZE_ADDRESS | |
| 298 size_t encodedSize() const { return m_size; } | |
| 299 | |
| 300 NO_SANITIZE_ADDRESS | |
| 301 size_t age() const { return m_size >> maxHeapObjectSizeLog2; } | |
| 302 | |
| 303 NO_SANITIZE_ADDRESS | |
| 304 void incAge() | |
| 305 { | |
| 306 size_t current = age(); | |
| 307 if (current < maxHeapObjectAge) | |
| 308 m_size = ((current + 1) << maxHeapObjectSizeLog2) | (m_size & ~heapO
bjectAgeMask); | |
| 309 } | |
| 310 #endif | |
| 311 | |
| 312 protected: | |
| 313 volatile unsigned m_size; | |
| 314 }; | |
| 315 | |
| 316 // Our heap object layout is layered with the HeapObjectHeader closest | |
| 317 // to the payload, this can be wrapped in a FinalizedObjectHeader if the | |
| 318 // object is on the GeneralHeap and not on a specific TypedHeap. | |
| 319 // Finally if the object is a large object (> blinkPageSize/2) then it is | |
| 320 // wrapped with a LargeObjectHeader. | |
| 321 // | |
| 322 // Object memory layout: | |
| 323 // [ LargeObjectHeader | ] [ FinalizedObjectHeader | ] HeapObjectHeader | payloa
d | |
| 324 // The [ ] notation denotes that the LargeObjectHeader and the FinalizedObjectHe
ader | |
| 325 // are independently optional. | |
| 326 class PLATFORM_EXPORT HeapObjectHeader : public BasicObjectHeader { | |
| 327 public: | |
| 328 NO_SANITIZE_ADDRESS | |
| 329 explicit HeapObjectHeader(size_t encodedSize) | |
| 330 : BasicObjectHeader(encodedSize) | |
| 331 #if ENABLE(ASSERT) | |
| 332 , m_magic(magic) | |
| 333 #endif | |
| 334 { } | |
| 335 | |
| 336 NO_SANITIZE_ADDRESS | |
| 337 HeapObjectHeader(size_t encodedSize, const GCInfo*) | |
| 338 : BasicObjectHeader(encodedSize) | |
| 339 #if ENABLE(ASSERT) | |
| 340 , m_magic(magic) | |
| 341 #endif | |
| 342 { } | |
| 343 | |
| 344 inline void checkHeader() const; | |
| 345 inline bool isMarked() const; | |
| 346 | |
| 347 inline void mark(); | |
| 348 inline void unmark(); | |
| 349 | |
| 350 inline const GCInfo* gcInfo() { return 0; } | |
| 351 | |
| 352 inline Address payload(); | |
| 353 inline size_t payloadSize(); | |
| 354 inline Address payloadEnd(); | |
| 355 | |
| 356 inline void setDeadMark(); | |
| 357 inline void clearDeadMark(); | |
| 358 inline bool hasDeadMark() const; | |
| 359 | |
| 360 // Zap magic number with a new magic number that means there was once an | |
| 361 // object allocated here, but it was freed because nobody marked it during | |
| 362 // GC. | |
| 363 void zapMagic(); | |
| 364 | |
| 365 static void finalize(const GCInfo*, Address, size_t); | |
| 366 static HeapObjectHeader* fromPayload(const void*); | |
| 367 | |
| 368 static const intptr_t magic = 0xc0de247; | |
| 369 static const intptr_t zappedMagic = 0xC0DEdead; | |
| 370 // The zap value for vtables should be < 4K to ensure it cannot be | |
| 371 // used for dispatch. | |
| 372 static const intptr_t zappedVTable = 0xd0d; | |
| 373 | |
| 374 private: | |
| 375 #if ENABLE(ASSERT) | |
| 376 intptr_t m_magic; | |
| 377 #endif | |
| 378 }; | |
| 379 | |
| 380 const size_t objectHeaderSize = sizeof(HeapObjectHeader); | |
| 381 | |
| 382 // Each object on the GeneralHeap needs to carry a pointer to its | |
| 383 // own GCInfo structure for tracing and potential finalization. | |
| 384 class PLATFORM_EXPORT FinalizedHeapObjectHeader : public HeapObjectHeader { | |
| 385 public: | |
| 386 NO_SANITIZE_ADDRESS | |
| 387 FinalizedHeapObjectHeader(size_t encodedSize, const GCInfo* gcInfo) | |
| 388 : HeapObjectHeader(encodedSize) | |
| 389 , m_gcInfo(gcInfo) | |
| 390 { | |
| 391 } | |
| 392 | |
| 393 inline Address payload(); | |
| 394 inline size_t payloadSize(); | |
| 395 | |
| 396 NO_SANITIZE_ADDRESS | |
| 397 const GCInfo* gcInfo() { return m_gcInfo; } | |
| 398 | |
| 399 NO_SANITIZE_ADDRESS | |
| 400 TraceCallback traceCallback() { return m_gcInfo->m_trace; } | |
| 401 | |
| 402 void finalize(); | |
| 403 | |
| 404 NO_SANITIZE_ADDRESS | |
| 405 inline bool hasFinalizer() { return m_gcInfo->hasFinalizer(); } | |
| 406 | |
| 407 static FinalizedHeapObjectHeader* fromPayload(const void*); | |
| 408 | |
| 409 NO_SANITIZE_ADDRESS | |
| 410 bool hasVTable() { return m_gcInfo->hasVTable(); } | |
| 411 | |
| 412 private: | |
| 413 const GCInfo* m_gcInfo; | |
| 414 }; | |
| 415 | |
| 416 const size_t finalizedHeaderSize = sizeof(FinalizedHeapObjectHeader); | |
| 417 | |
| 418 class FreeListEntry : public HeapObjectHeader { | |
| 419 public: | |
| 420 NO_SANITIZE_ADDRESS | |
| 421 explicit FreeListEntry(size_t size) | |
| 422 : HeapObjectHeader(freeListEncodedSize(size)) | |
| 423 , m_next(0) | |
| 424 { | |
| 425 #if ENABLE(ASSERT) && !defined(ADDRESS_SANITIZER) | |
| 426 // Zap free area with asterisks, aka 0x2a2a2a2a. | |
| 427 // For ASan don't zap since we keep accounting in the freelist entry. | |
| 428 for (size_t i = sizeof(*this); i < size; i++) | |
| 429 reinterpret_cast<Address>(this)[i] = freelistZapValue; | |
| 430 ASSERT(size >= objectHeaderSize); | |
| 431 zapMagic(); | |
| 432 #endif | |
| 433 } | |
| 434 | |
| 435 Address address() { return reinterpret_cast<Address>(this); } | |
| 436 | |
| 437 NO_SANITIZE_ADDRESS | |
| 438 void unlink(FreeListEntry** prevNext) | |
| 439 { | |
| 440 *prevNext = m_next; | |
| 441 m_next = 0; | |
| 442 } | |
| 443 | |
| 444 NO_SANITIZE_ADDRESS | |
| 445 void link(FreeListEntry** prevNext) | |
| 446 { | |
| 447 m_next = *prevNext; | |
| 448 *prevNext = this; | |
| 449 } | |
| 450 | |
| 451 NO_SANITIZE_ADDRESS | |
| 452 FreeListEntry* next() const { return m_next; } | |
| 453 | |
| 454 NO_SANITIZE_ADDRESS | |
| 455 void append(FreeListEntry* next) | |
| 456 { | |
| 457 ASSERT(!m_next); | |
| 458 m_next = next; | |
| 459 } | |
| 460 | |
| 461 #if defined(ADDRESS_SANITIZER) | |
| 462 NO_SANITIZE_ADDRESS | |
| 463 bool shouldAddToFreeList() | |
| 464 { | |
| 465 // Init if not already magic. | |
| 466 if ((m_asanMagic & ~asanDeferMemoryReuseMask) != asanMagic) { | |
| 467 m_asanMagic = asanMagic | asanDeferMemoryReuseCount; | |
| 468 return false; | |
| 469 } | |
| 470 // Decrement if count part of asanMagic > 0. | |
| 471 if (m_asanMagic & asanDeferMemoryReuseMask) | |
| 472 m_asanMagic--; | |
| 473 return !(m_asanMagic & asanDeferMemoryReuseMask); | |
| 474 } | |
| 475 #endif | |
| 476 | |
| 477 private: | |
| 478 FreeListEntry* m_next; | |
| 479 #if defined(ADDRESS_SANITIZER) | |
| 480 unsigned m_asanMagic; | |
| 481 #endif | |
| 482 }; | |
| 483 | |
| 484 // Representation of Blink heap pages. | |
| 485 // | |
| 486 // Pages are specialized on the type of header on the object they | |
| 487 // contain. If a heap page only contains a certain type of object all | |
| 488 // of the objects will have the same GCInfo pointer and therefore that | |
| 489 // pointer can be stored in the HeapPage instead of in the header of | |
| 490 // each object. In that case objects have only a HeapObjectHeader and | |
| 491 // not a FinalizedHeapObjectHeader saving a word per object. | |
| 492 template<typename Header> | |
| 493 class HeapPage : public BaseHeapPage { | |
| 494 public: | |
| 495 HeapPage(PageMemory*, ThreadHeap<Header>*, const GCInfo*); | |
| 496 | |
| 497 void link(HeapPage**); | |
| 498 static void unlink(ThreadHeap<Header>*, HeapPage*, HeapPage**); | |
| 499 | |
| 500 bool isEmpty(); | |
| 501 | |
| 502 // Returns true for the whole blinkPageSize page that the page is on, even | |
| 503 // for the header, and the unmapped guard page at the start. That ensures | |
| 504 // the result can be used to populate the negative page cache. | |
| 505 virtual bool contains(Address addr) override | |
| 506 { | |
| 507 Address blinkPageStart = roundToBlinkPageStart(address()); | |
| 508 ASSERT(blinkPageStart == address() - osPageSize()); // Page is at aligne
d address plus guard page size. | |
| 509 return blinkPageStart <= addr && addr < blinkPageStart + blinkPageSize; | |
| 510 } | |
| 511 | |
| 512 HeapPage* next() { return m_next; } | |
| 513 | |
| 514 Address payload() | |
| 515 { | |
| 516 return address() + sizeof(*this) + headerPadding<Header>(); | |
| 517 } | |
| 518 | |
| 519 static size_t payloadSize() | |
| 520 { | |
| 521 return (blinkPagePayloadSize() - sizeof(HeapPage) - headerPadding<Header
>()) & ~allocationMask; | |
| 522 } | |
| 523 | |
| 524 Address end() { return payload() + payloadSize(); } | |
| 525 | |
| 526 void getStats(HeapStats&); | |
| 527 void clearLiveAndMarkDead(); | |
| 528 void sweep(HeapStats*, ThreadHeap<Header>*); | |
| 529 void clearObjectStartBitMap(); | |
| 530 void finalize(Header*); | |
| 531 virtual void checkAndMarkPointer(Visitor*, Address) override; | |
| 532 #if ENABLE(GC_PROFILE_MARKING) | |
| 533 const GCInfo* findGCInfo(Address) override; | |
| 534 #endif | |
| 535 #if ENABLE(GC_PROFILE_HEAP) | |
| 536 virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*); | |
| 537 #endif | |
| 538 | |
| 539 #if defined(ADDRESS_SANITIZER) | |
| 540 void poisonUnmarkedObjects(); | |
| 541 #endif | |
| 542 NO_SANITIZE_ADDRESS | |
| 543 virtual void markOrphaned() | |
| 544 { | |
| 545 // Zap the payload with a recognizable value to detect any incorrect | |
| 546 // cross thread pointer usage. | |
| 547 #if defined(ADDRESS_SANITIZER) | |
| 548 // Don't use memset when running with ASan since this needs to zap | |
| 549 // poisoned memory as well and the NO_SANITIZE_ADDRESS annotation | |
| 550 // only works for code in this method and not for calls to memset. | |
| 551 for (Address current = payload(); current < payload() + payloadSize(); +
+current) | |
| 552 *current = orphanedZapValue; | |
| 553 #else | |
| 554 memset(payload(), orphanedZapValue, payloadSize()); | |
| 555 #endif | |
| 556 BaseHeapPage::markOrphaned(); | |
| 557 } | |
| 558 | |
| 559 protected: | |
| 560 Header* findHeaderFromAddress(Address); | |
| 561 void populateObjectStartBitMap(); | |
| 562 bool isObjectStartBitMapComputed() { return m_objectStartBitMapComputed; } | |
| 563 TraceCallback traceCallback(Header*); | |
| 564 bool hasVTable(Header*); | |
| 565 | |
| 566 intptr_t padding() const { return m_padding; } | |
| 567 | |
| 568 HeapPage<Header>* m_next; | |
| 569 intptr_t m_padding; // Preserve 8-byte alignment on 32-bit systems. | |
| 570 bool m_objectStartBitMapComputed; | |
| 571 uint8_t m_objectStartBitMap[reservedForObjectBitMap]; | |
| 572 | |
| 573 friend class ThreadHeap<Header>; | |
| 574 }; | |
| 575 | |
| 576 class AddressEntry { | |
| 577 public: | |
| 578 AddressEntry() : m_address(0) { } | |
| 579 | |
| 580 explicit AddressEntry(Address address) : m_address(address) { } | |
| 581 | |
| 582 Address address() const { return m_address; } | |
| 583 | |
| 584 private: | |
| 585 Address m_address; | |
| 586 }; | |
| 587 | |
| 588 class PositiveEntry : public AddressEntry { | |
| 589 public: | |
| 590 PositiveEntry() | |
| 591 : AddressEntry() | |
| 592 , m_containingPage(0) | |
| 593 { | |
| 594 } | |
| 595 | |
| 596 PositiveEntry(Address address, BaseHeapPage* containingPage) | |
| 597 : AddressEntry(address) | |
| 598 , m_containingPage(containingPage) | |
| 599 { | |
| 600 } | |
| 601 | |
| 602 BaseHeapPage* result() const { return m_containingPage; } | |
| 603 | |
| 604 typedef BaseHeapPage* LookupResult; | |
| 605 | |
| 606 private: | |
| 607 BaseHeapPage* m_containingPage; | |
| 608 }; | |
| 609 | |
| 610 class NegativeEntry : public AddressEntry { | |
| 611 public: | |
| 612 NegativeEntry() : AddressEntry() { } | |
| 613 | |
| 614 NegativeEntry(Address address, bool) : AddressEntry(address) { } | |
| 615 | |
| 616 bool result() const { return true; } | |
| 617 | |
| 618 typedef bool LookupResult; | |
| 619 }; | |
| 620 | |
| 621 // A HeapExtentCache provides a fast way of taking an arbitrary | |
| 622 // pointer-sized word, and determining whether it can be interpreted | |
| 623 // as a pointer to an area that is managed by the garbage collected | |
| 624 // Blink heap. There is a cache of 'pages' that have previously been | |
| 625 // determined to be wholly inside the heap. The size of these pages must be | |
| 626 // smaller than the allocation alignment of the heap pages. We determine | |
| 627 // on-heap-ness by rounding down the pointer to the nearest page and looking up | |
| 628 // the page in the cache. If there is a miss in the cache we can ask the heap | |
| 629 // to determine the status of the pointer by iterating over all of the heap. | |
| 630 // The result is then cached in the two-way associative page cache. | |
| 631 // | |
| 632 // A HeapContainsCache is a positive cache. Therefore, it must be flushed when | |
| 633 // memory is removed from the Blink heap. The HeapDoesNotContainCache is a | |
| 634 // negative cache, so it must be flushed when memory is added to the heap. | |
| 635 template<typename Entry> | |
| 636 class HeapExtentCache { | |
| 637 public: | |
| 638 HeapExtentCache() | |
| 639 : m_entries(adoptArrayPtr(new Entry[HeapExtentCache::numberOfEntries])) | |
| 640 , m_hasEntries(false) | |
| 641 { | |
| 642 } | |
| 643 | |
| 644 void flush(); | |
| 645 bool contains(Address); | |
| 646 bool isEmpty() { return !m_hasEntries; } | |
| 647 | |
| 648 // Perform a lookup in the cache. | |
| 649 // | |
| 650 // If lookup returns null/false the argument address was not found in | |
| 651 // the cache and it is unknown if the address is in the Blink | |
| 652 // heap. | |
| 653 // | |
| 654 // If lookup returns true/a page, the argument address was found in the | |
| 655 // cache. For the HeapContainsCache this means the address is in the heap. | |
| 656 // For the HeapDoesNotContainCache this means the address is not in the | |
| 657 // heap. | |
| 658 PLATFORM_EXPORT typename Entry::LookupResult lookup(Address); | |
| 659 | |
| 660 // Add an entry to the cache. | |
| 661 PLATFORM_EXPORT void addEntry(Address, typename Entry::LookupResult); | |
| 662 | |
| 663 private: | |
| 664 static const int numberOfEntriesLog2 = 12; | |
| 665 static const int numberOfEntries = 1 << numberOfEntriesLog2; | |
| 666 | |
| 667 static size_t hash(Address); | |
| 668 | |
| 669 WTF::OwnPtr<Entry[]> m_entries; | |
| 670 bool m_hasEntries; | |
| 671 | |
| 672 friend class ThreadState; | |
| 673 }; | |
| 674 | |
| 675 // Normally these would be typedefs instead of subclasses, but that makes them | |
| 676 // very hard to forward declare. | |
| 677 class HeapContainsCache : public HeapExtentCache<PositiveEntry> { | |
| 678 public: | |
| 679 BaseHeapPage* lookup(Address); | |
| 680 void addEntry(Address, BaseHeapPage*); | |
| 681 }; | |
| 682 | |
| 683 class HeapDoesNotContainCache : public HeapExtentCache<NegativeEntry> { }; | |
| 684 | |
| 685 template<typename DataType> | |
| 686 class PagePool { | |
| 687 protected: | |
| 688 PagePool(); | |
| 689 | |
| 690 class PoolEntry { | |
| 691 public: | |
| 692 PoolEntry(DataType* data, PoolEntry* next) | |
| 693 : data(data) | |
| 694 , next(next) | |
| 695 { } | |
| 696 | |
| 697 DataType* data; | |
| 698 PoolEntry* next; | |
| 699 }; | |
| 700 | |
| 701 PoolEntry* m_pool[NumberOfHeaps]; | |
| 702 }; | |
| 703 | |
| 704 // Once pages have been used for one type of thread heap they will never be | |
| 705 // reused for another type of thread heap. Instead of unmapping, we add the | |
| 706 // pages to a pool of pages to be reused later by a thread heap of the same | |
| 707 // type. This is done as a security feature to avoid type confusion. The | |
| 708 // heaps are type segregated by having separate thread heaps for different | |
| 709 // types of objects. Holding on to pages ensures that the same virtual address | |
| 710 // space cannot be used for objects of another type than the type contained | |
| 711 // in this page to begin with. | |
| 712 class FreePagePool : public PagePool<PageMemory> { | |
| 713 public: | |
| 714 ~FreePagePool(); | |
| 715 void addFreePage(int, PageMemory*); | |
| 716 PageMemory* takeFreePage(int); | |
| 717 | |
| 718 private: | |
| 719 Mutex m_mutex[NumberOfHeaps]; | |
| 720 }; | |
| 721 | |
| 722 class OrphanedPagePool : public PagePool<BaseHeapPage> { | |
| 723 public: | |
| 724 ~OrphanedPagePool(); | |
| 725 void addOrphanedPage(int, BaseHeapPage*); | |
| 726 void decommitOrphanedPages(); | |
| 727 #if ENABLE(ASSERT) | |
| 728 bool contains(void*); | |
| 729 #endif | |
| 730 private: | |
| 731 void clearMemory(PageMemory*); | |
| 732 }; | |
| 733 | |
| 734 // The CallbackStack contains all the visitor callbacks used to trace and mark | |
| 735 // objects. A specific CallbackStack instance contains at most bufferSize elemen
ts. | |
| 736 // If more space is needed a new CallbackStack instance is created and chained | |
| 737 // together with the former instance. I.e. a logical CallbackStack can be made o
f | |
| 738 // multiple chained CallbackStack object instances. | |
| 739 // There are two logical callback stacks. One containing all the marking callbac
ks and | |
| 740 // one containing the weak pointer callbacks. | |
| 741 class CallbackStack { | |
| 742 public: | |
| 743 CallbackStack(CallbackStack** first) | |
| 744 : m_limit(&(m_buffer[bufferSize])) | |
| 745 , m_current(&(m_buffer[0])) | |
| 746 , m_next(*first) | |
| 747 { | |
| 748 #if ENABLE(ASSERT) | |
| 749 clearUnused(); | |
| 750 #endif | |
| 751 *first = this; | |
| 752 } | |
| 753 | |
| 754 ~CallbackStack(); | |
| 755 void clearUnused(); | |
| 756 | |
| 757 bool isEmpty(); | |
| 758 | |
| 759 CallbackStack* takeCallbacks(CallbackStack** first); | |
| 760 | |
| 761 class Item { | |
| 762 public: | |
| 763 Item() { } | |
| 764 Item(void* object, VisitorCallback callback) | |
| 765 : m_object(object) | |
| 766 , m_callback(callback) | |
| 767 { | |
| 768 } | |
| 769 void* object() { return m_object; } | |
| 770 VisitorCallback callback() { return m_callback; } | |
| 771 | |
| 772 private: | |
| 773 void* m_object; | |
| 774 VisitorCallback m_callback; | |
| 775 }; | |
| 776 | |
| 777 static void init(CallbackStack** first); | |
| 778 static void shutdown(CallbackStack** first); | |
| 779 static void clear(CallbackStack** first) | |
| 780 { | |
| 781 if (!(*first)->isEmpty()) { | |
| 782 shutdown(first); | |
| 783 init(first); | |
| 784 } | |
| 785 } | |
| 786 template<CallbackInvocationMode Mode> bool popAndInvokeCallback(CallbackStac
k** first, Visitor*); | |
| 787 static void invokeCallbacks(CallbackStack** first, Visitor*); | |
| 788 | |
| 789 Item* allocateEntry(CallbackStack** first) | |
| 790 { | |
| 791 if (m_current < m_limit) | |
| 792 return m_current++; | |
| 793 return (new CallbackStack(first))->allocateEntry(first); | |
| 794 } | |
| 795 | |
| 796 #if ENABLE(ASSERT) | |
| 797 bool hasCallbackForObject(const void*); | |
| 798 #endif | |
| 799 | |
| 800 bool numberOfBlocksExceeds(int blocks) | |
| 801 { | |
| 802 CallbackStack* current = this; | |
| 803 for (int i = 0; i < blocks; ++i) { | |
| 804 if (!current->m_next) | |
| 805 return false; | |
| 806 current = current->m_next; | |
| 807 } | |
| 808 return true; | |
| 809 } | |
| 810 | |
| 811 private: | |
| 812 void invokeOldestCallbacks(Visitor*); | |
| 813 bool currentBlockIsEmpty() { return m_current == &(m_buffer[0]); } | |
| 814 | |
| 815 static const size_t bufferSize = 200; | |
| 816 Item m_buffer[bufferSize]; | |
| 817 Item* m_limit; | |
| 818 Item* m_current; | |
| 819 CallbackStack* m_next; | |
| 820 }; | |
| 821 | |
| 822 // Non-template super class used to pass a heap around to other classes. | |
| 823 class BaseHeap { | |
| 824 public: | |
| 825 virtual ~BaseHeap() { } | |
| 826 virtual void cleanupPages() = 0; | |
| 827 | |
| 828 // Find the page in this thread heap containing the given | |
| 829 // address. Returns 0 if the address is not contained in any | |
| 830 // page in this thread heap. | |
| 831 virtual BaseHeapPage* heapPageFromAddress(Address) = 0; | |
| 832 | |
| 833 #if ENABLE(GC_PROFILE_MARKING) | |
| 834 virtual const GCInfo* findGCInfoOfLargeHeapObject(Address) = 0; | |
| 835 #endif | |
| 836 | |
| 837 #if ENABLE(GC_PROFILE_HEAP) | |
| 838 virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*) = 0; | |
| 839 #endif | |
| 840 | |
| 841 // Sweep this part of the Blink heap. This finalizes dead objects | |
| 842 // and builds freelists for all the unused memory. | |
| 843 virtual void sweep(HeapStats*) = 0; | |
| 844 virtual void postSweepProcessing() = 0; | |
| 845 | |
| 846 virtual void clearFreeLists() = 0; | |
| 847 virtual void clearLiveAndMarkDead() = 0; | |
| 848 | |
| 849 virtual void makeConsistentForSweeping() = 0; | |
| 850 | |
| 851 #if ENABLE(ASSERT) | |
| 852 virtual bool isConsistentForSweeping() = 0; | |
| 853 | |
| 854 virtual void getScannedStats(HeapStats&) = 0; | |
| 855 #endif | |
| 856 | |
| 857 virtual void prepareHeapForTermination() = 0; | |
| 858 | |
| 859 virtual int normalPageCount() = 0; | |
| 860 | |
| 861 virtual BaseHeap* split(int normalPages) = 0; | |
| 862 virtual void merge(BaseHeap* other) = 0; | |
| 863 | |
| 864 // Returns a bucket number for inserting a FreeListEntry of a | |
| 865 // given size. All FreeListEntries in the given bucket, n, have | |
| 866 // size >= 2^n. | |
| 867 static int bucketIndexForSize(size_t); | |
| 868 }; | |
| 869 | |
| 870 // Thread heaps represent a part of the per-thread Blink heap. | |
| 871 // | |
| 872 // Each Blink thread has a number of thread heaps: one general heap | |
| 873 // that contains any type of object and a number of heaps specialized | |
| 874 // for specific object types (such as Node). | |
| 875 // | |
| 876 // Each thread heap contains the functionality to allocate new objects | |
| 877 // (potentially adding new pages to the heap), to find and mark | |
| 878 // objects during conservative stack scanning and to sweep the set of | |
| 879 // pages after a GC. | |
| 880 template<typename Header> | |
| 881 class ThreadHeap : public BaseHeap { | |
| 882 public: | |
| 883 ThreadHeap(ThreadState*, int); | |
| 884 virtual ~ThreadHeap(); | |
| 885 virtual void cleanupPages(); | |
| 886 | |
| 887 virtual BaseHeapPage* heapPageFromAddress(Address); | |
| 888 #if ENABLE(GC_PROFILE_MARKING) | |
| 889 virtual const GCInfo* findGCInfoOfLargeHeapObject(Address); | |
| 890 #endif | |
| 891 #if ENABLE(GC_PROFILE_HEAP) | |
| 892 virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*); | |
| 893 #endif | |
| 894 | |
| 895 virtual void sweep(HeapStats*); | |
| 896 virtual void postSweepProcessing(); | |
| 897 | |
| 898 virtual void clearFreeLists(); | |
| 899 virtual void clearLiveAndMarkDead(); | |
| 900 | |
| 901 virtual void makeConsistentForSweeping(); | |
| 902 | |
| 903 #if ENABLE(ASSERT) | |
| 904 virtual bool isConsistentForSweeping(); | |
| 905 | |
| 906 virtual void getScannedStats(HeapStats&); | |
| 907 #endif | |
| 908 | |
| 909 ThreadState* threadState() { return m_threadState; } | |
| 910 HeapStats& stats() { return m_threadState->stats(); } | |
| 911 void flushHeapContainsCache() | |
| 912 { | |
| 913 m_threadState->heapContainsCache()->flush(); | |
| 914 } | |
| 915 | |
| 916 inline Address allocate(size_t, const GCInfo*); | |
| 917 void addToFreeList(Address, size_t); | |
| 918 inline static size_t roundedAllocationSize(size_t size) | |
| 919 { | |
| 920 return allocationSizeFromSize(size) - sizeof(Header); | |
| 921 } | |
| 922 | |
| 923 virtual void prepareHeapForTermination(); | |
| 924 | |
| 925 virtual int normalPageCount() { return m_numberOfNormalPages; } | |
| 926 | |
| 927 virtual BaseHeap* split(int numberOfNormalPages); | |
| 928 virtual void merge(BaseHeap* splitOffBase); | |
| 929 | |
| 930 void removePageFromHeap(HeapPage<Header>*); | |
| 931 | |
| 932 PLATFORM_EXPORT void promptlyFreeObject(Header*); | |
| 933 | |
| 934 private: | |
| 935 void addPageToHeap(const GCInfo*); | |
| 936 PLATFORM_EXPORT Address outOfLineAllocate(size_t, const GCInfo*); | |
| 937 static size_t allocationSizeFromSize(size_t); | |
| 938 PLATFORM_EXPORT Address allocateLargeObject(size_t, const GCInfo*); | |
| 939 Address currentAllocationPoint() const { return m_currentAllocationPoint; } | |
| 940 size_t remainingAllocationSize() const { return m_remainingAllocationSize; } | |
| 941 bool ownsNonEmptyAllocationArea() const { return currentAllocationPoint() &&
remainingAllocationSize(); } | |
| 942 void setAllocationPoint(Address point, size_t size) | |
| 943 { | |
| 944 ASSERT(!point || heapPageFromAddress(point)); | |
| 945 ASSERT(size <= HeapPage<Header>::payloadSize()); | |
| 946 m_currentAllocationPoint = point; | |
| 947 m_remainingAllocationSize = size; | |
| 948 } | |
| 949 void ensureCurrentAllocation(size_t, const GCInfo*); | |
| 950 bool allocateFromFreeList(size_t); | |
| 951 | |
| 952 void freeLargeObject(LargeHeapObject<Header>*, LargeHeapObject<Header>**); | |
| 953 void allocatePage(const GCInfo*); | |
| 954 | |
| 955 #if ENABLE(ASSERT) | |
| 956 bool pagesToBeSweptContains(Address); | |
| 957 bool pagesAllocatedDuringSweepingContains(Address); | |
| 958 #endif | |
| 959 | |
| 960 void sweepNormalPages(HeapStats*); | |
| 961 void sweepLargePages(HeapStats*); | |
| 962 bool coalesce(size_t); | |
| 963 | |
| 964 Address m_currentAllocationPoint; | |
| 965 size_t m_remainingAllocationSize; | |
| 966 | |
| 967 HeapPage<Header>* m_firstPage; | |
| 968 LargeHeapObject<Header>* m_firstLargeHeapObject; | |
| 969 | |
| 970 HeapPage<Header>* m_firstPageAllocatedDuringSweeping; | |
| 971 HeapPage<Header>* m_lastPageAllocatedDuringSweeping; | |
| 972 | |
| 973 // Merge point for parallel sweep. | |
| 974 HeapPage<Header>* m_mergePoint; | |
| 975 | |
| 976 int m_biggestFreeListIndex; | |
| 977 | |
| 978 ThreadState* m_threadState; | |
| 979 | |
| 980 // All FreeListEntries in the nth list have size >= 2^n. | |
| 981 FreeListEntry* m_freeLists[blinkPageSizeLog2]; | |
| 982 FreeListEntry* m_lastFreeListEntries[blinkPageSizeLog2]; | |
| 983 | |
| 984 // Index into the page pools. This is used to ensure that the pages of the | |
| 985 // same type go into the correct page pool and thus avoid type confusion. | |
| 986 int m_index; | |
| 987 | |
| 988 int m_numberOfNormalPages; | |
| 989 | |
| 990 // The promptly freed count contains the number of promptly freed objects | |
| 991 // since the last sweep or since it was manually reset to delay coalescing. | |
| 992 size_t m_promptlyFreedCount; | |
| 993 }; | |
| 994 | |
| 995 class PLATFORM_EXPORT Heap { | |
| 996 public: | |
| 997 static BaseHeapPage* contains(Address); | |
| 998 static BaseHeapPage* contains(void* pointer) { return contains(reinterpret_c
ast<Address>(pointer)); } | |
| 999 static BaseHeapPage* contains(const void* pointer) { return contains(const_c
ast<void*>(pointer)); } | |
| 1000 #if ENABLE(ASSERT) | |
| 1001 static bool containedInHeapOrOrphanedPage(void*); | |
| 1002 #endif | |
| 1003 | |
| 1004 // Push a trace callback on the marking stack. | |
| 1005 static void pushTraceCallback(CallbackStack**, void* containerObject, TraceC
allback); | |
| 1006 | |
| 1007 // Push a trace callback on the post-marking callback stack. These callbacks | |
| 1008 // are called after normal marking (including ephemeron iteration). | |
| 1009 static void pushPostMarkingCallback(void*, TraceCallback); | |
| 1010 | |
| 1011 // Add a weak pointer callback to the weak callback work list. General | |
| 1012 // object pointer callbacks are added to a thread local weak callback work | |
| 1013 // list and the callback is called on the thread that owns the object, with | |
| 1014 // the closure pointer as an argument. Most of the time, the closure and | |
| 1015 // the containerObject can be the same thing, but the containerObject is | |
| 1016 // constrained to be on the heap, since the heap is used to identify the | |
| 1017 // correct thread. | |
| 1018 static void pushWeakObjectPointerCallback(void* closure, void* containerObje
ct, WeakPointerCallback); | |
| 1019 | |
| 1020 // Similar to the more general pushWeakObjectPointerCallback, but cell | |
| 1021 // pointer callbacks are added to a static callback work list and the weak | |
| 1022 // callback is performed on the thread performing garbage collection. This | |
| 1023 // is OK because cells are just cleared and no deallocation can happen. | |
| 1024 static void pushWeakCellPointerCallback(void** cell, WeakPointerCallback); | |
| 1025 | |
| 1026 // Pop the top of the marking stack and call the callback with the visitor | |
| 1027 // and the object. Returns false when there is nothing more to do. | |
| 1028 template<CallbackInvocationMode Mode> static bool popAndInvokeTraceCallback(
Visitor*); | |
| 1029 | |
| 1030 // Remove an item from the post-marking callback stack and call | |
| 1031 // the callback with the visitor and the object pointer. Returns | |
| 1032 // false when there is nothing more to do. | |
| 1033 static bool popAndInvokePostMarkingCallback(Visitor*); | |
| 1034 | |
| 1035 // Remove an item from the weak callback work list and call the callback | |
| 1036 // with the visitor and the closure pointer. Returns false when there is | |
| 1037 // nothing more to do. | |
| 1038 static bool popAndInvokeWeakPointerCallback(Visitor*); | |
| 1039 | |
| 1040 // Register an ephemeron table for fixed-point iteration. | |
| 1041 static void registerWeakTable(void* containerObject, EphemeronCallback, Ephe
meronCallback); | |
| 1042 #if ENABLE(ASSERT) | |
| 1043 static bool weakTableRegistered(const void*); | |
| 1044 #endif | |
| 1045 | |
| 1046 template<typename T, typename HeapTraits = HeapTypeTrait<T> > static Address
allocate(size_t); | |
| 1047 template<typename T> static Address reallocate(void* previous, size_t); | |
| 1048 | |
| 1049 static void collectGarbage(ThreadState::StackState); | |
| 1050 static void collectGarbageForTerminatingThread(ThreadState*); | |
| 1051 static void collectAllGarbage(); | |
| 1052 static void processMarkingStackEntries(int* numberOfMarkingThreads); | |
| 1053 static void processMarkingStackOnMultipleThreads(); | |
| 1054 static void processMarkingStackInParallel(); | |
| 1055 template<CallbackInvocationMode Mode> static void processMarkingStack(); | |
| 1056 static void postMarkingProcessing(); | |
| 1057 static void globalWeakProcessing(); | |
| 1058 static void setForcePreciseGCForTesting(); | |
| 1059 | |
| 1060 static void prepareForGC(); | |
| 1061 | |
| 1062 // Conservatively checks whether an address is a pointer in any of the threa
d | |
| 1063 // heaps. If so marks the object pointed to as live. | |
| 1064 static Address checkAndMarkPointer(Visitor*, Address); | |
| 1065 | |
| 1066 #if ENABLE(GC_PROFILE_MARKING) | |
| 1067 // Dump the path to specified object on the next GC. This method is to be in
voked from GDB. | |
| 1068 static void dumpPathToObjectOnNextGC(void* p); | |
| 1069 | |
| 1070 // Forcibly find GCInfo of the object at Address. | |
| 1071 // This is slow and should only be used for debug purposes. | |
| 1072 // It involves finding the heap page and scanning the heap page for an objec
t header. | |
| 1073 static const GCInfo* findGCInfo(Address); | |
| 1074 | |
| 1075 static String createBacktraceString(); | |
| 1076 #endif | |
| 1077 | |
| 1078 // Collect heap stats for all threads attached to the Blink | |
| 1079 // garbage collector. Should only be called during garbage | |
| 1080 // collection where threads are known to be at safe points. | |
| 1081 static void getStats(HeapStats*); | |
| 1082 | |
| 1083 static void getHeapSpaceSize(uint64_t*, uint64_t*); | |
| 1084 | |
| 1085 static void makeConsistentForSweeping(); | |
| 1086 | |
| 1087 #if ENABLE(ASSERT) | |
| 1088 static bool isConsistentForSweeping(); | |
| 1089 #endif | |
| 1090 | |
| 1091 static void flushHeapDoesNotContainCache(); | |
| 1092 static bool heapDoesNotContainCacheIsEmpty() { return s_heapDoesNotContainCa
che->isEmpty(); } | |
| 1093 | |
| 1094 // Return true if the last GC found a pointer into a heap page | |
| 1095 // during conservative scanning. | |
| 1096 static bool lastGCWasConservative() { return s_lastGCWasConservative; } | |
| 1097 | |
| 1098 static FreePagePool* freePagePool() { return s_freePagePool; } | |
| 1099 static OrphanedPagePool* orphanedPagePool() { return s_orphanedPagePool; } | |
| 1100 | |
| 1101 private: | |
| 1102 static Visitor* s_markingVisitor; | |
| 1103 static Vector<OwnPtr<blink::WebThread> >* s_markingThreads; | |
| 1104 static CallbackStack* s_markingStack; | |
| 1105 static CallbackStack* s_postMarkingCallbackStack; | |
| 1106 static CallbackStack* s_weakCallbackStack; | |
| 1107 static CallbackStack* s_ephemeronStack; | |
| 1108 static HeapDoesNotContainCache* s_heapDoesNotContainCache; | |
| 1109 static bool s_shutdownCalled; | |
| 1110 static bool s_lastGCWasConservative; | |
| 1111 static FreePagePool* s_freePagePool; | |
| 1112 static OrphanedPagePool* s_orphanedPagePool; | |
| 1113 friend class ThreadState; | |
| 1114 }; | |
| 1115 | |
| 1116 // The NoAllocationScope class is used in debug mode to catch unwanted | |
| 1117 // allocations. E.g. allocations during GC. | |
| 1118 template<ThreadAffinity Affinity> | |
| 1119 class NoAllocationScope { | |
| 1120 public: | |
| 1121 NoAllocationScope() : m_active(true) { enter(); } | |
| 1122 | |
| 1123 explicit NoAllocationScope(bool active) : m_active(active) { enter(); } | |
| 1124 | |
| 1125 NoAllocationScope(const NoAllocationScope& other) : m_active(other.m_active)
{ enter(); } | |
| 1126 | |
| 1127 NoAllocationScope& operator=(const NoAllocationScope& other) | |
| 1128 { | |
| 1129 release(); | |
| 1130 m_active = other.m_active; | |
| 1131 enter(); | |
| 1132 return *this; | |
| 1133 } | |
| 1134 | |
| 1135 ~NoAllocationScope() { release(); } | |
| 1136 | |
| 1137 void release() | |
| 1138 { | |
| 1139 if (m_active) { | |
| 1140 ThreadStateFor<Affinity>::state()->leaveNoAllocationScope(); | |
| 1141 m_active = false; | |
| 1142 } | |
| 1143 } | |
| 1144 | |
| 1145 private: | |
| 1146 void enter() const | |
| 1147 { | |
| 1148 if (m_active) | |
| 1149 ThreadStateFor<Affinity>::state()->enterNoAllocationScope(); | |
| 1150 } | |
| 1151 | |
| 1152 bool m_active; | |
| 1153 }; | |
| 1154 | |
| 1155 // Classes that contain heap references but aren't themselves heap | |
| 1156 // allocated, have some extra macros available which allows their use | |
| 1157 // to be restricted to cases where the garbage collector is able | |
| 1158 // to discover their heap references. | |
| 1159 // | |
| 1160 // STACK_ALLOCATED(): Use if the object is only stack allocated. Heap objects | |
| 1161 // should be in Members but you do not need the trace method as they are on | |
| 1162 // the stack. (Down the line these might turn in to raw pointers, but for | |
| 1163 // now Members indicates that we have thought about them and explicitly | |
| 1164 // taken care of them.) | |
| 1165 // | |
| 1166 // DISALLOW_ALLOCATION(): Cannot be allocated with new operators but can | |
| 1167 // be a part object. If it has Members you need a trace method and the | |
| 1168 // containing object needs to call that trace method. | |
| 1169 // | |
| 1170 // ALLOW_ONLY_INLINE_ALLOCATION(): Allows only placement new operator. | |
| 1171 // This disallows general allocation of this object but allows to put | |
| 1172 // the object as a value object in collections. If these have Members you | |
| 1173 // need to have a trace method. That trace method will be called | |
| 1174 // automatically by the Heap collections. | |
| 1175 // | |
| 1176 #define DISALLOW_ALLOCATION() \ | |
| 1177 private: \ | |
| 1178 void* operator new(size_t) = delete; \ | |
| 1179 void* operator new(size_t, NotNullTag, void*) = delete; \ | |
| 1180 void* operator new(size_t, void*) = delete; | |
| 1181 | |
| 1182 #define ALLOW_ONLY_INLINE_ALLOCATION()
\ | |
| 1183 public:
\ | |
| 1184 void* operator new(size_t, NotNullTag, void* location) { return location
; } \ | |
| 1185 void* operator new(size_t, void* location) { return location; }
\ | |
| 1186 private:
\ | |
| 1187 void* operator new(size_t) = delete; | |
| 1188 | |
| 1189 #define STATIC_ONLY(Type) \ | |
| 1190 private: \ | |
| 1191 Type() = delete; | |
| 1192 | |
| 1193 // These macros insert annotations that the Blink GC plugin for clang uses for | |
| 1194 // verification. STACK_ALLOCATED is used to declare that objects of this type | |
| 1195 // are always stack allocated. GC_PLUGIN_IGNORE is used to make the plugin | |
| 1196 // ignore a particular class or field when checking for proper usage. When using | |
| 1197 // GC_PLUGIN_IGNORE a bug-number should be provided as an argument where the | |
| 1198 // bug describes what needs to happen to remove the GC_PLUGIN_IGNORE again. | |
| 1199 #if COMPILER(CLANG) | |
| 1200 #define STACK_ALLOCATED() \ | |
| 1201 private: \ | |
| 1202 __attribute__((annotate("blink_stack_allocated"))) \ | |
| 1203 void* operator new(size_t) = delete; \ | |
| 1204 void* operator new(size_t, NotNullTag, void*) = delete; \ | |
| 1205 void* operator new(size_t, void*) = delete; | |
| 1206 | |
| 1207 #define GC_PLUGIN_IGNORE(bug) \ | |
| 1208 __attribute__((annotate("blink_gc_plugin_ignore"))) | |
| 1209 #else | |
| 1210 #define STACK_ALLOCATED() DISALLOW_ALLOCATION() | |
| 1211 #define GC_PLUGIN_IGNORE(bug) | |
| 1212 #endif | |
| 1213 | |
| 1214 NO_SANITIZE_ADDRESS | |
| 1215 void HeapObjectHeader::checkHeader() const | |
| 1216 { | |
| 1217 #if ENABLE(ASSERT) | |
| 1218 BaseHeapPage* page = pageHeaderFromObject(this); | |
| 1219 ASSERT(page->orphaned() || m_magic == magic); | |
| 1220 #endif | |
| 1221 } | |
| 1222 | |
| 1223 Address HeapObjectHeader::payload() | |
| 1224 { | |
| 1225 return reinterpret_cast<Address>(this) + objectHeaderSize; | |
| 1226 } | |
| 1227 | |
| 1228 size_t HeapObjectHeader::payloadSize() | |
| 1229 { | |
| 1230 return size() - objectHeaderSize; | |
| 1231 } | |
| 1232 | |
| 1233 Address HeapObjectHeader::payloadEnd() | |
| 1234 { | |
| 1235 return reinterpret_cast<Address>(this) + size(); | |
| 1236 } | |
| 1237 | |
| 1238 NO_SANITIZE_ADDRESS | |
| 1239 void HeapObjectHeader::mark() | |
| 1240 { | |
| 1241 checkHeader(); | |
| 1242 // The use of atomic ops guarantees that the reads and writes are | |
| 1243 // atomic and that no memory operation reorderings take place. | |
| 1244 // Multiple threads can still read the old value and all store the | |
| 1245 // new value. However, the new value will be the same for all of | |
| 1246 // the threads and the end result is therefore consistent. | |
| 1247 unsigned size = acquireLoad(&m_size); | |
| 1248 releaseStore(&m_size, size | markBitMask); | |
| 1249 } | |
| 1250 | |
| 1251 Address FinalizedHeapObjectHeader::payload() | |
| 1252 { | |
| 1253 return reinterpret_cast<Address>(this) + finalizedHeaderSize; | |
| 1254 } | |
| 1255 | |
| 1256 size_t FinalizedHeapObjectHeader::payloadSize() | |
| 1257 { | |
| 1258 return size() - finalizedHeaderSize; | |
| 1259 } | |
| 1260 | |
| 1261 template<typename Header> | |
| 1262 size_t ThreadHeap<Header>::allocationSizeFromSize(size_t size) | |
| 1263 { | |
| 1264 // Check the size before computing the actual allocation size. The | |
| 1265 // allocation size calculation can overflow for large sizes and | |
| 1266 // the check therefore has to happen before any calculation on the | |
| 1267 // size. | |
| 1268 RELEASE_ASSERT(size < maxHeapObjectSize); | |
| 1269 | |
| 1270 // Add space for header. | |
| 1271 size_t allocationSize = size + sizeof(Header); | |
| 1272 // Align size with allocation granularity. | |
| 1273 allocationSize = (allocationSize + allocationMask) & ~allocationMask; | |
| 1274 return allocationSize; | |
| 1275 } | |
| 1276 | |
| 1277 template<typename Header> | |
| 1278 Address ThreadHeap<Header>::allocate(size_t size, const GCInfo* gcInfo) | |
| 1279 { | |
| 1280 size_t allocationSize = allocationSizeFromSize(size); | |
| 1281 bool isLargeObject = allocationSize > blinkPageSize / 2; | |
| 1282 if (isLargeObject) | |
| 1283 return allocateLargeObject(allocationSize, gcInfo); | |
| 1284 if (m_remainingAllocationSize < allocationSize) | |
| 1285 return outOfLineAllocate(size, gcInfo); | |
| 1286 Address headerAddress = m_currentAllocationPoint; | |
| 1287 m_currentAllocationPoint += allocationSize; | |
| 1288 m_remainingAllocationSize -= allocationSize; | |
| 1289 Header* header = new (NotNull, headerAddress) Header(allocationSize, gcInfo)
; | |
| 1290 size_t payloadSize = allocationSize - sizeof(Header); | |
| 1291 stats().increaseObjectSpace(payloadSize); | |
| 1292 Address result = headerAddress + sizeof(*header); | |
| 1293 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | |
| 1294 // Unpoison the memory used for the object (payload). | |
| 1295 ASAN_UNPOISON_MEMORY_REGION(result, payloadSize); | |
| 1296 #if ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER) | |
| 1297 memset(result, 0, payloadSize); | |
| 1298 #endif | |
| 1299 ASSERT(heapPageFromAddress(headerAddress + allocationSize - 1)); | |
| 1300 return result; | |
| 1301 } | |
| 1302 | |
| 1303 template<typename T, typename HeapTraits> | |
| 1304 Address Heap::allocate(size_t size) | |
| 1305 { | |
| 1306 ASSERT_NOT_REACHED(); | |
| 1307 return 0; | |
| 1308 } | |
| 1309 | |
| 1310 template<typename T> | |
| 1311 Address Heap::reallocate(void* previous, size_t size) | |
| 1312 { | |
| 1313 if (!size) { | |
| 1314 // If the new size is 0 this is equivalent to either | |
| 1315 // free(previous) or malloc(0). In both cases we do | |
| 1316 // nothing and return 0. | |
| 1317 return 0; | |
| 1318 } | |
| 1319 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); | |
| 1320 ASSERT(state->isAllocationAllowed()); | |
| 1321 const GCInfo* gcInfo = GCInfoTrait<T>::get(); | |
| 1322 int heapIndex = HeapTypeTrait<T>::index(gcInfo->hasFinalizer()); | |
| 1323 // FIXME: Currently only supports raw allocation on the | |
| 1324 // GeneralHeap. Hence we assume the header is a | |
| 1325 // FinalizedHeapObjectHeader. | |
| 1326 ASSERT(heapIndex == GeneralHeap || heapIndex == GeneralHeapNonFinalized); | |
| 1327 BaseHeap* heap = state->heap(heapIndex); | |
| 1328 Address address = static_cast<typename HeapTypeTrait<T>::HeapType*>(heap)->a
llocate(size, gcInfo); | |
| 1329 if (!previous) { | |
| 1330 // This is equivalent to malloc(size). | |
| 1331 return address; | |
| 1332 } | |
| 1333 FinalizedHeapObjectHeader* previousHeader = FinalizedHeapObjectHeader::fromP
ayload(previous); | |
| 1334 ASSERT(!previousHeader->hasFinalizer()); | |
| 1335 ASSERT(previousHeader->gcInfo() == gcInfo); | |
| 1336 size_t copySize = previousHeader->payloadSize(); | |
| 1337 if (copySize > size) | |
| 1338 copySize = size; | |
| 1339 memcpy(address, previous, copySize); | |
| 1340 return address; | |
| 1341 } | |
| 1342 | |
| 1343 class HeapAllocatorQuantizer { | |
| 1344 public: | |
| 1345 template<typename T> | |
| 1346 static size_t quantizedSize(size_t count) | |
| 1347 { | |
| 1348 RELEASE_ASSERT(count <= kMaxUnquantizedAllocation / sizeof(T)); | |
| 1349 return HeapIndexTrait<CollectionBackingHeap>::HeapType::roundedAllocatio
nSize(count * sizeof(T)); | |
| 1350 } | |
| 1351 static const size_t kMaxUnquantizedAllocation = maxHeapObjectSize; | |
| 1352 }; | |
| 1353 | |
| 1354 // This is a static-only class used as a trait on collections to make them heap
allocated. | |
| 1355 // However see also HeapListHashSetAllocator. | |
| 1356 class HeapAllocator { | |
| 1357 public: | |
| 1358 typedef HeapAllocatorQuantizer Quantizer; | |
| 1359 typedef blink::Visitor Visitor; | |
| 1360 static const bool isGarbageCollected = true; | |
| 1361 | |
| 1362 template <typename Return, typename Metadata> | |
| 1363 static Return backingMalloc(size_t size) | |
| 1364 { | |
| 1365 return reinterpret_cast<Return>(Heap::allocate<Metadata, HeapIndexTrait<
CollectionBackingHeap> >(size)); | |
| 1366 } | |
| 1367 template <typename Return, typename Metadata> | |
| 1368 static Return zeroedBackingMalloc(size_t size) | |
| 1369 { | |
| 1370 return backingMalloc<Return, Metadata>(size); | |
| 1371 } | |
| 1372 template <typename Return, typename Metadata> | |
| 1373 static Return malloc(size_t size) | |
| 1374 { | |
| 1375 return reinterpret_cast<Return>(Heap::allocate<Metadata>(size)); | |
| 1376 } | |
| 1377 PLATFORM_EXPORT static void backingFree(void* address); | |
| 1378 | |
| 1379 static void free(void* address) { } | |
| 1380 template<typename T> | |
| 1381 static void* newArray(size_t bytes) | |
| 1382 { | |
| 1383 ASSERT_NOT_REACHED(); | |
| 1384 return 0; | |
| 1385 } | |
| 1386 | |
| 1387 static void deleteArray(void* ptr) | |
| 1388 { | |
| 1389 ASSERT_NOT_REACHED(); | |
| 1390 } | |
| 1391 | |
| 1392 static bool isAllocationAllowed() | |
| 1393 { | |
| 1394 ASSERT_NOT_REACHED(); | |
| 1395 return false; | |
| 1396 } | |
| 1397 | |
| 1398 static void markUsingGCInfo(Visitor* visitor, const void* buffer) | |
| 1399 { | |
| 1400 visitor->mark(buffer, FinalizedHeapObjectHeader::fromPayload(buffer)->tr
aceCallback()); | |
| 1401 } | |
| 1402 | |
| 1403 static void markNoTracing(Visitor* visitor, const void* t) { visitor->markNo
Tracing(t); } | |
| 1404 | |
| 1405 template<typename T, typename Traits> | |
| 1406 static void trace(Visitor* visitor, T& t) | |
| 1407 { | |
| 1408 } | |
| 1409 | |
| 1410 static void registerDelayedMarkNoTracing(Visitor* visitor, const void* objec
t) | |
| 1411 { | |
| 1412 visitor->registerDelayedMarkNoTracing(object); | |
| 1413 } | |
| 1414 | |
| 1415 static void registerWeakMembers(Visitor* visitor, const void* closure, const
void* object, WeakPointerCallback callback) | |
| 1416 { | |
| 1417 visitor->registerWeakMembers(closure, object, callback); | |
| 1418 } | |
| 1419 | |
| 1420 static void registerWeakTable(Visitor* visitor, const void* closure, Ephemer
onCallback iterationCallback, EphemeronCallback iterationDoneCallback) | |
| 1421 { | |
| 1422 visitor->registerWeakTable(closure, iterationCallback, iterationDoneCall
back); | |
| 1423 } | |
| 1424 | |
| 1425 #if ENABLE(ASSERT) | |
| 1426 static bool weakTableRegistered(Visitor* visitor, const void* closure) | |
| 1427 { | |
| 1428 return visitor->weakTableRegistered(closure); | |
| 1429 } | |
| 1430 #endif | |
| 1431 | |
| 1432 template<typename T> | |
| 1433 struct ResultType { | |
| 1434 typedef T* Type; | |
| 1435 }; | |
| 1436 | |
| 1437 template<typename T> | |
| 1438 struct OtherType { | |
| 1439 typedef T* Type; | |
| 1440 }; | |
| 1441 | |
| 1442 template<typename T> | |
| 1443 static T& getOther(T* other) | |
| 1444 { | |
| 1445 return *other; | |
| 1446 } | |
| 1447 | |
| 1448 static void enterNoAllocationScope() | |
| 1449 { | |
| 1450 #if ENABLE(ASSERT) | |
| 1451 ThreadStateFor<AnyThread>::state()->enterNoAllocationScope(); | |
| 1452 #endif | |
| 1453 } | |
| 1454 | |
| 1455 static void leaveNoAllocationScope() | |
| 1456 { | |
| 1457 #if ENABLE(ASSERT) | |
| 1458 ThreadStateFor<AnyThread>::state()->leaveNoAllocationScope(); | |
| 1459 #endif | |
| 1460 } | |
| 1461 | |
| 1462 private: | |
| 1463 template<typename T, size_t u, typename V> friend class WTF::Vector; | |
| 1464 template<typename T, typename U, typename V, typename W> friend class WTF::H
ashSet; | |
| 1465 template<typename T, typename U, typename V, typename W, typename X, typenam
e Y> friend class WTF::HashMap; | |
| 1466 }; | |
| 1467 | |
| 1468 template<typename Value> | |
| 1469 static void traceListHashSetValue(Visitor* visitor, Value& value) | |
| 1470 { | |
| 1471 } | |
| 1472 | |
| 1473 // The inline capacity is just a dummy template argument to match the off-heap | |
| 1474 // allocator. | |
| 1475 // This inherits from the static-only HeapAllocator trait class, but we do | |
| 1476 // declare pointers to instances. These pointers are always null, and no | |
| 1477 // objects are instantiated. | |
| 1478 template<typename ValueArg, size_t inlineCapacity> | |
| 1479 struct HeapListHashSetAllocator : public HeapAllocator { | |
| 1480 typedef HeapAllocator TableAllocator; | |
| 1481 typedef WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator> Node; | |
| 1482 | |
| 1483 public: | |
| 1484 class AllocatorProvider { | |
| 1485 public: | |
| 1486 // For the heap allocation we don't need an actual allocator object, so
we just | |
| 1487 // return null. | |
| 1488 HeapListHashSetAllocator* get() const { return 0; } | |
| 1489 | |
| 1490 // No allocator object is needed. | |
| 1491 void createAllocatorIfNeeded() { } | |
| 1492 | |
| 1493 // There is no allocator object in the HeapListHashSet (unlike in | |
| 1494 // the regular ListHashSet) so there is nothing to swap. | |
| 1495 void swap(AllocatorProvider& other) { } | |
| 1496 }; | |
| 1497 | |
| 1498 void deallocate(void* dummy) { } | |
| 1499 | |
| 1500 // This is not a static method even though it could be, because it | |
| 1501 // needs to match the one that the (off-heap) ListHashSetAllocator | |
| 1502 // has. The 'this' pointer will always be null. | |
| 1503 void* allocateNode() | |
| 1504 { | |
| 1505 COMPILE_ASSERT(!WTF::IsWeak<ValueArg>::value, WeakPointersInAListHashSet
WillJustResultInNullEntriesInTheSetThatsNotWhatYouWantConsiderUsingLinkedHashSet
Instead); | |
| 1506 return malloc<void*, Node>(sizeof(Node)); | |
| 1507 } | |
| 1508 | |
| 1509 static void traceValue(Visitor* visitor, Node* node) | |
| 1510 { | |
| 1511 traceListHashSetValue(visitor, node->m_value); | |
| 1512 } | |
| 1513 }; | |
| 1514 | |
| 1515 // CollectionBackingTraceTrait. Do nothing for things in collections that don't | |
| 1516 // need tracing, or call TraceInCollectionTrait for those that do. | |
| 1517 | |
| 1518 // Specialization for things that don't need marking and have no weak pointers.
We | |
| 1519 // do nothing, even if WTF::WeakPointersActStrong. | |
| 1520 template<WTF::ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename
Traits> | |
| 1521 struct CollectionBackingTraceTrait<false, WTF::NoWeakHandlingInCollections, stro
ngify, T, Traits> { | |
| 1522 static bool trace(Visitor*, T&) { return false; } | |
| 1523 }; | |
| 1524 | |
| 1525 // Specialization for things that either need marking or have weak pointers or | |
| 1526 // both. | |
| 1527 template<bool needsTracing, WTF::WeakHandlingFlag weakHandlingFlag, WTF::ShouldW
eakPointersBeMarkedStrongly strongify, typename T, typename Traits> | |
| 1528 struct CollectionBackingTraceTrait { | |
| 1529 static bool trace(Visitor* visitor, T&t) | |
| 1530 { | |
| 1531 return false; | |
| 1532 } | |
| 1533 }; | |
| 1534 | |
| 1535 template<typename T> struct WeakHandlingHashTraits : WTF::SimpleClassHashTraits<
T> { | |
| 1536 // We want to treat the object as a weak object in the sense that it can | |
| 1537 // disappear from hash sets and hash maps. | |
| 1538 static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCol
lections; | |
| 1539 // Normally whether or not an object needs tracing is inferred | |
| 1540 // automatically from the presence of the trace method, but we don't | |
| 1541 // necessarily have a trace method, and we may not need one because T | |
| 1542 // can perhaps only be allocated inside collections, never as indpendent | |
| 1543 // objects. Explicitly mark this as needing tracing and it will be traced | |
| 1544 // in collections using the traceInCollection method, which it must have. | |
| 1545 template<typename U = void> struct NeedsTracingLazily { | |
| 1546 static const bool value = true; | |
| 1547 }; | |
| 1548 // The traceInCollection method traces differently depending on whether we | |
| 1549 // are strongifying the trace operation. We strongify the trace operation | |
| 1550 // when there are active iterators on the object. In this case all | |
| 1551 // WeakMembers are marked like strong members so that elements do not | |
| 1552 // suddenly disappear during iteration. Returns true if weak pointers to | |
| 1553 // dead objects were found: In this case any strong pointers were not yet | |
| 1554 // traced and the entry should be removed from the collection. | |
| 1555 static bool traceInCollection(Visitor* visitor, T& t, WTF::ShouldWeakPointer
sBeMarkedStrongly strongify) | |
| 1556 { | |
| 1557 return t.traceInCollection(visitor, strongify); | |
| 1558 } | |
| 1559 }; | |
| 1560 | |
| 1561 template<typename T, typename Traits> | |
| 1562 struct TraceTrait<HeapVectorBacking<T, Traits> > { | |
| 1563 typedef HeapVectorBacking<T, Traits> Backing; | |
| 1564 static void trace(Visitor* visitor, void* self) | |
| 1565 { | |
| 1566 } | |
| 1567 static void mark(Visitor* visitor, const Backing* backing) | |
| 1568 { | |
| 1569 } | |
| 1570 }; | |
| 1571 | |
| 1572 template<typename T> | |
| 1573 struct IfWeakMember; | |
| 1574 | |
| 1575 template<typename T> | |
| 1576 struct IfWeakMember { | |
| 1577 template<typename U> | |
| 1578 static bool isDead(Visitor*, const U&) { return false; } | |
| 1579 }; | |
| 1580 | |
| 1581 template<typename T> | |
| 1582 struct IfWeakMember<WeakMember<T> > { | |
| 1583 static bool isDead(Visitor* visitor, const WeakMember<T>& t) { return !visit
or->isAlive(t.get()); } | |
| 1584 }; | |
| 1585 | |
| 1586 } | |
| 1587 | |
| 1588 #endif // Heap_h | |
| OLD | NEW |