Home | History | Annotate | Download | only in heap
      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 #include "config.h"
     32 #include "platform/heap/Heap.h"
     33 
     34 #include "platform/TraceEvent.h"
     35 #include "platform/heap/ThreadState.h"
     36 #include "public/platform/Platform.h"
     37 #include "wtf/Assertions.h"
     38 #include "wtf/LeakAnnotations.h"
     39 #include "wtf/PassOwnPtr.h"
     40 #if ENABLE(GC_TRACING)
     41 #include "wtf/HashMap.h"
     42 #include "wtf/HashSet.h"
     43 #include "wtf/text/StringBuilder.h"
     44 #include "wtf/text/StringHash.h"
     45 #include <stdio.h>
     46 #include <utility>
     47 #endif
     48 
     49 #if OS(POSIX)
     50 #include <sys/mman.h>
     51 #include <unistd.h>
     52 #elif OS(WIN)
     53 #include <windows.h>
     54 #endif
     55 
     56 namespace WebCore {
     57 
     58 #if ENABLE(GC_TRACING)
     59 static String classOf(const void* object)
     60 {
     61     const GCInfo* gcInfo = Heap::findGCInfo(reinterpret_cast<Address>(const_cast<void*>(object)));
     62     if (gcInfo)
     63         return gcInfo->m_className;
     64 
     65     return "unknown";
     66 }
     67 #endif
     68 
     69 static bool vTableInitialized(void* objectPointer)
     70 {
     71     return !!(*reinterpret_cast<Address*>(objectPointer));
     72 }
     73 
     74 #if OS(WIN)
     75 static bool IsPowerOf2(size_t power)
     76 {
     77     return !((power - 1) & power);
     78 }
     79 #endif
     80 
     81 static Address roundToBlinkPageBoundary(void* base)
     82 {
     83     return reinterpret_cast<Address>((reinterpret_cast<uintptr_t>(base) + blinkPageOffsetMask) & blinkPageBaseMask);
     84 }
     85 
     86 static size_t roundToOsPageSize(size_t size)
     87 {
     88     return (size + osPageSize() - 1) & ~(osPageSize() - 1);
     89 }
     90 
     91 size_t osPageSize()
     92 {
     93 #if OS(POSIX)
     94     static const size_t pageSize = getpagesize();
     95 #else
     96     static size_t pageSize = 0;
     97     if (!pageSize) {
     98         SYSTEM_INFO info;
     99         GetSystemInfo(&info);
    100         pageSize = info.dwPageSize;
    101         ASSERT(IsPowerOf2(pageSize));
    102     }
    103 #endif
    104     return pageSize;
    105 }
    106 
    107 class MemoryRegion {
    108 public:
    109     MemoryRegion(Address base, size_t size)
    110         : m_base(base)
    111         , m_size(size)
    112     {
    113         ASSERT(size > 0);
    114     }
    115 
    116     bool contains(Address addr) const
    117     {
    118         return m_base <= addr && addr < (m_base + m_size);
    119     }
    120 
    121 
    122     bool contains(const MemoryRegion& other) const
    123     {
    124         return contains(other.m_base) && contains(other.m_base + other.m_size - 1);
    125     }
    126 
    127     void release()
    128     {
    129 #if OS(POSIX)
    130         int err = munmap(m_base, m_size);
    131         RELEASE_ASSERT(!err);
    132 #else
    133         bool success = VirtualFree(m_base, 0, MEM_RELEASE);
    134         RELEASE_ASSERT(success);
    135 #endif
    136     }
    137 
    138     WARN_UNUSED_RETURN bool commit()
    139     {
    140         ASSERT(Heap::heapDoesNotContainCacheIsEmpty());
    141 #if OS(POSIX)
    142         int err = mprotect(m_base, m_size, PROT_READ | PROT_WRITE);
    143         if (!err) {
    144             madvise(m_base, m_size, MADV_NORMAL);
    145             return true;
    146         }
    147         return false;
    148 #else
    149         void* result = VirtualAlloc(m_base, m_size, MEM_COMMIT, PAGE_READWRITE);
    150         return !!result;
    151 #endif
    152     }
    153 
    154     void decommit()
    155     {
    156 #if OS(POSIX)
    157         int err = mprotect(m_base, m_size, PROT_NONE);
    158         RELEASE_ASSERT(!err);
    159         // FIXME: Consider using MADV_FREE on MacOS.
    160         madvise(m_base, m_size, MADV_DONTNEED);
    161 #else
    162         bool success = VirtualFree(m_base, m_size, MEM_DECOMMIT);
    163         RELEASE_ASSERT(success);
    164 #endif
    165     }
    166 
    167     Address base() const { return m_base; }
    168     size_t size() const { return m_size; }
    169 
    170 private:
    171     Address m_base;
    172     size_t m_size;
    173 };
    174 
    175 // Representation of the memory used for a Blink heap page.
    176 //
    177 // The representation keeps track of two memory regions:
    178 //
    179 // 1. The virtual memory reserved from the sytem in order to be able
    180 //    to free all the virtual memory reserved on destruction.
    181 //
    182 // 2. The writable memory (a sub-region of the reserved virtual
    183 //    memory region) that is used for the actual heap page payload.
    184 //
    185 // Guard pages are created before and after the writable memory.
    186 class PageMemory {
    187 public:
    188     ~PageMemory()
    189     {
    190         __lsan_unregister_root_region(m_writable.base(), m_writable.size());
    191         m_reserved.release();
    192     }
    193 
    194     bool commit() WARN_UNUSED_RETURN { return m_writable.commit(); }
    195     void decommit() { m_writable.decommit(); }
    196 
    197     Address writableStart() { return m_writable.base(); }
    198 
    199     // Allocate a virtual address space for the blink page with the
    200     // following layout:
    201     //
    202     //    [ guard os page | ... payload ... | guard os page ]
    203     //    ^---{ aligned to blink page size }
    204     //
    205     static PageMemory* allocate(size_t payloadSize)
    206     {
    207         ASSERT(payloadSize > 0);
    208 
    209         // Virtual memory allocation routines operate in OS page sizes.
    210         // Round up the requested size to nearest os page size.
    211         payloadSize = roundToOsPageSize(payloadSize);
    212 
    213         // Overallocate by blinkPageSize and 2 times OS page size to
    214         // ensure a chunk of memory which is blinkPageSize aligned and
    215         // has a system page before and after to use for guarding. We
    216         // unmap the excess memory before returning.
    217         size_t allocationSize = payloadSize + 2 * osPageSize() + blinkPageSize;
    218 
    219         ASSERT(Heap::heapDoesNotContainCacheIsEmpty());
    220 #if OS(POSIX)
    221         Address base = static_cast<Address>(mmap(0, allocationSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0));
    222         RELEASE_ASSERT(base != MAP_FAILED);
    223 
    224         Address end = base + allocationSize;
    225         Address alignedBase = roundToBlinkPageBoundary(base);
    226         Address payloadBase = alignedBase + osPageSize();
    227         Address payloadEnd = payloadBase + payloadSize;
    228         Address blinkPageEnd = payloadEnd + osPageSize();
    229 
    230         // If the allocate memory was not blink page aligned release
    231         // the memory before the aligned address.
    232         if (alignedBase != base)
    233             MemoryRegion(base, alignedBase - base).release();
    234 
    235         // Create guard pages by decommiting an OS page before and
    236         // after the payload.
    237         MemoryRegion(alignedBase, osPageSize()).decommit();
    238         MemoryRegion(payloadEnd, osPageSize()).decommit();
    239 
    240         // Free the additional memory at the end of the page if any.
    241         if (blinkPageEnd < end)
    242             MemoryRegion(blinkPageEnd, end - blinkPageEnd).release();
    243 
    244         return new PageMemory(MemoryRegion(alignedBase, blinkPageEnd - alignedBase), MemoryRegion(payloadBase, payloadSize));
    245 #else
    246         Address base = 0;
    247         Address alignedBase = 0;
    248 
    249         // On Windows it is impossible to partially release a region
    250         // of memory allocated by VirtualAlloc. To avoid wasting
    251         // virtual address space we attempt to release a large region
    252         // of memory returned as a whole and then allocate an aligned
    253         // region inside this larger region.
    254         for (int attempt = 0; attempt < 3; attempt++) {
    255             base = static_cast<Address>(VirtualAlloc(0, allocationSize, MEM_RESERVE, PAGE_NOACCESS));
    256             RELEASE_ASSERT(base);
    257             VirtualFree(base, 0, MEM_RELEASE);
    258 
    259             alignedBase = roundToBlinkPageBoundary(base);
    260             base = static_cast<Address>(VirtualAlloc(alignedBase, payloadSize + 2 * osPageSize(), MEM_RESERVE, PAGE_NOACCESS));
    261             if (base) {
    262                 RELEASE_ASSERT(base == alignedBase);
    263                 allocationSize = payloadSize + 2 * osPageSize();
    264                 break;
    265             }
    266         }
    267 
    268         if (!base) {
    269             // We failed to avoid wasting virtual address space after
    270             // several attempts.
    271             base = static_cast<Address>(VirtualAlloc(0, allocationSize, MEM_RESERVE, PAGE_NOACCESS));
    272             RELEASE_ASSERT(base);
    273 
    274             // FIXME: If base is by accident blink page size aligned
    275             // here then we can create two pages out of reserved
    276             // space. Do this.
    277             alignedBase = roundToBlinkPageBoundary(base);
    278         }
    279 
    280         Address payloadBase = alignedBase + osPageSize();
    281         PageMemory* storage = new PageMemory(MemoryRegion(base, allocationSize), MemoryRegion(payloadBase, payloadSize));
    282         bool res = storage->commit();
    283         RELEASE_ASSERT(res);
    284         return storage;
    285 #endif
    286     }
    287 
    288 private:
    289     PageMemory(const MemoryRegion& reserved, const MemoryRegion& writable)
    290         : m_reserved(reserved)
    291         , m_writable(writable)
    292     {
    293         ASSERT(reserved.contains(writable));
    294 
    295         // Register the writable area of the memory as part of the LSan root set.
    296         // Only the writable area is mapped and can contain C++ objects. Those
    297         // C++ objects can contain pointers to objects outside of the heap and
    298         // should therefore be part of the LSan root set.
    299         __lsan_register_root_region(m_writable.base(), m_writable.size());
    300     }
    301 
    302     MemoryRegion m_reserved;
    303     MemoryRegion m_writable;
    304 };
    305 
    306 class GCScope {
    307 public:
    308     explicit GCScope(ThreadState::StackState stackState)
    309         : m_state(ThreadState::current())
    310         , m_safePointScope(stackState)
    311         , m_parkedAllThreads(false)
    312     {
    313         TRACE_EVENT0("Blink", "Heap::GCScope");
    314         const char* samplingState = TRACE_EVENT_GET_SAMPLING_STATE();
    315         if (m_state->isMainThread())
    316             TRACE_EVENT_SET_SAMPLING_STATE("Blink", "BlinkGCWaiting");
    317 
    318         m_state->checkThread();
    319 
    320         // FIXME: in an unlikely coincidence that two threads decide
    321         // to collect garbage at the same time, avoid doing two GCs in
    322         // a row.
    323         RELEASE_ASSERT(!m_state->isInGC());
    324         RELEASE_ASSERT(!m_state->isSweepInProgress());
    325         if (LIKELY(ThreadState::stopThreads())) {
    326             m_parkedAllThreads = true;
    327             m_state->enterGC();
    328         }
    329         if (m_state->isMainThread())
    330             TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(samplingState);
    331     }
    332 
    333     bool allThreadsParked() { return m_parkedAllThreads; }
    334 
    335     ~GCScope()
    336     {
    337         // Only cleanup if we parked all threads in which case the GC happened
    338         // and we need to resume the other threads.
    339         if (LIKELY(m_parkedAllThreads)) {
    340             m_state->leaveGC();
    341             ASSERT(!m_state->isInGC());
    342             ThreadState::resumeThreads();
    343         }
    344     }
    345 
    346 private:
    347     ThreadState* m_state;
    348     ThreadState::SafePointScope m_safePointScope;
    349     bool m_parkedAllThreads; // False if we fail to park all threads
    350 };
    351 
    352 NO_SANITIZE_ADDRESS
    353 bool HeapObjectHeader::isMarked() const
    354 {
    355     checkHeader();
    356     return m_size & markBitMask;
    357 }
    358 
    359 NO_SANITIZE_ADDRESS
    360 void HeapObjectHeader::unmark()
    361 {
    362     checkHeader();
    363     m_size &= ~markBitMask;
    364 }
    365 
    366 NO_SANITIZE_ADDRESS
    367 bool HeapObjectHeader::hasDebugMark() const
    368 {
    369     checkHeader();
    370     return m_size & debugBitMask;
    371 }
    372 
    373 NO_SANITIZE_ADDRESS
    374 void HeapObjectHeader::clearDebugMark()
    375 {
    376     checkHeader();
    377     m_size &= ~debugBitMask;
    378 }
    379 
    380 NO_SANITIZE_ADDRESS
    381 void HeapObjectHeader::setDebugMark()
    382 {
    383     checkHeader();
    384     m_size |= debugBitMask;
    385 }
    386 
    387 #ifndef NDEBUG
    388 NO_SANITIZE_ADDRESS
    389 void HeapObjectHeader::zapMagic()
    390 {
    391     m_magic = zappedMagic;
    392 }
    393 #endif
    394 
    395 HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload)
    396 {
    397     Address addr = reinterpret_cast<Address>(const_cast<void*>(payload));
    398     HeapObjectHeader* header =
    399         reinterpret_cast<HeapObjectHeader*>(addr - objectHeaderSize);
    400     return header;
    401 }
    402 
    403 void HeapObjectHeader::finalize(const GCInfo* gcInfo, Address object, size_t objectSize)
    404 {
    405     ASSERT(gcInfo);
    406     if (gcInfo->hasFinalizer()) {
    407         gcInfo->m_finalize(object);
    408     }
    409 #if !defined(NDEBUG) || defined(LEAK_SANITIZER)
    410     // Zap freed memory with a recognizable zap value in debug mode.
    411     // Also zap when using leak sanitizer because the heap is used as
    412     // a root region for lsan and therefore pointers in unreachable
    413     // memory could hide leaks.
    414     for (size_t i = 0; i < objectSize; i++)
    415         object[i] = finalizedZapValue;
    416 #endif
    417     // Zap the primary vTable entry (secondary vTable entries are not zapped)
    418     *(reinterpret_cast<uintptr_t*>(object)) = zappedVTable;
    419 }
    420 
    421 NO_SANITIZE_ADDRESS
    422 void FinalizedHeapObjectHeader::finalize()
    423 {
    424     HeapObjectHeader::finalize(m_gcInfo, payload(), payloadSize());
    425 }
    426 
    427 template<typename Header>
    428 void LargeHeapObject<Header>::unmark()
    429 {
    430     return heapObjectHeader()->unmark();
    431 }
    432 
    433 template<typename Header>
    434 bool LargeHeapObject<Header>::isMarked()
    435 {
    436     return heapObjectHeader()->isMarked();
    437 }
    438 
    439 template<typename Header>
    440 void LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address address)
    441 {
    442     ASSERT(contains(address));
    443     if (!objectContains(address))
    444         return;
    445 #if ENABLE(GC_TRACING)
    446     visitor->setHostInfo(&address, "stack");
    447 #endif
    448     mark(visitor);
    449 }
    450 
    451 template<>
    452 void LargeHeapObject<FinalizedHeapObjectHeader>::mark(Visitor* visitor)
    453 {
    454     if (heapObjectHeader()->hasVTable() && !vTableInitialized(payload()))
    455         visitor->markConservatively(heapObjectHeader());
    456     else
    457         visitor->mark(heapObjectHeader(), heapObjectHeader()->traceCallback());
    458 }
    459 
    460 template<>
    461 void LargeHeapObject<HeapObjectHeader>::mark(Visitor* visitor)
    462 {
    463     ASSERT(gcInfo());
    464     if (gcInfo()->hasVTable() && !vTableInitialized(payload()))
    465         visitor->markConservatively(heapObjectHeader());
    466     else
    467         visitor->mark(heapObjectHeader(), gcInfo()->m_trace);
    468 }
    469 
    470 template<>
    471 void LargeHeapObject<FinalizedHeapObjectHeader>::finalize()
    472 {
    473     heapObjectHeader()->finalize();
    474 }
    475 
    476 template<>
    477 void LargeHeapObject<HeapObjectHeader>::finalize()
    478 {
    479     ASSERT(gcInfo());
    480     HeapObjectHeader::finalize(gcInfo(), payload(), payloadSize());
    481 }
    482 
    483 FinalizedHeapObjectHeader* FinalizedHeapObjectHeader::fromPayload(const void* payload)
    484 {
    485     Address addr = reinterpret_cast<Address>(const_cast<void*>(payload));
    486     FinalizedHeapObjectHeader* header =
    487         reinterpret_cast<FinalizedHeapObjectHeader*>(addr - finalizedHeaderSize);
    488     return header;
    489 }
    490 
    491 template<typename Header>
    492 ThreadHeap<Header>::ThreadHeap(ThreadState* state)
    493     : m_currentAllocationPoint(0)
    494     , m_remainingAllocationSize(0)
    495     , m_firstPage(0)
    496     , m_firstLargeHeapObject(0)
    497     , m_biggestFreeListIndex(0)
    498     , m_threadState(state)
    499     , m_pagePool(0)
    500 {
    501     clearFreeLists();
    502 }
    503 
    504 template<typename Header>
    505 ThreadHeap<Header>::~ThreadHeap()
    506 {
    507     clearFreeLists();
    508     if (!ThreadState::current()->isMainThread())
    509         assertEmpty();
    510     deletePages();
    511 }
    512 
    513 template<typename Header>
    514 Address ThreadHeap<Header>::outOfLineAllocate(size_t size, const GCInfo* gcInfo)
    515 {
    516     size_t allocationSize = allocationSizeFromSize(size);
    517     if (threadState()->shouldGC()) {
    518         if (threadState()->shouldForceConservativeGC())
    519             Heap::collectGarbage(ThreadState::HeapPointersOnStack);
    520         else
    521             threadState()->setGCRequested();
    522     }
    523     ensureCurrentAllocation(allocationSize, gcInfo);
    524     return allocate(size, gcInfo);
    525 }
    526 
    527 template<typename Header>
    528 bool ThreadHeap<Header>::allocateFromFreeList(size_t minSize)
    529 {
    530     size_t bucketSize = 1 << m_biggestFreeListIndex;
    531     int i = m_biggestFreeListIndex;
    532     for (; i > 0; i--, bucketSize >>= 1) {
    533         if (bucketSize < minSize)
    534             break;
    535         FreeListEntry* entry = m_freeLists[i];
    536         if (entry) {
    537             m_biggestFreeListIndex = i;
    538             entry->unlink(&m_freeLists[i]);
    539             setAllocationPoint(entry->address(), entry->size());
    540             ASSERT(currentAllocationPoint() && remainingAllocationSize() >= minSize);
    541             return true;
    542         }
    543     }
    544     m_biggestFreeListIndex = i;
    545     return false;
    546 }
    547 
    548 template<typename Header>
    549 void ThreadHeap<Header>::ensureCurrentAllocation(size_t minSize, const GCInfo* gcInfo)
    550 {
    551     ASSERT(minSize >= allocationGranularity);
    552     if (remainingAllocationSize() >= minSize)
    553         return;
    554 
    555     if (remainingAllocationSize() > 0)
    556         addToFreeList(currentAllocationPoint(), remainingAllocationSize());
    557     if (allocateFromFreeList(minSize))
    558         return;
    559     addPageToHeap(gcInfo);
    560     bool success = allocateFromFreeList(minSize);
    561     RELEASE_ASSERT(success);
    562 }
    563 
    564 template<typename Header>
    565 BaseHeapPage* ThreadHeap<Header>::heapPageFromAddress(Address address)
    566 {
    567     for (HeapPage<Header>* page = m_firstPage; page; page = page->next()) {
    568         if (page->contains(address))
    569             return page;
    570     }
    571     for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) {
    572         // Check that large pages are blinkPageSize aligned (modulo the
    573         // osPageSize for the guard page).
    574         ASSERT(reinterpret_cast<Address>(current) - osPageSize() == roundToBlinkPageStart(reinterpret_cast<Address>(current)));
    575         if (current->contains(address))
    576             return current;
    577     }
    578     return 0;
    579 }
    580 
    581 #if ENABLE(GC_TRACING)
    582 template<typename Header>
    583 const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address)
    584 {
    585     for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) {
    586         if (current->contains(address))
    587             return current->gcInfo();
    588     }
    589     return 0;
    590 }
    591 #endif
    592 
    593 template<typename Header>
    594 void ThreadHeap<Header>::addToFreeList(Address address, size_t size)
    595 {
    596     ASSERT(heapPageFromAddress(address));
    597     ASSERT(heapPageFromAddress(address + size - 1));
    598     ASSERT(size < blinkPagePayloadSize());
    599     // The free list entries are only pointer aligned (but when we allocate
    600     // from them we are 8 byte aligned due to the header size).
    601     ASSERT(!((reinterpret_cast<uintptr_t>(address) + sizeof(Header)) & allocationMask));
    602     ASSERT(!(size & allocationMask));
    603     ASAN_POISON_MEMORY_REGION(address, size);
    604     FreeListEntry* entry;
    605     if (size < sizeof(*entry)) {
    606         // Create a dummy header with only a size and freelist bit set.
    607         ASSERT(size >= sizeof(BasicObjectHeader));
    608         // Free list encode the size to mark the lost memory as freelist memory.
    609         new (NotNull, address) BasicObjectHeader(BasicObjectHeader::freeListEncodedSize(size));
    610         // This memory gets lost. Sweeping can reclaim it.
    611         return;
    612     }
    613     entry = new (NotNull, address) FreeListEntry(size);
    614 #if defined(ADDRESS_SANITIZER)
    615     // For ASAN we don't add the entry to the free lists until the asanDeferMemoryReuseCount
    616     // reaches zero. However we always add entire pages to ensure that adding a new page will
    617     // increase the allocation space.
    618     if (HeapPage<Header>::payloadSize() != size && !entry->shouldAddToFreeList())
    619         return;
    620 #endif
    621     int index = bucketIndexForSize(size);
    622     entry->link(&m_freeLists[index]);
    623     if (index > m_biggestFreeListIndex)
    624         m_biggestFreeListIndex = index;
    625 }
    626 
    627 template<typename Header>
    628 Address ThreadHeap<Header>::allocateLargeObject(size_t size, const GCInfo* gcInfo)
    629 {
    630     // Caller already added space for object header and rounded up to allocation alignment
    631     ASSERT(!(size & allocationMask));
    632 
    633     size_t allocationSize = sizeof(LargeHeapObject<Header>) + size;
    634 
    635     // Ensure that there is enough space for alignment. If the header
    636     // is not a multiple of 8 bytes we will allocate an extra
    637     // headerPadding<Header> bytes to ensure it 8 byte aligned.
    638     allocationSize += headerPadding<Header>();
    639 
    640     // If ASAN is supported we add allocationGranularity bytes to the allocated space and
    641     // poison that to detect overflows
    642 #if defined(ADDRESS_SANITIZER)
    643     allocationSize += allocationGranularity;
    644 #endif
    645     if (threadState()->shouldGC())
    646         threadState()->setGCRequested();
    647     Heap::flushHeapDoesNotContainCache();
    648     PageMemory* pageMemory = PageMemory::allocate(allocationSize);
    649     Address largeObjectAddress = pageMemory->writableStart();
    650     Address headerAddress = largeObjectAddress + sizeof(LargeHeapObject<Header>) + headerPadding<Header>();
    651     memset(headerAddress, 0, size);
    652     Header* header = new (NotNull, headerAddress) Header(size, gcInfo);
    653     Address result = headerAddress + sizeof(*header);
    654     ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask));
    655     LargeHeapObject<Header>* largeObject = new (largeObjectAddress) LargeHeapObject<Header>(pageMemory, gcInfo, threadState());
    656 
    657     // Poison the object header and allocationGranularity bytes after the object
    658     ASAN_POISON_MEMORY_REGION(header, sizeof(*header));
    659     ASAN_POISON_MEMORY_REGION(largeObject->address() + largeObject->size(), allocationGranularity);
    660     largeObject->link(&m_firstLargeHeapObject);
    661     stats().increaseAllocatedSpace(largeObject->size());
    662     stats().increaseObjectSpace(largeObject->payloadSize());
    663     return result;
    664 }
    665 
    666 template<typename Header>
    667 void ThreadHeap<Header>::freeLargeObject(LargeHeapObject<Header>* object, LargeHeapObject<Header>** previousNext)
    668 {
    669     flushHeapContainsCache();
    670     object->unlink(previousNext);
    671     object->finalize();
    672 
    673     // Unpoison the object header and allocationGranularity bytes after the
    674     // object before freeing.
    675     ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(Header));
    676     ASAN_UNPOISON_MEMORY_REGION(object->address() + object->size(), allocationGranularity);
    677     delete object->storage();
    678 }
    679 
    680 template<>
    681 void ThreadHeap<FinalizedHeapObjectHeader>::addPageToHeap(const GCInfo* gcInfo)
    682 {
    683     // When adding a page to the ThreadHeap using FinalizedHeapObjectHeaders the GCInfo on
    684     // the heap should be unused (ie. 0).
    685     allocatePage(0);
    686 }
    687 
    688 template<>
    689 void ThreadHeap<HeapObjectHeader>::addPageToHeap(const GCInfo* gcInfo)
    690 {
    691     // When adding a page to the ThreadHeap using HeapObjectHeaders store the GCInfo on the heap
    692     // since it is the same for all objects
    693     ASSERT(gcInfo);
    694     allocatePage(gcInfo);
    695 }
    696 
    697 template<typename Header>
    698 void ThreadHeap<Header>::clearPagePool()
    699 {
    700     while (takePageFromPool()) { }
    701 }
    702 
    703 template<typename Header>
    704 PageMemory* ThreadHeap<Header>::takePageFromPool()
    705 {
    706     Heap::flushHeapDoesNotContainCache();
    707     while (PagePoolEntry* entry = m_pagePool) {
    708         m_pagePool = entry->next();
    709         PageMemory* storage = entry->storage();
    710         delete entry;
    711 
    712         if (storage->commit())
    713             return storage;
    714 
    715         // Failed to commit pooled storage. Release it.
    716         delete storage;
    717     }
    718 
    719     return 0;
    720 }
    721 
    722 template<typename Header>
    723 void ThreadHeap<Header>::addPageToPool(HeapPage<Header>* unused)
    724 {
    725     flushHeapContainsCache();
    726     PageMemory* storage = unused->storage();
    727     PagePoolEntry* entry = new PagePoolEntry(storage, m_pagePool);
    728     m_pagePool = entry;
    729     storage->decommit();
    730 }
    731 
    732 template<typename Header>
    733 void ThreadHeap<Header>::allocatePage(const GCInfo* gcInfo)
    734 {
    735     Heap::flushHeapDoesNotContainCache();
    736     PageMemory* pageMemory = takePageFromPool();
    737     if (!pageMemory) {
    738         pageMemory = PageMemory::allocate(blinkPagePayloadSize());
    739         RELEASE_ASSERT(pageMemory);
    740     }
    741     HeapPage<Header>* page = new (pageMemory->writableStart()) HeapPage<Header>(pageMemory, this, gcInfo);
    742     // FIXME: Oilpan: Linking new pages into the front of the list is
    743     // crucial when performing allocations during finalization because
    744     // it ensures that those pages are not swept in the current GC
    745     // round. We should create a separate page list for that to
    746     // separate out the pages allocated during finalization clearly
    747     // from the pages currently being swept.
    748     page->link(&m_firstPage);
    749     addToFreeList(page->payload(), HeapPage<Header>::payloadSize());
    750 }
    751 
    752 #ifndef NDEBUG
    753 template<typename Header>
    754 void ThreadHeap<Header>::getScannedStats(HeapStats& scannedStats)
    755 {
    756     for (HeapPage<Header>* page = m_firstPage; page; page = page->next())
    757         page->getStats(scannedStats);
    758     for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next())
    759         current->getStats(scannedStats);
    760 }
    761 #endif
    762 
    763 // STRICT_ASAN_FINALIZATION_CHECKING turns on poisoning of all objects during
    764 // sweeping to catch cases where dead objects touch eachother. This is not
    765 // turned on by default because it also triggers for cases that are safe.
    766 // Examples of such safe cases are context life cycle observers and timers
    767 // embedded in garbage collected objects.
    768 #define STRICT_ASAN_FINALIZATION_CHECKING 0
    769 
    770 template<typename Header>
    771 void ThreadHeap<Header>::sweep()
    772 {
    773     ASSERT(isConsistentForGC());
    774 #if defined(ADDRESS_SANITIZER) && STRICT_ASAN_FINALIZATION_CHECKING
    775     // When using ASAN do a pre-sweep where all unmarked objects are poisoned before
    776     // calling their finalizer methods. This can catch the cases where one objects
    777     // finalizer tries to modify another object as part of finalization.
    778     for (HeapPage<Header>* page = m_firstPage; page; page = page->next())
    779         page->poisonUnmarkedObjects();
    780 #endif
    781     HeapPage<Header>* page = m_firstPage;
    782     HeapPage<Header>** previous = &m_firstPage;
    783     bool pagesRemoved = false;
    784     while (page) {
    785         if (page->isEmpty()) {
    786             flushHeapContainsCache();
    787             HeapPage<Header>* unused = page;
    788             page = page->next();
    789             HeapPage<Header>::unlink(unused, previous);
    790             pagesRemoved = true;
    791         } else {
    792             page->sweep();
    793             previous = &page->m_next;
    794             page = page->next();
    795         }
    796     }
    797     if (pagesRemoved)
    798         flushHeapContainsCache();
    799 
    800     LargeHeapObject<Header>** previousNext = &m_firstLargeHeapObject;
    801     for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current;) {
    802         if (current->isMarked()) {
    803             stats().increaseAllocatedSpace(current->size());
    804             stats().increaseObjectSpace(current->payloadSize());
    805             current->unmark();
    806             previousNext = &current->m_next;
    807             current = current->next();
    808         } else {
    809             LargeHeapObject<Header>* next = current->next();
    810             freeLargeObject(current, previousNext);
    811             current = next;
    812         }
    813     }
    814 }
    815 
    816 template<typename Header>
    817 void ThreadHeap<Header>::assertEmpty()
    818 {
    819     // No allocations are permitted. The thread is exiting.
    820     NoAllocationScope<AnyThread> noAllocation;
    821     makeConsistentForGC();
    822     for (HeapPage<Header>* page = m_firstPage; page; page = page->next()) {
    823         Address end = page->end();
    824         Address headerAddress;
    825         for (headerAddress = page->payload(); headerAddress < end; ) {
    826             BasicObjectHeader* basicHeader = reinterpret_cast<BasicObjectHeader*>(headerAddress);
    827             ASSERT(basicHeader->size() < blinkPagePayloadSize());
    828             // A live object is potentially a dangling pointer from
    829             // some root. Treat that as a bug. Unfortunately, it is
    830             // hard to reliably check in the presence of conservative
    831             // stack scanning. Something could be conservatively kept
    832             // alive because a non-pointer on another thread's stack
    833             // is treated as a pointer into the heap.
    834             //
    835             // FIXME: This assert can currently trigger in cases where
    836             // worker shutdown does not get enough precise GCs to get
    837             // all objects removed from the worker heap. There are two
    838             // issues: 1) conservative GCs keeping objects alive, and
    839             // 2) long chains of RefPtrs/Persistents that require more
    840             // GCs to get everything cleaned up. Maybe we can keep
    841             // threads alive until their heaps become empty instead of
    842             // forcing the threads to die immediately?
    843             ASSERT(Heap::lastGCWasConservative() || basicHeader->isFree());
    844             if (basicHeader->isFree())
    845                 addToFreeList(headerAddress, basicHeader->size());
    846             headerAddress += basicHeader->size();
    847         }
    848         ASSERT(headerAddress == end);
    849     }
    850 
    851     ASSERT(Heap::lastGCWasConservative() || !m_firstLargeHeapObject);
    852 }
    853 
    854 template<typename Header>
    855 bool ThreadHeap<Header>::isConsistentForGC()
    856 {
    857     for (size_t i = 0; i < blinkPageSizeLog2; i++) {
    858         if (m_freeLists[i])
    859             return false;
    860     }
    861     return !ownsNonEmptyAllocationArea();
    862 }
    863 
    864 template<typename Header>
    865 void ThreadHeap<Header>::makeConsistentForGC()
    866 {
    867     if (ownsNonEmptyAllocationArea())
    868         addToFreeList(currentAllocationPoint(), remainingAllocationSize());
    869     setAllocationPoint(0, 0);
    870     clearFreeLists();
    871 }
    872 
    873 template<typename Header>
    874 void ThreadHeap<Header>::clearMarks()
    875 {
    876     ASSERT(isConsistentForGC());
    877     for (HeapPage<Header>* page = m_firstPage; page; page = page->next())
    878         page->clearMarks();
    879     for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next())
    880         current->unmark();
    881 }
    882 
    883 template<typename Header>
    884 void ThreadHeap<Header>::deletePages()
    885 {
    886     flushHeapContainsCache();
    887     // Add all pages in the pool to the heap's list of pages before deleting
    888     clearPagePool();
    889 
    890     for (HeapPage<Header>* page = m_firstPage; page; ) {
    891         HeapPage<Header>* dead = page;
    892         page = page->next();
    893         PageMemory* storage = dead->storage();
    894         dead->~HeapPage();
    895         delete storage;
    896     }
    897     m_firstPage = 0;
    898 
    899     for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current;) {
    900         LargeHeapObject<Header>* dead = current;
    901         current = current->next();
    902         PageMemory* storage = dead->storage();
    903         dead->~LargeHeapObject();
    904         delete storage;
    905     }
    906     m_firstLargeHeapObject = 0;
    907 }
    908 
    909 template<typename Header>
    910 void ThreadHeap<Header>::clearFreeLists()
    911 {
    912     for (size_t i = 0; i < blinkPageSizeLog2; i++)
    913         m_freeLists[i] = 0;
    914 }
    915 
    916 int BaseHeap::bucketIndexForSize(size_t size)
    917 {
    918     ASSERT(size > 0);
    919     int index = -1;
    920     while (size) {
    921         size >>= 1;
    922         index++;
    923     }
    924     return index;
    925 }
    926 
    927 template<typename Header>
    928 HeapPage<Header>::HeapPage(PageMemory* storage, ThreadHeap<Header>* heap, const GCInfo* gcInfo)
    929     : BaseHeapPage(storage, gcInfo, heap->threadState())
    930     , m_next(0)
    931     , m_heap(heap)
    932 {
    933     COMPILE_ASSERT(!(sizeof(HeapPage<Header>) & allocationMask), page_header_incorrectly_aligned);
    934     m_objectStartBitMapComputed = false;
    935     ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this)));
    936     heap->stats().increaseAllocatedSpace(blinkPageSize);
    937 }
    938 
    939 template<typename Header>
    940 void HeapPage<Header>::link(HeapPage** prevNext)
    941 {
    942     m_next = *prevNext;
    943     *prevNext = this;
    944 }
    945 
    946 template<typename Header>
    947 void HeapPage<Header>::unlink(HeapPage* unused, HeapPage** prevNext)
    948 {
    949     *prevNext = unused->m_next;
    950     unused->heap()->addPageToPool(unused);
    951 }
    952 
    953 template<typename Header>
    954 void HeapPage<Header>::getStats(HeapStats& stats)
    955 {
    956     stats.increaseAllocatedSpace(blinkPageSize);
    957     Address headerAddress = payload();
    958     ASSERT(headerAddress != end());
    959     do {
    960         Header* header = reinterpret_cast<Header*>(headerAddress);
    961         if (!header->isFree())
    962             stats.increaseObjectSpace(header->payloadSize());
    963         ASSERT(header->size() < blinkPagePayloadSize());
    964         headerAddress += header->size();
    965         ASSERT(headerAddress <= end());
    966     } while (headerAddress < end());
    967 }
    968 
    969 template<typename Header>
    970 bool HeapPage<Header>::isEmpty()
    971 {
    972     BasicObjectHeader* header = reinterpret_cast<BasicObjectHeader*>(payload());
    973     return header->isFree() && (header->size() == payloadSize());
    974 }
    975 
    976 template<typename Header>
    977 void HeapPage<Header>::sweep()
    978 {
    979     clearObjectStartBitMap();
    980     heap()->stats().increaseAllocatedSpace(blinkPageSize);
    981     Address startOfGap = payload();
    982     for (Address headerAddress = startOfGap; headerAddress < end(); ) {
    983         BasicObjectHeader* basicHeader = reinterpret_cast<BasicObjectHeader*>(headerAddress);
    984         ASSERT(basicHeader->size() < blinkPagePayloadSize());
    985 
    986         if (basicHeader->isFree()) {
    987             headerAddress += basicHeader->size();
    988             continue;
    989         }
    990         // At this point we know this is a valid object of type Header
    991         Header* header = static_cast<Header*>(basicHeader);
    992 
    993         if (!header->isMarked()) {
    994             // For ASAN we unpoison the specific object when calling the finalizer and
    995             // poison it again when done to allow the object's own finalizer to operate
    996             // on the object, but not have other finalizers be allowed to access it.
    997             ASAN_UNPOISON_MEMORY_REGION(header->payload(), header->payloadSize());
    998             finalize(header);
    999             ASAN_POISON_MEMORY_REGION(header->payload(), header->payloadSize());
   1000             headerAddress += header->size();
   1001             continue;
   1002         }
   1003 
   1004         if (startOfGap != headerAddress)
   1005             heap()->addToFreeList(startOfGap, headerAddress - startOfGap);
   1006         header->unmark();
   1007         headerAddress += header->size();
   1008         heap()->stats().increaseObjectSpace(header->payloadSize());
   1009         startOfGap = headerAddress;
   1010     }
   1011     if (startOfGap != end())
   1012         heap()->addToFreeList(startOfGap, end() - startOfGap);
   1013 }
   1014 
   1015 template<typename Header>
   1016 void HeapPage<Header>::clearMarks()
   1017 {
   1018     for (Address headerAddress = payload(); headerAddress < end();) {
   1019         Header* header = reinterpret_cast<Header*>(headerAddress);
   1020         ASSERT(header->size() < blinkPagePayloadSize());
   1021         if (!header->isFree())
   1022             header->unmark();
   1023         headerAddress += header->size();
   1024     }
   1025 }
   1026 
   1027 template<typename Header>
   1028 void HeapPage<Header>::populateObjectStartBitMap()
   1029 {
   1030     memset(&m_objectStartBitMap, 0, objectStartBitMapSize);
   1031     Address start = payload();
   1032     for (Address headerAddress = start; headerAddress < end();) {
   1033         Header* header = reinterpret_cast<Header*>(headerAddress);
   1034         size_t objectOffset = headerAddress - start;
   1035         ASSERT(!(objectOffset & allocationMask));
   1036         size_t objectStartNumber = objectOffset / allocationGranularity;
   1037         size_t mapIndex = objectStartNumber / 8;
   1038         ASSERT(mapIndex < objectStartBitMapSize);
   1039         m_objectStartBitMap[mapIndex] |= (1 << (objectStartNumber & 7));
   1040         headerAddress += header->size();
   1041         ASSERT(headerAddress <= end());
   1042     }
   1043     m_objectStartBitMapComputed = true;
   1044 }
   1045 
   1046 template<typename Header>
   1047 void HeapPage<Header>::clearObjectStartBitMap()
   1048 {
   1049     m_objectStartBitMapComputed = false;
   1050 }
   1051 
   1052 static int numberOfLeadingZeroes(uint8_t byte)
   1053 {
   1054     if (!byte)
   1055         return 8;
   1056     int result = 0;
   1057     if (byte <= 0x0F) {
   1058         result += 4;
   1059         byte = byte << 4;
   1060     }
   1061     if (byte <= 0x3F) {
   1062         result += 2;
   1063         byte = byte << 2;
   1064     }
   1065     if (byte <= 0x7F)
   1066         result++;
   1067     return result;
   1068 }
   1069 
   1070 template<typename Header>
   1071 Header* HeapPage<Header>::findHeaderFromAddress(Address address)
   1072 {
   1073     if (address < payload())
   1074         return 0;
   1075     if (!isObjectStartBitMapComputed())
   1076         populateObjectStartBitMap();
   1077     size_t objectOffset = address - payload();
   1078     size_t objectStartNumber = objectOffset / allocationGranularity;
   1079     size_t mapIndex = objectStartNumber / 8;
   1080     ASSERT(mapIndex < objectStartBitMapSize);
   1081     size_t bit = objectStartNumber & 7;
   1082     uint8_t byte = m_objectStartBitMap[mapIndex] & ((1 << (bit + 1)) - 1);
   1083     while (!byte) {
   1084         ASSERT(mapIndex > 0);
   1085         byte = m_objectStartBitMap[--mapIndex];
   1086     }
   1087     int leadingZeroes = numberOfLeadingZeroes(byte);
   1088     objectStartNumber = (mapIndex * 8) + 7 - leadingZeroes;
   1089     objectOffset = objectStartNumber * allocationGranularity;
   1090     Address objectAddress = objectOffset + payload();
   1091     Header* header = reinterpret_cast<Header*>(objectAddress);
   1092     if (header->isFree())
   1093         return 0;
   1094     return header;
   1095 }
   1096 
   1097 template<typename Header>
   1098 void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address)
   1099 {
   1100     ASSERT(contains(address));
   1101     Header* header = findHeaderFromAddress(address);
   1102     if (!header)
   1103         return;
   1104 
   1105 #if ENABLE(GC_TRACING)
   1106     visitor->setHostInfo(&address, "stack");
   1107 #endif
   1108     if (hasVTable(header) && !vTableInitialized(header->payload()))
   1109         visitor->markConservatively(header);
   1110     else
   1111         visitor->mark(header, traceCallback(header));
   1112 }
   1113 
   1114 #if ENABLE(GC_TRACING)
   1115 template<typename Header>
   1116 const GCInfo* HeapPage<Header>::findGCInfo(Address address)
   1117 {
   1118     if (address < payload())
   1119         return 0;
   1120 
   1121     if (gcInfo()) // for non FinalizedObjectHeader
   1122         return gcInfo();
   1123 
   1124     Header* header = findHeaderFromAddress(address);
   1125     if (!header)
   1126         return 0;
   1127 
   1128     return header->gcInfo();
   1129 }
   1130 #endif
   1131 
   1132 #if defined(ADDRESS_SANITIZER)
   1133 template<typename Header>
   1134 void HeapPage<Header>::poisonUnmarkedObjects()
   1135 {
   1136     for (Address headerAddress = payload(); headerAddress < end(); ) {
   1137         Header* header = reinterpret_cast<Header*>(headerAddress);
   1138         ASSERT(header->size() < blinkPagePayloadSize());
   1139 
   1140         if (!header->isFree() && !header->isMarked())
   1141             ASAN_POISON_MEMORY_REGION(header->payload(), header->payloadSize());
   1142         headerAddress += header->size();
   1143     }
   1144 }
   1145 #endif
   1146 
   1147 template<>
   1148 inline void HeapPage<FinalizedHeapObjectHeader>::finalize(FinalizedHeapObjectHeader* header)
   1149 {
   1150     header->finalize();
   1151 }
   1152 
   1153 template<>
   1154 inline void HeapPage<HeapObjectHeader>::finalize(HeapObjectHeader* header)
   1155 {
   1156     ASSERT(gcInfo());
   1157     HeapObjectHeader::finalize(gcInfo(), header->payload(), header->payloadSize());
   1158 }
   1159 
   1160 template<>
   1161 inline TraceCallback HeapPage<HeapObjectHeader>::traceCallback(HeapObjectHeader* header)
   1162 {
   1163     ASSERT(gcInfo());
   1164     return gcInfo()->m_trace;
   1165 }
   1166 
   1167 template<>
   1168 inline TraceCallback HeapPage<FinalizedHeapObjectHeader>::traceCallback(FinalizedHeapObjectHeader* header)
   1169 {
   1170     return header->traceCallback();
   1171 }
   1172 
   1173 template<>
   1174 inline bool HeapPage<HeapObjectHeader>::hasVTable(HeapObjectHeader* header)
   1175 {
   1176     ASSERT(gcInfo());
   1177     return gcInfo()->hasVTable();
   1178 }
   1179 
   1180 template<>
   1181 inline bool HeapPage<FinalizedHeapObjectHeader>::hasVTable(FinalizedHeapObjectHeader* header)
   1182 {
   1183     return header->hasVTable();
   1184 }
   1185 
   1186 template<typename Header>
   1187 void LargeHeapObject<Header>::getStats(HeapStats& stats)
   1188 {
   1189     stats.increaseAllocatedSpace(size());
   1190     stats.increaseObjectSpace(payloadSize());
   1191 }
   1192 
   1193 template<typename Entry>
   1194 void HeapExtentCache<Entry>::flush()
   1195 {
   1196     if (m_hasEntries) {
   1197         for (int i = 0; i < numberOfEntries; i++)
   1198             m_entries[i] = Entry();
   1199         m_hasEntries = false;
   1200     }
   1201 }
   1202 
   1203 template<typename Entry>
   1204 size_t HeapExtentCache<Entry>::hash(Address address)
   1205 {
   1206     size_t value = (reinterpret_cast<size_t>(address) >> blinkPageSizeLog2);
   1207     value ^= value >> numberOfEntriesLog2;
   1208     value ^= value >> (numberOfEntriesLog2 * 2);
   1209     value &= numberOfEntries - 1;
   1210     return value & ~1; // Returns only even number.
   1211 }
   1212 
   1213 template<typename Entry>
   1214 typename Entry::LookupResult HeapExtentCache<Entry>::lookup(Address address)
   1215 {
   1216     size_t index = hash(address);
   1217     ASSERT(!(index & 1));
   1218     Address cachePage = roundToBlinkPageStart(address);
   1219     if (m_entries[index].address() == cachePage)
   1220         return m_entries[index].result();
   1221     if (m_entries[index + 1].address() == cachePage)
   1222         return m_entries[index + 1].result();
   1223     return 0;
   1224 }
   1225 
   1226 template<typename Entry>
   1227 void HeapExtentCache<Entry>::addEntry(Address address, typename Entry::LookupResult entry)
   1228 {
   1229     m_hasEntries = true;
   1230     size_t index = hash(address);
   1231     ASSERT(!(index & 1));
   1232     Address cachePage = roundToBlinkPageStart(address);
   1233     m_entries[index + 1] = m_entries[index];
   1234     m_entries[index] = Entry(cachePage, entry);
   1235 }
   1236 
   1237 // These should not be needed, but it seems impossible to persuade clang to
   1238 // instantiate the template functions and export them from a shared library, so
   1239 // we add these in the non-templated subclass, which does not have that issue.
   1240 void HeapContainsCache::addEntry(Address address, BaseHeapPage* page)
   1241 {
   1242     HeapExtentCache<PositiveEntry>::addEntry(address, page);
   1243 }
   1244 
   1245 BaseHeapPage* HeapContainsCache::lookup(Address address)
   1246 {
   1247     return HeapExtentCache<PositiveEntry>::lookup(address);
   1248 }
   1249 
   1250 void Heap::flushHeapDoesNotContainCache()
   1251 {
   1252     s_heapDoesNotContainCache->flush();
   1253 }
   1254 
   1255 void CallbackStack::init(CallbackStack** first)
   1256 {
   1257     // The stacks are chained, so we start by setting this to null as terminator.
   1258     *first = 0;
   1259     *first = new CallbackStack(first);
   1260 }
   1261 
   1262 void CallbackStack::shutdown(CallbackStack** first)
   1263 {
   1264     CallbackStack* next;
   1265     for (CallbackStack* current = *first; current; current = next) {
   1266         next = current->m_next;
   1267         delete current;
   1268     }
   1269     *first = 0;
   1270 }
   1271 
   1272 CallbackStack::~CallbackStack()
   1273 {
   1274 #ifndef NDEBUG
   1275     clearUnused();
   1276 #endif
   1277 }
   1278 
   1279 void CallbackStack::clearUnused()
   1280 {
   1281     ASSERT(m_current == &(m_buffer[0]));
   1282     for (size_t i = 0; i < bufferSize; i++)
   1283         m_buffer[i] = Item(0, 0);
   1284 }
   1285 
   1286 void CallbackStack::assertIsEmpty()
   1287 {
   1288     ASSERT(m_current == &(m_buffer[0]));
   1289     ASSERT(!m_next);
   1290 }
   1291 
   1292 bool CallbackStack::popAndInvokeCallback(CallbackStack** first, Visitor* visitor)
   1293 {
   1294     if (m_current == &(m_buffer[0])) {
   1295         if (!m_next) {
   1296 #ifndef NDEBUG
   1297             clearUnused();
   1298 #endif
   1299             return false;
   1300         }
   1301         CallbackStack* nextStack = m_next;
   1302         *first = nextStack;
   1303         delete this;
   1304         return nextStack->popAndInvokeCallback(first, visitor);
   1305     }
   1306     Item* item = --m_current;
   1307 
   1308     VisitorCallback callback = item->callback();
   1309 #if ENABLE(GC_TRACING)
   1310     if (ThreadState::isAnyThreadInGC()) // weak-processing will also use popAndInvokeCallback
   1311         visitor->setHostInfo(item->object(), classOf(item->object()));
   1312 #endif
   1313     callback(visitor, item->object());
   1314 
   1315     return true;
   1316 }
   1317 
   1318 class MarkingVisitor : public Visitor {
   1319 public:
   1320 #if ENABLE(GC_TRACING)
   1321     typedef HashSet<uintptr_t> LiveObjectSet;
   1322     typedef HashMap<String, LiveObjectSet> LiveObjectMap;
   1323     typedef HashMap<uintptr_t, std::pair<uintptr_t, String> > ObjectGraph;
   1324 #endif
   1325 
   1326     inline void visitHeader(HeapObjectHeader* header, const void* objectPointer, TraceCallback callback)
   1327     {
   1328         ASSERT(header);
   1329         ASSERT(objectPointer);
   1330         if (header->isMarked())
   1331             return;
   1332         header->mark();
   1333 #if ENABLE(GC_TRACING)
   1334         MutexLocker locker(objectGraphMutex());
   1335         String className(classOf(objectPointer));
   1336         {
   1337             LiveObjectMap::AddResult result = currentlyLive().add(className, LiveObjectSet());
   1338             result.storedValue->value.add(reinterpret_cast<uintptr_t>(objectPointer));
   1339         }
   1340         ObjectGraph::AddResult result = objectGraph().add(reinterpret_cast<uintptr_t>(objectPointer), std::make_pair(reinterpret_cast<uintptr_t>(m_hostObject), m_hostName));
   1341         ASSERT(result.isNewEntry);
   1342         // fprintf(stderr, "%s[%p] -> %s[%p]\n", m_hostName.ascii().data(), m_hostObject, className.ascii().data(), objectPointer);
   1343 #endif
   1344         if (callback)
   1345             Heap::pushTraceCallback(const_cast<void*>(objectPointer), callback);
   1346     }
   1347 
   1348     virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE
   1349     {
   1350         // We need both the HeapObjectHeader and FinalizedHeapObjectHeader
   1351         // version to correctly find the payload.
   1352         visitHeader(header, header->payload(), callback);
   1353     }
   1354 
   1355     virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE
   1356     {
   1357         // We need both the HeapObjectHeader and FinalizedHeapObjectHeader
   1358         // version to correctly find the payload.
   1359         visitHeader(header, header->payload(), callback);
   1360     }
   1361 
   1362     virtual void mark(const void* objectPointer, TraceCallback callback) OVERRIDE
   1363     {
   1364         if (!objectPointer)
   1365             return;
   1366         FinalizedHeapObjectHeader* header = FinalizedHeapObjectHeader::fromPayload(objectPointer);
   1367         visitHeader(header, header->payload(), callback);
   1368     }
   1369 
   1370 
   1371     inline void visitConservatively(HeapObjectHeader* header, void* objectPointer, size_t objectSize)
   1372     {
   1373         ASSERT(header);
   1374         ASSERT(objectPointer);
   1375         if (header->isMarked())
   1376             return;
   1377         header->mark();
   1378 
   1379         // Scan through the object's fields and visit them conservatively.
   1380         Address* objectFields = reinterpret_cast<Address*>(objectPointer);
   1381         for (size_t i = 0; i < objectSize / sizeof(Address); ++i)
   1382             Heap::checkAndMarkPointer(this, objectFields[i]);
   1383     }
   1384 
   1385     virtual void markConservatively(HeapObjectHeader* header)
   1386     {
   1387         // We need both the HeapObjectHeader and FinalizedHeapObjectHeader
   1388         // version to correctly find the payload.
   1389         visitConservatively(header, header->payload(), header->payloadSize());
   1390     }
   1391 
   1392     virtual void markConservatively(FinalizedHeapObjectHeader* header)
   1393     {
   1394         // We need both the HeapObjectHeader and FinalizedHeapObjectHeader
   1395         // version to correctly find the payload.
   1396         visitConservatively(header, header->payload(), header->payloadSize());
   1397     }
   1398 
   1399     virtual void registerWeakMembers(const void* closure, const void* containingObject, WeakPointerCallback callback) OVERRIDE
   1400     {
   1401         Heap::pushWeakObjectPointerCallback(const_cast<void*>(closure), const_cast<void*>(containingObject), callback);
   1402     }
   1403 
   1404     virtual bool isMarked(const void* objectPointer) OVERRIDE
   1405     {
   1406         return FinalizedHeapObjectHeader::fromPayload(objectPointer)->isMarked();
   1407     }
   1408 
   1409     // This macro defines the necessary visitor methods for typed heaps
   1410 #define DEFINE_VISITOR_METHODS(Type)                                              \
   1411     virtual void mark(const Type* objectPointer, TraceCallback callback) OVERRIDE \
   1412     {                                                                             \
   1413         if (!objectPointer)                                                       \
   1414             return;                                                               \
   1415         HeapObjectHeader* header =                                                \
   1416             HeapObjectHeader::fromPayload(objectPointer);                         \
   1417         visitHeader(header, header->payload(), callback);                         \
   1418     }                                                                             \
   1419     virtual bool isMarked(const Type* objectPointer) OVERRIDE                     \
   1420     {                                                                             \
   1421         return HeapObjectHeader::fromPayload(objectPointer)->isMarked();          \
   1422     }
   1423 
   1424     FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
   1425 #undef DEFINE_VISITOR_METHODS
   1426 
   1427 #if ENABLE(GC_TRACING)
   1428     void reportStats()
   1429     {
   1430         fprintf(stderr, "\n---------- AFTER MARKING -------------------\n");
   1431         for (LiveObjectMap::iterator it = currentlyLive().begin(), end = currentlyLive().end(); it != end; ++it) {
   1432             fprintf(stderr, "%s %u", it->key.ascii().data(), it->value.size());
   1433 
   1434             if (it->key == "WebCore::Document")
   1435                 reportStillAlive(it->value, previouslyLive().get(it->key));
   1436 
   1437             fprintf(stderr, "\n");
   1438         }
   1439 
   1440         previouslyLive().swap(currentlyLive());
   1441         currentlyLive().clear();
   1442 
   1443         for (HashSet<uintptr_t>::iterator it = objectsToFindPath().begin(), end = objectsToFindPath().end(); it != end; ++it) {
   1444             dumpPathToObjectFromObjectGraph(objectGraph(), *it);
   1445         }
   1446     }
   1447 
   1448     static void reportStillAlive(LiveObjectSet current, LiveObjectSet previous)
   1449     {
   1450         int count = 0;
   1451 
   1452         fprintf(stderr, " [previously %u]", previous.size());
   1453         for (LiveObjectSet::iterator it = current.begin(), end = current.end(); it != end; ++it) {
   1454             if (previous.find(*it) == previous.end())
   1455                 continue;
   1456             count++;
   1457         }
   1458 
   1459         if (!count)
   1460             return;
   1461 
   1462         fprintf(stderr, " {survived 2GCs %d: ", count);
   1463         for (LiveObjectSet::iterator it = current.begin(), end = current.end(); it != end; ++it) {
   1464             if (previous.find(*it) == previous.end())
   1465                 continue;
   1466             fprintf(stderr, "%ld", *it);
   1467             if (--count)
   1468                 fprintf(stderr, ", ");
   1469         }
   1470         ASSERT(!count);
   1471         fprintf(stderr, "}");
   1472     }
   1473 
   1474     static void dumpPathToObjectFromObjectGraph(const ObjectGraph& graph, uintptr_t target)
   1475     {
   1476         ObjectGraph::const_iterator it = graph.find(target);
   1477         if (it == graph.end())
   1478             return;
   1479         fprintf(stderr, "Path to %lx of %s\n", target, classOf(reinterpret_cast<const void*>(target)).ascii().data());
   1480         while (it != graph.end()) {
   1481             fprintf(stderr, "<- %lx of %s\n", it->value.first, it->value.second.utf8().data());
   1482             it = graph.find(it->value.first);
   1483         }
   1484         fprintf(stderr, "\n");
   1485     }
   1486 
   1487     static void dumpPathToObjectOnNextGC(void* p)
   1488     {
   1489         objectsToFindPath().add(reinterpret_cast<uintptr_t>(p));
   1490     }
   1491 
   1492     static Mutex& objectGraphMutex()
   1493     {
   1494         AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
   1495         return mutex;
   1496     }
   1497 
   1498     static LiveObjectMap& previouslyLive()
   1499     {
   1500         DEFINE_STATIC_LOCAL(LiveObjectMap, map, ());
   1501         return map;
   1502     }
   1503 
   1504     static LiveObjectMap& currentlyLive()
   1505     {
   1506         DEFINE_STATIC_LOCAL(LiveObjectMap, map, ());
   1507         return map;
   1508     }
   1509 
   1510     static ObjectGraph& objectGraph()
   1511     {
   1512         DEFINE_STATIC_LOCAL(ObjectGraph, graph, ());
   1513         return graph;
   1514     }
   1515 
   1516     static HashSet<uintptr_t>& objectsToFindPath()
   1517     {
   1518         DEFINE_STATIC_LOCAL(HashSet<uintptr_t>, set, ());
   1519         return set;
   1520     }
   1521 #endif
   1522 
   1523 protected:
   1524     virtual void registerWeakCell(void** cell, WeakPointerCallback callback) OVERRIDE
   1525     {
   1526         Heap::pushWeakCellPointerCallback(cell, callback);
   1527     }
   1528 };
   1529 
   1530 void Heap::init()
   1531 {
   1532     ThreadState::init();
   1533     CallbackStack::init(&s_markingStack);
   1534     CallbackStack::init(&s_weakCallbackStack);
   1535     s_heapDoesNotContainCache = new HeapDoesNotContainCache();
   1536     s_markingVisitor = new MarkingVisitor();
   1537 }
   1538 
   1539 void Heap::shutdown()
   1540 {
   1541     s_shutdownCalled = true;
   1542     ThreadState::shutdownHeapIfNecessary();
   1543 }
   1544 
   1545 void Heap::doShutdown()
   1546 {
   1547     // We don't want to call doShutdown() twice.
   1548     if (!s_markingVisitor)
   1549         return;
   1550 
   1551     ASSERT(!ThreadState::isAnyThreadInGC());
   1552     ASSERT(!ThreadState::attachedThreads().size());
   1553     delete s_markingVisitor;
   1554     s_markingVisitor = 0;
   1555     delete s_heapDoesNotContainCache;
   1556     s_heapDoesNotContainCache = 0;
   1557     CallbackStack::shutdown(&s_weakCallbackStack);
   1558     CallbackStack::shutdown(&s_markingStack);
   1559     ThreadState::shutdown();
   1560 }
   1561 
   1562 BaseHeapPage* Heap::contains(Address address)
   1563 {
   1564     ASSERT(ThreadState::isAnyThreadInGC());
   1565     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1566     for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
   1567         BaseHeapPage* page = (*it)->contains(address);
   1568         if (page)
   1569             return page;
   1570     }
   1571     return 0;
   1572 }
   1573 
   1574 Address Heap::checkAndMarkPointer(Visitor* visitor, Address address)
   1575 {
   1576     ASSERT(ThreadState::isAnyThreadInGC());
   1577 
   1578 #ifdef NDEBUG
   1579     if (s_heapDoesNotContainCache->lookup(address))
   1580         return 0;
   1581 #endif
   1582 
   1583     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1584     for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
   1585         if ((*it)->checkAndMarkPointer(visitor, address)) {
   1586             // Pointer was in a page of that thread. If it actually pointed
   1587             // into an object then that object was found and marked.
   1588             ASSERT(!s_heapDoesNotContainCache->lookup(address));
   1589             s_lastGCWasConservative = true;
   1590             return address;
   1591         }
   1592     }
   1593 
   1594 #ifdef NDEBUG
   1595     s_heapDoesNotContainCache->addEntry(address, true);
   1596 #else
   1597     if (!s_heapDoesNotContainCache->lookup(address))
   1598         s_heapDoesNotContainCache->addEntry(address, true);
   1599 #endif
   1600     return 0;
   1601 }
   1602 
   1603 #if ENABLE(GC_TRACING)
   1604 const GCInfo* Heap::findGCInfo(Address address)
   1605 {
   1606     return ThreadState::findGCInfoFromAllThreads(address);
   1607 }
   1608 
   1609 void Heap::dumpPathToObjectOnNextGC(void* p)
   1610 {
   1611     static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p);
   1612 }
   1613 
   1614 String Heap::createBacktraceString()
   1615 {
   1616     int framesToShow = 3;
   1617     int stackFrameSize = 16;
   1618     ASSERT(stackFrameSize >= framesToShow);
   1619     typedef void* FramePointer;
   1620     FramePointer* stackFrame = static_cast<FramePointer*>(alloca(sizeof(FramePointer) * stackFrameSize));
   1621     WTFGetBacktrace(stackFrame, &stackFrameSize);
   1622 
   1623     StringBuilder builder;
   1624     builder.append("Persistent");
   1625     bool didAppendFirstName = false;
   1626     // Skip frames before/including "WebCore::Persistent".
   1627     bool didSeePersistent = false;
   1628     for (int i = 0; i < stackFrameSize && framesToShow > 0; ++i) {
   1629         FrameToNameScope frameToName(stackFrame[i]);
   1630         if (!frameToName.nullableName())
   1631             continue;
   1632         if (strstr(frameToName.nullableName(), "WebCore::Persistent")) {
   1633             didSeePersistent = true;
   1634             continue;
   1635         }
   1636         if (!didSeePersistent)
   1637             continue;
   1638         if (!didAppendFirstName) {
   1639             didAppendFirstName = true;
   1640             builder.append(" ... Backtrace:");
   1641         }
   1642         builder.append("\n\t");
   1643         builder.append(frameToName.nullableName());
   1644         --framesToShow;
   1645     }
   1646     return builder.toString().replace("WebCore::", "");
   1647 }
   1648 #endif
   1649 
   1650 void Heap::pushTraceCallback(void* object, TraceCallback callback)
   1651 {
   1652     ASSERT(Heap::contains(object));
   1653     CallbackStack::Item* slot = s_markingStack->allocateEntry(&s_markingStack);
   1654     *slot = CallbackStack::Item(object, callback);
   1655 }
   1656 
   1657 bool Heap::popAndInvokeTraceCallback(Visitor* visitor)
   1658 {
   1659     return s_markingStack->popAndInvokeCallback(&s_markingStack, visitor);
   1660 }
   1661 
   1662 void Heap::pushWeakCellPointerCallback(void** cell, WeakPointerCallback callback)
   1663 {
   1664     ASSERT(Heap::contains(cell));
   1665     CallbackStack::Item* slot = s_weakCallbackStack->allocateEntry(&s_weakCallbackStack);
   1666     *slot = CallbackStack::Item(cell, callback);
   1667 }
   1668 
   1669 void Heap::pushWeakObjectPointerCallback(void* closure, void* object, WeakPointerCallback callback)
   1670 {
   1671     ASSERT(Heap::contains(object));
   1672     BaseHeapPage* heapPageForObject = reinterpret_cast<BaseHeapPage*>(pageHeaderAddress(reinterpret_cast<Address>(object)));
   1673     ASSERT(Heap::contains(object) == heapPageForObject);
   1674     ThreadState* state = heapPageForObject->threadState();
   1675     state->pushWeakObjectPointerCallback(closure, callback);
   1676 }
   1677 
   1678 bool Heap::popAndInvokeWeakPointerCallback(Visitor* visitor)
   1679 {
   1680     return s_weakCallbackStack->popAndInvokeCallback(&s_weakCallbackStack, visitor);
   1681 }
   1682 
   1683 void Heap::prepareForGC()
   1684 {
   1685     ASSERT(ThreadState::isAnyThreadInGC());
   1686     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1687     for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
   1688         (*it)->prepareForGC();
   1689 }
   1690 
   1691 void Heap::collectGarbage(ThreadState::StackState stackState)
   1692 {
   1693     ThreadState* state = ThreadState::current();
   1694     state->clearGCRequested();
   1695 
   1696     GCScope gcScope(stackState);
   1697     // Check if we successfully parked the other threads. If not we bail out of the GC.
   1698     if (!gcScope.allThreadsParked()) {
   1699         ThreadState::current()->setGCRequested();
   1700         return;
   1701     }
   1702 
   1703     s_lastGCWasConservative = false;
   1704 
   1705     TRACE_EVENT0("Blink", "Heap::collectGarbage");
   1706     TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "BlinkGC");
   1707     double timeStamp = WTF::currentTimeMS();
   1708 #if ENABLE(GC_TRACING)
   1709     static_cast<MarkingVisitor*>(s_markingVisitor)->objectGraph().clear();
   1710 #endif
   1711 
   1712     // Disallow allocation during garbage collection (but not
   1713     // during the finalization that happens when the gcScope is
   1714     // torn down).
   1715     NoAllocationScope<AnyThread> noAllocationScope;
   1716 
   1717     prepareForGC();
   1718 
   1719     ThreadState::visitRoots(s_markingVisitor);
   1720     // Recursively mark all objects that are reachable from the roots.
   1721     while (popAndInvokeTraceCallback(s_markingVisitor)) { }
   1722 
   1723     // Call weak callbacks on objects that may now be pointing to dead
   1724     // objects.
   1725     while (popAndInvokeWeakPointerCallback(s_markingVisitor)) { }
   1726 
   1727     // It is not permitted to trace pointers of live objects in the weak
   1728     // callback phase, so the marking stack should still be empty here.
   1729     s_markingStack->assertIsEmpty();
   1730 
   1731 #if ENABLE(GC_TRACING)
   1732     static_cast<MarkingVisitor*>(s_markingVisitor)->reportStats();
   1733 #endif
   1734 
   1735     if (blink::Platform::current()) {
   1736         uint64_t objectSpaceSize;
   1737         uint64_t allocatedSpaceSize;
   1738         getHeapSpaceSize(&objectSpaceSize, &allocatedSpaceSize);
   1739         blink::Platform::current()->histogramCustomCounts("BlinkGC.CollectGarbage", WTF::currentTimeMS() - timeStamp, 0, 10 * 1000, 50);
   1740         blink::Platform::current()->histogramCustomCounts("BlinkGC.TotalObjectSpace", objectSpaceSize / 1024, 0, 4 * 1024 * 1024, 50);
   1741         blink::Platform::current()->histogramCustomCounts("BlinkGC.TotalAllocatedSpace", allocatedSpaceSize / 1024, 0, 4 * 1024 * 1024, 50);
   1742     }
   1743 }
   1744 
   1745 void Heap::collectAllGarbage()
   1746 {
   1747     // FIXME: oilpan: we should perform a single GC and everything
   1748     // should die. Unfortunately it is not the case for all objects
   1749     // because the hierarchy was not completely moved to the heap and
   1750     // some heap allocated objects own objects that contain persistents
   1751     // pointing to other heap allocated objects.
   1752     for (int i = 0; i < 5; i++)
   1753         collectGarbage(ThreadState::NoHeapPointersOnStack);
   1754 }
   1755 
   1756 void Heap::setForcePreciseGCForTesting()
   1757 {
   1758     ThreadState::current()->setForcePreciseGCForTesting(true);
   1759 }
   1760 
   1761 void Heap::getHeapSpaceSize(uint64_t* objectSpaceSize, uint64_t* allocatedSpaceSize)
   1762 {
   1763     *objectSpaceSize = 0;
   1764     *allocatedSpaceSize = 0;
   1765     ASSERT(ThreadState::isAnyThreadInGC());
   1766     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1767     typedef ThreadState::AttachedThreadStateSet::iterator ThreadStateIterator;
   1768     for (ThreadStateIterator it = threads.begin(), end = threads.end(); it != end; ++it) {
   1769         *objectSpaceSize += (*it)->stats().totalObjectSpace();
   1770         *allocatedSpaceSize += (*it)->stats().totalAllocatedSpace();
   1771     }
   1772 }
   1773 
   1774 void Heap::getStats(HeapStats* stats)
   1775 {
   1776     stats->clear();
   1777     ASSERT(ThreadState::isAnyThreadInGC());
   1778     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1779     typedef ThreadState::AttachedThreadStateSet::iterator ThreadStateIterator;
   1780     for (ThreadStateIterator it = threads.begin(), end = threads.end(); it != end; ++it) {
   1781         HeapStats temp;
   1782         (*it)->getStats(temp);
   1783         stats->add(&temp);
   1784     }
   1785 }
   1786 
   1787 bool Heap::isConsistentForGC()
   1788 {
   1789     ASSERT(ThreadState::isAnyThreadInGC());
   1790     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1791     for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
   1792         if (!(*it)->isConsistentForGC())
   1793             return false;
   1794     }
   1795     return true;
   1796 }
   1797 
   1798 void Heap::makeConsistentForGC()
   1799 {
   1800     ASSERT(ThreadState::isAnyThreadInGC());
   1801     ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
   1802     for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
   1803         (*it)->makeConsistentForGC();
   1804 }
   1805 
   1806 // Force template instantiations for the types that we need.
   1807 template class HeapPage<FinalizedHeapObjectHeader>;
   1808 template class HeapPage<HeapObjectHeader>;
   1809 template class ThreadHeap<FinalizedHeapObjectHeader>;
   1810 template class ThreadHeap<HeapObjectHeader>;
   1811 
   1812 Visitor* Heap::s_markingVisitor;
   1813 CallbackStack* Heap::s_markingStack;
   1814 CallbackStack* Heap::s_weakCallbackStack;
   1815 HeapDoesNotContainCache* Heap::s_heapDoesNotContainCache;
   1816 bool Heap::s_shutdownCalled = false;
   1817 bool Heap::s_lastGCWasConservative = false;
   1818 }
   1819