| 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 10 matching lines...) Expand all Loading... |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #ifndef Heap_h | 31 #ifndef HeapPage_h |
| 32 #define Heap_h | 32 #define HeapPage_h |
| 33 | 33 |
| 34 #include "platform/PlatformExport.h" | 34 #include "platform/PlatformExport.h" |
| 35 #include "platform/heap/GCInfo.h" | 35 #include "platform/heap/GCInfo.h" |
| 36 #include "platform/heap/ThreadState.h" | 36 #include "platform/heap/ThreadState.h" |
| 37 #include "platform/heap/Visitor.h" | 37 #include "platform/heap/Visitor.h" |
| 38 #include "public/platform/WebThread.h" | |
| 39 #include "wtf/AddressSanitizer.h" | 38 #include "wtf/AddressSanitizer.h" |
| 40 #include "wtf/Assertions.h" | 39 #include "wtf/Assertions.h" |
| 41 #include "wtf/Atomics.h" | 40 #include "wtf/Atomics.h" |
| 42 #include "wtf/ContainerAnnotations.h" | 41 #include "wtf/ContainerAnnotations.h" |
| 43 #include "wtf/Forward.h" | 42 #include "wtf/Forward.h" |
| 44 #include "wtf/PageAllocator.h" | 43 #include "wtf/PageAllocator.h" |
| 45 #include <stdint.h> | 44 #include <stdint.h> |
| 46 | 45 |
| 47 namespace blink { | 46 namespace blink { |
| 48 | 47 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 FreeList::zapFreedMemory(address, size); \ | 99 FreeList::zapFreedMemory(address, size); \ |
| 101 ASAN_POISON_MEMORY_REGION(address, size) | 100 ASAN_POISON_MEMORY_REGION(address, size) |
| 102 #define SET_MEMORY_ACCESSIBLE(address, size) \ | 101 #define SET_MEMORY_ACCESSIBLE(address, size) \ |
| 103 ASAN_UNPOISON_MEMORY_REGION(address, size); \ | 102 ASAN_UNPOISON_MEMORY_REGION(address, size); \ |
| 104 memset((address), 0, (size)) | 103 memset((address), 0, (size)) |
| 105 #else | 104 #else |
| 106 #define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size)) | 105 #define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size)) |
| 107 #define SET_MEMORY_ACCESSIBLE(address, size) do { } while (false) | 106 #define SET_MEMORY_ACCESSIBLE(address, size) do { } while (false) |
| 108 #endif | 107 #endif |
| 109 | 108 |
| 109 #if !ENABLE(ASSERT) && !ENABLE(GC_PROFILING) && CPU(64BIT) |
| 110 #define USE_4BYTE_HEADER_PADDING 1 |
| 111 #else |
| 112 #define USE_4BYTE_HEADER_PADDING 0 |
| 113 #endif |
| 114 |
| 110 class CallbackStack; | 115 class CallbackStack; |
| 111 class FreePagePool; | 116 class FreePagePool; |
| 112 class NormalPageHeap; | 117 class NormalPageHeap; |
| 113 class OrphanedPagePool; | 118 class OrphanedPagePool; |
| 114 class PageMemory; | 119 class PageMemory; |
| 115 class PageMemoryRegion; | 120 class PageMemoryRegion; |
| 116 class WebProcessMemoryDump; | 121 class WebProcessMemoryDump; |
| 117 | 122 |
| 118 #if ENABLE(GC_PROFILING) | 123 #if ENABLE(GC_PROFILING) |
| 119 class TracedValue; | 124 class TracedValue; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 size_t age() const { return m_age; } | 229 size_t age() const { return m_age; } |
| 225 | 230 |
| 226 NO_SANITIZE_ADDRESS | 231 NO_SANITIZE_ADDRESS |
| 227 void incrementAge() | 232 void incrementAge() |
| 228 { | 233 { |
| 229 if (m_age < maxHeapObjectAge) | 234 if (m_age < maxHeapObjectAge) |
| 230 m_age++; | 235 m_age++; |
| 231 } | 236 } |
| 232 #endif | 237 #endif |
| 233 | 238 |
| 234 #if !ENABLE(ASSERT) && !ENABLE(GC_PROFILING) && CPU(64BIT) | |
| 235 // This method is needed just to avoid compilers from removing m_padding. | |
| 236 uint64_t unusedMethod() const { return m_padding; } | |
| 237 #endif | |
| 238 | |
| 239 private: | 239 private: |
| 240 uint32_t m_encoded; | 240 uint32_t m_encoded; |
| 241 #if ENABLE(ASSERT) | 241 #if ENABLE(ASSERT) |
| 242 uint16_t m_magic; | 242 uint16_t m_magic; |
| 243 #endif | 243 #endif |
| 244 #if ENABLE(GC_PROFILING) | 244 #if ENABLE(GC_PROFILING) |
| 245 uint8_t m_age; | 245 uint8_t m_age; |
| 246 #endif | 246 #endif |
| 247 | 247 |
| 248 // In 64 bit architectures, we intentionally add 4 byte padding immediately | 248 // In 64 bit architectures, we intentionally add 4 byte padding immediately |
| 249 // after the HeapHeaderObject. This is because: | 249 // after the HeapHeaderObject. This is because: |
| 250 // | 250 // |
| 251 // | HeapHeaderObject (4 byte) | padding (4 byte) | object payload (8 * n by
te) | | 251 // | HeapHeaderObject (4 byte) | padding (4 byte) | object payload (8 * n by
te) | |
| 252 // ^8 byte aligned ^8 byte aligned | 252 // ^8 byte aligned ^8 byte aligned |
| 253 // | 253 // |
| 254 // is better than: | 254 // is better than: |
| 255 // | 255 // |
| 256 // | HeapHeaderObject (4 byte) | object payload (8 * n byte) | padding (4 by
te) | | 256 // | HeapHeaderObject (4 byte) | object payload (8 * n byte) | padding (4 by
te) | |
| 257 // ^4 byte aligned ^8 byte aligned ^4 byte aligned | 257 // ^4 byte aligned ^8 byte aligned ^4 byte aligned |
| 258 // | 258 // |
| 259 // since the former layout aligns both header and payload to 8 byte. | 259 // since the former layout aligns both header and payload to 8 byte. |
| 260 #if !ENABLE(ASSERT) && !ENABLE(GC_PROFILING) && CPU(64BIT) | 260 #if USE_4BYTE_HEADER_PADDING |
| 261 public: |
| 261 uint32_t m_padding; | 262 uint32_t m_padding; |
| 262 #endif | 263 #endif |
| 263 }; | 264 }; |
| 264 | 265 |
| 265 class FreeListEntry final : public HeapObjectHeader { | 266 class FreeListEntry final : public HeapObjectHeader { |
| 266 public: | 267 public: |
| 267 NO_SANITIZE_ADDRESS | 268 NO_SANITIZE_ADDRESS |
| 268 explicit FreeListEntry(size_t size) | 269 explicit FreeListEntry(size_t size) |
| 269 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader) | 270 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader) |
| 270 , m_next(nullptr) | 271 , m_next(nullptr) |
| (...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 814 // FIXME: Remove PLATFORM_EXPORT once we get a proper public interface to our | 815 // FIXME: Remove PLATFORM_EXPORT once we get a proper public interface to our |
| 815 // typed heaps. This is only exported to enable tests in HeapTest.cpp. | 816 // typed heaps. This is only exported to enable tests in HeapTest.cpp. |
| 816 PLATFORM_EXPORT inline BasePage* pageFromObject(const void* object) | 817 PLATFORM_EXPORT inline BasePage* pageFromObject(const void* object) |
| 817 { | 818 { |
| 818 Address address = reinterpret_cast<Address>(const_cast<void*>(object)); | 819 Address address = reinterpret_cast<Address>(const_cast<void*>(object)); |
| 819 BasePage* page = reinterpret_cast<BasePage*>(blinkPageAddress(address) + bli
nkGuardPageSize); | 820 BasePage* page = reinterpret_cast<BasePage*>(blinkPageAddress(address) + bli
nkGuardPageSize); |
| 820 ASSERT(page->contains(address)); | 821 ASSERT(page->contains(address)); |
| 821 return page; | 822 return page; |
| 822 } | 823 } |
| 823 | 824 |
| 824 template<typename T, bool = NeedsAdjustAndMark<T>::value> class ObjectAliveTrait
; | |
| 825 | |
| 826 template<typename T> | |
| 827 class ObjectAliveTrait<T, false> { | |
| 828 public: | |
| 829 static bool isHeapObjectAlive(T* object) | |
| 830 { | |
| 831 static_assert(sizeof(T), "T must be fully defined"); | |
| 832 return HeapObjectHeader::fromPayload(object)->isMarked(); | |
| 833 } | |
| 834 }; | |
| 835 | |
| 836 template<typename T> | |
| 837 class ObjectAliveTrait<T, true> { | |
| 838 public: | |
| 839 static bool isHeapObjectAlive(T* object) | |
| 840 { | |
| 841 static_assert(sizeof(T), "T must be fully defined"); | |
| 842 return object->isHeapObjectAlive(); | |
| 843 } | |
| 844 }; | |
| 845 | |
| 846 class PLATFORM_EXPORT Heap { | |
| 847 public: | |
| 848 static void init(); | |
| 849 static void shutdown(); | |
| 850 static void doShutdown(); | |
| 851 | |
| 852 #if ENABLE(ASSERT) || ENABLE(GC_PROFILING) | |
| 853 static BasePage* findPageFromAddress(Address); | |
| 854 static BasePage* findPageFromAddress(const void* pointer) { return findPageF
romAddress(reinterpret_cast<Address>(const_cast<void*>(pointer))); } | |
| 855 #endif | |
| 856 | |
| 857 template<typename T> | |
| 858 static inline bool isHeapObjectAlive(T* object) | |
| 859 { | |
| 860 static_assert(sizeof(T), "T must be fully defined"); | |
| 861 // The strongification of collections relies on the fact that once a | |
| 862 // collection has been strongified, there is no way that it can contain | |
| 863 // non-live entries, so no entries will be removed. Since you can't set | |
| 864 // the mark bit on a null pointer, that means that null pointers are | |
| 865 // always 'alive'. | |
| 866 if (!object) | |
| 867 return true; | |
| 868 return ObjectAliveTrait<T>::isHeapObjectAlive(object); | |
| 869 } | |
| 870 template<typename T> | |
| 871 static inline bool isHeapObjectAlive(const Member<T>& member) | |
| 872 { | |
| 873 return isHeapObjectAlive(member.get()); | |
| 874 } | |
| 875 template<typename T> | |
| 876 static inline bool isHeapObjectAlive(const WeakMember<T>& member) | |
| 877 { | |
| 878 return isHeapObjectAlive(member.get()); | |
| 879 } | |
| 880 template<typename T> | |
| 881 static inline bool isHeapObjectAlive(const RawPtr<T>& ptr) | |
| 882 { | |
| 883 return isHeapObjectAlive(ptr.get()); | |
| 884 } | |
| 885 | |
| 886 // Is the finalizable GC object still alive, but slated for lazy sweeping? | |
| 887 // If a lazy sweep is in progress, returns true if the object was found | |
| 888 // to be not reachable during the marking phase, but it has yet to be swept | |
| 889 // and finalized. The predicate returns false in all other cases. | |
| 890 // | |
| 891 // Holding a reference to an already-dead object is not a valid state | |
| 892 // to be in; willObjectBeLazilySwept() has undefined behavior if passed | |
| 893 // such a reference. | |
| 894 template<typename T> | |
| 895 NO_LAZY_SWEEP_SANITIZE_ADDRESS | |
| 896 static bool willObjectBeLazilySwept(const T* objectPointer) | |
| 897 { | |
| 898 static_assert(IsGarbageCollectedType<T>::value, "only objects deriving f
rom GarbageCollected can be used."); | |
| 899 #if ENABLE(LAZY_SWEEPING) | |
| 900 BasePage* page = pageFromObject(objectPointer); | |
| 901 if (page->hasBeenSwept()) | |
| 902 return false; | |
| 903 ASSERT(page->heap()->threadState()->isSweepingInProgress()); | |
| 904 | |
| 905 return !Heap::isHeapObjectAlive(const_cast<T*>(objectPointer)); | |
| 906 #else | |
| 907 return false; | |
| 908 #endif | |
| 909 } | |
| 910 | |
| 911 // Push a trace callback on the marking stack. | |
| 912 static void pushTraceCallback(void* containerObject, TraceCallback); | |
| 913 | |
| 914 // Push a trace callback on the post-marking callback stack. These | |
| 915 // callbacks are called after normal marking (including ephemeron | |
| 916 // iteration). | |
| 917 static void pushPostMarkingCallback(void*, TraceCallback); | |
| 918 | |
| 919 // Add a weak pointer callback to the weak callback work list. General | |
| 920 // object pointer callbacks are added to a thread local weak callback work | |
| 921 // list and the callback is called on the thread that owns the object, with | |
| 922 // the closure pointer as an argument. Most of the time, the closure and | |
| 923 // the containerObject can be the same thing, but the containerObject is | |
| 924 // constrained to be on the heap, since the heap is used to identify the | |
| 925 // correct thread. | |
| 926 static void pushThreadLocalWeakCallback(void* closure, void* containerObject
, WeakCallback); | |
| 927 | |
| 928 // Similar to the more general pushThreadLocalWeakCallback, but cell | |
| 929 // pointer callbacks are added to a static callback work list and the weak | |
| 930 // callback is performed on the thread performing garbage collection. This | |
| 931 // is OK because cells are just cleared and no deallocation can happen. | |
| 932 static void pushGlobalWeakCallback(void** cell, WeakCallback); | |
| 933 | |
| 934 // Pop the top of a marking stack and call the callback with the visitor | |
| 935 // and the object. Returns false when there is nothing more to do. | |
| 936 static bool popAndInvokeTraceCallback(Visitor*); | |
| 937 | |
| 938 // Remove an item from the post-marking callback stack and call | |
| 939 // the callback with the visitor and the object pointer. Returns | |
| 940 // false when there is nothing more to do. | |
| 941 static bool popAndInvokePostMarkingCallback(Visitor*); | |
| 942 | |
| 943 // Remove an item from the weak callback work list and call the callback | |
| 944 // with the visitor and the closure pointer. Returns false when there is | |
| 945 // nothing more to do. | |
| 946 static bool popAndInvokeGlobalWeakCallback(Visitor*); | |
| 947 | |
| 948 // Register an ephemeron table for fixed-point iteration. | |
| 949 static void registerWeakTable(void* containerObject, EphemeronCallback, Ephe
meronCallback); | |
| 950 #if ENABLE(ASSERT) | |
| 951 static bool weakTableRegistered(const void*); | |
| 952 #endif | |
| 953 | |
| 954 static inline size_t allocationSizeFromSize(size_t size) | |
| 955 { | |
| 956 // Check the size before computing the actual allocation size. The | |
| 957 // allocation size calculation can overflow for large sizes and the chec
k | |
| 958 // therefore has to happen before any calculation on the size. | |
| 959 RELEASE_ASSERT(size < maxHeapObjectSize); | |
| 960 | |
| 961 // Add space for header. | |
| 962 size_t allocationSize = size + sizeof(HeapObjectHeader); | |
| 963 // Align size with allocation granularity. | |
| 964 allocationSize = (allocationSize + allocationMask) & ~allocationMask; | |
| 965 return allocationSize; | |
| 966 } | |
| 967 static Address allocateOnHeapIndex(ThreadState*, size_t, int heapIndex, size
_t gcInfoIndex); | |
| 968 template<typename T> static Address allocate(size_t, bool eagerlySweep = fal
se); | |
| 969 template<typename T> static Address reallocate(void* previous, size_t); | |
| 970 | |
| 971 enum GCReason { | |
| 972 IdleGC, | |
| 973 PreciseGC, | |
| 974 ConservativeGC, | |
| 975 ForcedGC, | |
| 976 NumberOfGCReason | |
| 977 }; | |
| 978 static const char* gcReasonString(GCReason); | |
| 979 static void collectGarbage(ThreadState::StackState, ThreadState::GCType, GCR
eason); | |
| 980 static void collectGarbageForTerminatingThread(ThreadState*); | |
| 981 static void collectAllGarbage(); | |
| 982 | |
| 983 static void processMarkingStack(Visitor*); | |
| 984 static void postMarkingProcessing(Visitor*); | |
| 985 static void globalWeakProcessing(Visitor*); | |
| 986 static void setForcePreciseGCForTesting(); | |
| 987 | |
| 988 static void preGC(); | |
| 989 static void postGC(ThreadState::GCType); | |
| 990 | |
| 991 // Conservatively checks whether an address is a pointer in any of the | |
| 992 // thread heaps. If so marks the object pointed to as live. | |
| 993 static Address checkAndMarkPointer(Visitor*, Address); | |
| 994 | |
| 995 #if ENABLE(GC_PROFILING) | |
| 996 // Dump the path to specified object on the next GC. This method is to be | |
| 997 // invoked from GDB. | |
| 998 static void dumpPathToObjectOnNextGC(void* p); | |
| 999 | |
| 1000 // Forcibly find GCInfo of the object at Address. This is slow and should | |
| 1001 // only be used for debug purposes. It involves finding the heap page and | |
| 1002 // scanning the heap page for an object header. | |
| 1003 static const GCInfo* findGCInfo(Address); | |
| 1004 | |
| 1005 static String createBacktraceString(); | |
| 1006 #endif | |
| 1007 | |
| 1008 static size_t objectPayloadSizeForTesting(); | |
| 1009 | |
| 1010 static void flushHeapDoesNotContainCache(); | |
| 1011 | |
| 1012 static FreePagePool* freePagePool() { return s_freePagePool; } | |
| 1013 static OrphanedPagePool* orphanedPagePool() { return s_orphanedPagePool; } | |
| 1014 | |
| 1015 // This look-up uses the region search tree and a negative contains cache to | |
| 1016 // provide an efficient mapping from arbitrary addresses to the containing | |
| 1017 // heap-page if one exists. | |
| 1018 static BasePage* lookup(Address); | |
| 1019 static void addPageMemoryRegion(PageMemoryRegion*); | |
| 1020 static void removePageMemoryRegion(PageMemoryRegion*); | |
| 1021 | |
| 1022 static const GCInfo* gcInfo(size_t gcInfoIndex) | |
| 1023 { | |
| 1024 ASSERT(gcInfoIndex >= 1); | |
| 1025 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); | |
| 1026 ASSERT(s_gcInfoTable); | |
| 1027 const GCInfo* info = s_gcInfoTable[gcInfoIndex]; | |
| 1028 ASSERT(info); | |
| 1029 return info; | |
| 1030 } | |
| 1031 | |
| 1032 static void setMarkedObjectSizeAtLastCompleteSweep(size_t size) { releaseSto
re(&s_markedObjectSizeAtLastCompleteSweep, size); } | |
| 1033 static size_t markedObjectSizeAtLastCompleteSweep() { return acquireLoad(&s_
markedObjectSizeAtLastCompleteSweep); } | |
| 1034 static void increaseAllocatedObjectSize(size_t delta) { atomicAdd(&s_allocat
edObjectSize, static_cast<long>(delta)); } | |
| 1035 static void decreaseAllocatedObjectSize(size_t delta) { atomicSubtract(&s_al
locatedObjectSize, static_cast<long>(delta)); } | |
| 1036 static size_t allocatedObjectSize() { return acquireLoad(&s_allocatedObjectS
ize); } | |
| 1037 static void increaseMarkedObjectSize(size_t delta) { atomicAdd(&s_markedObje
ctSize, static_cast<long>(delta)); } | |
| 1038 static size_t markedObjectSize() { return acquireLoad(&s_markedObjectSize);
} | |
| 1039 static void increaseAllocatedSpace(size_t delta) { atomicAdd(&s_allocatedSpa
ce, static_cast<long>(delta)); } | |
| 1040 static void decreaseAllocatedSpace(size_t delta) { atomicSubtract(&s_allocat
edSpace, static_cast<long>(delta)); } | |
| 1041 static size_t allocatedSpace() { return acquireLoad(&s_allocatedSpace); } | |
| 1042 static size_t objectSizeAtLastGC() { return acquireLoad(&s_objectSizeAtLastG
C); } | |
| 1043 static void increasePersistentCount(size_t delta) { atomicAdd(&s_persistentC
ount, static_cast<long>(delta)); } | |
| 1044 static void decreasePersistentCount(size_t delta) { atomicSubtract(&s_persis
tentCount, static_cast<long>(delta)); } | |
| 1045 static size_t persistentCount() { return acquireLoad(&s_persistentCount); } | |
| 1046 static size_t persistentCountAtLastGC() { return acquireLoad(&s_persistentCo
untAtLastGC); } | |
| 1047 static void increaseCollectedPersistentCount(size_t delta) { atomicAdd(&s_co
llectedPersistentCount, static_cast<long>(delta)); } | |
| 1048 static size_t collectedPersistentCount() { return acquireLoad(&s_collectedPe
rsistentCount); } | |
| 1049 static size_t partitionAllocSizeAtLastGC() { return acquireLoad(&s_partition
AllocSizeAtLastGC); } | |
| 1050 | |
| 1051 static double estimatedMarkingTime(); | |
| 1052 static void reportMemoryUsageHistogram(); | |
| 1053 static void reportMemoryUsageForTracing(); | |
| 1054 | |
| 1055 private: | |
| 1056 // A RegionTree is a simple binary search tree of PageMemoryRegions sorted | |
| 1057 // by base addresses. | |
| 1058 class RegionTree { | |
| 1059 public: | |
| 1060 explicit RegionTree(PageMemoryRegion* region) : m_region(region), m_left
(nullptr), m_right(nullptr) { } | |
| 1061 ~RegionTree() | |
| 1062 { | |
| 1063 delete m_left; | |
| 1064 delete m_right; | |
| 1065 } | |
| 1066 PageMemoryRegion* lookup(Address); | |
| 1067 static void add(RegionTree*, RegionTree**); | |
| 1068 static void remove(PageMemoryRegion*, RegionTree**); | |
| 1069 private: | |
| 1070 PageMemoryRegion* m_region; | |
| 1071 RegionTree* m_left; | |
| 1072 RegionTree* m_right; | |
| 1073 }; | |
| 1074 | |
| 1075 // Reset counters that track live and allocated-since-last-GC sizes. | |
| 1076 static void resetHeapCounters(); | |
| 1077 | |
| 1078 static int heapIndexForObjectSize(size_t); | |
| 1079 static bool isNormalHeapIndex(int); | |
| 1080 | |
| 1081 static CallbackStack* s_markingStack; | |
| 1082 static CallbackStack* s_postMarkingCallbackStack; | |
| 1083 static CallbackStack* s_globalWeakCallbackStack; | |
| 1084 static CallbackStack* s_ephemeronStack; | |
| 1085 static HeapDoesNotContainCache* s_heapDoesNotContainCache; | |
| 1086 static bool s_shutdownCalled; | |
| 1087 static FreePagePool* s_freePagePool; | |
| 1088 static OrphanedPagePool* s_orphanedPagePool; | |
| 1089 static RegionTree* s_regionTree; | |
| 1090 static size_t s_allocatedSpace; | |
| 1091 static size_t s_allocatedObjectSize; | |
| 1092 static size_t s_objectSizeAtLastGC; | |
| 1093 static size_t s_markedObjectSize; | |
| 1094 static size_t s_markedObjectSizeAtLastCompleteSweep; | |
| 1095 static size_t s_persistentCount; | |
| 1096 static size_t s_persistentCountAtLastGC; | |
| 1097 static size_t s_collectedPersistentCount; | |
| 1098 static size_t s_partitionAllocSizeAtLastGC; | |
| 1099 static double s_estimatedMarkingTimePerByte; | |
| 1100 | |
| 1101 friend class ThreadState; | |
| 1102 }; | |
| 1103 | |
| 1104 template<typename T> | |
| 1105 struct IsEagerlyFinalizedType { | |
| 1106 private: | |
| 1107 typedef char YesType; | |
| 1108 struct NoType { | |
| 1109 char padding[8]; | |
| 1110 }; | |
| 1111 | |
| 1112 template <typename U> static YesType checkMarker(typename U::IsEagerlyFinali
zedMarker*); | |
| 1113 template <typename U> static NoType checkMarker(...); | |
| 1114 | |
| 1115 public: | |
| 1116 static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType)
; | |
| 1117 }; | |
| 1118 | |
| 1119 template<typename T> class GarbageCollected { | |
| 1120 WTF_MAKE_NONCOPYABLE(GarbageCollected); | |
| 1121 | |
| 1122 // For now direct allocation of arrays on the heap is not allowed. | |
| 1123 void* operator new[](size_t size); | |
| 1124 | |
| 1125 #if OS(WIN) && COMPILER(MSVC) | |
| 1126 // Due to some quirkiness in the MSVC compiler we have to provide | |
| 1127 // the delete[] operator in the GarbageCollected subclasses as it | |
| 1128 // is called when a class is exported in a DLL. | |
| 1129 protected: | |
| 1130 void operator delete[](void* p) | |
| 1131 { | |
| 1132 ASSERT_NOT_REACHED(); | |
| 1133 } | |
| 1134 #else | |
| 1135 void operator delete[](void* p); | |
| 1136 #endif | |
| 1137 | |
| 1138 public: | |
| 1139 using GarbageCollectedBase = T; | |
| 1140 | |
| 1141 void* operator new(size_t size) | |
| 1142 { | |
| 1143 return allocateObject(size, IsEagerlyFinalizedType<T>::value); | |
| 1144 } | |
| 1145 | |
| 1146 static void* allocateObject(size_t size, bool eagerlySweep) | |
| 1147 { | |
| 1148 return Heap::allocate<T>(size, eagerlySweep); | |
| 1149 } | |
| 1150 | |
| 1151 void operator delete(void* p) | |
| 1152 { | |
| 1153 ASSERT_NOT_REACHED(); | |
| 1154 } | |
| 1155 | |
| 1156 protected: | |
| 1157 GarbageCollected() | |
| 1158 { | |
| 1159 } | |
| 1160 }; | |
| 1161 | |
| 1162 // Assigning class types to their heaps. | |
| 1163 // | |
| 1164 // We use sized heaps for most 'normal' objects to improve memory locality. | |
| 1165 // It seems that the same type of objects are likely to be accessed together, | |
| 1166 // which means that we want to group objects by type. That's one reason | |
| 1167 // why we provide dedicated heaps for popular types (e.g., Node, CSSValue), | |
| 1168 // but it's not practical to prepare dedicated heaps for all types. | |
| 1169 // Thus we group objects by their sizes, hoping that this will approximately | |
| 1170 // group objects by their types. | |
| 1171 // | |
| 1172 // An exception to the use of sized heaps is made for class types that | |
| 1173 // require prompt finalization after a garbage collection. That is, their | |
| 1174 // instances have to be finalized early and cannot be delayed until lazy | |
| 1175 // sweeping kicks in for their heap and page. The EAGERLY_FINALIZE() | |
| 1176 // macro is used to declare a class (and its derived classes) as being | |
| 1177 // in need of eager finalization. Must be defined with 'public' visibility | |
| 1178 // for a class. | |
| 1179 // | |
| 1180 | |
| 1181 inline int Heap::heapIndexForObjectSize(size_t size) | |
| 1182 { | |
| 1183 if (size < 64) { | |
| 1184 if (size < 32) | |
| 1185 return ThreadState::NormalPage1HeapIndex; | |
| 1186 return ThreadState::NormalPage2HeapIndex; | |
| 1187 } | |
| 1188 if (size < 128) | |
| 1189 return ThreadState::NormalPage3HeapIndex; | |
| 1190 return ThreadState::NormalPage4HeapIndex; | |
| 1191 } | |
| 1192 | |
| 1193 inline bool Heap::isNormalHeapIndex(int index) | |
| 1194 { | |
| 1195 return index >= ThreadState::NormalPage1HeapIndex && index <= ThreadState::N
ormalPage4HeapIndex; | |
| 1196 } | |
| 1197 | |
| 1198 #define DECLARE_EAGER_FINALIZATION_OPERATOR_NEW() \ | |
| 1199 public: \ | |
| 1200 GC_PLUGIN_IGNORE("491488") \ | |
| 1201 void* operator new(size_t size) \ | |
| 1202 { \ | |
| 1203 return allocateObject(size, true); \ | |
| 1204 } | |
| 1205 | |
| 1206 #define IS_EAGERLY_FINALIZED() (pageFromObject(this)->heap()->heapIndex() == Thr
eadState::EagerSweepHeapIndex) | |
| 1207 #if ENABLE(ASSERT) && ENABLE(OILPAN) | |
| 1208 class VerifyEagerFinalization { | |
| 1209 public: | |
| 1210 ~VerifyEagerFinalization() | |
| 1211 { | |
| 1212 // If this assert triggers, the class annotated as eagerly | |
| 1213 // finalized ended up not being allocated on the heap | |
| 1214 // set aside for eager finalization. The reason is most | |
| 1215 // likely that the effective 'operator new' overload for | |
| 1216 // this class' leftmost base is for a class that is not | |
| 1217 // eagerly finalized. Declaring and defining an 'operator new' | |
| 1218 // for this class is what's required -- consider using | |
| 1219 // DECLARE_EAGER_FINALIZATION_OPERATOR_NEW(). | |
| 1220 ASSERT(IS_EAGERLY_FINALIZED()); | |
| 1221 } | |
| 1222 }; | |
| 1223 #define EAGERLY_FINALIZE() \ | |
| 1224 private: \ | |
| 1225 VerifyEagerFinalization m_verifyEagerFinalization; \ | |
| 1226 public: \ | |
| 1227 typedef int IsEagerlyFinalizedMarker | |
| 1228 #else | |
| 1229 #define EAGERLY_FINALIZE() typedef int IsEagerlyFinalizedMarker | |
| 1230 #endif | |
| 1231 | |
| 1232 #if !ENABLE(OILPAN) && ENABLE(LAZY_SWEEPING) | |
| 1233 #define EAGERLY_FINALIZE_WILL_BE_REMOVED() EAGERLY_FINALIZE() | |
| 1234 #else | |
| 1235 #define EAGERLY_FINALIZE_WILL_BE_REMOVED() | |
| 1236 #endif | |
| 1237 | |
| 1238 NO_SANITIZE_ADDRESS inline | 825 NO_SANITIZE_ADDRESS inline |
| 1239 size_t HeapObjectHeader::size() const | 826 size_t HeapObjectHeader::size() const |
| 1240 { | 827 { |
| 1241 size_t result = m_encoded & headerSizeMask; | 828 size_t result = m_encoded & headerSizeMask; |
| 1242 // Large objects should not refer to header->size(). | 829 // Large objects should not refer to header->size(). |
| 1243 // The actual size of a large object is stored in | 830 // The actual size of a large object is stored in |
| 1244 // LargeObjectPage::m_payloadSize. | 831 // LargeObjectPage::m_payloadSize. |
| 1245 ASSERT(result != largeObjectSizeInHeader); | 832 ASSERT(result != largeObjectSizeInHeader); |
| 1246 ASSERT(!pageFromObject(this)->isLargeObjectPage()); | 833 ASSERT(!pageFromObject(this)->isLargeObjectPage()); |
| 1247 return result; | 834 return result; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1342 Address result = headerAddress + sizeof(HeapObjectHeader); | 929 Address result = headerAddress + sizeof(HeapObjectHeader); |
| 1343 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | 930 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); |
| 1344 | 931 |
| 1345 SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader))
; | 932 SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader))
; |
| 1346 ASSERT(findPageFromAddress(headerAddress + allocationSize - 1)); | 933 ASSERT(findPageFromAddress(headerAddress + allocationSize - 1)); |
| 1347 return result; | 934 return result; |
| 1348 } | 935 } |
| 1349 return outOfLineAllocate(allocationSize, gcInfoIndex); | 936 return outOfLineAllocate(allocationSize, gcInfoIndex); |
| 1350 } | 937 } |
| 1351 | 938 |
| 1352 template<typename Derived> | |
| 1353 template<typename T> | |
| 1354 void VisitorHelper<Derived>::handleWeakCell(Visitor* self, void* object) | |
| 1355 { | |
| 1356 T** cell = reinterpret_cast<T**>(object); | |
| 1357 if (*cell && !ObjectAliveTrait<T>::isHeapObjectAlive(*cell)) | |
| 1358 *cell = nullptr; | |
| 1359 } | |
| 1360 | |
| 1361 inline Address Heap::allocateOnHeapIndex(ThreadState* state, size_t size, int he
apIndex, size_t gcInfoIndex) | |
| 1362 { | |
| 1363 ASSERT(state->isAllocationAllowed()); | |
| 1364 ASSERT(heapIndex != ThreadState::LargeObjectHeapIndex); | |
| 1365 NormalPageHeap* heap = static_cast<NormalPageHeap*>(state->heap(heapIndex)); | |
| 1366 return heap->allocateObject(allocationSizeFromSize(size), gcInfoIndex); | |
| 1367 } | |
| 1368 | |
| 1369 template<typename T> | |
| 1370 Address Heap::allocate(size_t size, bool eagerlySweep) | |
| 1371 { | |
| 1372 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); | |
| 1373 return Heap::allocateOnHeapIndex(state, size, eagerlySweep ? ThreadState::Ea
gerSweepHeapIndex : Heap::heapIndexForObjectSize(size), GCInfoTrait<T>::index())
; | |
| 1374 } | |
| 1375 | |
| 1376 template<typename T> | |
| 1377 Address Heap::reallocate(void* previous, size_t size) | |
| 1378 { | |
| 1379 // Not intended to be a full C realloc() substitute; | |
| 1380 // realloc(nullptr, size) is not a supported alias for malloc(size). | |
| 1381 | |
| 1382 // TODO(sof): promptly free the previous object. | |
| 1383 if (!size) { | |
| 1384 // If the new size is 0 this is considered equivalent to free(previous). | |
| 1385 return nullptr; | |
| 1386 } | |
| 1387 | |
| 1388 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); | |
| 1389 HeapObjectHeader* previousHeader = HeapObjectHeader::fromPayload(previous); | |
| 1390 BasePage* page = pageFromObject(previousHeader); | |
| 1391 ASSERT(page); | |
| 1392 int heapIndex = page->heap()->heapIndex(); | |
| 1393 // Recompute the effective heap index if previous allocation | |
| 1394 // was on the normal heaps or a large object. | |
| 1395 if (isNormalHeapIndex(heapIndex) || heapIndex == ThreadState::LargeObjectHea
pIndex) | |
| 1396 heapIndex = heapIndexForObjectSize(size); | |
| 1397 | |
| 1398 // TODO(haraken): We don't support reallocate() for finalizable objects. | |
| 1399 ASSERT(!Heap::gcInfo(previousHeader->gcInfoIndex())->hasFinalizer()); | |
| 1400 ASSERT(previousHeader->gcInfoIndex() == GCInfoTrait<T>::index()); | |
| 1401 Address address = Heap::allocateOnHeapIndex(state, size, heapIndex, GCInfoTr
ait<T>::index()); | |
| 1402 size_t copySize = previousHeader->payloadSize(); | |
| 1403 if (copySize > size) | |
| 1404 copySize = size; | |
| 1405 memcpy(address, previous, copySize); | |
| 1406 return address; | |
| 1407 } | |
| 1408 | |
| 1409 } // namespace blink | 939 } // namespace blink |
| 1410 | 940 |
| 1411 #endif // Heap_h | 941 #endif // HeapPage_h |
| OLD | NEW |