Index: Source/platform/heap/HeapPage.h |
diff --git a/Source/platform/heap/Heap.h b/Source/platform/heap/HeapPage.h |
similarity index 63% |
copy from Source/platform/heap/Heap.h |
copy to Source/platform/heap/HeapPage.h |
index 18a435a46a32c09576781621e5ec7675ae21a9aa..d3689300d01f0cca5f3ab981ea8fd1fa1130d6bc 100644 |
--- a/Source/platform/heap/Heap.h |
+++ b/Source/platform/heap/HeapPage.h |
@@ -28,14 +28,13 @@ |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
-#ifndef Heap_h |
-#define Heap_h |
+#ifndef HeapPage_h |
+#define HeapPage_h |
#include "platform/PlatformExport.h" |
#include "platform/heap/GCInfo.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" |
@@ -107,6 +106,12 @@ const uint8_t reuseForbiddenZapValue = 0x2c; |
#define SET_MEMORY_ACCESSIBLE(address, size) do { } while (false) |
#endif |
+#if !ENABLE(ASSERT) && !ENABLE(GC_PROFILING) && CPU(64BIT) |
+#define USE_4BYTE_HEADER_PADDING 1 |
+#else |
+#define USE_4BYTE_HEADER_PADDING 0 |
+#endif |
+ |
class CallbackStack; |
class FreePagePool; |
class NormalPageHeap; |
@@ -231,11 +236,6 @@ public: |
} |
#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) |
@@ -257,7 +257,8 @@ private: |
// ^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) |
+#if USE_4BYTE_HEADER_PADDING |
+public: |
uint32_t m_padding; |
#endif |
}; |
@@ -821,420 +822,6 @@ PLATFORM_EXPORT inline BasePage* pageFromObject(const void* object) |
return page; |
} |
-template<typename T, bool = NeedsAdjustAndMark<T>::value> class ObjectAliveTrait; |
- |
-template<typename T> |
-class ObjectAliveTrait<T, false> { |
-public: |
- static bool isHeapObjectAlive(T* object) |
- { |
- static_assert(sizeof(T), "T must be fully defined"); |
- return HeapObjectHeader::fromPayload(object)->isMarked(); |
- } |
-}; |
- |
-template<typename T> |
-class ObjectAliveTrait<T, true> { |
-public: |
- static bool isHeapObjectAlive(T* object) |
- { |
- static_assert(sizeof(T), "T must be fully defined"); |
- return object->isHeapObjectAlive(); |
- } |
-}; |
- |
-class PLATFORM_EXPORT Heap { |
-public: |
- static void init(); |
- static void shutdown(); |
- static void doShutdown(); |
- |
-#if ENABLE(ASSERT) || ENABLE(GC_PROFILING) |
- static BasePage* findPageFromAddress(Address); |
- static BasePage* findPageFromAddress(const void* pointer) { return findPageFromAddress(reinterpret_cast<Address>(const_cast<void*>(pointer))); } |
-#endif |
- |
- template<typename T> |
- static inline bool isHeapObjectAlive(T* object) |
- { |
- static_assert(sizeof(T), "T must be fully defined"); |
- // The strongification of collections relies on the fact that once a |
- // collection has been strongified, there is no way that it can contain |
- // non-live entries, so no entries will be removed. Since you can't set |
- // the mark bit on a null pointer, that means that null pointers are |
- // always 'alive'. |
- if (!object) |
- return true; |
- return ObjectAliveTrait<T>::isHeapObjectAlive(object); |
- } |
- template<typename T> |
- static inline bool isHeapObjectAlive(const Member<T>& member) |
- { |
- return isHeapObjectAlive(member.get()); |
- } |
- template<typename T> |
- static inline bool isHeapObjectAlive(const WeakMember<T>& member) |
- { |
- return isHeapObjectAlive(member.get()); |
- } |
- template<typename T> |
- static inline bool isHeapObjectAlive(const RawPtr<T>& ptr) |
- { |
- return isHeapObjectAlive(ptr.get()); |
- } |
- |
- // Is the finalizable GC object still alive, but slated for lazy sweeping? |
- // If a lazy sweep is in progress, returns true if the object was found |
- // to be not reachable during the marking phase, but it has yet to be swept |
- // and finalized. The predicate returns false in all other cases. |
- // |
- // Holding a reference to an already-dead object is not a valid state |
- // to be in; willObjectBeLazilySwept() has undefined behavior if passed |
- // such a reference. |
- template<typename T> |
- NO_LAZY_SWEEP_SANITIZE_ADDRESS |
- static bool willObjectBeLazilySwept(const T* objectPointer) |
- { |
- static_assert(IsGarbageCollectedType<T>::value, "only objects deriving from GarbageCollected can be used."); |
-#if ENABLE(LAZY_SWEEPING) |
- BasePage* page = pageFromObject(objectPointer); |
- if (page->hasBeenSwept()) |
- return false; |
- ASSERT(page->heap()->threadState()->isSweepingInProgress()); |
- |
- return !Heap::isHeapObjectAlive(const_cast<T*>(objectPointer)); |
-#else |
- return false; |
-#endif |
- } |
- |
- // Push a trace callback on the marking stack. |
- static void pushTraceCallback(void* containerObject, TraceCallback); |
- |
- // Push a trace callback on the post-marking callback stack. These |
- // callbacks are called after normal marking (including ephemeron |
- // iteration). |
- static void pushPostMarkingCallback(void*, TraceCallback); |
- |
- // Add a weak pointer callback to the weak callback work list. General |
- // object pointer callbacks are added to a thread local weak callback work |
- // list and the callback is called on the thread that owns the object, with |
- // the closure pointer as an argument. Most of the time, the closure and |
- // the containerObject can be the same thing, but the containerObject is |
- // constrained to be on the heap, since the heap is used to identify the |
- // correct thread. |
- static void pushThreadLocalWeakCallback(void* closure, void* containerObject, WeakCallback); |
- |
- // Similar to the more general pushThreadLocalWeakCallback, but cell |
- // pointer callbacks are added to a static callback work list and the weak |
- // callback is performed on the thread performing garbage collection. This |
- // is OK because cells are just cleared and no deallocation can happen. |
- static void pushGlobalWeakCallback(void** cell, WeakCallback); |
- |
- // Pop the top of a marking stack and call the callback with the visitor |
- // and the object. Returns false when there is nothing more to do. |
- static bool popAndInvokeTraceCallback(Visitor*); |
- |
- // Remove an item from the post-marking callback stack and call |
- // the callback with the visitor and the object pointer. Returns |
- // false when there is nothing more to do. |
- static bool popAndInvokePostMarkingCallback(Visitor*); |
- |
- // Remove an item from the weak callback work list and call the callback |
- // with the visitor and the closure pointer. Returns false when there is |
- // nothing more to do. |
- static bool popAndInvokeGlobalWeakCallback(Visitor*); |
- |
- // Register an ephemeron table for fixed-point iteration. |
- static void registerWeakTable(void* containerObject, EphemeronCallback, EphemeronCallback); |
-#if ENABLE(ASSERT) |
- static bool weakTableRegistered(const void*); |
-#endif |
- |
- static inline size_t allocationSizeFromSize(size_t size) |
- { |
- // Check the size before computing the actual allocation size. The |
- // allocation size calculation can overflow for large sizes and the check |
- // therefore has to happen before any calculation on the size. |
- RELEASE_ASSERT(size < maxHeapObjectSize); |
- |
- // Add space for header. |
- size_t allocationSize = size + sizeof(HeapObjectHeader); |
- // Align size with allocation granularity. |
- allocationSize = (allocationSize + allocationMask) & ~allocationMask; |
- return allocationSize; |
- } |
- static Address allocateOnHeapIndex(ThreadState*, size_t, int heapIndex, size_t gcInfoIndex); |
- template<typename T> static Address allocate(size_t, bool eagerlySweep = false); |
- template<typename T> static Address reallocate(void* previous, size_t); |
- |
- enum GCReason { |
- IdleGC, |
- PreciseGC, |
- ConservativeGC, |
- ForcedGC, |
- NumberOfGCReason |
- }; |
- static const char* gcReasonString(GCReason); |
- static void collectGarbage(ThreadState::StackState, ThreadState::GCType, GCReason); |
- static void collectGarbageForTerminatingThread(ThreadState*); |
- static void collectAllGarbage(); |
- |
- static void processMarkingStack(Visitor*); |
- static void postMarkingProcessing(Visitor*); |
- static void globalWeakProcessing(Visitor*); |
- static void setForcePreciseGCForTesting(); |
- |
- static void preGC(); |
- static void postGC(ThreadState::GCType); |
- |
- // Conservatively checks whether an address is a pointer in any of the |
- // thread heaps. If so marks the object pointed to as live. |
- static Address checkAndMarkPointer(Visitor*, Address); |
- |
-#if ENABLE(GC_PROFILING) |
- // Dump the path to specified object on the next GC. This method is to be |
- // invoked from GDB. |
- static void dumpPathToObjectOnNextGC(void* p); |
- |
- // Forcibly find GCInfo of the object at Address. This is slow and should |
- // only be used for debug purposes. It involves finding the heap page and |
- // scanning the heap page for an object header. |
- static const GCInfo* findGCInfo(Address); |
- |
- static String createBacktraceString(); |
-#endif |
- |
- static size_t objectPayloadSizeForTesting(); |
- |
- static void flushHeapDoesNotContainCache(); |
- |
- static FreePagePool* freePagePool() { return s_freePagePool; } |
- static OrphanedPagePool* orphanedPagePool() { return s_orphanedPagePool; } |
- |
- // This look-up uses the region search tree and a negative contains cache to |
- // provide an efficient mapping from arbitrary addresses to the containing |
- // heap-page if one exists. |
- static BasePage* lookup(Address); |
- static void addPageMemoryRegion(PageMemoryRegion*); |
- static void removePageMemoryRegion(PageMemoryRegion*); |
- |
- static const GCInfo* gcInfo(size_t gcInfoIndex) |
- { |
- ASSERT(gcInfoIndex >= 1); |
- ASSERT(gcInfoIndex < GCInfoTable::maxIndex); |
- ASSERT(s_gcInfoTable); |
- const GCInfo* info = s_gcInfoTable[gcInfoIndex]; |
- ASSERT(info); |
- return info; |
- } |
- |
- static void setMarkedObjectSizeAtLastCompleteSweep(size_t size) { releaseStore(&s_markedObjectSizeAtLastCompleteSweep, size); } |
- static size_t markedObjectSizeAtLastCompleteSweep() { return acquireLoad(&s_markedObjectSizeAtLastCompleteSweep); } |
- static void increaseAllocatedObjectSize(size_t delta) { atomicAdd(&s_allocatedObjectSize, static_cast<long>(delta)); } |
- static void decreaseAllocatedObjectSize(size_t delta) { atomicSubtract(&s_allocatedObjectSize, static_cast<long>(delta)); } |
- static size_t allocatedObjectSize() { return acquireLoad(&s_allocatedObjectSize); } |
- static void increaseMarkedObjectSize(size_t delta) { atomicAdd(&s_markedObjectSize, static_cast<long>(delta)); } |
- static size_t markedObjectSize() { return acquireLoad(&s_markedObjectSize); } |
- static void increaseAllocatedSpace(size_t delta) { atomicAdd(&s_allocatedSpace, static_cast<long>(delta)); } |
- static void decreaseAllocatedSpace(size_t delta) { atomicSubtract(&s_allocatedSpace, static_cast<long>(delta)); } |
- static size_t allocatedSpace() { return acquireLoad(&s_allocatedSpace); } |
- static size_t objectSizeAtLastGC() { return acquireLoad(&s_objectSizeAtLastGC); } |
- static void increasePersistentCount(size_t delta) { atomicAdd(&s_persistentCount, static_cast<long>(delta)); } |
- static void decreasePersistentCount(size_t delta) { atomicSubtract(&s_persistentCount, static_cast<long>(delta)); } |
- static size_t persistentCount() { return acquireLoad(&s_persistentCount); } |
- static size_t persistentCountAtLastGC() { return acquireLoad(&s_persistentCountAtLastGC); } |
- static void increaseCollectedPersistentCount(size_t delta) { atomicAdd(&s_collectedPersistentCount, static_cast<long>(delta)); } |
- static size_t collectedPersistentCount() { return acquireLoad(&s_collectedPersistentCount); } |
- static size_t partitionAllocSizeAtLastGC() { return acquireLoad(&s_partitionAllocSizeAtLastGC); } |
- |
- static double estimatedMarkingTime(); |
- static void reportMemoryUsageHistogram(); |
- static void reportMemoryUsageForTracing(); |
- |
-private: |
- // A RegionTree is a simple binary search tree of PageMemoryRegions sorted |
- // by base addresses. |
- class RegionTree { |
- public: |
- explicit RegionTree(PageMemoryRegion* region) : m_region(region), m_left(nullptr), m_right(nullptr) { } |
- ~RegionTree() |
- { |
- delete m_left; |
- delete m_right; |
- } |
- PageMemoryRegion* lookup(Address); |
- static void add(RegionTree*, RegionTree**); |
- static void remove(PageMemoryRegion*, RegionTree**); |
- private: |
- PageMemoryRegion* m_region; |
- RegionTree* m_left; |
- RegionTree* m_right; |
- }; |
- |
- // Reset counters that track live and allocated-since-last-GC sizes. |
- static void resetHeapCounters(); |
- |
- static int heapIndexForObjectSize(size_t); |
- static bool isNormalHeapIndex(int); |
- |
- static CallbackStack* s_markingStack; |
- static CallbackStack* s_postMarkingCallbackStack; |
- static CallbackStack* s_globalWeakCallbackStack; |
- static CallbackStack* s_ephemeronStack; |
- static HeapDoesNotContainCache* s_heapDoesNotContainCache; |
- static bool s_shutdownCalled; |
- static FreePagePool* s_freePagePool; |
- static OrphanedPagePool* s_orphanedPagePool; |
- static RegionTree* s_regionTree; |
- static size_t s_allocatedSpace; |
- static size_t s_allocatedObjectSize; |
- static size_t s_objectSizeAtLastGC; |
- static size_t s_markedObjectSize; |
- static size_t s_markedObjectSizeAtLastCompleteSweep; |
- static size_t s_persistentCount; |
- static size_t s_persistentCountAtLastGC; |
- static size_t s_collectedPersistentCount; |
- static size_t s_partitionAllocSizeAtLastGC; |
- static double s_estimatedMarkingTimePerByte; |
- |
- friend class ThreadState; |
-}; |
- |
-template<typename T> |
-struct IsEagerlyFinalizedType { |
-private: |
- typedef char YesType; |
- struct NoType { |
- char padding[8]; |
- }; |
- |
- template <typename U> static YesType checkMarker(typename U::IsEagerlyFinalizedMarker*); |
- template <typename U> static NoType checkMarker(...); |
- |
-public: |
- static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType); |
-}; |
- |
-template<typename T> class GarbageCollected { |
- WTF_MAKE_NONCOPYABLE(GarbageCollected); |
- |
- // For now direct allocation of arrays on the heap is not allowed. |
- void* operator new[](size_t size); |
- |
-#if OS(WIN) && COMPILER(MSVC) |
- // Due to some quirkiness in the MSVC compiler we have to provide |
- // the delete[] operator in the GarbageCollected subclasses as it |
- // is called when a class is exported in a DLL. |
-protected: |
- void operator delete[](void* p) |
- { |
- ASSERT_NOT_REACHED(); |
- } |
-#else |
- void operator delete[](void* p); |
-#endif |
- |
-public: |
- using GarbageCollectedBase = T; |
- |
- void* operator new(size_t size) |
- { |
- return allocateObject(size, IsEagerlyFinalizedType<T>::value); |
- } |
- |
- static void* allocateObject(size_t size, bool eagerlySweep) |
- { |
- return Heap::allocate<T>(size, eagerlySweep); |
- } |
- |
- void operator delete(void* p) |
- { |
- ASSERT_NOT_REACHED(); |
- } |
- |
-protected: |
- GarbageCollected() |
- { |
- } |
-}; |
- |
-// Assigning class types to their heaps. |
-// |
-// We use sized heaps for most 'normal' objects to improve memory locality. |
-// It seems that the same type of objects are likely to be accessed together, |
-// which means that we want to group objects by type. That's one reason |
-// why we provide dedicated heaps for popular types (e.g., Node, CSSValue), |
-// but it's not practical to prepare dedicated heaps for all types. |
-// Thus we group objects by their sizes, hoping that this will approximately |
-// group objects by their types. |
-// |
-// An exception to the use of sized heaps is made for class types that |
-// require prompt finalization after a garbage collection. That is, their |
-// instances have to be finalized early and cannot be delayed until lazy |
-// sweeping kicks in for their heap and page. The EAGERLY_FINALIZE() |
-// macro is used to declare a class (and its derived classes) as being |
-// in need of eager finalization. Must be defined with 'public' visibility |
-// for a class. |
-// |
- |
-inline int Heap::heapIndexForObjectSize(size_t size) |
-{ |
- if (size < 64) { |
- if (size < 32) |
- return ThreadState::NormalPage1HeapIndex; |
- return ThreadState::NormalPage2HeapIndex; |
- } |
- if (size < 128) |
- return ThreadState::NormalPage3HeapIndex; |
- return ThreadState::NormalPage4HeapIndex; |
-} |
- |
-inline bool Heap::isNormalHeapIndex(int index) |
-{ |
- return index >= ThreadState::NormalPage1HeapIndex && index <= ThreadState::NormalPage4HeapIndex; |
-} |
- |
-#define DECLARE_EAGER_FINALIZATION_OPERATOR_NEW() \ |
-public: \ |
- GC_PLUGIN_IGNORE("491488") \ |
- void* operator new(size_t size) \ |
- { \ |
- return allocateObject(size, true); \ |
- } |
- |
-#define IS_EAGERLY_FINALIZED() (pageFromObject(this)->heap()->heapIndex() == ThreadState::EagerSweepHeapIndex) |
-#if ENABLE(ASSERT) && ENABLE(OILPAN) |
-class VerifyEagerFinalization { |
-public: |
- ~VerifyEagerFinalization() |
- { |
- // If this assert triggers, the class annotated as eagerly |
- // finalized ended up not being allocated on the heap |
- // set aside for eager finalization. The reason is most |
- // likely that the effective 'operator new' overload for |
- // this class' leftmost base is for a class that is not |
- // eagerly finalized. Declaring and defining an 'operator new' |
- // for this class is what's required -- consider using |
- // DECLARE_EAGER_FINALIZATION_OPERATOR_NEW(). |
- ASSERT(IS_EAGERLY_FINALIZED()); |
- } |
-}; |
-#define EAGERLY_FINALIZE() \ |
-private: \ |
- VerifyEagerFinalization m_verifyEagerFinalization; \ |
-public: \ |
- typedef int IsEagerlyFinalizedMarker |
-#else |
-#define EAGERLY_FINALIZE() typedef int IsEagerlyFinalizedMarker |
-#endif |
- |
-#if !ENABLE(OILPAN) && ENABLE(LAZY_SWEEPING) |
-#define EAGERLY_FINALIZE_WILL_BE_REMOVED() EAGERLY_FINALIZE() |
-#else |
-#define EAGERLY_FINALIZE_WILL_BE_REMOVED() |
-#endif |
- |
NO_SANITIZE_ADDRESS inline |
size_t HeapObjectHeader::size() const |
{ |
@@ -1349,63 +936,6 @@ inline Address NormalPageHeap::allocateObject(size_t allocationSize, size_t gcIn |
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()); |
- ASSERT(heapIndex != ThreadState::LargeObjectHeapIndex); |
- NormalPageHeap* heap = static_cast<NormalPageHeap*>(state->heap(heapIndex)); |
- return heap->allocateObject(allocationSizeFromSize(size), gcInfoIndex); |
-} |
- |
-template<typename T> |
-Address Heap::allocate(size_t size, bool eagerlySweep) |
-{ |
- ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); |
- return Heap::allocateOnHeapIndex(state, size, eagerlySweep ? ThreadState::EagerSweepHeapIndex : Heap::heapIndexForObjectSize(size), GCInfoTrait<T>::index()); |
-} |
- |
-template<typename T> |
-Address Heap::reallocate(void* previous, size_t size) |
-{ |
- // Not intended to be a full C realloc() substitute; |
- // realloc(nullptr, size) is not a supported alias for malloc(size). |
- |
- // TODO(sof): promptly free the previous object. |
- if (!size) { |
- // If the new size is 0 this is considered equivalent to free(previous). |
- return nullptr; |
- } |
- |
- ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); |
- HeapObjectHeader* previousHeader = HeapObjectHeader::fromPayload(previous); |
- BasePage* page = pageFromObject(previousHeader); |
- ASSERT(page); |
- int heapIndex = page->heap()->heapIndex(); |
- // Recompute the effective heap index if previous allocation |
- // was on the normal heaps or a large object. |
- if (isNormalHeapIndex(heapIndex) || heapIndex == ThreadState::LargeObjectHeapIndex) |
- heapIndex = heapIndexForObjectSize(size); |
- |
- // TODO(haraken): We don't support reallocate() for finalizable objects. |
- ASSERT(!Heap::gcInfo(previousHeader->gcInfoIndex())->hasFinalizer()); |
- ASSERT(previousHeader->gcInfoIndex() == GCInfoTrait<T>::index()); |
- Address address = Heap::allocateOnHeapIndex(state, size, heapIndex, GCInfoTrait<T>::index()); |
- size_t copySize = previousHeader->payloadSize(); |
- if (copySize > size) |
- copySize = size; |
- memcpy(address, previous, copySize); |
- return address; |
-} |
- |
} // namespace blink |
-#endif // Heap_h |
+#endif // HeapPage_h |