Index: Source/platform/heap/Heap.h |
diff --git a/Source/platform/heap/Heap.h b/Source/platform/heap/Heap.h |
index e464e89dcfb4c2596f1cc1f532ebc3f2c16f394c..3ed53923db6c589f346a340efd17fc424803eea7 100644 |
--- a/Source/platform/heap/Heap.h |
+++ b/Source/platform/heap/Heap.h |
@@ -88,6 +88,11 @@ 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; |
+} |
+ |
// 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. |
template<typename Header> |
@@ -134,17 +139,15 @@ public: |
ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
} |
- // Check if the given address could point to an object in 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. |
- // |
- // Returns true if the object was found and marked, returns false |
- // otherwise. |
+ // 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 bool checkAndMarkPointer(Visitor*, Address) = 0; |
+ virtual void checkAndMarkPointer(Visitor*, Address) = 0; |
#if ENABLE(GC_TRACING) |
virtual const GCInfo* findGCInfo(Address) = 0; |
@@ -154,6 +157,7 @@ public: |
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. |
@@ -185,11 +189,14 @@ public: |
COMPILE_ASSERT(!(sizeof(LargeHeapObject<Header>) & allocationMask), large_heap_object_header_misaligned); |
} |
- virtual bool checkAndMarkPointer(Visitor*, Address); |
+ virtual void checkAndMarkPointer(Visitor*, Address) OVERRIDE; |
+ virtual bool isLargeObject() OVERRIDE { return true; } |
#if ENABLE(GC_TRACING) |
- virtual const GCInfo* findGCInfo(Address) |
+ virtual const GCInfo* findGCInfo(Address address) |
{ |
+ if (!objectContains(address)) |
+ return 0; |
return gcInfo(); |
} |
#endif |
@@ -205,9 +212,19 @@ public: |
*previousNext = m_next; |
} |
+ // The LargeHeapObject pseudo-page contains one actual object. Determine |
+ // whether the pointer is within that object. |
+ bool objectContains(Address object) |
+ { |
+ return (payload() <= object) && (object < address() + size()); |
+ } |
+ |
+ // 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) |
{ |
- return (address() <= object) && (object <= (address() + size())); |
+ return roundToBlinkPageStart(address()) <= object && object < roundToBlinkPageEnd(address() + size()); |
} |
LargeHeapObject<Header>* next() |
@@ -236,7 +253,6 @@ public: |
void finalize(); |
private: |
- friend class Heap; |
friend class ThreadHeap<Header>; |
LargeHeapObject<Header>* m_next; |
@@ -439,10 +455,14 @@ public: |
bool isEmpty(); |
+ // 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) |
{ |
Address blinkPageStart = roundToBlinkPageStart(address()); |
- return blinkPageStart <= addr && (blinkPageStart + blinkPageSize) > addr; |
+ ASSERT(blinkPageStart = address() - osPageSize()); // Page is at aligned address plus guard page size. |
+ return blinkPageStart <= addr && addr < blinkPageStart + blinkPageSize; |
} |
HeapPage* next() { return m_next; } |
@@ -464,7 +484,7 @@ public: |
void sweep(); |
void clearObjectStartBitMap(); |
void finalize(Header*); |
- virtual bool checkAndMarkPointer(Visitor*, Address); |
+ virtual void checkAndMarkPointer(Visitor*, Address) OVERRIDE; |
#if ENABLE(GC_TRACING) |
const GCInfo* findGCInfo(Address) OVERRIDE; |
#endif |
@@ -488,77 +508,115 @@ protected: |
friend class ThreadHeap<Header>; |
}; |
-// A HeapContainsCache provides a fast way of taking an arbitrary |
+class AddressEntry { |
+public: |
+ AddressEntry() : m_address(0) { } |
+ |
+ explicit AddressEntry(Address address) : m_address(address) { } |
+ |
+ Address address() const { return m_address; } |
+ |
+private: |
+ Address m_address; |
+}; |
+ |
+class PositiveEntry : public AddressEntry { |
+public: |
+ PositiveEntry() |
+ : AddressEntry() |
+ , m_containingPage(0) |
+ { |
+ } |
+ |
+ PositiveEntry(Address address, BaseHeapPage* containingPage) |
+ : AddressEntry(address) |
+ , m_containingPage(containingPage) |
+ { |
+ } |
+ |
+ BaseHeapPage* result() const { return m_containingPage; } |
+ |
+ typedef BaseHeapPage* LookupResult; |
+ |
+private: |
+ BaseHeapPage* m_containingPage; |
+}; |
+ |
+class NegativeEntry : public AddressEntry { |
+public: |
+ NegativeEntry() : AddressEntry() { } |
+ |
+ NegativeEntry(Address address, bool) : AddressEntry(address) { } |
+ |
+ bool result() const { return true; } |
+ |
+ typedef bool LookupResult; |
+}; |
+ |
+// A HeapExtentCache provides a fast way of taking an arbitrary |
// pointer-sized word, and determining whether it can be interpreted |
// as a pointer to an area that is managed by the garbage collected |
// Blink heap. There is a cache of 'pages' that have previously been |
-// determined to be either wholly inside or wholly outside the |
-// heap. The size of these pages must be smaller than the allocation |
-// alignment of the heap pages. We determine on-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 ask the heap to determine |
-// the status of the pointer by iterating over all of the heap. The |
-// result is then cached in the two-way associative page cache. |
+// determined to be wholly inside the heap. The size of these pages must be |
+// smaller than the allocation alignment of the heap pages. We determine |
+// on-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 ask the heap |
+// to determine the status of the pointer by iterating over all of the heap. |
+// The result is then cached in the two-way associative page cache. |
// |
-// A HeapContainsCache is both a positive and negative |
-// cache. Therefore, it must be flushed both when new memory is added |
-// and when memory is removed from the Blink heap. |
-class HeapContainsCache { |
+// A HeapContainsCache is a positive cache. Therefore, it must be flushed when |
+// memory is removed from the Blink heap. The HeapDoesNotContainCache is a |
+// negative cache, so it must be flushed when memory is added to the heap. |
+template<typename Entry> |
+class HeapExtentCache { |
public: |
- HeapContainsCache(); |
+ HeapExtentCache() |
+ : m_entries(adoptArrayPtr(new Entry[HeapExtentCache::numberOfEntries])) |
+ , m_hasEntries(false) |
+ { |
+ } |
void flush(); |
bool contains(Address); |
+ bool isEmpty() { return !m_hasEntries; } |
// Perform a lookup in the cache. |
// |
- // If lookup returns false the argument address was not found in |
+ // If lookup returns null/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. In that case, the address is in the heap if the base |
- // heap page out parameter is different from 0 and is not in the |
- // heap if the base heap page out parameter is 0. |
- bool lookup(Address, BaseHeapPage**); |
- |
- // Add an entry to the cache. Use a 0 base heap page pointer to |
- // add a negative entry. |
- void addEntry(Address, BaseHeapPage*); |
- |
-private: |
- class Entry { |
- public: |
- Entry() |
- : m_address(0) |
- , m_containingPage(0) |
- { |
- } |
- |
- Entry(Address address, BaseHeapPage* containingPage) |
- : m_address(address) |
- , m_containingPage(containingPage) |
- { |
- } |
- |
- BaseHeapPage* containingPage() { return m_containingPage; } |
- Address address() { return m_address; } |
+ // If lookup returns true/a page, the argument address was found in the |
+ // cache. For the HeapContainsCache this means the address is in the heap. |
+ // For the HeapDoesNotContainCache this means the address is not in the |
+ // heap. |
+ PLATFORM_EXPORT typename Entry::LookupResult lookup(Address); |
- private: |
- Address m_address; |
- BaseHeapPage* m_containingPage; |
- }; |
+ // Add an entry to the cache. |
+ PLATFORM_EXPORT void addEntry(Address, typename Entry::LookupResult); |
+private: |
static const int numberOfEntriesLog2 = 12; |
static const int numberOfEntries = 1 << numberOfEntriesLog2; |
static size_t hash(Address); |
- WTF::OwnPtr<HeapContainsCache::Entry[]> m_entries; |
+ WTF::OwnPtr<Entry[]> m_entries; |
+ bool m_hasEntries; |
friend class ThreadState; |
}; |
+// Normally these would be typedefs instead of subclasses, but that makes them |
+// very hard to forward declare. |
+class HeapContainsCache : public HeapExtentCache<PositiveEntry> { |
+public: |
+ BaseHeapPage* lookup(Address); |
+ void addEntry(Address, BaseHeapPage*); |
+}; |
+ |
+class HeapDoesNotContainCache : public HeapExtentCache<NegativeEntry> { }; |
+ |
// 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 |
@@ -629,27 +687,10 @@ public: |
// page in this thread heap. |
virtual BaseHeapPage* heapPageFromAddress(Address) = 0; |
- // Find the large object in this thread heap containing the given |
- // address. Returns 0 if the address is not contained in any |
- // page in this thread heap. |
- virtual BaseHeapPage* largeHeapObjectFromAddress(Address) = 0; |
- |
#if ENABLE(GC_TRACING) |
virtual const GCInfo* findGCInfoOfLargeHeapObject(Address) = 0; |
#endif |
- // Check if the given address could point to an object in this |
- // heap. If so, find the start of that object and mark it using |
- // the given Visitor. |
- // |
- // Returns true if the object was found and marked, returns false |
- // otherwise. |
- // |
- // This is used during conservative stack scanning to |
- // conservatively mark all objects that could be referenced from |
- // the stack. |
- virtual bool checkAndMarkLargeHeapObject(Visitor*, Address) = 0; |
- |
// Sweep this part of the Blink heap. This finalizes dead objects |
// and builds freelists for all the unused memory. |
virtual void sweep() = 0; |
@@ -692,11 +733,9 @@ public: |
virtual ~ThreadHeap(); |
virtual BaseHeapPage* heapPageFromAddress(Address); |
- virtual BaseHeapPage* largeHeapObjectFromAddress(Address); |
#if ENABLE(GC_TRACING) |
virtual const GCInfo* findGCInfoOfLargeHeapObject(Address); |
#endif |
- virtual bool checkAndMarkLargeHeapObject(Visitor*, Address); |
virtual void sweep(); |
virtual void assertEmpty(); |
virtual void clearFreeLists(); |
@@ -710,7 +749,10 @@ public: |
ThreadState* threadState() { return m_threadState; } |
HeapStats& stats() { return m_threadState->stats(); } |
- HeapContainsCache* heapContainsCache() { return m_threadState->heapContainsCache(); } |
+ void flushHeapContainsCache() |
+ { |
+ m_threadState->heapContainsCache()->flush(); |
+ } |
inline Address allocate(size_t, const GCInfo*); |
void addToFreeList(Address, size_t); |
@@ -854,11 +896,17 @@ public: |
static bool isConsistentForGC(); |
static void makeConsistentForGC(); |
+ static void flushHeapDoesNotContainCache(); |
+ static bool heapDoesNotContainCacheIsEmpty() { return s_heapDoesNotContainCache->isEmpty(); } |
+ |
+private: |
static Visitor* s_markingVisitor; |
static CallbackStack* s_markingStack; |
static CallbackStack* s_weakCallbackStack; |
+ static HeapDoesNotContainCache* s_heapDoesNotContainCache; |
static bool s_shutdownCalled; |
+ friend class ThreadState; |
}; |
// The NoAllocationScope class is used in debug mode to catch unwanted |