Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1494)

Unified Diff: Source/platform/heap/Heap.h

Issue 1314793002: Oilpan: Split Heap.h into two files (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/platform/heap/BUILD.gn ('k') | Source/platform/heap/Heap.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/platform/heap/Heap.h
diff --git a/Source/platform/heap/Heap.h b/Source/platform/heap/Heap.h
index 18a435a46a32c09576781621e5ec7675ae21a9aa..d3b4b4d9519c3b7f1e35ff32a2b34ec79e72dec7 100644
--- a/Source/platform/heap/Heap.h
+++ b/Source/platform/heap/Heap.h
@@ -33,794 +33,16 @@
#include "platform/PlatformExport.h"
#include "platform/heap/GCInfo.h"
+#include "platform/heap/HeapPage.h"
#include "platform/heap/ThreadState.h"
#include "platform/heap/Visitor.h"
-#include "public/platform/WebThread.h"
#include "wtf/AddressSanitizer.h"
#include "wtf/Assertions.h"
#include "wtf/Atomics.h"
-#include "wtf/ContainerAnnotations.h"
#include "wtf/Forward.h"
-#include "wtf/PageAllocator.h"
-#include <stdint.h>
namespace blink {
-const size_t blinkPageSizeLog2 = 17;
-const size_t blinkPageSize = 1 << blinkPageSizeLog2;
-const size_t blinkPageOffsetMask = blinkPageSize - 1;
-const size_t blinkPageBaseMask = ~blinkPageOffsetMask;
-
-// We allocate pages at random addresses but in groups of
-// blinkPagesPerRegion at a given random address. We group pages to
-// not spread out too much over the address space which would blow
-// away the page tables and lead to bad performance.
-const size_t blinkPagesPerRegion = 10;
-
-// TODO(nya): Replace this with something like #if ENABLE_NACL.
-#if 0
-// NaCl's system page size is 64 KB. This causes a problem in Oilpan's heap
-// layout because Oilpan allocates two guard pages for each blink page
-// (whose size is 128 KB). So we don't use guard pages in NaCl.
-const size_t blinkGuardPageSize = 0;
-#else
-const size_t blinkGuardPageSize = WTF::kSystemPageSize;
-#endif
-
-// Double precision floats are more efficient when 8 byte aligned, so we 8 byte
-// align all allocations even on 32 bit.
-const size_t allocationGranularity = 8;
-const size_t allocationMask = allocationGranularity - 1;
-const size_t objectStartBitMapSize = (blinkPageSize + ((8 * allocationGranularity) - 1)) / (8 * allocationGranularity);
-const size_t reservedForObjectBitMap = ((objectStartBitMapSize + allocationMask) & ~allocationMask);
-const size_t maxHeapObjectSizeLog2 = 27;
-const size_t maxHeapObjectSize = 1 << maxHeapObjectSizeLog2;
-const size_t largeObjectSizeThreshold = blinkPageSize / 2;
-
-// A zap value used for freed memory that is allowed to be added to the free
-// list in the next addToFreeList().
-const uint8_t reuseAllowedZapValue = 0x2a;
-// A zap value used for freed memory that is forbidden to be added to the free
-// list in the next addToFreeList().
-const uint8_t reuseForbiddenZapValue = 0x2c;
-
-// In non-production builds, memory is zapped when it's freed. The zapped
-// memory is zeroed out when the memory is reused in Heap::allocateObject().
-// In production builds, memory is not zapped (for performance). The memory
-// is just zeroed out when it is added to the free list.
-#if defined(MEMORY_SANITIZER)
-// TODO(kojii): We actually need __msan_poison/unpoison here, but it'll be
-// added later.
-#define SET_MEMORY_INACCESSIBLE(address, size) \
- FreeList::zapFreedMemory(address, size);
-#define SET_MEMORY_ACCESSIBLE(address, size) \
- memset((address), 0, (size))
-#elif ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
-#define SET_MEMORY_INACCESSIBLE(address, size) \
- FreeList::zapFreedMemory(address, size); \
- ASAN_POISON_MEMORY_REGION(address, size)
-#define SET_MEMORY_ACCESSIBLE(address, size) \
- ASAN_UNPOISON_MEMORY_REGION(address, size); \
- memset((address), 0, (size))
-#else
-#define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size))
-#define SET_MEMORY_ACCESSIBLE(address, size) do { } while (false)
-#endif
-
-class CallbackStack;
-class FreePagePool;
-class NormalPageHeap;
-class OrphanedPagePool;
-class PageMemory;
-class PageMemoryRegion;
-class WebProcessMemoryDump;
-
-#if ENABLE(GC_PROFILING)
-class TracedValue;
-#endif
-
-// HeapObjectHeader is 4 byte (32 bit) that has the following layout:
-//
-// | gcInfoIndex (14 bit) | DOM mark bit (1 bit) | size (14 bit) | dead bit (1 bit) | freed bit (1 bit) | mark bit (1 bit) |
-//
-// - For non-large objects, 14 bit is enough for |size| because the blink
-// page size is 2^17 byte and each object is guaranteed to be aligned with
-// 2^3 byte.
-// - For large objects, |size| is 0. The actual size of a large object is
-// stored in LargeObjectPage::m_payloadSize.
-// - 1 bit used to mark DOM trees for V8.
-// - 14 bit is enough for gcInfoIndex because there are less than 2^14 types
-// in Blink.
-const size_t headerDOMMarkBitMask = 1u << 17;
-const size_t headerGCInfoIndexShift = 18;
-const size_t headerGCInfoIndexMask = (static_cast<size_t>((1 << 14) - 1)) << headerGCInfoIndexShift;
-const size_t headerSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3;
-const size_t headerMarkBitMask = 1;
-const size_t headerFreedBitMask = 2;
-// The dead bit is used for objects that have gone through a GC marking, but did
-// not get swept before a new GC started. In that case we set the dead bit on
-// objects that were not marked in the previous GC to ensure we are not tracing
-// them via a conservatively found pointer. Tracing dead objects could lead to
-// tracing of already finalized objects in another thread's heap which is a
-// use-after-free situation.
-const size_t headerDeadBitMask = 4;
-// On free-list entries we reuse the dead bit to distinguish a normal free-list
-// entry from one that has been promptly freed.
-const size_t headerPromptlyFreedBitMask = headerFreedBitMask | headerDeadBitMask;
-const size_t largeObjectSizeInHeader = 0;
-const size_t gcInfoIndexForFreeListHeader = 0;
-const size_t nonLargeObjectPageSizeMax = 1 << 17;
-
-static_assert(nonLargeObjectPageSizeMax >= blinkPageSize, "max size supported by HeapObjectHeader must at least be blinkPageSize");
-
-class PLATFORM_EXPORT HeapObjectHeader {
-public:
- // If gcInfoIndex is 0, this header is interpreted as a free list header.
- NO_SANITIZE_ADDRESS
- HeapObjectHeader(size_t size, size_t gcInfoIndex)
- {
-#if ENABLE(ASSERT)
- m_magic = magic;
-#endif
-#if ENABLE(GC_PROFILING)
- m_age = 0;
-#endif
- // sizeof(HeapObjectHeader) must be equal to or smaller than
- // allocationGranurarity, because HeapObjectHeader is used as a header
- // for an freed entry. Given that the smallest entry size is
- // allocationGranurarity, HeapObjectHeader must fit into the size.
- static_assert(sizeof(HeapObjectHeader) <= allocationGranularity, "size of HeapObjectHeader must be smaller than allocationGranularity");
-#if CPU(64BIT)
- static_assert(sizeof(HeapObjectHeader) == 8, "size of HeapObjectHeader must be 8 byte aligned");
-#endif
-
- ASSERT(gcInfoIndex < GCInfoTable::maxIndex);
- ASSERT(size < nonLargeObjectPageSizeMax);
- ASSERT(!(size & allocationMask));
- m_encoded = (gcInfoIndex << headerGCInfoIndexShift) | size | (gcInfoIndex ? 0 : headerFreedBitMask);
- }
-
- NO_SANITIZE_ADDRESS
- bool isFree() const { return m_encoded & headerFreedBitMask; }
- NO_SANITIZE_ADDRESS
- bool isPromptlyFreed() const { return (m_encoded & headerPromptlyFreedBitMask) == headerPromptlyFreedBitMask; }
- NO_SANITIZE_ADDRESS
- void markPromptlyFreed() { m_encoded |= headerPromptlyFreedBitMask; }
- size_t size() const;
-
- NO_SANITIZE_ADDRESS
- size_t gcInfoIndex() const { return (m_encoded & headerGCInfoIndexMask) >> headerGCInfoIndexShift; }
- NO_SANITIZE_ADDRESS
- void setSize(size_t size) { m_encoded = size | (m_encoded & ~headerSizeMask); }
- bool isMarked() const;
- void mark();
- void unmark();
- void markDead();
- bool isDead() const;
-
- Address payload();
- size_t payloadSize();
- Address payloadEnd();
-
-#if ENABLE(ASSERT)
- bool checkHeader() const;
- // Zap magic number with a new magic number that means there was once an
- // object allocated here, but it was freed because nobody marked it during
- // GC.
- void zapMagic();
-#endif
-
- void finalize(Address, size_t);
- static HeapObjectHeader* fromPayload(const void*);
-
- static const uint16_t magic = 0xfff1;
- static const uint16_t zappedMagic = 0x4321;
-
-#if ENABLE(GC_PROFILING)
- NO_SANITIZE_ADDRESS
- size_t encodedSize() const { return m_encoded; }
-
- NO_SANITIZE_ADDRESS
- size_t age() const { return m_age; }
-
- NO_SANITIZE_ADDRESS
- void incrementAge()
- {
- if (m_age < maxHeapObjectAge)
- m_age++;
- }
-#endif
-
-#if !ENABLE(ASSERT) && !ENABLE(GC_PROFILING) && CPU(64BIT)
- // This method is needed just to avoid compilers from removing m_padding.
- uint64_t unusedMethod() const { return m_padding; }
-#endif
-
-private:
- uint32_t m_encoded;
-#if ENABLE(ASSERT)
- uint16_t m_magic;
-#endif
-#if ENABLE(GC_PROFILING)
- uint8_t m_age;
-#endif
-
- // In 64 bit architectures, we intentionally add 4 byte padding immediately
- // after the HeapHeaderObject. This is because:
- //
- // | HeapHeaderObject (4 byte) | padding (4 byte) | object payload (8 * n byte) |
- // ^8 byte aligned ^8 byte aligned
- //
- // is better than:
- //
- // | HeapHeaderObject (4 byte) | object payload (8 * n byte) | padding (4 byte) |
- // ^4 byte aligned ^8 byte aligned ^4 byte aligned
- //
- // since the former layout aligns both header and payload to 8 byte.
-#if !ENABLE(ASSERT) && !ENABLE(GC_PROFILING) && CPU(64BIT)
- uint32_t m_padding;
-#endif
-};
-
-class FreeListEntry final : public HeapObjectHeader {
-public:
- NO_SANITIZE_ADDRESS
- explicit FreeListEntry(size_t size)
- : HeapObjectHeader(size, gcInfoIndexForFreeListHeader)
- , m_next(nullptr)
- {
-#if ENABLE(ASSERT)
- ASSERT(size >= sizeof(HeapObjectHeader));
- zapMagic();
-#endif
- }
-
- Address address() { return reinterpret_cast<Address>(this); }
-
- NO_SANITIZE_ADDRESS
- void unlink(FreeListEntry** prevNext)
- {
- *prevNext = m_next;
- m_next = nullptr;
- }
-
- NO_SANITIZE_ADDRESS
- void link(FreeListEntry** prevNext)
- {
- m_next = *prevNext;
- *prevNext = this;
- }
-
- NO_SANITIZE_ADDRESS
- FreeListEntry* next() const { return m_next; }
-
- NO_SANITIZE_ADDRESS
- void append(FreeListEntry* next)
- {
- ASSERT(!m_next);
- m_next = next;
- }
-
-private:
- FreeListEntry* m_next;
-};
-
-// Blink heap pages are set up with a guard page before and after the payload.
-inline size_t blinkPagePayloadSize()
-{
- return blinkPageSize - 2 * blinkGuardPageSize;
-}
-
-// Blink heap pages are aligned to the Blink heap page size.
-// Therefore, the start of a Blink page can be obtained by
-// rounding down to the Blink page size.
-inline Address roundToBlinkPageStart(Address address)
-{
- return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address) & blinkPageBaseMask);
-}
-
-inline Address roundToBlinkPageEnd(Address address)
-{
- return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address - 1) & blinkPageBaseMask) + blinkPageSize;
-}
-
-// Masks an address down to the enclosing blink page base address.
-inline Address blinkPageAddress(Address address)
-{
- return reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address) & blinkPageBaseMask);
-}
-
-inline bool vTableInitialized(void* objectPointer)
-{
- return !!(*reinterpret_cast<Address*>(objectPointer));
-}
-
-#if ENABLE(ASSERT)
-// Sanity check for a page header address: the address of the page
-// header should be OS page size away from being Blink page size
-// aligned.
-inline bool isPageHeaderAddress(Address address)
-{
- return !((reinterpret_cast<uintptr_t>(address) & blinkPageOffsetMask) - blinkGuardPageSize);
-}
-#endif
-
-// BasePage is a base class for NormalPage and LargeObjectPage.
-//
-// - NormalPage is a page whose size is |blinkPageSize|. NormalPage can contain
-// multiple objects in the page. An object whose size is smaller than
-// |largeObjectSizeThreshold| is stored in NormalPage.
-//
-// - LargeObjectPage is a page that contains only one object. The object size
-// is arbitrary. An object whose size is larger than |blinkPageSize| is stored
-// as a single project in LargeObjectPage.
-//
-// Note: An object whose size is between |largeObjectSizeThreshold| and
-// |blinkPageSize| can go to either of NormalPage or LargeObjectPage.
-class BasePage {
-public:
- BasePage(PageMemory*, BaseHeap*);
- virtual ~BasePage() { }
-
- void link(BasePage** previousNext)
- {
- m_next = *previousNext;
- *previousNext = this;
- }
- void unlink(BasePage** previousNext)
- {
- *previousNext = m_next;
- m_next = nullptr;
- }
- BasePage* next() const { return m_next; }
-
- // virtual methods are slow. So performance-sensitive methods
- // should be defined as non-virtual methods on NormalPage and LargeObjectPage.
- // The following methods are not performance-sensitive.
- virtual size_t objectPayloadSizeForTesting() = 0;
- virtual bool isEmpty() = 0;
- virtual void removeFromHeap() = 0;
- virtual void sweep() = 0;
- virtual void makeConsistentForGC() = 0;
- virtual void makeConsistentForMutator() = 0;
-
-#if defined(ADDRESS_SANITIZER)
- virtual void poisonObjects(ThreadState::ObjectsToPoison, ThreadState::Poisoning) = 0;
-#endif
- // Check if the given address points to an object in this
- // heap page. If so, find the start of that object and mark it
- // using the given Visitor. Otherwise do nothing. The pointer must
- // be within the same aligned blinkPageSize as the this-pointer.
- //
- // This is used during conservative stack scanning to
- // conservatively mark all objects that could be referenced from
- // the stack.
- virtual void checkAndMarkPointer(Visitor*, Address) = 0;
- virtual void markOrphaned();
-
- virtual void takeSnapshot(String dumpBaseName, size_t pageIndex, ThreadState::GCSnapshotInfo&, size_t* outFreeSize, size_t* outFreeCount) = 0;
-#if ENABLE(GC_PROFILING)
- virtual const GCInfo* findGCInfo(Address) = 0;
- virtual void snapshot(TracedValue*, ThreadState::SnapshotInfo*) = 0;
- virtual void incrementMarkedObjectsAge() = 0;
- virtual void countMarkedObjects(ClassAgeCountsMap&) = 0;
- virtual void countObjectsToSweep(ClassAgeCountsMap&) = 0;
-#endif
-#if ENABLE(ASSERT) || ENABLE(GC_PROFILING)
- virtual bool contains(Address) = 0;
-#endif
- virtual size_t size() = 0;
- virtual bool isLargeObjectPage() { return false; }
-
- Address address() { return reinterpret_cast<Address>(this); }
- PageMemory* storage() const { return m_storage; }
- BaseHeap* heap() const { return m_heap; }
- bool orphaned() { return !m_heap; }
- bool terminating() { return m_terminating; }
- void setTerminating() { m_terminating = true; }
-
- // Returns true if this page has been swept by the ongoing lazy sweep.
- bool hasBeenSwept() const { return m_swept; }
-
- void markAsSwept()
- {
- ASSERT(!m_swept);
- m_swept = true;
- }
-
- void markAsUnswept()
- {
- ASSERT(m_swept);
- m_swept = false;
- }
-
-private:
- PageMemory* m_storage;
- BaseHeap* m_heap;
- BasePage* m_next;
- // Whether the page is part of a terminating thread or not.
- bool m_terminating;
-
- // Track the sweeping state of a page. Set to true once
- // the lazy sweep completes has processed it.
- //
- // Set to false at the start of a sweep, true upon completion
- // of lazy sweeping.
- bool m_swept;
- friend class BaseHeap;
-};
-
-class NormalPage final : public BasePage {
-public:
- NormalPage(PageMemory*, BaseHeap*);
-
- Address payload()
- {
- return address() + pageHeaderSize();
- }
- size_t payloadSize()
- {
- return (blinkPagePayloadSize() - pageHeaderSize()) & ~allocationMask;
- }
- Address payloadEnd() { return payload() + payloadSize(); }
- bool containedInObjectPayload(Address address)
- {
- return payload() <= address && address < payloadEnd();
- }
-
- size_t objectPayloadSizeForTesting() override;
- bool isEmpty() override;
- void removeFromHeap() override;
- void sweep() override;
- void makeConsistentForGC() override;
- void makeConsistentForMutator() override;
-#if defined(ADDRESS_SANITIZER)
- void poisonObjects(ThreadState::ObjectsToPoison, ThreadState::Poisoning) override;
-#endif
- void checkAndMarkPointer(Visitor*, Address) override;
- void markOrphaned() override;
-
- void takeSnapshot(String dumpBaseName, size_t pageIndex, ThreadState::GCSnapshotInfo&, size_t* outFreeSize, size_t* outFreeCount) override;
-#if ENABLE(GC_PROFILING)
- const GCInfo* findGCInfo(Address) override;
- void snapshot(TracedValue*, ThreadState::SnapshotInfo*) override;
- void incrementMarkedObjectsAge() override;
- void countMarkedObjects(ClassAgeCountsMap&) override;
- void countObjectsToSweep(ClassAgeCountsMap&) override;
-#endif
-#if ENABLE(ASSERT) || ENABLE(GC_PROFILING)
- // Returns true for the whole blinkPageSize page that the page is on, even
- // for the header, and the unmapped guard page at the start. That ensures
- // the result can be used to populate the negative page cache.
- bool contains(Address) override;
-#endif
- size_t size() override { return blinkPageSize; }
- static size_t pageHeaderSize()
- {
- // Compute the amount of padding we have to add to a header to make
- // the size of the header plus the padding a multiple of 8 bytes.
- size_t paddingSize = (sizeof(NormalPage) + allocationGranularity - (sizeof(HeapObjectHeader) % allocationGranularity)) % allocationGranularity;
- return sizeof(NormalPage) + paddingSize;
- }
-
-
- NormalPageHeap* heapForNormalPage();
- void clearObjectStartBitMap();
-
-private:
- HeapObjectHeader* findHeaderFromAddress(Address);
- void populateObjectStartBitMap();
- bool isObjectStartBitMapComputed() { return m_objectStartBitMapComputed; }
-
- bool m_objectStartBitMapComputed;
- uint8_t m_objectStartBitMap[reservedForObjectBitMap];
-};
-
-// Large allocations are allocated as separate objects and linked in a list.
-//
-// In order to use the same memory allocation routines for everything allocated
-// in the heap, large objects are considered heap pages containing only one
-// object.
-class LargeObjectPage final : public BasePage {
-public:
- LargeObjectPage(PageMemory*, BaseHeap*, size_t);
-
- Address payload() { return heapObjectHeader()->payload(); }
- size_t payloadSize() { return m_payloadSize; }
- Address payloadEnd() { return payload() + payloadSize(); }
- bool containedInObjectPayload(Address address)
- {
- return payload() <= address && address < payloadEnd();
- }
-
- size_t objectPayloadSizeForTesting() override;
- bool isEmpty() override;
- void removeFromHeap() override;
- void sweep() override;
- void makeConsistentForGC() override;
- void makeConsistentForMutator() override;
-#if defined(ADDRESS_SANITIZER)
- void poisonObjects(ThreadState::ObjectsToPoison, ThreadState::Poisoning) override;
-#endif
- void checkAndMarkPointer(Visitor*, Address) override;
- void markOrphaned() override;
-
- void takeSnapshot(String dumpBaseName, size_t pageIndex, ThreadState::GCSnapshotInfo&, size_t* outFreeSize, size_t* outFreeCount) override;
-#if ENABLE(GC_PROFILING)
- const GCInfo* findGCInfo(Address) override;
- void snapshot(TracedValue*, ThreadState::SnapshotInfo*) override;
- void incrementMarkedObjectsAge() override;
- void countMarkedObjects(ClassAgeCountsMap&) override;
- void countObjectsToSweep(ClassAgeCountsMap&) override;
-#endif
-#if ENABLE(ASSERT) || ENABLE(GC_PROFILING)
- // Returns true for any address that is on one of the pages that this
- // large object uses. That ensures that we can use a negative result to
- // populate the negative page cache.
- bool contains(Address) override;
-#endif
- virtual size_t size()
- {
- return pageHeaderSize() + sizeof(HeapObjectHeader) + m_payloadSize;
- }
- static size_t pageHeaderSize()
- {
- // Compute the amount of padding we have to add to a header to make
- // the size of the header plus the padding a multiple of 8 bytes.
- size_t paddingSize = (sizeof(LargeObjectPage) + allocationGranularity - (sizeof(HeapObjectHeader) % allocationGranularity)) % allocationGranularity;
- return sizeof(LargeObjectPage) + paddingSize;
- }
- bool isLargeObjectPage() override { return true; }
-
- HeapObjectHeader* heapObjectHeader()
- {
- Address headerAddress = address() + pageHeaderSize();
- return reinterpret_cast<HeapObjectHeader*>(headerAddress);
- }
-
-#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
- void setIsVectorBackingPage() { m_isVectorBackingPage = true; }
- bool isVectorBackingPage() const { return m_isVectorBackingPage; }
-#endif
-
-private:
-
- size_t m_payloadSize;
-#ifdef ANNOTATE_CONTIGUOUS_CONTAINER
- bool m_isVectorBackingPage;
-#endif
-};
-
-// A HeapDoesNotContainCache provides a fast way of taking an arbitrary
-// pointer-sized word, and determining whether it cannot be interpreted as a
-// pointer to an area that is managed by the garbage collected Blink heap. This
-// is a cache of 'pages' that have previously been determined to be wholly
-// outside of the heap. The size of these pages must be smaller than the
-// allocation alignment of the heap pages. We determine off-heap-ness by
-// rounding down the pointer to the nearest page and looking up the page in the
-// cache. If there is a miss in the cache we can determine the status of the
-// pointer precisely using the heap RegionTree.
-//
-// The HeapDoesNotContainCache is a negative cache, so it must be flushed when
-// memory is added to the heap.
-class HeapDoesNotContainCache {
-public:
- HeapDoesNotContainCache()
- : m_entries(adoptArrayPtr(new Address[HeapDoesNotContainCache::numberOfEntries]))
- , m_hasEntries(false)
- {
- // Start by flushing the cache in a non-empty state to initialize all the cache entries.
- for (int i = 0; i < numberOfEntries; ++i)
- m_entries[i] = nullptr;
- }
-
- void flush();
- bool isEmpty() { return !m_hasEntries; }
-
- // Perform a lookup in the cache.
- //
- // If lookup returns false, the argument address was not found in
- // the cache and it is unknown if the address is in the Blink
- // heap.
- //
- // If lookup returns true, the argument address was found in the
- // cache which means the address is not in the heap.
- PLATFORM_EXPORT bool lookup(Address);
-
- // Add an entry to the cache.
- PLATFORM_EXPORT void addEntry(Address);
-
-private:
- static const int numberOfEntriesLog2 = 12;
- static const int numberOfEntries = 1 << numberOfEntriesLog2;
-
- static size_t hash(Address);
-
- WTF::OwnPtr<Address[]> m_entries;
- bool m_hasEntries;
-};
-
-class FreeList {
-public:
- FreeList();
-
- void addToFreeList(Address, size_t);
- void clear();
-
- // Returns a bucket number for inserting a FreeListEntry of a given size.
- // All FreeListEntries in the given bucket, n, have size >= 2^n.
- static int bucketIndexForSize(size_t);
-
- // Returns true if the freelist snapshot is captured.
- bool takeSnapshot(const String& dumpBaseName);
-
-#if ENABLE(GC_PROFILING)
- struct PerBucketFreeListStats {
- size_t entryCount;
- size_t freeSize;
-
- PerBucketFreeListStats() : entryCount(0), freeSize(0) { }
- };
-
- void getFreeSizeStats(PerBucketFreeListStats bucketStats[], size_t& totalSize) const;
-#endif
-
-#if ENABLE(ASSERT) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)
- static void zapFreedMemory(Address, size_t);
-#endif
-
-private:
- int m_biggestFreeListIndex;
-
- // All FreeListEntries in the nth list have size >= 2^n.
- FreeListEntry* m_freeLists[blinkPageSizeLog2];
-
- friend class NormalPageHeap;
-};
-
-// Each thread has a number of thread heaps (e.g., Generic heaps,
-// typed heaps for Node, heaps for collection backings etc)
-// and BaseHeap represents each thread heap.
-//
-// BaseHeap is a parent class of NormalPageHeap and LargeObjectHeap.
-// NormalPageHeap represents a heap that contains NormalPages
-// and LargeObjectHeap represents a heap that contains LargeObjectPages.
-class PLATFORM_EXPORT BaseHeap {
-public:
- BaseHeap(ThreadState*, int);
- virtual ~BaseHeap();
- void cleanupPages();
-
- void takeSnapshot(const String& dumpBaseName, ThreadState::GCSnapshotInfo&);
-#if ENABLE(ASSERT) || ENABLE(GC_PROFILING)
- BasePage* findPageFromAddress(Address);
-#endif
- virtual void takeFreelistSnapshot(const String& dumpBaseName) { }
-#if ENABLE(GC_PROFILING)
- void snapshot(TracedValue*, ThreadState::SnapshotInfo*);
- virtual void snapshotFreeList(TracedValue&) { }
-
- void countMarkedObjects(ClassAgeCountsMap&) const;
- void countObjectsToSweep(ClassAgeCountsMap&) const;
- void incrementMarkedObjectsAge();
-#endif
-
- virtual void clearFreeLists() { }
- void makeConsistentForGC();
- void makeConsistentForMutator();
-#if ENABLE(ASSERT)
- virtual bool isConsistentForGC() = 0;
-#endif
- size_t objectPayloadSizeForTesting();
- void prepareHeapForTermination();
- void prepareForSweep();
-#if defined(ADDRESS_SANITIZER)
- void poisonHeap(ThreadState::ObjectsToPoison, ThreadState::Poisoning);
-#endif
- Address lazySweep(size_t, size_t gcInfoIndex);
- void sweepUnsweptPage();
- // Returns true if we have swept all pages within the deadline.
- // Returns false otherwise.
- bool lazySweepWithDeadline(double deadlineSeconds);
- void completeSweep();
-
- ThreadState* threadState() { return m_threadState; }
- int heapIndex() const { return m_index; }
-
-protected:
- BasePage* m_firstPage;
- BasePage* m_firstUnsweptPage;
-
-private:
- virtual Address lazySweepPages(size_t, size_t gcInfoIndex) = 0;
-
- ThreadState* m_threadState;
-
- // Index into the page pools. This is used to ensure that the pages of the
- // same type go into the correct page pool and thus avoid type confusion.
- int m_index;
-};
-
-class PLATFORM_EXPORT NormalPageHeap final : public BaseHeap {
-public:
- NormalPageHeap(ThreadState*, int);
- void addToFreeList(Address address, size_t size)
- {
- ASSERT(findPageFromAddress(address));
- ASSERT(findPageFromAddress(address + size - 1));
- m_freeList.addToFreeList(address, size);
- }
- void clearFreeLists() override;
-#if ENABLE(ASSERT)
- bool isConsistentForGC() override;
- bool pagesToBeSweptContains(Address);
-#endif
- void takeFreelistSnapshot(const String& dumpBaseName) override;
-#if ENABLE(GC_PROFILING)
- void snapshotFreeList(TracedValue&) override;
-#endif
-
- Address allocateObject(size_t allocationSize, size_t gcInfoIndex);
-
- void freePage(NormalPage*);
-
- bool coalesce();
- void promptlyFreeObject(HeapObjectHeader*);
- bool expandObject(HeapObjectHeader*, size_t);
- bool shrinkObject(HeapObjectHeader*, size_t);
- void decreasePromptlyFreedSize(size_t size) { m_promptlyFreedSize -= size; }
-
-private:
- void allocatePage();
- Address lazySweepPages(size_t, size_t gcInfoIndex) override;
- Address outOfLineAllocate(size_t allocationSize, size_t gcInfoIndex);
- Address currentAllocationPoint() const { return m_currentAllocationPoint; }
- size_t remainingAllocationSize() const { return m_remainingAllocationSize; }
- bool hasCurrentAllocationArea() const { return currentAllocationPoint() && remainingAllocationSize(); }
- void setAllocationPoint(Address, size_t);
- void updateRemainingAllocationSize();
- Address allocateFromFreeList(size_t, size_t gcInfoIndex);
-
- FreeList m_freeList;
- Address m_currentAllocationPoint;
- size_t m_remainingAllocationSize;
- size_t m_lastRemainingAllocationSize;
-
- // The size of promptly freed objects in the heap.
- size_t m_promptlyFreedSize;
-
-#if ENABLE(GC_PROFILING)
- size_t m_cumulativeAllocationSize;
- size_t m_allocationCount;
- size_t m_inlineAllocationCount;
-#endif
-};
-
-class LargeObjectHeap final : public BaseHeap {
-public:
- LargeObjectHeap(ThreadState*, int);
- Address allocateLargeObjectPage(size_t, size_t gcInfoIndex);
- void freeLargeObjectPage(LargeObjectPage*);
-#if ENABLE(ASSERT)
- bool isConsistentForGC() override { return true; }
-#endif
-private:
- Address doAllocateLargeObjectPage(size_t, size_t gcInfoIndex);
- Address lazySweepPages(size_t, size_t gcInfoIndex) override;
-};
-
-// Mask an address down to the enclosing oilpan heap base page. All oilpan heap
-// pages are aligned at blinkPageBase plus the size of a guard size.
-// FIXME: Remove PLATFORM_EXPORT once we get a proper public interface to our
-// typed heaps. This is only exported to enable tests in HeapTest.cpp.
-PLATFORM_EXPORT inline BasePage* pageFromObject(const void* object)
-{
- Address address = reinterpret_cast<Address>(const_cast<void*>(object));
- BasePage* page = reinterpret_cast<BasePage*>(blinkPageAddress(address) + blinkGuardPageSize);
- ASSERT(page->contains(address));
- return page;
-}
-
template<typename T, bool = NeedsAdjustAndMark<T>::value> class ObjectAliveTrait;
template<typename T>
@@ -1235,129 +457,6 @@ public: \
#define EAGERLY_FINALIZE_WILL_BE_REMOVED()
#endif
-NO_SANITIZE_ADDRESS inline
-size_t HeapObjectHeader::size() const
-{
- size_t result = m_encoded & headerSizeMask;
- // Large objects should not refer to header->size().
- // The actual size of a large object is stored in
- // LargeObjectPage::m_payloadSize.
- ASSERT(result != largeObjectSizeInHeader);
- ASSERT(!pageFromObject(this)->isLargeObjectPage());
- return result;
-}
-
-#if ENABLE(ASSERT)
-NO_SANITIZE_ADDRESS inline
-bool HeapObjectHeader::checkHeader() const
-{
- return !pageFromObject(this)->orphaned() && m_magic == magic;
-}
-#endif
-
-inline Address HeapObjectHeader::payload()
-{
- return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader);
-}
-
-inline Address HeapObjectHeader::payloadEnd()
-{
- return reinterpret_cast<Address>(this) + size();
-}
-
-NO_SANITIZE_ADDRESS inline
-size_t HeapObjectHeader::payloadSize()
-{
- size_t size = m_encoded & headerSizeMask;
- if (UNLIKELY(size == largeObjectSizeInHeader)) {
- ASSERT(pageFromObject(this)->isLargeObjectPage());
- return static_cast<LargeObjectPage*>(pageFromObject(this))->payloadSize();
- }
- ASSERT(!pageFromObject(this)->isLargeObjectPage());
- return size - sizeof(HeapObjectHeader);
-}
-
-inline HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload)
-{
- Address addr = reinterpret_cast<Address>(const_cast<void*>(payload));
- HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(addr - sizeof(HeapObjectHeader));
- ASSERT(header->checkHeader());
- return header;
-}
-
-NO_SANITIZE_ADDRESS inline
-bool HeapObjectHeader::isMarked() const
-{
- ASSERT(checkHeader());
- return m_encoded & headerMarkBitMask;
-}
-
-NO_SANITIZE_ADDRESS inline
-void HeapObjectHeader::mark()
-{
- ASSERT(checkHeader());
- ASSERT(!isMarked());
- m_encoded = m_encoded | headerMarkBitMask;
-}
-
-NO_SANITIZE_ADDRESS inline
-void HeapObjectHeader::unmark()
-{
- ASSERT(checkHeader());
- ASSERT(isMarked());
- m_encoded &= ~headerMarkBitMask;
-}
-
-NO_SANITIZE_ADDRESS inline
-bool HeapObjectHeader::isDead() const
-{
- ASSERT(checkHeader());
- return m_encoded & headerDeadBitMask;
-}
-
-NO_SANITIZE_ADDRESS inline
-void HeapObjectHeader::markDead()
-{
- ASSERT(checkHeader());
- ASSERT(!isMarked());
- m_encoded |= headerDeadBitMask;
-}
-
-inline Address NormalPageHeap::allocateObject(size_t allocationSize, size_t gcInfoIndex)
-{
-#if ENABLE(GC_PROFILING)
- m_cumulativeAllocationSize += allocationSize;
- ++m_allocationCount;
-#endif
-
- if (LIKELY(allocationSize <= m_remainingAllocationSize)) {
-#if ENABLE(GC_PROFILING)
- ++m_inlineAllocationCount;
-#endif
- Address headerAddress = m_currentAllocationPoint;
- m_currentAllocationPoint += allocationSize;
- m_remainingAllocationSize -= allocationSize;
- ASSERT(gcInfoIndex > 0);
- new (NotNull, headerAddress) HeapObjectHeader(allocationSize, gcInfoIndex);
- Address result = headerAddress + sizeof(HeapObjectHeader);
- ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask));
-
- SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader));
- ASSERT(findPageFromAddress(headerAddress + allocationSize - 1));
- return result;
- }
- return outOfLineAllocate(allocationSize, gcInfoIndex);
-}
-
-template<typename Derived>
-template<typename T>
-void VisitorHelper<Derived>::handleWeakCell(Visitor* self, void* object)
-{
- T** cell = reinterpret_cast<T**>(object);
- if (*cell && !ObjectAliveTrait<T>::isHeapObjectAlive(*cell))
- *cell = nullptr;
-}
-
inline Address Heap::allocateOnHeapIndex(ThreadState* state, size_t size, int heapIndex, size_t gcInfoIndex)
{
ASSERT(state->isAllocationAllowed());
@@ -1406,6 +505,15 @@ Address Heap::reallocate(void* previous, size_t size)
return address;
}
+template<typename Derived>
+template<typename T>
+void VisitorHelper<Derived>::handleWeakCell(Visitor* self, void* object)
+{
+ T** cell = reinterpret_cast<T**>(object);
+ if (*cell && !ObjectAliveTrait<T>::isHeapObjectAlive(*cell))
+ *cell = nullptr;
+}
+
} // namespace blink
#endif // Heap_h
« no previous file with comments | « Source/platform/heap/BUILD.gn ('k') | Source/platform/heap/Heap.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698