Index: Source/platform/heap/Heap.cpp |
diff --git a/Source/platform/heap/Heap.cpp b/Source/platform/heap/Heap.cpp |
index a22210a99087c2470bffceac5fc53ca83faa6e46..01b16804b1e214ba49a8f086903e1898843cccef 100644 |
--- a/Source/platform/heap/Heap.cpp |
+++ b/Source/platform/heap/Heap.cpp |
@@ -131,6 +131,7 @@ public: |
WARN_UNUSED_RETURN bool commit() |
{ |
+ ASSERT(Heap::heapDoesNotContainCacheIsEmpty()); |
#if OS(POSIX) |
int err = mprotect(m_base, m_size, PROT_READ | PROT_WRITE); |
if (!err) { |
@@ -204,6 +205,7 @@ public: |
// unmap the excess memory before returning. |
size_t allocationSize = payloadSize + 2 * osPageSize() + blinkPageSize; |
+ ASSERT(Heap::heapDoesNotContainCacheIsEmpty()); |
#if OS(POSIX) |
Address base = static_cast<Address>(mmap(0, allocationSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)); |
RELEASE_ASSERT(base != MAP_FAILED); |
@@ -426,16 +428,15 @@ bool LargeHeapObject<Header>::isMarked() |
} |
template<typename Header> |
-bool LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
+void LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
{ |
- if (contains(address)) { |
+ ASSERT(contains(address)); |
+ if (!objectContains(address)) |
+ return; |
#if ENABLE(GC_TRACING) |
- visitor->setHostInfo(&address, "stack"); |
+ visitor->setHostInfo(&address, "stack"); |
#endif |
- mark(visitor); |
- return true; |
- } |
- return false; |
+ mark(visitor); |
} |
template<> |
@@ -558,13 +559,10 @@ BaseHeapPage* ThreadHeap<Header>::heapPageFromAddress(Address address) |
if (page->contains(address)) |
return page; |
} |
- return 0; |
-} |
- |
-template<typename Header> |
-BaseHeapPage* ThreadHeap<Header>::largeHeapObjectFromAddress(Address address) |
-{ |
for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) { |
+ // Check that large pages are blinkPageSize aligned (modulo the |
+ // osPageSize for the guard page). |
+ ASSERT(reinterpret_cast<Address>(current) - osPageSize() == roundToBlinkPageStart(reinterpret_cast<Address>(current))); |
if (current->contains(address)) |
return current; |
} |
@@ -584,16 +582,6 @@ const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address) |
#endif |
template<typename Header> |
-bool ThreadHeap<Header>::checkAndMarkLargeHeapObject(Visitor* visitor, Address address) |
-{ |
- for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) { |
- if (current->checkAndMarkPointer(visitor, address)) |
- return true; |
- } |
- return false; |
-} |
- |
-template<typename Header> |
void ThreadHeap<Header>::addToFreeList(Address address, size_t size) |
{ |
ASSERT(heapPageFromAddress(address)); |
@@ -647,6 +635,7 @@ Address ThreadHeap<Header>::allocateLargeObject(size_t size, const GCInfo* gcInf |
#endif |
if (threadState()->shouldGC()) |
threadState()->setGCRequested(); |
+ Heap::flushHeapDoesNotContainCache(); |
PageMemory* pageMemory = PageMemory::allocate(allocationSize); |
Address largeObjectAddress = pageMemory->writableStart(); |
Address headerAddress = largeObjectAddress + sizeof(LargeHeapObject<Header>) + headerPadding<Header>(); |
@@ -668,6 +657,7 @@ Address ThreadHeap<Header>::allocateLargeObject(size_t size, const GCInfo* gcInf |
template<typename Header> |
void ThreadHeap<Header>::freeLargeObject(LargeHeapObject<Header>* object, LargeHeapObject<Header>** previousNext) |
{ |
+ flushHeapContainsCache(); |
object->unlink(previousNext); |
object->finalize(); |
@@ -704,6 +694,7 @@ void ThreadHeap<Header>::clearPagePool() |
template<typename Header> |
PageMemory* ThreadHeap<Header>::takePageFromPool() |
{ |
+ Heap::flushHeapDoesNotContainCache(); |
while (PagePoolEntry* entry = m_pagePool) { |
m_pagePool = entry->next(); |
PageMemory* storage = entry->storage(); |
@@ -722,6 +713,7 @@ PageMemory* ThreadHeap<Header>::takePageFromPool() |
template<typename Header> |
void ThreadHeap<Header>::addPageToPool(HeapPage<Header>* unused) |
{ |
+ flushHeapContainsCache(); |
PageMemory* storage = unused->storage(); |
PagePoolEntry* entry = new PagePoolEntry(storage, m_pagePool); |
m_pagePool = entry; |
@@ -731,7 +723,7 @@ void ThreadHeap<Header>::addPageToPool(HeapPage<Header>* unused) |
template<typename Header> |
void ThreadHeap<Header>::allocatePage(const GCInfo* gcInfo) |
{ |
- heapContainsCache()->flush(); |
+ Heap::flushHeapDoesNotContainCache(); |
PageMemory* pageMemory = takePageFromPool(); |
if (!pageMemory) { |
pageMemory = PageMemory::allocate(blinkPagePayloadSize()); |
@@ -782,6 +774,7 @@ void ThreadHeap<Header>::sweep() |
bool pagesRemoved = false; |
while (page) { |
if (page->isEmpty()) { |
+ flushHeapContainsCache(); |
HeapPage<Header>* unused = page; |
page = page->next(); |
HeapPage<Header>::unlink(unused, previous); |
@@ -793,7 +786,7 @@ void ThreadHeap<Header>::sweep() |
} |
} |
if (pagesRemoved) |
- heapContainsCache()->flush(); |
+ flushHeapContainsCache(); |
LargeHeapObject<Header>** previousNext = &m_firstLargeHeapObject; |
for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current;) { |
@@ -867,7 +860,7 @@ void ThreadHeap<Header>::clearMarks() |
template<typename Header> |
void ThreadHeap<Header>::deletePages() |
{ |
- heapContainsCache()->flush(); |
+ flushHeapContainsCache(); |
// Add all pages in the pool to the heap's list of pages before deleting |
clearPagePool(); |
@@ -1079,11 +1072,12 @@ Header* HeapPage<Header>::findHeaderFromAddress(Address address) |
} |
template<typename Header> |
-bool HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
+void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
{ |
+ ASSERT(contains(address)); |
Header* header = findHeaderFromAddress(address); |
if (!header) |
- return false; |
+ return; |
#if ENABLE(GC_TRACING) |
visitor->setHostInfo(&address, "stack"); |
@@ -1092,7 +1086,6 @@ bool HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
visitor->markConservatively(header); |
else |
visitor->mark(header, traceCallback(header)); |
- return true; |
} |
#if ENABLE(GC_TRACING) |
@@ -1174,18 +1167,18 @@ void LargeHeapObject<Header>::getStats(HeapStats& stats) |
stats.increaseObjectSpace(payloadSize()); |
} |
-HeapContainsCache::HeapContainsCache() |
- : m_entries(adoptArrayPtr(new Entry[HeapContainsCache::numberOfEntries])) |
-{ |
-} |
- |
-void HeapContainsCache::flush() |
+template<typename Entry> |
+void HeapExtentCache<Entry>::flush() |
{ |
- for (int i = 0; i < numberOfEntries; i++) |
- m_entries[i] = Entry(); |
+ if (m_hasEntries) { |
+ for (int i = 0; i < numberOfEntries; i++) |
+ m_entries[i] = Entry(); |
+ m_hasEntries = false; |
+ } |
} |
-size_t HeapContainsCache::hash(Address address) |
+template<typename Entry> |
+size_t HeapExtentCache<Entry>::hash(Address address) |
{ |
size_t value = (reinterpret_cast<size_t>(address) >> blinkPageSizeLog2); |
value ^= value >> numberOfEntriesLog2; |
@@ -1194,31 +1187,46 @@ size_t HeapContainsCache::hash(Address address) |
return value & ~1; // Returns only even number. |
} |
-bool HeapContainsCache::lookup(Address address, BaseHeapPage** page) |
+template<typename Entry> |
+typename Entry::LookupResult HeapExtentCache<Entry>::lookup(Address address) |
{ |
- ASSERT(page); |
size_t index = hash(address); |
ASSERT(!(index & 1)); |
Address cachePage = roundToBlinkPageStart(address); |
- if (m_entries[index].address() == cachePage) { |
- *page = m_entries[index].containingPage(); |
- return true; |
- } |
- if (m_entries[index + 1].address() == cachePage) { |
- *page = m_entries[index + 1].containingPage(); |
- return true; |
- } |
- *page = 0; |
- return false; |
+ if (m_entries[index].address() == cachePage) |
+ return m_entries[index].result(); |
+ if (m_entries[index + 1].address() == cachePage) |
+ return m_entries[index + 1].result(); |
+ return 0; |
} |
-void HeapContainsCache::addEntry(Address address, BaseHeapPage* page) |
+template<typename Entry> |
+void HeapExtentCache<Entry>::addEntry(Address address, typename Entry::LookupResult entry) |
{ |
+ m_hasEntries = true; |
size_t index = hash(address); |
ASSERT(!(index & 1)); |
Address cachePage = roundToBlinkPageStart(address); |
m_entries[index + 1] = m_entries[index]; |
- m_entries[index] = Entry(cachePage, page); |
+ m_entries[index] = Entry(cachePage, entry); |
+} |
+ |
+// These should not be needed, but it seems impossible to persuade clang to |
+// instantiate the template functions and export them from a shared library, so |
+// we add these in the non-templated subclass, which does not have that issue. |
+void HeapContainsCache::addEntry(Address address, BaseHeapPage* page) |
+{ |
+ HeapExtentCache<PositiveEntry>::addEntry(address, page); |
+} |
+ |
+BaseHeapPage* HeapContainsCache::lookup(Address address) |
+{ |
+ return HeapExtentCache<PositiveEntry>::lookup(address); |
+} |
+ |
+void Heap::flushHeapDoesNotContainCache() |
+{ |
+ s_heapDoesNotContainCache->flush(); |
} |
void CallbackStack::init(CallbackStack** first) |
@@ -1492,6 +1500,7 @@ void Heap::init() |
ThreadState::init(); |
CallbackStack::init(&s_markingStack); |
CallbackStack::init(&s_weakCallbackStack); |
+ s_heapDoesNotContainCache = new HeapDoesNotContainCache(); |
s_markingVisitor = new MarkingVisitor(); |
} |
@@ -1511,6 +1520,8 @@ void Heap::doShutdown() |
ASSERT(!ThreadState::attachedThreads().size()); |
delete s_markingVisitor; |
s_markingVisitor = 0; |
+ delete s_heapDoesNotContainCache; |
+ s_heapDoesNotContainCache = 0; |
CallbackStack::shutdown(&s_weakCallbackStack); |
CallbackStack::shutdown(&s_markingStack); |
ThreadState::shutdown(); |
@@ -1531,16 +1542,28 @@ BaseHeapPage* Heap::contains(Address address) |
Address Heap::checkAndMarkPointer(Visitor* visitor, Address address) |
{ |
ASSERT(ThreadState::isAnyThreadInGC()); |
- if (!address) |
+ |
+#ifdef NDEBUG |
+ if (s_heapDoesNotContainCache->lookup(address)) |
return 0; |
+#endif |
ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads(); |
for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) { |
if ((*it)->checkAndMarkPointer(visitor, address)) { |
- // Pointer found and marked. |
+ // Pointer was in a page of that thread. If it actually pointed |
+ // into an object then that object was found and marked. |
+ ASSERT(!s_heapDoesNotContainCache->lookup(address)); |
return address; |
} |
} |
+ |
+#ifdef NDEBUG |
+ s_heapDoesNotContainCache->addEntry(address, true); |
+#else |
+ if (!s_heapDoesNotContainCache->lookup(address)) |
+ s_heapDoesNotContainCache->addEntry(address, true); |
+#endif |
return 0; |
} |
@@ -1701,5 +1724,6 @@ template class ThreadHeap<HeapObjectHeader>; |
Visitor* Heap::s_markingVisitor; |
CallbackStack* Heap::s_markingStack; |
CallbackStack* Heap::s_weakCallbackStack; |
+HeapDoesNotContainCache* Heap::s_heapDoesNotContainCache; |
bool Heap::s_shutdownCalled = false; |
} |