| 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 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 for (size_t i = 0; i < page->payloadSize(); i++) | 667 for (size_t i = 0; i < page->payloadSize(); i++) |
| 670 address[i] = reuseAllowedZapValue; | 668 address[i] = reuseAllowedZapValue; |
| 671 ASAN_POISON_MEMORY_REGION(page->payload(), page->payloadSize()); | 669 ASAN_POISON_MEMORY_REGION(page->payload(), page->payloadSize()); |
| 672 #endif | 670 #endif |
| 673 addToFreeList(page->payload(), page->payloadSize()); | 671 addToFreeList(page->payload(), page->payloadSize()); |
| 674 } | 672 } |
| 675 | 673 |
| 676 void NormalPageArena::freePage(NormalPage* page) { | 674 void NormalPageArena::freePage(NormalPage* page) { |
| 677 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()); | 675 getThreadState()->heap().heapStats().decreaseAllocatedSpace(page->size()); |
| 678 | 676 |
| 679 if (page->terminating()) { | 677 PageMemory* memory = page->storage(); |
| 680 // The thread is shutting down and this page is being removed as a part | 678 page->~NormalPage(); |
| 681 // of the thread local GC. In that case the object could be traced in | 679 getThreadState()->heap().getFreePagePool()->addFreePage(arenaIndex(), memory); |
| 682 // the next global GC if there is a dangling pointer from a live thread | |
| 683 // heap to this dead thread heap. To guard against this, we put the | |
| 684 // page into the orphaned page pool and zap the page memory. This | |
| 685 // ensures that tracing the dangling pointer in the next global GC just | |
| 686 // crashes instead of causing use-after-frees. After the next global | |
| 687 // GC, the orphaned pages are removed. | |
| 688 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage( | |
| 689 arenaIndex(), page); | |
| 690 } else { | |
| 691 PageMemory* memory = page->storage(); | |
| 692 page->~NormalPage(); | |
| 693 getThreadState()->heap().getFreePagePool()->addFreePage(arenaIndex(), | |
| 694 memory); | |
| 695 } | |
| 696 } | 680 } |
| 697 | 681 |
| 698 bool NormalPageArena::coalesce() { | 682 bool NormalPageArena::coalesce() { |
| 699 // Don't coalesce arenas if there are not enough promptly freed entries | 683 // Don't coalesce arenas if there are not enough promptly freed entries |
| 700 // to be coalesced. | 684 // to be coalesced. |
| 701 // | 685 // |
| 702 // FIXME: This threshold is determined just to optimize blink_perf | 686 // FIXME: This threshold is determined just to optimize blink_perf |
| 703 // benchmarks. Coalescing is very sensitive to the threashold and | 687 // benchmarks. Coalescing is very sensitive to the threashold and |
| 704 // we need further investigations on the coalescing scheme. | 688 // we need further investigations on the coalescing scheme. |
| 705 if (m_promptlyFreedSize < 1024 * 1024) | 689 if (m_promptlyFreedSize < 1024 * 1024) |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1067 object->payloadSize()); | 1051 object->payloadSize()); |
| 1068 getThreadState()->heap().heapStats().decreaseAllocatedSpace(object->size()); | 1052 getThreadState()->heap().heapStats().decreaseAllocatedSpace(object->size()); |
| 1069 | 1053 |
| 1070 // Unpoison the object header and allocationGranularity bytes after the | 1054 // Unpoison the object header and allocationGranularity bytes after the |
| 1071 // object before freeing. | 1055 // object before freeing. |
| 1072 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), | 1056 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), |
| 1073 sizeof(HeapObjectHeader)); | 1057 sizeof(HeapObjectHeader)); |
| 1074 ASAN_UNPOISON_MEMORY_REGION(object->getAddress() + object->size(), | 1058 ASAN_UNPOISON_MEMORY_REGION(object->getAddress() + object->size(), |
| 1075 allocationGranularity); | 1059 allocationGranularity); |
| 1076 | 1060 |
| 1077 if (object->terminating()) { | 1061 PageMemory* memory = object->storage(); |
| 1078 ASSERT(ThreadState::current()->isTerminating()); | 1062 object->~LargeObjectPage(); |
| 1079 // The thread is shutting down and this page is being removed as a part | 1063 delete memory; |
| 1080 // of the thread local GC. In that case the object could be traced in | |
| 1081 // the next global GC if there is a dangling pointer from a live thread | |
| 1082 // heap to this dead thread heap. To guard against this, we put the | |
| 1083 // page into the orphaned page pool and zap the page memory. This | |
| 1084 // ensures that tracing the dangling pointer in the next global GC just | |
| 1085 // crashes instead of causing use-after-frees. After the next global | |
| 1086 // GC, the orphaned pages are removed. | |
| 1087 getThreadState()->heap().getOrphanedPagePool()->addOrphanedPage( | |
| 1088 arenaIndex(), object); | |
| 1089 } else { | |
| 1090 ASSERT(!ThreadState::current()->isTerminating()); | |
| 1091 PageMemory* memory = object->storage(); | |
| 1092 object->~LargeObjectPage(); | |
| 1093 delete memory; | |
| 1094 } | |
| 1095 } | 1064 } |
| 1096 | 1065 |
| 1097 Address LargeObjectArena::lazySweepPages(size_t allocationSize, | 1066 Address LargeObjectArena::lazySweepPages(size_t allocationSize, |
| 1098 size_t gcInfoIndex) { | 1067 size_t gcInfoIndex) { |
| 1099 Address result = nullptr; | 1068 Address result = nullptr; |
| 1100 size_t sweptSize = 0; | 1069 size_t sweptSize = 0; |
| 1101 while (m_firstUnsweptPage) { | 1070 while (m_firstUnsweptPage) { |
| 1102 BasePage* page = m_firstUnsweptPage; | 1071 BasePage* page = m_firstUnsweptPage; |
| 1103 if (page->isEmpty()) { | 1072 if (page->isEmpty()) { |
| 1104 sweptSize += static_cast<LargeObjectPage*>(page)->payloadSize() + | 1073 sweptSize += static_cast<LargeObjectPage*>(page)->payloadSize() + |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 | 1259 |
| 1291 BasePage::BasePage(PageMemory* storage, BaseArena* arena) | 1260 BasePage::BasePage(PageMemory* storage, BaseArena* arena) |
| 1292 : m_storage(storage), | 1261 : m_storage(storage), |
| 1293 m_arena(arena), | 1262 m_arena(arena), |
| 1294 m_next(nullptr), | 1263 m_next(nullptr), |
| 1295 m_terminating(false), | 1264 m_terminating(false), |
| 1296 m_swept(true) { | 1265 m_swept(true) { |
| 1297 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | 1266 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 1298 } | 1267 } |
| 1299 | 1268 |
| 1300 void BasePage::markOrphaned() { | |
| 1301 m_arena = nullptr; | |
| 1302 m_terminating = false; | |
| 1303 // Since we zap the page payload for orphaned pages we need to mark it as | |
| 1304 // unused so a conservative pointer won't interpret the object headers. | |
| 1305 storage()->markUnused(); | |
| 1306 } | |
| 1307 | |
| 1308 NormalPage::NormalPage(PageMemory* storage, BaseArena* arena) | 1269 NormalPage::NormalPage(PageMemory* storage, BaseArena* arena) |
| 1309 : BasePage(storage, arena), m_objectStartBitMapComputed(false) { | 1270 : BasePage(storage, arena), m_objectStartBitMapComputed(false) { |
| 1310 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | 1271 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 1311 } | 1272 } |
| 1312 | 1273 |
| 1313 size_t NormalPage::objectPayloadSizeForTesting() { | 1274 size_t NormalPage::objectPayloadSizeForTesting() { |
| 1314 size_t objectPayloadSize = 0; | 1275 size_t objectPayloadSize = 0; |
| 1315 Address headerAddress = payload(); | 1276 Address headerAddress = payload(); |
| 1316 markAsSwept(); | 1277 markAsSwept(); |
| 1317 ASSERT(headerAddress != payloadEnd()); | 1278 ASSERT(headerAddress != payloadEnd()); |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1714 MarkedPointerCallbackForTesting callback) { | 1675 MarkedPointerCallbackForTesting callback) { |
| 1715 DCHECK(contains(address)); | 1676 DCHECK(contains(address)); |
| 1716 HeapObjectHeader* header = findHeaderFromAddress(address); | 1677 HeapObjectHeader* header = findHeaderFromAddress(address); |
| 1717 if (!header || header->isDead()) | 1678 if (!header || header->isDead()) |
| 1718 return; | 1679 return; |
| 1719 if (!callback(header)) | 1680 if (!callback(header)) |
| 1720 markPointer(visitor, header); | 1681 markPointer(visitor, header); |
| 1721 } | 1682 } |
| 1722 #endif | 1683 #endif |
| 1723 | 1684 |
| 1724 void NormalPage::markOrphaned() { | |
| 1725 // Zap the payload with a recognizable value to detect any incorrect | |
| 1726 // cross thread pointer usage. | |
| 1727 #if defined(ADDRESS_SANITIZER) | |
| 1728 // This needs to zap poisoned memory as well. | |
| 1729 // Force unpoison memory before memset. | |
| 1730 ASAN_UNPOISON_MEMORY_REGION(payload(), payloadSize()); | |
| 1731 #endif | |
| 1732 OrphanedPagePool::asanDisabledMemset( | |
| 1733 payload(), OrphanedPagePool::orphanedZapValue, payloadSize()); | |
| 1734 BasePage::markOrphaned(); | |
| 1735 } | |
| 1736 | |
| 1737 void NormalPage::takeSnapshot(base::trace_event::MemoryAllocatorDump* pageDump, | 1685 void NormalPage::takeSnapshot(base::trace_event::MemoryAllocatorDump* pageDump, |
| 1738 ThreadState::GCSnapshotInfo& info, | 1686 ThreadState::GCSnapshotInfo& info, |
| 1739 HeapSnapshotInfo& heapInfo) { | 1687 HeapSnapshotInfo& heapInfo) { |
| 1740 HeapObjectHeader* header = nullptr; | 1688 HeapObjectHeader* header = nullptr; |
| 1741 size_t liveCount = 0; | 1689 size_t liveCount = 0; |
| 1742 size_t deadCount = 0; | 1690 size_t deadCount = 0; |
| 1743 size_t freeCount = 0; | 1691 size_t freeCount = 0; |
| 1744 size_t liveSize = 0; | 1692 size_t liveSize = 0; |
| 1745 size_t deadSize = 0; | 1693 size_t deadSize = 0; |
| 1746 size_t freeSize = 0; | 1694 size_t freeSize = 0; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1855 Address address, | 1803 Address address, |
| 1856 MarkedPointerCallbackForTesting callback) { | 1804 MarkedPointerCallbackForTesting callback) { |
| 1857 DCHECK(contains(address)); | 1805 DCHECK(contains(address)); |
| 1858 if (!containedInObjectPayload(address) || heapObjectHeader()->isDead()) | 1806 if (!containedInObjectPayload(address) || heapObjectHeader()->isDead()) |
| 1859 return; | 1807 return; |
| 1860 if (!callback(heapObjectHeader())) | 1808 if (!callback(heapObjectHeader())) |
| 1861 markPointer(visitor, heapObjectHeader()); | 1809 markPointer(visitor, heapObjectHeader()); |
| 1862 } | 1810 } |
| 1863 #endif | 1811 #endif |
| 1864 | 1812 |
| 1865 void LargeObjectPage::markOrphaned() { | |
| 1866 // Zap the payload with a recognizable value to detect any incorrect | |
| 1867 // cross thread pointer usage. | |
| 1868 OrphanedPagePool::asanDisabledMemset( | |
| 1869 payload(), OrphanedPagePool::orphanedZapValue, payloadSize()); | |
| 1870 BasePage::markOrphaned(); | |
| 1871 } | |
| 1872 | |
| 1873 void LargeObjectPage::takeSnapshot( | 1813 void LargeObjectPage::takeSnapshot( |
| 1874 base::trace_event::MemoryAllocatorDump* pageDump, | 1814 base::trace_event::MemoryAllocatorDump* pageDump, |
| 1875 ThreadState::GCSnapshotInfo& info, | 1815 ThreadState::GCSnapshotInfo& info, |
| 1876 HeapSnapshotInfo&) { | 1816 HeapSnapshotInfo&) { |
| 1877 size_t liveSize = 0; | 1817 size_t liveSize = 0; |
| 1878 size_t deadSize = 0; | 1818 size_t deadSize = 0; |
| 1879 size_t liveCount = 0; | 1819 size_t liveCount = 0; |
| 1880 size_t deadCount = 0; | 1820 size_t deadCount = 0; |
| 1881 HeapObjectHeader* header = heapObjectHeader(); | 1821 HeapObjectHeader* header = heapObjectHeader(); |
| 1882 size_t gcInfoIndex = header->gcInfoIndex(); | 1822 size_t gcInfoIndex = header->gcInfoIndex(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1940 | 1880 |
| 1941 m_hasEntries = true; | 1881 m_hasEntries = true; |
| 1942 size_t index = hash(address); | 1882 size_t index = hash(address); |
| 1943 ASSERT(!(index & 1)); | 1883 ASSERT(!(index & 1)); |
| 1944 Address cachePage = roundToBlinkPageStart(address); | 1884 Address cachePage = roundToBlinkPageStart(address); |
| 1945 m_entries[index + 1] = m_entries[index]; | 1885 m_entries[index + 1] = m_entries[index]; |
| 1946 m_entries[index] = cachePage; | 1886 m_entries[index] = cachePage; |
| 1947 } | 1887 } |
| 1948 | 1888 |
| 1949 } // namespace blink | 1889 } // namespace blink |
| OLD | NEW |