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

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

Issue 393823003: Revert "Revert "[oilpan]: Make thread shutdown more robust."" (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 5 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/Handle.h ('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 d4d15bf4f54e7d54a7521d853c57ed60041d17db..6e3c70b8a6155ac7a2ce0a496bb68cc9e4fa2326 100644
--- a/Source/platform/heap/Heap.h
+++ b/Source/platform/heap/Heap.h
@@ -69,10 +69,25 @@ const size_t maxHeapObjectSize = 1 << 27;
const size_t markBitMask = 1;
const size_t freeListMask = 2;
-const size_t debugBitMask = 4;
+// 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 deadBitMask = 4;
const size_t sizeMask = ~7;
const uint8_t freelistZapValue = 42;
const uint8_t finalizedZapValue = 24;
+// The orphaned zap value must be zero in the lowest bits to allow for using
+// the mark bit when tracing.
+const uint8_t orphanedZapValue = 240;
+
+enum CallbackInvocationMode {
+ GlobalMarking,
+ ThreadLocalMarking,
+ WeaknessProcessing,
+};
class HeapStats;
class PageMemory;
@@ -127,60 +142,16 @@ inline bool isPageHeaderAddress(Address address)
}
#endif
-// Mask an address down to the enclosing oilpan heap page base address.
+// Mask an address down to the enclosing oilpan heap base page.
// All oilpan heap pages are aligned at blinkPageBase plus an OS page 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 Address pageHeaderAddress(Address address)
+PLATFORM_EXPORT inline BaseHeapPage* pageHeaderFromObject(const void* object)
{
- return blinkPageAddress(address) + osPageSize();
+ Address address = reinterpret_cast<Address>(const_cast<void*>(object));
+ return reinterpret_cast<BaseHeapPage*>(blinkPageAddress(address) + osPageSize());
}
-// Common header for heap pages.
-class BaseHeapPage {
-public:
- BaseHeapPage(PageMemory* storage, const GCInfo* gcInfo, ThreadState* state)
- : m_storage(storage)
- , m_gcInfo(gcInfo)
- , m_threadState(state)
- , m_padding(0)
- {
- ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this)));
- }
-
- // 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;
-
-#if ENABLE(GC_TRACING)
- virtual const GCInfo* findGCInfo(Address) = 0;
-#endif
-
- Address address() { return reinterpret_cast<Address>(this); }
- PageMemory* storage() const { return m_storage; }
- ThreadState* threadState() const { return m_threadState; }
- const GCInfo* gcInfo() { return m_gcInfo; }
- virtual bool isLargeObject() { return false; }
-
-private:
- // Accessor to silence unused warnings for the m_padding field.
- intptr_t padding() const { return m_padding; }
-
- PageMemory* m_storage;
- const GCInfo* m_gcInfo;
- ThreadState* m_threadState;
- // Pointer sized integer to ensure proper alignment of the
- // HeapPage header. This can be used as a bit field if we need
- // to associate more information with pages.
- intptr_t m_padding;
-};
-
// Large allocations are allocated as separate objects and linked in a
// list.
//
@@ -232,7 +203,7 @@ public:
// 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 object)
+ virtual bool contains(Address object) OVERRIDE
{
return roundToBlinkPageStart(address()) <= object && object < roundToBlinkPageEnd(address() + size());
}
@@ -261,6 +232,14 @@ public:
void getStats(HeapStats&);
void mark(Visitor*);
void finalize();
+ void setDeadMark();
+ virtual void markOrphaned()
+ {
+ // Zap the payload with a recognizable value to detect any incorrect
+ // cross thread pointer usage.
+ memset(payload(), orphanedZapValue, payloadSize());
+ BaseHeapPage::markOrphaned();
+ }
private:
friend class ThreadHeap<Header>;
@@ -329,9 +308,9 @@ public:
inline size_t payloadSize();
inline Address payloadEnd();
- inline void setDebugMark();
- inline void clearDebugMark();
- inline bool hasDebugMark() const;
+ inline void setDeadMark();
+ inline void clearDeadMark();
+ inline bool hasDeadMark() 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
@@ -468,7 +447,7 @@ public:
// 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 addr)
+ virtual bool contains(Address addr) OVERRIDE
{
Address blinkPageStart = roundToBlinkPageStart(address());
ASSERT(blinkPageStart == address() - osPageSize()); // Page is at aligned address plus guard page size.
@@ -490,7 +469,7 @@ public:
Address end() { return payload() + payloadSize(); }
void getStats(HeapStats&);
- void clearMarks();
+ void clearLiveAndMarkDead();
void sweep();
void clearObjectStartBitMap();
void finalize(Header*);
@@ -502,6 +481,22 @@ public:
#if defined(ADDRESS_SANITIZER)
void poisonUnmarkedObjects();
#endif
+ NO_SANITIZE_ADDRESS
+ virtual void markOrphaned()
+ {
+ // Zap the payload with a recognizable value to detect any incorrect
+ // cross thread pointer usage.
+#if defined(ADDRESS_SANITIZER)
+ // Don't use memset when running with ASan since this needs to zap
+ // poisoned memory as well and the NO_SANITIZE_ADDRESS annotation
+ // only works for code in this method and not for calls to memset.
+ for (Address current = payload(); current < payload() + payloadSize(); ++current)
+ *current = orphanedZapValue;
+#else
+ memset(payload(), orphanedZapValue, payloadSize());
+#endif
+ BaseHeapPage::markOrphaned();
+ }
protected:
Header* findHeaderFromAddress(Address);
@@ -677,6 +672,55 @@ private:
mutable Mutex m_mutex;
};
+template<typename DataType>
+class PagePool {
+protected:
+ PagePool();
+
+ class PoolEntry {
+ public:
+ PoolEntry(DataType* data, PoolEntry* next)
+ : data(data)
+ , next(next)
+ { }
+
+ DataType* data;
+ PoolEntry* next;
+ };
+
+ PoolEntry* m_pool[NumberOfHeaps];
+};
+
+// Once pages have been used for one type of thread heap they will never be
+// reused for another type of thread heap. Instead of unmapping, we add the
+// pages to a pool of pages to be reused later by a thread heap of the same
+// type. This is done as a security feature to avoid type confusion. The
+// heaps are type segregated by having separate thread heaps for different
+// types of objects. Holding on to pages ensures that the same virtual address
+// space cannot be used for objects of another type than the type contained
+// in this page to begin with.
+class FreePagePool : public PagePool<PageMemory> {
+public:
+ ~FreePagePool();
+ void addFreePage(int, PageMemory*);
+ PageMemory* takeFreePage(int);
+
+private:
+ Mutex m_mutex[NumberOfHeaps];
+};
+
+class OrphanedPagePool : public PagePool<BaseHeapPage> {
+public:
+ ~OrphanedPagePool();
+ void addOrphanedPage(int, BaseHeapPage*);
+ void decommitOrphanedPages();
+#ifndef NDEBUG
+ bool contains(void*);
+#endif
+private:
+ void clearMemory(PageMemory*);
+};
+
// The CallbackStack contains all the visitor callbacks used to trace and mark
// objects. A specific CallbackStack instance contains at most bufferSize elements.
// If more space is needed a new CallbackStack instance is created and chained
@@ -727,7 +771,7 @@ public:
init(first);
}
}
- bool popAndInvokeCallback(CallbackStack** first, Visitor*);
+ template<CallbackInvocationMode Mode> bool popAndInvokeCallback(CallbackStack** first, Visitor*);
static void invokeCallbacks(CallbackStack** first, Visitor*);
Item* allocateEntry(CallbackStack** first)
@@ -755,6 +799,7 @@ private:
class BaseHeap {
public:
virtual ~BaseHeap() { }
+ virtual void cleanupPages() = 0;
// Find the page in this thread heap containing the given
// address. Returns 0 if the address is not contained in any
@@ -769,14 +814,8 @@ public:
// and builds freelists for all the unused memory.
virtual void sweep() = 0;
- // Forcefully finalize all objects in this part of the Blink heap
- // (potentially with the exception of one object). This is used
- // during thread termination to make sure that all objects for the
- // dying thread are finalized.
- virtual void assertEmpty() = 0;
-
virtual void clearFreeLists() = 0;
- virtual void clearMarks() = 0;
+ virtual void clearLiveAndMarkDead() = 0;
#ifndef NDEBUG
virtual void getScannedStats(HeapStats&) = 0;
#endif
@@ -784,6 +823,8 @@ public:
virtual void makeConsistentForGC() = 0;
virtual bool isConsistentForGC() = 0;
+ virtual void prepareHeapForTermination() = 0;
+
// Returns a bucket number for inserting a FreeListEntry of a
// given size. All FreeListEntries in the given bucket, n, have
// size >= 2^n.
@@ -803,17 +844,17 @@ public:
template<typename Header>
class ThreadHeap : public BaseHeap {
public:
- ThreadHeap(ThreadState*);
+ ThreadHeap(ThreadState*, int);
virtual ~ThreadHeap();
+ virtual void cleanupPages();
virtual BaseHeapPage* heapPageFromAddress(Address);
#if ENABLE(GC_TRACING)
virtual const GCInfo* findGCInfoOfLargeHeapObject(Address);
#endif
virtual void sweep();
- virtual void assertEmpty();
virtual void clearFreeLists();
- virtual void clearMarks();
+ virtual void clearLiveAndMarkDead();
#ifndef NDEBUG
virtual void getScannedStats(HeapStats&);
#endif
@@ -830,41 +871,18 @@ public:
inline Address allocate(size_t, const GCInfo*);
void addToFreeList(Address, size_t);
- void addPageMemoryToPool(PageMemory*);
- void addPageToPool(HeapPage<Header>*);
inline static size_t roundedAllocationSize(size_t size)
{
return allocationSizeFromSize(size) - sizeof(Header);
}
-private:
- // Once pages have been used for one thread heap they will never
- // be reused for another thread heap. Instead of unmapping, we add
- // the pages to a pool of pages to be reused later by this thread
- // heap. This is done as a security feature to avoid type
- // confusion. The heap is type segregated by having separate
- // thread heaps for various types of objects. Holding on to pages
- // ensures that the same virtual address space cannot be used for
- // objects of another type than the type contained in this thread
- // heap.
- class PagePoolEntry {
- public:
- PagePoolEntry(PageMemory* storage, PagePoolEntry* next)
- : m_storage(storage)
- , m_next(next)
- { }
-
- PageMemory* storage() { return m_storage; }
- PagePoolEntry* next() { return m_next; }
-
- private:
- PageMemory* m_storage;
- PagePoolEntry* m_next;
- };
+ void prepareHeapForTermination();
+ void removePageFromHeap(HeapPage<Header>*);
+private:
+ void addPageToHeap(const GCInfo*);
PLATFORM_EXPORT Address outOfLineAllocate(size_t, const GCInfo*);
static size_t allocationSizeFromSize(size_t);
- void addPageToHeap(const GCInfo*);
PLATFORM_EXPORT Address allocateLargeObject(size_t, const GCInfo*);
Address currentAllocationPoint() const { return m_currentAllocationPoint; }
size_t remainingAllocationSize() const { return m_remainingAllocationSize; }
@@ -880,11 +898,7 @@ private:
bool allocateFromFreeList(size_t);
void freeLargeObject(LargeHeapObject<Header>*, LargeHeapObject<Header>**);
-
void allocatePage(const GCInfo*);
- PageMemory* takePageFromPool();
- void clearPagePool();
- void deletePages();
Address m_currentAllocationPoint;
size_t m_remainingAllocationSize;
@@ -898,9 +912,9 @@ private:
// All FreeListEntries in the nth list have size >= 2^n.
FreeListEntry* m_freeLists[blinkPageSizeLog2];
- // List of pages that have been previously allocated, but are now
- // unused.
- PagePoolEntry* m_pagePool;
+ // 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 Heap {
@@ -912,6 +926,9 @@ public:
static BaseHeapPage* contains(Address);
static BaseHeapPage* contains(void* pointer) { return contains(reinterpret_cast<Address>(pointer)); }
static BaseHeapPage* contains(const void* pointer) { return contains(const_cast<void*>(pointer)); }
+#ifndef NDEBUG
+ static bool containedInHeapOrOrphanedPage(void*);
+#endif
// Push a trace callback on the marking stack.
static void pushTraceCallback(void* containerObject, TraceCallback);
@@ -933,7 +950,7 @@ public:
// Pop the top of the 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*);
+ template<CallbackInvocationMode Mode> static bool popAndInvokeTraceCallback(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
@@ -950,7 +967,9 @@ public:
template<typename T> static Address reallocate(void* previous, size_t);
static void collectGarbage(ThreadState::StackState);
+ static void collectGarbageForTerminatingThread(ThreadState*);
static void collectAllGarbage();
+ template<CallbackInvocationMode Mode> static void traceRootsAndPerformGlobalWeakProcessing();
static void setForcePreciseGCForTesting();
static void prepareForGC();
@@ -988,6 +1007,9 @@ public:
// during conservative scanning.
static bool lastGCWasConservative() { return s_lastGCWasConservative; }
+ static FreePagePool* freePagePool() { return s_freePagePool; }
+ static OrphanedPagePool* orphanedPagePool() { return s_orphanedPagePool; }
+
private:
static Visitor* s_markingVisitor;
@@ -997,6 +1019,8 @@ private:
static HeapDoesNotContainCache* s_heapDoesNotContainCache;
static bool s_shutdownCalled;
static bool s_lastGCWasConservative;
+ static FreePagePool* s_freePagePool;
+ static OrphanedPagePool* s_orphanedPagePool;
friend class ThreadState;
};
@@ -1303,7 +1327,10 @@ T* adoptRefCountedGarbageCollected(T* ptr)
NO_SANITIZE_ADDRESS
void HeapObjectHeader::checkHeader() const
{
- ASSERT(m_magic == magic);
+#ifndef NDEBUG
+ BaseHeapPage* page = pageHeaderFromObject(this);
+ ASSERT(page->orphaned() || m_magic == magic);
+#endif
}
Address HeapObjectHeader::payload()
« no previous file with comments | « Source/platform/heap/Handle.h ('k') | Source/platform/heap/Heap.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698