| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 : m_firstPage(nullptr), | 109 : m_firstPage(nullptr), |
| 110 m_firstUnsweptPage(nullptr), | 110 m_firstUnsweptPage(nullptr), |
| 111 m_threadState(state), | 111 m_threadState(state), |
| 112 m_index(index) {} | 112 m_index(index) {} |
| 113 | 113 |
| 114 BaseArena::~BaseArena() { | 114 BaseArena::~BaseArena() { |
| 115 ASSERT(!m_firstPage); | 115 ASSERT(!m_firstPage); |
| 116 ASSERT(!m_firstUnsweptPage); | 116 ASSERT(!m_firstUnsweptPage); |
| 117 } | 117 } |
| 118 | 118 |
| 119 void BaseArena::cleanupPages() { | 119 void BaseArena::removeAllPages() { |
| 120 clearFreeLists(); | 120 clearFreeLists(); |
| 121 | 121 |
| 122 ASSERT(!m_firstUnsweptPage); | 122 ASSERT(!m_firstUnsweptPage); |
| 123 // Add the BaseArena's pages to the orphanedPagePool. | 123 while (m_firstPage) { |
| 124 for (BasePage* page = m_firstPage; page; page = page->next()) { | 124 BasePage* page = m_firstPage; |
| 125 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()); | 125 page->unlink(&m_firstPage); |
| 126 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage( | 126 page->removeFromHeap(); |
| 127 arenaIndex(), page); | |
| 128 } | 127 } |
| 129 m_firstPage = nullptr; | |
| 130 } | 128 } |
| 131 | 129 |
| 132 void BaseArena::takeSnapshot(const String& dumpBaseName, | 130 void BaseArena::takeSnapshot(const String& dumpBaseName, |
| 133 ThreadState::GCSnapshotInfo& info) { | 131 ThreadState::GCSnapshotInfo& info) { |
| 134 // |dumpBaseName| at this point is "blink_gc/thread_X/heaps/HeapName" | 132 // |dumpBaseName| at this point is "blink_gc/thread_X/heaps/HeapName" |
| 135 base::trace_event::MemoryAllocatorDump* allocatorDump = | 133 base::trace_event::MemoryAllocatorDump* allocatorDump = |
| 136 BlinkGCMemoryDumpProvider::instance() | 134 BlinkGCMemoryDumpProvider::instance() |
| 137 ->createMemoryAllocatorDumpForCurrentGC(dumpBaseName); | 135 ->createMemoryAllocatorDumpForCurrentGC(dumpBaseName); |
| 138 size_t pageCount = 0; | 136 size_t pageCount = 0; |
| 139 BasePage::HeapSnapshotInfo heapInfo; | 137 BasePage::HeapSnapshotInfo heapInfo; |
| (...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 for (size_t i = 0; i < page->payloadSize(); i++) | 648 for (size_t i = 0; i < page->payloadSize(); i++) |
| 651 address[i] = reuseAllowedZapValue; | 649 address[i] = reuseAllowedZapValue; |
| 652 ASAN_POISON_MEMORY_REGION(page->payload(), page->payloadSize()); | 650 ASAN_POISON_MEMORY_REGION(page->payload(), page->payloadSize()); |
| 653 #endif | 651 #endif |
| 654 addToFreeList(page->payload(), page->payloadSize()); | 652 addToFreeList(page->payload(), page->payloadSize()); |
| 655 } | 653 } |
| 656 | 654 |
| 657 void NormalPageArena::freePage(NormalPage* page) { | 655 void NormalPageArena::freePage(NormalPage* page) { |
| 658 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()); | 656 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()); |
| 659 | 657 |
| 660 if (page->terminating()) { | 658 PageMemory* memory = page->storage(); |
| 661 // The thread is shutting down and this page is being removed as a part | 659 page->~NormalPage(); |
| 662 // of the thread local GC. In that case the object could be traced in | 660 getThreadState()->heap().getFreePagePool()->addFreePage(arenaIndex(), memory); |
| 663 // the next global GC if there is a dangling pointer from a live thread | |
| 664 // heap to this dead thread heap. To guard against this, we put the | |
| 665 // page into the orphaned page pool and zap the page memory. This | |
| 666 // ensures that tracing the dangling pointer in the next global GC just | |
| 667 // crashes instead of causing use-after-frees. After the next global | |
| 668 // GC, the orphaned pages are removed. | |
| 669 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage( | |
| 670 arenaIndex(), page); | |
| 671 } else { | |
| 672 PageMemory* memory = page->storage(); | |
| 673 page->~NormalPage(); | |
| 674 getThreadState()->heap().getFreePagePool()->addFreePage(arenaIndex(), | |
| 675 memory); | |
| 676 } | |
| 677 } | 661 } |
| 678 | 662 |
| 679 bool NormalPageArena::coalesce() { | 663 bool NormalPageArena::coalesce() { |
| 680 // Don't coalesce arenas if there are not enough promptly freed entries | 664 // Don't coalesce arenas if there are not enough promptly freed entries |
| 681 // to be coalesced. | 665 // to be coalesced. |
| 682 // | 666 // |
| 683 // FIXME: This threshold is determined just to optimize blink_perf | 667 // FIXME: This threshold is determined just to optimize blink_perf |
| 684 // benchmarks. Coalescing is very sensitive to the threashold and | 668 // benchmarks. Coalescing is very sensitive to the threashold and |
| 685 // we need further investigations on the coalescing scheme. | 669 // we need further investigations on the coalescing scheme. |
| 686 if (m_promptlyFreedSize < 1024 * 1024) | 670 if (m_promptlyFreedSize < 1024 * 1024) |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 object->payloadSize()); | 1032 object->payloadSize()); |
| 1049 getThreadState()->heap().heapStats().decreaseAllocatedSpace(object->size()); | 1033 getThreadState()->heap().heapStats().decreaseAllocatedSpace(object->size()); |
| 1050 | 1034 |
| 1051 // Unpoison the object header and allocationGranularity bytes after the | 1035 // Unpoison the object header and allocationGranularity bytes after the |
| 1052 // object before freeing. | 1036 // object before freeing. |
| 1053 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), | 1037 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), |
| 1054 sizeof(HeapObjectHeader)); | 1038 sizeof(HeapObjectHeader)); |
| 1055 ASAN_UNPOISON_MEMORY_REGION(object->getAddress() + object->size(), | 1039 ASAN_UNPOISON_MEMORY_REGION(object->getAddress() + object->size(), |
| 1056 allocationGranularity); | 1040 allocationGranularity); |
| 1057 | 1041 |
| 1058 if (object->terminating()) { | 1042 PageMemory* memory = object->storage(); |
| 1059 ASSERT(ThreadState::current()->isTerminating()); | 1043 object->~LargeObjectPage(); |
| 1060 // The thread is shutting down and this page is being removed as a part | 1044 delete memory; |
| 1061 // of the thread local GC. In that case the object could be traced in | |
| 1062 // the next global GC if there is a dangling pointer from a live thread | |
| 1063 // heap to this dead thread heap. To guard against this, we put the | |
| 1064 // page into the orphaned page pool and zap the page memory. This | |
| 1065 // ensures that tracing the dangling pointer in the next global GC just | |
| 1066 // crashes instead of causing use-after-frees. After the next global | |
| 1067 // GC, the orphaned pages are removed. | |
| 1068 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage( | |
| 1069 arenaIndex(), object); | |
| 1070 } else { | |
| 1071 ASSERT(!ThreadState::current()->isTerminating()); | |
| 1072 PageMemory* memory = object->storage(); | |
| 1073 object->~LargeObjectPage(); | |
| 1074 delete memory; | |
| 1075 } | |
| 1076 } | 1045 } |
| 1077 | 1046 |
| 1078 Address LargeObjectArena::lazySweepPages(size_t allocationSize, | 1047 Address LargeObjectArena::lazySweepPages(size_t allocationSize, |
| 1079 size_t gcInfoIndex) { | 1048 size_t gcInfoIndex) { |
| 1080 Address result = nullptr; | 1049 Address result = nullptr; |
| 1081 size_t sweptSize = 0; | 1050 size_t sweptSize = 0; |
| 1082 while (m_firstUnsweptPage) { | 1051 while (m_firstUnsweptPage) { |
| 1083 BasePage* page = m_firstUnsweptPage; | 1052 BasePage* page = m_firstUnsweptPage; |
| 1084 if (page->isEmpty()) { | 1053 if (page->isEmpty()) { |
| 1085 sweptSize += static_cast<LargeObjectPage*>(page)->payloadSize() + | 1054 sweptSize += static_cast<LargeObjectPage*>(page)->payloadSize() + |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1271 | 1240 |
| 1272 BasePage::BasePage(PageMemory* storage, BaseArena* arena) | 1241 BasePage::BasePage(PageMemory* storage, BaseArena* arena) |
| 1273 : m_storage(storage), | 1242 : m_storage(storage), |
| 1274 m_arena(arena), | 1243 m_arena(arena), |
| 1275 m_next(nullptr), | 1244 m_next(nullptr), |
| 1276 m_terminating(false), | 1245 m_terminating(false), |
| 1277 m_swept(true) { | 1246 m_swept(true) { |
| 1278 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | 1247 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 1279 } | 1248 } |
| 1280 | 1249 |
| 1281 void BasePage::markOrphaned() { | |
| 1282 m_arena = nullptr; | |
| 1283 m_terminating = false; | |
| 1284 // Since we zap the page payload for orphaned pages we need to mark it as | |
| 1285 // unused so a conservative pointer won't interpret the object headers. | |
| 1286 storage()->markUnused(); | |
| 1287 } | |
| 1288 | |
| 1289 NormalPage::NormalPage(PageMemory* storage, BaseArena* arena) | 1250 NormalPage::NormalPage(PageMemory* storage, BaseArena* arena) |
| 1290 : BasePage(storage, arena), m_objectStartBitMapComputed(false) { | 1251 : BasePage(storage, arena), m_objectStartBitMapComputed(false) { |
| 1291 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | 1252 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 1292 } | 1253 } |
| 1293 | 1254 |
| 1294 size_t NormalPage::objectPayloadSizeForTesting() { | 1255 size_t NormalPage::objectPayloadSizeForTesting() { |
| 1295 size_t objectPayloadSize = 0; | 1256 size_t objectPayloadSize = 0; |
| 1296 Address headerAddress = payload(); | 1257 Address headerAddress = payload(); |
| 1297 markAsSwept(); | 1258 markAsSwept(); |
| 1298 ASSERT(headerAddress != payloadEnd()); | 1259 ASSERT(headerAddress != payloadEnd()); |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1670 MarkedPointerCallbackForTesting callback) { | 1631 MarkedPointerCallbackForTesting callback) { |
| 1671 DCHECK(contains(address)); | 1632 DCHECK(contains(address)); |
| 1672 HeapObjectHeader* header = findHeaderFromAddress(address); | 1633 HeapObjectHeader* header = findHeaderFromAddress(address); |
| 1673 if (!header) | 1634 if (!header) |
| 1674 return; | 1635 return; |
| 1675 if (!callback(header)) | 1636 if (!callback(header)) |
| 1676 markPointer(visitor, header); | 1637 markPointer(visitor, header); |
| 1677 } | 1638 } |
| 1678 #endif | 1639 #endif |
| 1679 | 1640 |
| 1680 void NormalPage::markOrphaned() { | |
| 1681 // Zap the payload with a recognizable value to detect any incorrect | |
| 1682 // cross thread pointer usage. | |
| 1683 #if defined(ADDRESS_SANITIZER) | |
| 1684 // This needs to zap poisoned memory as well. | |
| 1685 // Force unpoison memory before memset. | |
| 1686 ASAN_UNPOISON_MEMORY_REGION(payload(), payloadSize()); | |
| 1687 #endif | |
| 1688 OrphanedPagePool::asanDisabledMemset( | |
| 1689 payload(), OrphanedPagePool::orphanedZapValue, payloadSize()); | |
| 1690 BasePage::markOrphaned(); | |
| 1691 } | |
| 1692 | |
| 1693 void NormalPage::takeSnapshot(base::trace_event::MemoryAllocatorDump* pageDump, | 1641 void NormalPage::takeSnapshot(base::trace_event::MemoryAllocatorDump* pageDump, |
| 1694 ThreadState::GCSnapshotInfo& info, | 1642 ThreadState::GCSnapshotInfo& info, |
| 1695 HeapSnapshotInfo& heapInfo) { | 1643 HeapSnapshotInfo& heapInfo) { |
| 1696 HeapObjectHeader* header = nullptr; | 1644 HeapObjectHeader* header = nullptr; |
| 1697 size_t liveCount = 0; | 1645 size_t liveCount = 0; |
| 1698 size_t deadCount = 0; | 1646 size_t deadCount = 0; |
| 1699 size_t freeCount = 0; | 1647 size_t freeCount = 0; |
| 1700 size_t liveSize = 0; | 1648 size_t liveSize = 0; |
| 1701 size_t deadSize = 0; | 1649 size_t deadSize = 0; |
| 1702 size_t freeSize = 0; | 1650 size_t freeSize = 0; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1801 Address address, | 1749 Address address, |
| 1802 MarkedPointerCallbackForTesting callback) { | 1750 MarkedPointerCallbackForTesting callback) { |
| 1803 DCHECK(contains(address)); | 1751 DCHECK(contains(address)); |
| 1804 if (!containedInObjectPayload(address)) | 1752 if (!containedInObjectPayload(address)) |
| 1805 return; | 1753 return; |
| 1806 if (!callback(heapObjectHeader())) | 1754 if (!callback(heapObjectHeader())) |
| 1807 markPointer(visitor, heapObjectHeader()); | 1755 markPointer(visitor, heapObjectHeader()); |
| 1808 } | 1756 } |
| 1809 #endif | 1757 #endif |
| 1810 | 1758 |
| 1811 void LargeObjectPage::markOrphaned() { | |
| 1812 // Zap the payload with a recognizable value to detect any incorrect | |
| 1813 // cross thread pointer usage. | |
| 1814 OrphanedPagePool::asanDisabledMemset( | |
| 1815 payload(), OrphanedPagePool::orphanedZapValue, payloadSize()); | |
| 1816 BasePage::markOrphaned(); | |
| 1817 } | |
| 1818 | |
| 1819 void LargeObjectPage::takeSnapshot( | 1759 void LargeObjectPage::takeSnapshot( |
| 1820 base::trace_event::MemoryAllocatorDump* pageDump, | 1760 base::trace_event::MemoryAllocatorDump* pageDump, |
| 1821 ThreadState::GCSnapshotInfo& info, | 1761 ThreadState::GCSnapshotInfo& info, |
| 1822 HeapSnapshotInfo&) { | 1762 HeapSnapshotInfo&) { |
| 1823 size_t liveSize = 0; | 1763 size_t liveSize = 0; |
| 1824 size_t deadSize = 0; | 1764 size_t deadSize = 0; |
| 1825 size_t liveCount = 0; | 1765 size_t liveCount = 0; |
| 1826 size_t deadCount = 0; | 1766 size_t deadCount = 0; |
| 1827 HeapObjectHeader* header = heapObjectHeader(); | 1767 HeapObjectHeader* header = heapObjectHeader(); |
| 1828 size_t gcInfoIndex = header->gcInfoIndex(); | 1768 size_t gcInfoIndex = header->gcInfoIndex(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1886 | 1826 |
| 1887 m_hasEntries = true; | 1827 m_hasEntries = true; |
| 1888 size_t index = hash(address); | 1828 size_t index = hash(address); |
| 1889 ASSERT(!(index & 1)); | 1829 ASSERT(!(index & 1)); |
| 1890 Address cachePage = roundToBlinkPageStart(address); | 1830 Address cachePage = roundToBlinkPageStart(address); |
| 1891 m_entries[index + 1] = m_entries[index]; | 1831 m_entries[index + 1] = m_entries[index]; |
| 1892 m_entries[index] = cachePage; | 1832 m_entries[index] = cachePage; |
| 1893 } | 1833 } |
| 1894 | 1834 |
| 1895 } // namespace blink | 1835 } // namespace blink |
| OLD | NEW |