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 #define CHECK_MEMORY_INACCESSIBLE(address, size) \ | 109 #define CHECK_MEMORY_INACCESSIBLE(address, size) \ |
110 ASAN_UNPOISON_MEMORY_REGION(address, size); \ | 110 ASAN_UNPOISON_MEMORY_REGION(address, size); \ |
111 FreeList::checkFreedMemoryIsZapped(address, size); \ | 111 FreeList::checkFreedMemoryIsZapped(address, size); \ |
112 ASAN_POISON_MEMORY_REGION(address, size) | 112 ASAN_POISON_MEMORY_REGION(address, size) |
113 #else | 113 #else |
114 #define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size)) | 114 #define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size)) |
115 #define SET_MEMORY_ACCESSIBLE(address, size) do { } while (false) | 115 #define SET_MEMORY_ACCESSIBLE(address, size) do { } while (false) |
116 #define CHECK_MEMORY_INACCESSIBLE(address, size) do { } while (false) | 116 #define CHECK_MEMORY_INACCESSIBLE(address, size) do { } while (false) |
117 #endif | 117 #endif |
118 | 118 |
119 #if !ENABLE(ASSERT) && CPU(64BIT) | |
120 #define USE_4BYTE_HEADER_PADDING 1 | |
121 #else | |
122 #define USE_4BYTE_HEADER_PADDING 0 | |
123 #endif | |
124 | |
125 class CallbackStack; | 119 class CallbackStack; |
126 class FreePagePool; | 120 class FreePagePool; |
127 class NormalPageHeap; | 121 class NormalPageHeap; |
128 class OrphanedPagePool; | 122 class OrphanedPagePool; |
129 class PageMemory; | 123 class PageMemory; |
130 class PageMemoryRegion; | 124 class PageMemoryRegion; |
131 class WebProcessMemoryDump; | 125 class WebProcessMemoryDump; |
132 | 126 |
133 // HeapObjectHeader is 4 byte (32 bit) that has the following layout: | 127 // HeapObjectHeader has two 4 byte (32 bit) members, and one of them has |
128 // the following bit field layout: | |
134 // | 129 // |
135 // | gcInfoIndex (14 bit) | DOM mark bit (1 bit) | size (14 bit) | dead bit (1 b it) | freed bit (1 bit) | mark bit (1 bit) | | 130 // | gcInfoIndex (14 bit) | DOM mark bit (1 bit) | size (14 bit) | dead bit (1 b it) | freed bit (1 bit) | mark bit (1 bit) |
136 // | 131 // |
137 // - For non-large objects, 14 bit is enough for |size| because the blink | 132 // - For non-large objects, 14 bit is enough for |size| because the blink |
138 // page size is 2^17 byte and each object is guaranteed to be aligned with | 133 // page size is 2^17 byte and each object is guaranteed to be aligned with |
139 // 2^3 byte. | 134 // 2^3 byte. |
140 // - For large objects, |size| is 0. The actual size of a large object is | 135 // - For large objects, |size| is 0. The actual size of a large object is |
141 // stored in LargeObjectPage::m_payloadSize. | 136 // stored in LargeObjectPage::m_payloadSize. |
142 // - 1 bit used to mark DOM trees for V8. | 137 // - 1 bit used to mark DOM trees for V8. |
143 // - 14 bit is enough for gcInfoIndex because there are less than 2^14 types | 138 // - 14 bit is enough for gcInfoIndex because there are less than 2^14 types |
144 // in Blink. | 139 // in Blink. |
145 const size_t headerDOMMarkBitMask = 1u << 17; | 140 const size_t headerDOMMarkBitMask = 1u << 17; |
146 const size_t headerGCInfoIndexShift = 18; | 141 const size_t headerGCInfoIndexShift = 18; |
147 const size_t headerGCInfoIndexMask = (static_cast<size_t>((1 << 14) - 1)) << hea derGCInfoIndexShift; | 142 const size_t headerGCInfoIndexMask = (static_cast<size_t>((1 << 14) - 1)) << hea derGCInfoIndexShift; |
148 const size_t headerSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3; | 143 const size_t headerSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3; |
149 const size_t headerMarkBitMask = 1; | 144 const size_t headerMarkBitMask = 1; |
150 const size_t headerFreedBitMask = 2; | 145 const size_t headerFreedBitMask = 2; |
151 // The dead bit is used for objects that have gone through a GC marking, but did | 146 // The dead bit is used for objects that have gone through a GC marking, but did |
152 // not get swept before a new GC started. In that case we set the dead bit on | 147 // not get swept before a new GC started. In that case we set the dead bit on |
153 // objects that were not marked in the previous GC to ensure we are not tracing | 148 // objects that were not marked in the previous GC to ensure we are not tracing |
154 // them via a conservatively found pointer. Tracing dead objects could lead to | 149 // them via a conservatively found pointer. Tracing dead objects could lead to |
155 // tracing of already finalized objects in another thread's heap which is a | 150 // tracing of already finalized objects in another thread's heap which is a |
156 // use-after-free situation. | 151 // use-after-free situation. |
157 const size_t headerDeadBitMask = 4; | 152 const size_t headerDeadBitMask = 4; |
158 // On free-list entries we reuse the dead bit to distinguish a normal free-list | 153 // On free-list entries we reuse the dead bit to distinguish a normal free-list |
159 // entry from one that has been promptly freed. | 154 // entry from one that has been promptly freed. |
160 const size_t headerPromptlyFreedBitMask = headerFreedBitMask | headerDeadBitMask ; | 155 const size_t headerPromptlyFreedBitMask = headerFreedBitMask | headerDeadBitMask ; |
161 const size_t largeObjectSizeInHeader = 0; | 156 const size_t largeObjectSizeInHeader = 0; |
162 const size_t gcInfoIndexForFreeListHeader = 0; | 157 const size_t gcInfoIndexForFreeListHeader = 0; |
163 const size_t nonLargeObjectPageSizeMax = 1 << 17; | 158 const size_t nonLargeObjectPageSizeMax = 1 << 17; |
159 const uint32_t gcGenerationForFreeListEntry = 0; | |
164 | 160 |
165 static_assert(nonLargeObjectPageSizeMax >= blinkPageSize, "max size supported by HeapObjectHeader must at least be blinkPageSize"); | 161 static_assert(nonLargeObjectPageSizeMax >= blinkPageSize, "max size supported by HeapObjectHeader must at least be blinkPageSize"); |
166 | 162 |
167 class PLATFORM_EXPORT HeapObjectHeader { | 163 class PLATFORM_EXPORT HeapObjectHeader { |
168 public: | 164 public: |
169 // If gcInfoIndex is 0, this header is interpreted as a free list header. | 165 // If gcInfoIndex is 0, this header is interpreted as a free list header. |
170 NO_SANITIZE_ADDRESS | 166 NO_SANITIZE_ADDRESS |
171 HeapObjectHeader(size_t size, size_t gcInfoIndex) | 167 HeapObjectHeader(size_t size, size_t gcInfoIndex, uint32_t generation) |
168 : m_gcGeneration(generation) | |
172 { | 169 { |
173 #if ENABLE(ASSERT) | |
174 m_magic = magic; | |
175 #endif | |
176 // sizeof(HeapObjectHeader) must be equal to or smaller than | 170 // sizeof(HeapObjectHeader) must be equal to or smaller than |
177 // allocationGranurarity, because HeapObjectHeader is used as a header | 171 // allocationGranurarity, because HeapObjectHeader is used as a header |
178 // for an freed entry. Given that the smallest entry size is | 172 // for an freed entry. Given that the smallest entry size is |
179 // allocationGranurarity, HeapObjectHeader must fit into the size. | 173 // allocationGranurarity, HeapObjectHeader must fit into the size. |
180 static_assert(sizeof(HeapObjectHeader) <= allocationGranularity, "size o f HeapObjectHeader must be smaller than allocationGranularity"); | 174 static_assert(sizeof(HeapObjectHeader) <= allocationGranularity, "size o f HeapObjectHeader must be smaller than allocationGranularity"); |
181 #if CPU(64BIT) | 175 #if CPU(64BIT) |
182 static_assert(sizeof(HeapObjectHeader) == 8, "size of HeapObjectHeader m ust be 8 byte aligned"); | 176 static_assert(sizeof(HeapObjectHeader) == 8, "size of HeapObjectHeader m ust be 8 byte aligned"); |
183 #endif | 177 #endif |
184 | 178 |
185 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); | 179 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); |
(...skipping 19 matching lines...) Expand all Loading... | |
205 void unmark(); | 199 void unmark(); |
206 void markDead(); | 200 void markDead(); |
207 bool isDead() const; | 201 bool isDead() const; |
208 | 202 |
209 Address payload(); | 203 Address payload(); |
210 size_t payloadSize(); | 204 size_t payloadSize(); |
211 Address payloadEnd(); | 205 Address payloadEnd(); |
212 | 206 |
213 #if ENABLE(ASSERT) | 207 #if ENABLE(ASSERT) |
214 bool checkHeader() const; | 208 bool checkHeader() const; |
215 // Zap magic number with a new magic number that means there was once an | |
216 // object allocated here, but it was freed because nobody marked it during | |
217 // GC. | |
218 void zapMagic(); | |
219 #endif | 209 #endif |
210 NO_SANITIZE_ADDRESS | |
211 uint32_t gcGeneration() const { return m_gcGeneration; } | |
220 | 212 |
221 void finalize(Address, size_t); | 213 void finalize(Address, size_t); |
222 static HeapObjectHeader* fromPayload(const void*); | 214 static HeapObjectHeader* fromPayload(const void*); |
223 | 215 |
224 static const uint16_t magic = 0xfff1; | |
225 static const uint16_t zappedMagic = 0x4321; | |
226 | |
227 private: | 216 private: |
228 uint32_t m_encoded; | 217 uint32_t m_encoded; |
229 #if ENABLE(ASSERT) | 218 // m_gcGeneration keeps track of the number of GC cycles where the object ge ts |
230 uint16_t m_magic; | 219 // allocated. gcGenerationForFreeListentry indicates that the object has |
231 #endif | 220 // already been freed. |
232 | 221 uint32_t m_gcGeneration; |
233 // In 64 bit architectures, we intentionally add 4 byte padding immediately | |
234 // after the HeapHeaderObject. This is because: | |
235 // | |
236 // | HeapHeaderObject (4 byte) | padding (4 byte) | object payload (8 * n by te) | | |
237 // ^8 byte aligned ^8 byte aligned | |
238 // | |
239 // is better than: | |
240 // | |
241 // | HeapHeaderObject (4 byte) | object payload (8 * n byte) | padding (4 by te) | | |
242 // ^4 byte aligned ^8 byte aligned ^4 byte aligned | |
243 // | |
244 // since the former layout aligns both header and payload to 8 byte. | |
245 #if USE_4BYTE_HEADER_PADDING | |
246 public: | |
247 uint32_t m_padding; | |
248 #endif | |
249 }; | 222 }; |
250 | 223 |
251 class FreeListEntry final : public HeapObjectHeader { | 224 class FreeListEntry final : public HeapObjectHeader { |
252 public: | 225 public: |
253 NO_SANITIZE_ADDRESS | 226 NO_SANITIZE_ADDRESS |
254 explicit FreeListEntry(size_t size) | 227 explicit FreeListEntry(size_t size) |
255 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader) | 228 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader, gcGenerationForFr eeListEntry) |
256 , m_next(nullptr) | 229 , m_next(nullptr) |
257 { | 230 { |
258 #if ENABLE(ASSERT) | 231 #if ENABLE(ASSERT) |
259 ASSERT(size >= sizeof(HeapObjectHeader)); | 232 ASSERT(size >= sizeof(HeapObjectHeader)); |
260 zapMagic(); | |
261 #endif | 233 #endif |
262 } | 234 } |
263 | 235 |
264 Address address() { return reinterpret_cast<Address>(this); } | 236 Address address() { return reinterpret_cast<Address>(this); } |
265 | 237 |
266 NO_SANITIZE_ADDRESS | 238 NO_SANITIZE_ADDRESS |
267 void unlink(FreeListEntry** prevNext) | 239 void unlink(FreeListEntry** prevNext) |
268 { | 240 { |
269 *prevNext = m_next; | 241 *prevNext = m_next; |
270 m_next = nullptr; | 242 m_next = nullptr; |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
696 ASSERT(findPageFromAddress(address + size - 1)); | 668 ASSERT(findPageFromAddress(address + size - 1)); |
697 m_freeList.addToFreeList(address, size); | 669 m_freeList.addToFreeList(address, size); |
698 } | 670 } |
699 void clearFreeLists() override; | 671 void clearFreeLists() override; |
700 #if ENABLE(ASSERT) | 672 #if ENABLE(ASSERT) |
701 bool isConsistentForGC() override; | 673 bool isConsistentForGC() override; |
702 bool pagesToBeSweptContains(Address); | 674 bool pagesToBeSweptContains(Address); |
703 #endif | 675 #endif |
704 void takeFreelistSnapshot(const String& dumpBaseName) override; | 676 void takeFreelistSnapshot(const String& dumpBaseName) override; |
705 | 677 |
706 Address allocateObject(size_t allocationSize, size_t gcInfoIndex); | 678 Address allocateObject(size_t allocationSize, size_t gcInfoIndex, uint32_t g eneration); |
707 | 679 |
708 void freePage(NormalPage*); | 680 void freePage(NormalPage*); |
709 | 681 |
710 bool coalesce(); | 682 bool coalesce(); |
711 void promptlyFreeObject(HeapObjectHeader*); | 683 void promptlyFreeObject(HeapObjectHeader*); |
712 bool expandObject(HeapObjectHeader*, size_t); | 684 bool expandObject(HeapObjectHeader*, size_t); |
713 bool shrinkObject(HeapObjectHeader*, size_t); | 685 bool shrinkObject(HeapObjectHeader*, size_t); |
714 void decreasePromptlyFreedSize(size_t size) { m_promptlyFreedSize -= size; } | 686 void decreasePromptlyFreedSize(size_t size) { m_promptlyFreedSize -= size; } |
715 | 687 |
716 bool isObjectAllocatedAtAllocationPoint(HeapObjectHeader* header) | 688 bool isObjectAllocatedAtAllocationPoint(HeapObjectHeader* header) |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
776 // LargeObjectPage::m_payloadSize. | 748 // LargeObjectPage::m_payloadSize. |
777 ASSERT(result != largeObjectSizeInHeader); | 749 ASSERT(result != largeObjectSizeInHeader); |
778 ASSERT(!pageFromObject(this)->isLargeObjectPage()); | 750 ASSERT(!pageFromObject(this)->isLargeObjectPage()); |
779 return result; | 751 return result; |
780 } | 752 } |
781 | 753 |
782 #if ENABLE(ASSERT) | 754 #if ENABLE(ASSERT) |
783 NO_SANITIZE_ADDRESS inline | 755 NO_SANITIZE_ADDRESS inline |
784 bool HeapObjectHeader::checkHeader() const | 756 bool HeapObjectHeader::checkHeader() const |
785 { | 757 { |
786 return !pageFromObject(this)->orphaned() && m_magic == magic; | 758 ASSERT(isFree() == (m_gcGeneration == gcGenerationForFreeListEntry)); |
759 return !pageFromObject(this)->orphaned(); | |
787 } | 760 } |
788 #endif | 761 #endif |
789 | 762 |
790 inline Address HeapObjectHeader::payload() | 763 inline Address HeapObjectHeader::payload() |
791 { | 764 { |
792 return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader); | 765 return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader); |
793 } | 766 } |
794 | 767 |
795 inline Address HeapObjectHeader::payloadEnd() | 768 inline Address HeapObjectHeader::payloadEnd() |
796 { | 769 { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
848 } | 821 } |
849 | 822 |
850 NO_SANITIZE_ADDRESS inline | 823 NO_SANITIZE_ADDRESS inline |
851 void HeapObjectHeader::markDead() | 824 void HeapObjectHeader::markDead() |
852 { | 825 { |
853 ASSERT(checkHeader()); | 826 ASSERT(checkHeader()); |
854 ASSERT(!isMarked()); | 827 ASSERT(!isMarked()); |
855 m_encoded |= headerDeadBitMask; | 828 m_encoded |= headerDeadBitMask; |
856 } | 829 } |
857 | 830 |
858 inline Address NormalPageHeap::allocateObject(size_t allocationSize, size_t gcIn foIndex) | 831 inline Address NormalPageHeap::allocateObject(size_t allocationSize, size_t gcIn foIndex, uint32_t generation) |
haraken
2015/11/16 09:38:21
gcGeneration
peria
2015/11/16 12:28:45
Done.
| |
859 { | 832 { |
860 if (LIKELY(allocationSize <= m_remainingAllocationSize)) { | 833 if (LIKELY(allocationSize <= m_remainingAllocationSize)) { |
861 Address headerAddress = m_currentAllocationPoint; | 834 Address headerAddress = m_currentAllocationPoint; |
862 m_currentAllocationPoint += allocationSize; | 835 m_currentAllocationPoint += allocationSize; |
863 m_remainingAllocationSize -= allocationSize; | 836 m_remainingAllocationSize -= allocationSize; |
864 ASSERT(gcInfoIndex > 0); | 837 ASSERT(gcInfoIndex > 0); |
865 new (NotNull, headerAddress) HeapObjectHeader(allocationSize, gcInfoInde x); | 838 new (NotNull, headerAddress) HeapObjectHeader(allocationSize, gcInfoInde x, generation); |
866 Address result = headerAddress + sizeof(HeapObjectHeader); | 839 Address result = headerAddress + sizeof(HeapObjectHeader); |
867 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | 840 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); |
868 | 841 |
869 SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader)) ; | 842 SET_MEMORY_ACCESSIBLE(result, allocationSize - sizeof(HeapObjectHeader)) ; |
870 ASSERT(findPageFromAddress(headerAddress + allocationSize - 1)); | 843 ASSERT(findPageFromAddress(headerAddress + allocationSize - 1)); |
871 return result; | 844 return result; |
872 } | 845 } |
873 return outOfLineAllocate(allocationSize, gcInfoIndex); | 846 return outOfLineAllocate(allocationSize, gcInfoIndex); |
874 } | 847 } |
875 | 848 |
876 } // namespace blink | 849 } // namespace blink |
877 | 850 |
878 #endif // HeapPage_h | 851 #endif // HeapPage_h |
OLD | NEW |