Changeset 196845 in webkit
- Timestamp:
- Feb 19, 2016, 4:03:56 PM (11 years ago)
- Location:
- trunk/Source/bmalloc
- Files:
-
- 4 deleted
- 19 edited
-
ChangeLog (modified) (1 diff)
-
bmalloc.xcodeproj/project.pbxproj (modified) (11 diffs)
-
bmalloc/Allocator.cpp (modified) (7 diffs)
-
bmalloc/Allocator.h (modified) (3 diffs)
-
bmalloc/BumpAllocator.h (modified) (2 diffs)
-
bmalloc/Chunk.h (modified) (1 diff)
-
bmalloc/Deallocator.cpp (modified) (2 diffs)
-
bmalloc/Deallocator.h (modified) (1 diff)
-
bmalloc/Heap.cpp (modified) (10 diffs)
-
bmalloc/Heap.h (modified) (5 diffs)
-
bmalloc/LargeChunk.h (modified) (2 diffs)
-
bmalloc/Line.h (modified) (1 diff)
-
bmalloc/MediumChunk.h (deleted)
-
bmalloc/MediumLine.h (deleted)
-
bmalloc/MediumPage.h (deleted)
-
bmalloc/MediumTraits.h (deleted)
-
bmalloc/ObjectType.cpp (modified) (1 diff)
-
bmalloc/ObjectType.h (modified) (1 diff)
-
bmalloc/Page.h (modified) (1 diff)
-
bmalloc/Sizes.h (modified) (4 diffs)
-
bmalloc/SuperChunk.h (modified) (4 diffs)
-
bmalloc/VMHeap.cpp (modified) (2 diffs)
-
bmalloc/VMHeap.h (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/bmalloc/ChangeLog
r196840 r196845 1 2016-02-18 Geoffrey Garen <ggaren@apple.com> 2 3 bmalloc: Remove the concept of medium objects 4 https://bugs.webkit.org/show_bug.cgi?id=154436 5 6 Reviewed by Sam Weinig. 7 8 There's no need to distinguish medium objects from small: Small object 9 metadata works naturally for both as long as we allow an object to 10 span more than two small lines. (We already allow an object to span 11 more than one small line.) 12 13 This change reduces memory use because it eliminates the 1kB line size, 14 so we don't have to hold down 1kB lines for individual 264+ byte objects. 15 16 1kB lines were always a bit of a compromise. The main point of bump 17 allocation is to take advantage of cache lines. Cache lines are usually 18 64 bytes, so line sizes above 256 bytes are a bit of a stretch. 19 20 This change speeds up small object benchmarks because it eliminates the 21 branch to detect medium objects in deallocation log processing. 22 23 This change reduces virtual memory use from worst cast 4X to worst case 24 2X because the medium chunk is gone. iOS cares about virtual memory use 25 and terminates apps above ~1GB, so this change gives us more breathing room. 26 27 This change slows down medium benchmarks a bit because we end up doing 28 more work to recycle fragmented medium objects. Overall, the tradeoff 29 seems justified, since we have a net speedup and a memory use savings. 30 31 * bmalloc.xcodeproj/project.pbxproj: Removed all the medium files. We 32 can simplify even further in a follow-up patch, removing the base class 33 templates for Chunk, Page, and Line as well. 34 35 * bmalloc/Allocator.cpp: 36 (bmalloc::Allocator::Allocator): 37 (bmalloc::Allocator::allocate): 38 (bmalloc::Allocator::reallocate): 39 (bmalloc::Allocator::scavenge): 40 (bmalloc::Allocator::refillAllocatorSlowCase): 41 (bmalloc::Allocator::refillAllocator): 42 (bmalloc::Allocator::allocateSlowCase): Medium is gone. Small max is the 43 new medium max. 44 45 * bmalloc/Allocator.h: 46 (bmalloc::Allocator::allocateFastCase): Ditto. 47 48 * bmalloc/BumpAllocator.h: 49 (bmalloc::BumpAllocator::validate): 50 (bmalloc::BumpAllocator::allocate): No more medium. 51 52 * bmalloc/Chunk.h: No more medium. 53 54 * bmalloc/Deallocator.cpp: 55 (bmalloc::Deallocator::processObjectLog): No check for medium. This is 56 a speedup. 57 58 (bmalloc::Deallocator::deallocateSlowCase): No more medium. 59 60 * bmalloc/Deallocator.h: 61 (bmalloc::Deallocator::deallocateFastCase): Ditto. 62 63 * bmalloc/Heap.cpp: 64 (bmalloc::Heap::initializeLineMetadata): The algorithm here changed from 65 iterating each line to iterating each object. This helps us accomodate 66 objects that might span more than two lines -- i.e., all objects between 67 (512 bytes, 1024 bytes]. 68 69 (bmalloc::Heap::scavenge): 70 (bmalloc::Heap::scavengeSmallPages): 71 (bmalloc::Heap::scavengeLargeObjects): Medium is gone. 72 73 (bmalloc::Heap::allocateSmallBumpRanges): Allow for lines that allocate 74 zero objects. This happens when an object spans more than two lines -- 75 the middle lines allocate zero objects. 76 77 Also set the "has free lines" bit to false if we consume the last free 78 line. This needs to be a bit now because not all pages agree on their 79 maximum refcount anymore, so we need an explicit signal for the transition 80 from maximum to maximum - 1. 81 82 (bmalloc::Heap::allocateSmallPage): This code didn't change; I just removed 83 the medium code. 84 85 (bmalloc::Heap::deallocateSmallLine): Changed the algorithm to check 86 hasFreeLines. See allocateSmallBumpRanges. 87 88 (bmalloc::Heap::scavengeMediumPages): Deleted. 89 (bmalloc::Heap::allocateMediumBumpRanges): Deleted. 90 (bmalloc::Heap::allocateMediumPage): Deleted. 91 (bmalloc::Heap::deallocateMediumLine): Deleted. 92 * bmalloc/Heap.h: 93 (bmalloc::Heap::derefMediumLine): Deleted. 94 95 * bmalloc/LargeChunk.h: 96 (bmalloc::LargeChunk::get): 97 (bmalloc::LargeChunk::endTag): 98 * bmalloc/Line.h: No more medium. 99 100 * bmalloc/MediumChunk.h: Removed. 101 * bmalloc/MediumLine.h: Removed. 102 * bmalloc/MediumPage.h: Removed. 103 * bmalloc/MediumTraits.h: Removed. 104 105 * bmalloc/ObjectType.cpp: 106 (bmalloc::objectType): 107 * bmalloc/ObjectType.h: 108 (bmalloc::isSmall): 109 (bmalloc::isXLarge): 110 (bmalloc::isSmallOrMedium): Deleted. 111 (bmalloc::isMedium): Deleted. No more medium. 112 113 * bmalloc/Page.h: 114 (bmalloc::Page::sizeClass): 115 (bmalloc::Page::setSizeClass): 116 (bmalloc::Page::hasFreeLines): 117 (bmalloc::Page::setHasFreeLines): Add the free lines bit. You get better 118 codegen if you make it the low bit, since ref / deref can then add / sub 119 2. So do that. 120 121 * bmalloc/Sizes.h: 122 (bmalloc::Sizes::sizeClass): Expand the small size class to include the 123 medium size class. 124 125 * bmalloc/SuperChunk.h: 126 (bmalloc::SuperChunk::SuperChunk): 127 (bmalloc::SuperChunk::smallChunk): 128 (bmalloc::SuperChunk::largeChunk): 129 (bmalloc::SuperChunk::mediumChunk): Deleted. No more medium. 130 131 * bmalloc/VMHeap.cpp: 132 (bmalloc::VMHeap::grow): 133 * bmalloc/VMHeap.h: 134 (bmalloc::VMHeap::allocateSmallPage): Set the has free lines bit before 135 returning a Page to the Heap since this is the correct default state 136 when we first allocate a page. 137 138 (bmalloc::VMHeap::allocateMediumPage): Deleted. 139 (bmalloc::VMHeap::deallocateMediumPage): Deleted. 140 1 141 2016-02-19 Michael Saboff <msaboff@apple.com> 2 142 -
trunk/Source/bmalloc/bmalloc.xcodeproj/project.pbxproj
r196840 r196845 40 40 14DD78B418F48D6B00950702 /* Chunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 147AAA9418CE5CA6002201E4 /* Chunk.h */; settings = {ATTRIBUTES = (Private, ); }; }; 41 41 14DD78B518F48D6B00950702 /* Line.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DA32071885F9E6007269E0 /* Line.h */; settings = {ATTRIBUTES = (Private, ); }; }; 42 14DD78B618F48D6B00950702 /* MediumChunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 147AAA8E18CD89E3002201E4 /* MediumChunk.h */; settings = {ATTRIBUTES = (Private, ); }; };43 14DD78B718F48D6B00950702 /* MediumLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 1452478518BC757C00F80098 /* MediumLine.h */; settings = {ATTRIBUTES = (Private, ); }; };44 14DD78B818F48D6B00950702 /* MediumPage.h in Headers */ = {isa = PBXBuildFile; fileRef = 143E29E918CAE8BE00FE8A0F /* MediumPage.h */; settings = {ATTRIBUTES = (Private, ); }; };45 14DD78B918F48D6B00950702 /* MediumTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 147AAA9618CE5FB6002201E4 /* MediumTraits.h */; settings = {ATTRIBUTES = (Private, ); }; };46 42 14DD78BA18F48D6B00950702 /* Page.h in Headers */ = {isa = PBXBuildFile; fileRef = 146BEE2318C980D60002D5A2 /* Page.h */; settings = {ATTRIBUTES = (Private, ); }; }; 47 43 14DD78BB18F48D6B00950702 /* SmallChunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 147AAA8C18CD36A7002201E4 /* SmallChunk.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 94 90 143CB81A19022BC900B16A45 /* StaticMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StaticMutex.cpp; path = bmalloc/StaticMutex.cpp; sourceTree = "<group>"; }; 95 91 143CB81B19022BC900B16A45 /* StaticMutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StaticMutex.h; path = bmalloc/StaticMutex.h; sourceTree = "<group>"; }; 96 143E29E918CAE8BE00FE8A0F /* MediumPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MediumPage.h; path = bmalloc/MediumPage.h; sourceTree = "<group>"; };97 92 143E29ED18CAE90500FE8A0F /* SmallPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmallPage.h; path = bmalloc/SmallPage.h; sourceTree = "<group>"; }; 98 93 143EF9AD1A9FABF6004F5C77 /* FreeList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FreeList.cpp; path = bmalloc/FreeList.cpp; sourceTree = "<group>"; }; … … 110 105 144F7BFB18BFC517003537F3 /* VMHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VMHeap.cpp; path = bmalloc/VMHeap.cpp; sourceTree = "<group>"; }; 111 106 144F7BFC18BFC517003537F3 /* VMHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VMHeap.h; path = bmalloc/VMHeap.h; sourceTree = "<group>"; }; 112 1452478518BC757C00F80098 /* MediumLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MediumLine.h; path = bmalloc/MediumLine.h; sourceTree = "<group>"; };113 107 1452478618BC757C00F80098 /* SmallLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmallLine.h; path = bmalloc/SmallLine.h; sourceTree = "<group>"; }; 114 108 145F6855179DC8CA00D65598 /* Allocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Allocator.cpp; path = bmalloc/Allocator.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; … … 125 119 147AAA8818CD17CE002201E4 /* LargeChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LargeChunk.h; path = bmalloc/LargeChunk.h; sourceTree = "<group>"; }; 126 120 147AAA8C18CD36A7002201E4 /* SmallChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmallChunk.h; path = bmalloc/SmallChunk.h; sourceTree = "<group>"; }; 127 147AAA8E18CD89E3002201E4 /* MediumChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MediumChunk.h; path = bmalloc/MediumChunk.h; sourceTree = "<group>"; };128 121 147AAA9418CE5CA6002201E4 /* Chunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Chunk.h; path = bmalloc/Chunk.h; sourceTree = "<group>"; }; 129 147AAA9618CE5FB6002201E4 /* MediumTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MediumTraits.h; path = bmalloc/MediumTraits.h; sourceTree = "<group>"; };130 122 147AAA9718CE5FB6002201E4 /* SmallTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmallTraits.h; path = bmalloc/SmallTraits.h; sourceTree = "<group>"; }; 131 123 1485655E18A43AF900ED6942 /* BoundaryTag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BoundaryTag.h; path = bmalloc/BoundaryTag.h; sourceTree = "<group>"; }; … … 181 173 1448C2FD18F3752B00502839 /* api */, 182 174 14D9DB4D17F2865C00EAAB79 /* cache */, 183 147AAA9C18CE6010002201E4 /* heap: large | xlarge*/,175 147AAA9C18CE6010002201E4 /* heap: large */, 184 176 147AAA9A18CE5FD3002201E4 /* heap: small | medium */, 185 177 14D9DB4E17F2866E00EAAB79 /* heap */, … … 204 196 147AAA9418CE5CA6002201E4 /* Chunk.h */, 205 197 14DA32071885F9E6007269E0 /* Line.h */, 206 147AAA8E18CD89E3002201E4 /* MediumChunk.h */,207 1452478518BC757C00F80098 /* MediumLine.h */,208 143E29E918CAE8BE00FE8A0F /* MediumPage.h */,209 147AAA9618CE5FB6002201E4 /* MediumTraits.h */,210 198 146BEE2318C980D60002D5A2 /* Page.h */, 211 199 147AAA8C18CD36A7002201E4 /* SmallChunk.h */, … … 217 205 sourceTree = "<group>"; 218 206 }; 219 147AAA9C18CE6010002201E4 /* heap: large | xlarge*/ = {207 147AAA9C18CE6010002201E4 /* heap: large */ = { 220 208 isa = PBXGroup; 221 209 children = ( … … 231 219 14D2CD9A1AA12CFB00770440 /* VMState.h */, 232 220 ); 233 name = "heap: large | xlarge";221 name = "heap: large"; 234 222 sourceTree = "<group>"; 235 223 }; … … 327 315 14DD78CA18F48D7500950702 /* Mutex.h in Headers */, 328 316 143CB81D19022BC900B16A45 /* StaticMutex.h in Headers */, 329 14DD78B918F48D6B00950702 /* MediumTraits.h in Headers */,330 317 1448C30118F3754C00502839 /* bmalloc.h in Headers */, 331 318 14C6216F1A9A9A6200E72293 /* LargeObject.h in Headers */, … … 350 337 1400274A18F89C2300115C97 /* VMHeap.h in Headers */, 351 338 1400274918F89C1300115C97 /* Heap.h in Headers */, 352 14DD78B818F48D6B00950702 /* MediumPage.h in Headers */,353 339 140FA00319CE429C00FFD3C8 /* BumpRange.h in Headers */, 354 340 14DD78C518F48D7500950702 /* Algorithm.h in Headers */, … … 356 342 14DD788E18F48CCD00950702 /* BoundaryTag.h in Headers */, 357 343 14DD78C818F48D7500950702 /* FixedVector.h in Headers */, 358 14DD78B718F48D6B00950702 /* MediumLine.h in Headers */,359 344 14D2CD9B1AA12CFB00770440 /* VMState.h in Headers */, 360 14DD78B618F48D6B00950702 /* MediumChunk.h in Headers */,361 345 14DD78BC18F48D6B00950702 /* SmallLine.h in Headers */, 362 346 14DD789818F48D4A00950702 /* Allocator.h in Headers */, -
trunk/Source/bmalloc/bmalloc/Allocator.cpp
r193373 r196845 43 43 , m_deallocator(deallocator) 44 44 { 45 for (unsigned short size = alignment; size <= mediumMax; size += alignment)45 for (unsigned short size = alignment; size <= smallMax; size += alignment) 46 46 m_bumpAllocators[sizeClass(size)].init(size); 47 47 } … … 88 88 } 89 89 90 if (size <= mediumMax && alignment <= mediumLineSize) {91 size = std::max(size, smallMax + Sizes::alignment);92 size_t alignmentMask = alignment - 1;93 while (void* p = allocate(size)) {94 if (!test(p, alignmentMask))95 return p;96 m_deallocator.deallocate(p);97 }98 }99 100 90 if (size <= largeMax && alignment <= largeMax) { 101 91 size = std::max(largeMin, roundUpToMultipleOf<largeAlignment>(size)); … … 131 121 break; 132 122 } 133 case Medium: {134 MediumPage* page = MediumPage::get(MediumLine::get(object));135 oldSize = objectSize(page->sizeClass());136 break;137 }138 123 case Large: { 139 124 std::unique_lock<StaticMutex> lock(PerProcess<Heap>::mutex()); … … 141 126 oldSize = largeObject.size(); 142 127 143 if (newSize < oldSize && newSize > mediumMax) {128 if (newSize < oldSize && newSize > smallMax) { 144 129 newSize = roundUpToMultipleOf<largeAlignment>(newSize); 145 130 if (oldSize - newSize >= largeMin) { … … 203 188 void Allocator::scavenge() 204 189 { 205 for (unsigned short i = alignment; i <= mediumMax; i += alignment) {190 for (unsigned short i = alignment; i <= smallMax; i += alignment) { 206 191 BumpAllocator& allocator = m_bumpAllocators[sizeClass(i)]; 207 192 BumpRangeCache& bumpRangeCache = m_bumpRangeCaches[sizeClass(i)]; … … 225 210 226 211 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 227 if (sizeClass <= bmalloc::sizeClass(smallMax)) 228 PerProcess<Heap>::getFastCase()->allocateSmallBumpRanges(lock, sizeClass, allocator, bumpRangeCache); 229 else 230 PerProcess<Heap>::getFastCase()->allocateMediumBumpRanges(lock, sizeClass, allocator, bumpRangeCache); 212 PerProcess<Heap>::getFastCase()->allocateSmallBumpRanges(lock, sizeClass, allocator, bumpRangeCache); 231 213 } 232 214 … … 258 240 return malloc(size); 259 241 260 if (size <= mediumMax) {242 if (size <= smallMax) { 261 243 size_t sizeClass = bmalloc::sizeClass(size); 262 244 BumpAllocator& allocator = m_bumpAllocators[sizeClass]; -
trunk/Source/bmalloc/bmalloc/Allocator.h
r191196 r196845 53 53 void* allocateSlowCase(size_t); 54 54 55 void* allocateMedium(size_t);56 55 void* allocateLarge(size_t); 57 56 void* allocateXLarge(size_t); … … 60 59 void refillAllocatorSlowCase(BumpAllocator&, size_t sizeClass); 61 60 62 std::array<BumpAllocator, mediumMax / alignment> m_bumpAllocators;63 std::array<BumpRangeCache, mediumMax / alignment> m_bumpRangeCaches;61 std::array<BumpAllocator, smallMax / alignment> m_bumpAllocators; 62 std::array<BumpRangeCache, smallMax / alignment> m_bumpRangeCaches; 64 63 65 64 bool m_isBmallocEnabled; … … 69 68 inline bool Allocator::allocateFastCase(size_t size, void*& object) 70 69 { 71 if (size > mediumMax)70 if (size > smallMax) 72 71 return false; 73 72 -
trunk/Source/bmalloc/bmalloc/BumpAllocator.h
r173881 r196845 33 33 namespace bmalloc { 34 34 35 // Helper object for allocating small and mediumobjects.35 // Helper object for allocating small objects. 36 36 37 37 class BumpAllocator { … … 80 80 } 81 81 82 BASSERT(m_size <= mediumMax);83 BASSERT(is Medium(ptr));82 BASSERT(m_size <= smallMax); 83 BASSERT(isSmall(ptr)); 84 84 } 85 85 -
trunk/Source/bmalloc/bmalloc/Chunk.h
r180037 r196845 78 78 inline auto Chunk<Traits>::get(void* object) -> Chunk* 79 79 { 80 BASSERT(isSmall OrMedium(object));80 BASSERT(isSmall(object)); 81 81 return static_cast<Chunk*>(mask(object, chunkMask)); 82 82 } -
trunk/Source/bmalloc/bmalloc/Deallocator.cpp
r191002 r196845 78 78 79 79 for (auto* object : m_objectLog) { 80 if (isSmall(object)) { 81 SmallLine* line = SmallLine::get(object); 82 heap->derefSmallLine(lock, line); 83 } else { 84 BASSERT(isMedium(object)); 85 MediumLine* line = MediumLine::get(object); 86 heap->derefMediumLine(lock, line); 87 } 80 SmallLine* line = SmallLine::get(object); 81 heap->derefSmallLine(lock, line); 88 82 } 89 83 … … 104 98 return; 105 99 106 if (isSmall OrMedium(object)) {100 if (isSmall(object)) { 107 101 processObjectLog(); 108 102 m_objectLog.push(object); -
trunk/Source/bmalloc/bmalloc/Deallocator.h
r177181 r196845 57 57 inline bool Deallocator::deallocateFastCase(void* object) 58 58 { 59 if (!isSmall OrMedium(object))59 if (!isSmall(object)) 60 60 return false; 61 61 -
trunk/Source/bmalloc/bmalloc/Heap.cpp
r196840 r196845 29 29 #include "LargeObject.h" 30 30 #include "Line.h" 31 #include "MediumChunk.h"32 31 #include "Page.h" 33 32 #include "PerProcess.h" … … 47 46 void Heap::initializeLineMetadata() 48 47 { 49 for (unsigned short size = alignment; size <= smallMax; size += alignment) { 50 unsigned short startOffset = 0; 51 for (size_t lineNumber = 0; lineNumber < SmallPage::lineCount - 1; ++lineNumber) { 52 unsigned short objectCount; 53 unsigned short remainder; 54 divideRoundingUp(static_cast<unsigned short>(SmallPage::lineSize - startOffset), size, objectCount, remainder); 55 BASSERT(objectCount); 56 m_smallLineMetadata[sizeClass(size)][lineNumber] = { startOffset, objectCount }; 57 startOffset = remainder ? size - remainder : 0; 48 // We assume that m_smallLineMetadata is zero-filled. 49 50 for (size_t size = alignment; size <= smallMax; size += alignment) { 51 size_t sizeClass = bmalloc::sizeClass(size); 52 auto& metadata = m_smallLineMetadata[sizeClass]; 53 54 size_t object = 0; 55 size_t line = 0; 56 while (object < vmPageSize) { 57 line = object / SmallPage::lineSize; 58 size_t leftover = object % SmallPage::lineSize; 59 60 size_t objectCount; 61 size_t remainder; 62 divideRoundingUp(SmallPage::lineSize - leftover, size, objectCount, remainder); 63 64 metadata[line] = { static_cast<unsigned short>(leftover), static_cast<unsigned short>(objectCount) }; 65 66 object += objectCount * size; 58 67 } 59 68 60 // The last line in the page rounds down instead of up because it's not allowed to overlap into its neighbor. 61 unsigned short objectCount = static_cast<unsigned short>((SmallPage::lineSize - startOffset) / size); 62 m_smallLineMetadata[sizeClass(size)][SmallPage::lineCount - 1] = { startOffset, objectCount }; 63 } 64 65 for (unsigned short size = smallMax + alignment; size <= mediumMax; size += alignment) { 66 unsigned short startOffset = 0; 67 for (size_t lineNumber = 0; lineNumber < MediumPage::lineCount - 1; ++lineNumber) { 68 unsigned short objectCount; 69 unsigned short remainder; 70 divideRoundingUp(static_cast<unsigned short>(MediumPage::lineSize - startOffset), size, objectCount, remainder); 71 BASSERT(objectCount); 72 m_mediumLineMetadata[sizeClass(size)][lineNumber] = { startOffset, objectCount }; 73 startOffset = remainder ? size - remainder : 0; 69 // Don't allow the last object in a page to escape the page. 70 if (object > vmPageSize) { 71 BASSERT(metadata[line].objectCount); 72 --metadata[line].objectCount; 74 73 } 75 76 // The last line in the page rounds down instead of up because it's not allowed to overlap into its neighbor.77 unsigned short objectCount = static_cast<unsigned short>((MediumPage::lineSize - startOffset) / size);78 m_mediumLineMetadata[sizeClass(size)][MediumPage::lineCount - 1] = { startOffset, objectCount };79 74 } 80 75 } … … 91 86 92 87 scavengeSmallPages(lock, sleepDuration); 93 scavengeMediumPages(lock, sleepDuration);94 88 scavengeLargeObjects(lock, sleepDuration); 95 89 … … 105 99 } 106 100 107 void Heap::scavengeMediumPages(std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds sleepDuration)108 {109 while (m_mediumPages.size()) {110 m_vmHeap.deallocateMediumPage(lock, m_mediumPages.pop());111 waitUntilFalse(lock, sleepDuration, m_isAllocatingPages);112 }113 }114 115 101 void Heap::scavengeLargeObjects(std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds sleepDuration) 116 102 { … … 126 112 SmallPage* page = allocateSmallPage(lock, sizeClass); 127 113 SmallLine* lines = page->begin(); 128 129 // Due to overlap from the previous line, the last line in the page may not be able to fit any objects. 130 size_t end = SmallPage::lineCount; 131 if (!m_smallLineMetadata[sizeClass][SmallPage::lineCount - 1].objectCount) 132 --end; 114 BASSERT(page->hasFreeLines(lock)); 133 115 134 116 // Find a free line. 135 for (size_t lineNumber = 0; lineNumber < end; ++lineNumber) {117 for (size_t lineNumber = 0; lineNumber < SmallPage::lineCount; ++lineNumber) { 136 118 if (lines[lineNumber].refCount(lock)) 119 continue; 120 121 LineMetadata& lineMetadata = m_smallLineMetadata[sizeClass][lineNumber]; 122 if (!lineMetadata.objectCount) 137 123 continue; 138 124 … … 143 129 } 144 130 145 LineMetadata& lineMetadata = m_smallLineMetadata[sizeClass][lineNumber];146 131 char* begin = lines[lineNumber].begin() + lineMetadata.startOffset; 147 132 unsigned short objectCount = lineMetadata.objectCount; … … 150 135 151 136 // Merge with subsequent free lines. 152 while (++lineNumber < end) {137 while (++lineNumber < SmallPage::lineCount) { 153 138 if (lines[lineNumber].refCount(lock)) 154 139 break; 155 140 156 141 LineMetadata& lineMetadata = m_smallLineMetadata[sizeClass][lineNumber]; 142 if (!lineMetadata.objectCount) 143 continue; 144 157 145 objectCount += lineMetadata.objectCount; 158 146 lines[lineNumber].ref(lock, lineMetadata.objectCount); … … 165 153 rangeCache.push({ begin, objectCount }); 166 154 } 167 } 168 169 void Heap::allocateMediumBumpRanges(std::lock_guard<StaticMutex>& lock, size_t sizeClass, BumpAllocator& allocator, BumpRangeCache& rangeCache) 170 { 171 MediumPage* page = allocateMediumPage(lock, sizeClass); 172 BASSERT(!rangeCache.size()); 173 MediumLine* lines = page->begin(); 174 175 // Due to overlap from the previous line, the last line in the page may not be able to fit any objects. 176 size_t end = MediumPage::lineCount; 177 if (!m_mediumLineMetadata[sizeClass][MediumPage::lineCount - 1].objectCount) 178 --end; 179 180 // Find a free line. 181 for (size_t lineNumber = 0; lineNumber < end; ++lineNumber) { 182 if (lines[lineNumber].refCount(lock)) 183 continue; 184 185 // In a fragmented page, some free ranges might not fit in the cache. 186 if (rangeCache.size() == rangeCache.capacity()) { 187 m_mediumPagesWithFreeLines[sizeClass].push(page); 188 return; 189 } 190 191 LineMetadata& lineMetadata = m_mediumLineMetadata[sizeClass][lineNumber]; 192 char* begin = lines[lineNumber].begin() + lineMetadata.startOffset; 193 unsigned short objectCount = lineMetadata.objectCount; 194 lines[lineNumber].ref(lock, lineMetadata.objectCount); 195 page->ref(lock); 196 197 // Merge with subsequent free lines. 198 while (++lineNumber < end) { 199 if (lines[lineNumber].refCount(lock)) 200 break; 201 202 LineMetadata& lineMetadata = m_mediumLineMetadata[sizeClass][lineNumber]; 203 objectCount += lineMetadata.objectCount; 204 lines[lineNumber].ref(lock, lineMetadata.objectCount); 205 page->ref(lock); 206 } 207 208 if (!allocator.canAllocate()) 209 allocator.refill({ begin, objectCount }); 210 else 211 rangeCache.push({ begin, objectCount }); 212 } 155 156 page->setHasFreeLines(lock, false); 213 157 } 214 158 … … 223 167 } 224 168 225 SmallPage* page = [this, sizeClass]() {169 SmallPage* page = [this, &lock]() { 226 170 if (m_smallPages.size()) 227 171 return m_smallPages.pop(); 228 172 229 173 m_isAllocatingPages = true; 230 return m_vmHeap.allocateSmallPage(); 174 SmallPage* page = m_vmHeap.allocateSmallPage(lock); 175 return page; 231 176 }(); 232 177 … … 235 180 } 236 181 237 MediumPage* Heap::allocateMediumPage(std::lock_guard<StaticMutex>& lock, size_t sizeClass)238 {239 Vector<MediumPage*>& mediumPagesWithFreeLines = m_mediumPagesWithFreeLines[sizeClass];240 while (mediumPagesWithFreeLines.size()) {241 MediumPage* page = mediumPagesWithFreeLines.pop();242 if (!page->refCount(lock) || page->sizeClass() != sizeClass) // Page was promoted to the pages list.243 continue;244 return page;245 }246 247 MediumPage* page = [this, sizeClass]() {248 if (m_mediumPages.size())249 return m_mediumPages.pop();250 251 m_isAllocatingPages = true;252 return m_vmHeap.allocateMediumPage();253 }();254 255 page->setSizeClass(sizeClass);256 return page;257 }258 259 182 void Heap::deallocateSmallLine(std::lock_guard<StaticMutex>& lock, SmallLine* line) 260 183 { 261 184 BASSERT(!line->refCount(lock)); 262 185 SmallPage* page = SmallPage::get(line); 263 size_t refCount = page->refCount(lock);264 186 page->deref(lock); 265 187 266 switch (refCount) { 267 case SmallPage::lineCount: { 268 // First free line in the page. 188 if (!page->hasFreeLines(lock)) { 189 page->setHasFreeLines(lock, true); 269 190 m_smallPagesWithFreeLines[page->sizeClass()].push(page); 270 break; 271 } 272 case 1: { 273 // Last free line in the page. 274 m_smallPages.push(page); 275 m_scavenger.run(); 276 break; 277 } 278 } 279 } 280 281 void Heap::deallocateMediumLine(std::lock_guard<StaticMutex>& lock, MediumLine* line) 282 { 283 BASSERT(!line->refCount(lock)); 284 MediumPage* page = MediumPage::get(line); 285 size_t refCount = page->refCount(lock); 286 page->deref(lock); 287 288 switch (refCount) { 289 case MediumPage::lineCount: { 290 // First free line in the page. 291 m_mediumPagesWithFreeLines[page->sizeClass()].push(page); 292 break; 293 } 294 case 1: { 295 // Last free line in the page. 296 m_mediumPages.push(page); 297 m_scavenger.run(); 298 break; 299 } 300 } 191 192 BASSERT(page->refCount(lock)); 193 return; 194 } 195 196 if (page->refCount(lock)) 197 return; 198 199 m_smallPages.push(page); 200 m_scavenger.run(); 301 201 } 302 202 -
trunk/Source/bmalloc/bmalloc/Heap.h
r196840 r196845 30 30 #include "Environment.h" 31 31 #include "LineMetadata.h" 32 #include "MediumChunk.h"33 #include "MediumLine.h"34 #include "MediumPage.h"35 32 #include "Mutex.h" 36 33 #include "SegregatedFreeList.h" … … 58 55 void derefSmallLine(std::lock_guard<StaticMutex>&, SmallLine*); 59 56 60 void allocateMediumBumpRanges(std::lock_guard<StaticMutex>&, size_t sizeClass, BumpAllocator&, BumpRangeCache&);61 void derefMediumLine(std::lock_guard<StaticMutex>&, MediumLine*);62 63 57 void* allocateLarge(std::lock_guard<StaticMutex>&, size_t); 64 58 void* allocateLarge(std::lock_guard<StaticMutex>&, size_t alignment, size_t, size_t unalignedSize); … … 79 73 80 74 SmallPage* allocateSmallPage(std::lock_guard<StaticMutex>&, size_t sizeClass); 81 MediumPage* allocateMediumPage(std::lock_guard<StaticMutex>&, size_t sizeClass);82 75 83 76 void deallocateSmallLine(std::lock_guard<StaticMutex>&, SmallLine*); 84 void deallocateMediumLine(std::lock_guard<StaticMutex>&, MediumLine*);85 86 77 void deallocateLarge(std::lock_guard<StaticMutex>&, const LargeObject&); 87 78 … … 94 85 void concurrentScavenge(); 95 86 void scavengeSmallPages(std::unique_lock<StaticMutex>&, std::chrono::milliseconds); 96 void scavengeMediumPages(std::unique_lock<StaticMutex>&, std::chrono::milliseconds);97 87 void scavengeLargeObjects(std::unique_lock<StaticMutex>&, std::chrono::milliseconds); 98 88 99 89 std::array<std::array<LineMetadata, SmallPage::lineCount>, smallMax / alignment> m_smallLineMetadata; 100 std::array<std::array<LineMetadata, MediumPage::lineCount>, mediumMax / alignment> m_mediumLineMetadata;101 90 102 91 std::array<Vector<SmallPage*>, smallMax / alignment> m_smallPagesWithFreeLines; 103 std::array<Vector<MediumPage*>, mediumMax / alignment> m_mediumPagesWithFreeLines;104 92 105 93 Vector<SmallPage*> m_smallPages; 106 Vector<MediumPage*> m_mediumPages;107 94 108 95 SegregatedFreeList m_largeObjects; … … 124 111 } 125 112 126 inline void Heap::derefMediumLine(std::lock_guard<StaticMutex>& lock, MediumLine* line)127 {128 if (!line->deref(lock))129 return;130 deallocateMediumLine(lock, line);131 }132 133 113 } // namespace bmalloc 134 114 -
trunk/Source/bmalloc/bmalloc/LargeChunk.h
r196186 r196845 84 84 inline LargeChunk* LargeChunk::get(void* object) 85 85 { 86 BASSERT(!isSmall OrMedium(object));86 BASSERT(!isSmall(object)); 87 87 return static_cast<LargeChunk*>(mask(object, largeChunkMask)); 88 88 } … … 97 97 inline EndTag* LargeChunk::endTag(void* object, size_t size) 98 98 { 99 BASSERT(!isSmall OrMedium(object));99 BASSERT(!isSmall(object)); 100 100 101 101 LargeChunk* chunk = get(object); -
trunk/Source/bmalloc/bmalloc/Line.h
r179923 r196845 61 61 inline auto Line<Traits>::get(void* object) -> Line* 62 62 { 63 BASSERT(isSmall OrMedium(object));63 BASSERT(isSmall(object)); 64 64 Chunk* chunk = Chunk::get(object); 65 65 size_t lineNumber = (reinterpret_cast<char*>(object) - reinterpret_cast<char*>(chunk)) / lineSize; -
trunk/Source/bmalloc/bmalloc/ObjectType.cpp
r178621 r196845 31 31 ObjectType objectType(void* object) 32 32 { 33 if (isSmallOrMedium(object)) { 34 if (isSmall(object)) 35 return Small; 36 return Medium; 37 } 33 if (isSmall(object)) 34 return Small; 38 35 39 36 if (!isXLarge(object)) -
trunk/Source/bmalloc/bmalloc/ObjectType.h
r178621 r196845 32 32 namespace bmalloc { 33 33 34 enum ObjectType { Small, Medium,Large, XLarge };34 enum ObjectType { Small, Large, XLarge }; 35 35 36 36 ObjectType objectType(void*); 37 37 38 inline bool isSmall OrMedium(void* object)38 inline bool isSmall(void* object) 39 39 { 40 return test(object, smallOrMediumTypeMask); 41 } 42 43 inline bool isSmall(void* smallOrMedium) 44 { 45 BASSERT(isSmallOrMedium(smallOrMedium)); 46 return test(smallOrMedium, smallOrMediumSmallTypeMask); 47 } 48 49 inline bool isMedium(void* smallOrMedium) 50 { 51 return !isSmall(smallOrMedium); 40 return test(object, smallMask); 52 41 } 53 42 54 43 inline bool isXLarge(void* object) 55 44 { 56 return !test(object, superChunkSize - 1);45 return !test(object, ~superChunkMask); 57 46 } 58 47 -
trunk/Source/bmalloc/bmalloc/Page.h
r179923 r196845 55 55 void setSizeClass(size_t sizeClass) { m_sizeClass = sizeClass; } 56 56 57 bool hasFreeLines(std::lock_guard<StaticMutex>&) const { return m_hasFreeLines; } 58 void setHasFreeLines(std::lock_guard<StaticMutex>&, bool hasFreeLines) { m_hasFreeLines = hasFreeLines; } 59 57 60 Line* begin(); 58 61 Line* end(); 59 62 60 63 private: 61 unsigned char m_refCount; 64 unsigned char m_hasFreeLines: 1; 65 unsigned char m_refCount: 7; 62 66 unsigned char m_sizeClass; 63 67 }; -
trunk/Source/bmalloc/bmalloc/Sizes.h
r196186 r196845 55 55 56 56 static const size_t superChunkSize = 2 * MB; 57 static const size_t superChunkMask = ~(superChunkSize - 1); 57 58 58 static const size_t smallMax = 256;59 static const size_t smallMax = 1024; 59 60 static const size_t smallLineSize = 256; 60 61 static const size_t smallLineMask = ~(smallLineSize - 1ul); 61 62 62 static const size_t smallChunkSize = superChunkSize / 4;63 static const size_t smallChunkOffset = superChunkSize * 3 / 4;63 static const size_t smallChunkSize = superChunkSize / 2; 64 static const size_t smallChunkOffset = superChunkSize / 2; 64 65 static const size_t smallChunkMask = ~(smallChunkSize - 1ul); 65 66 static const size_t mediumMax = 1024;67 static const size_t mediumLineSize = 1024;68 static const size_t mediumLineMask = ~(mediumLineSize - 1ul);69 70 static const size_t mediumChunkSize = superChunkSize / 4;71 static const size_t mediumChunkOffset = superChunkSize * 2 / 4;72 static const size_t mediumChunkMask = ~(mediumChunkSize - 1ul);73 66 74 67 static const size_t largeChunkSize = superChunkSize / 2; … … 83 76 static const size_t largeAlignment = 64; 84 77 static const size_t largeMax = largeChunkSize - largeChunkMetadataSize; 85 static const size_t largeMin = mediumMax;78 static const size_t largeMin = smallMax; 86 79 87 80 static const size_t xLargeAlignment = vmPageSize; … … 91 84 static const size_t freeListGrowFactor = 2; 92 85 93 static const uintptr_t typeMask = (superChunkSize - 1) & ~((superChunkSize / 4) - 1); // 4 taggable chunks 94 static const uintptr_t smallType = (superChunkSize + smallChunkOffset) & typeMask; 95 static const uintptr_t mediumType = (superChunkSize + mediumChunkOffset) & typeMask; 96 static const uintptr_t largeTypeMask = ~(mediumType & smallType); 97 static const uintptr_t smallOrMediumTypeMask = mediumType & smallType; 98 static const uintptr_t smallOrMediumSmallTypeMask = smallType ^ mediumType; // Only valid if object is known to be small or medium. 86 static const uintptr_t typeMask = (superChunkSize - 1) & ~((superChunkSize / 2) - 1); // 2 taggable chunks 87 static const uintptr_t largeMask = typeMask & (superChunkSize + largeChunkOffset); 88 static const uintptr_t smallMask = typeMask & (superChunkSize + smallChunkOffset); 99 89 100 90 static const size_t deallocatorLogCapacity = 256; … … 105 95 inline size_t sizeClass(size_t size) 106 96 { 107 static const size_t sizeClassMask = ( mediumMax / alignment) - 1;97 static const size_t sizeClassMask = (smallMax / alignment) - 1; 108 98 return mask((size - 1) / alignment, sizeClassMask); 109 99 } -
trunk/Source/bmalloc/bmalloc/SuperChunk.h
r180272 r196845 28 28 29 29 #include "LargeChunk.h" 30 #include "MediumChunk.h"31 30 #include "SmallChunk.h" 32 31 … … 38 37 39 38 SmallChunk* smallChunk(); 40 MediumChunk* mediumChunk();41 39 LargeChunk* largeChunk(); 42 40 … … 54 52 { 55 53 new (smallChunk()) SmallChunk; 56 new (mediumChunk()) MediumChunk;57 54 new (largeChunk()) LargeChunk; 58 55 } … … 62 59 return reinterpret_cast<SmallChunk*>( 63 60 reinterpret_cast<char*>(this) + smallChunkOffset); 64 }65 66 inline MediumChunk* SuperChunk::mediumChunk()67 {68 return reinterpret_cast<MediumChunk*>(69 reinterpret_cast<char*>(this) + mediumChunkOffset);70 61 } 71 62 -
trunk/Source/bmalloc/bmalloc/VMHeap.cpp
r196840 r196845 25 25 26 26 #include "LargeObject.h" 27 #include "Line.h"28 27 #include "PerProcess.h" 29 28 #include "SuperChunk.h" … … 49 48 m_smallPages.push(it); 50 49 51 MediumChunk* mediumChunk = superChunk->mediumChunk();52 for (auto* it = mediumChunk->begin(); it != mediumChunk->end(); ++it)53 m_mediumPages.push(it);54 55 50 LargeChunk* largeChunk = superChunk->largeChunk(); 56 51 LargeObject result(LargeObject::init(largeChunk).begin()); -
trunk/Source/bmalloc/bmalloc/VMHeap.h
r196840 r196845 31 31 #include "LargeChunk.h" 32 32 #include "LargeObject.h" 33 #include "MediumChunk.h"34 33 #include "Range.h" 35 34 #include "SegregatedFreeList.h" … … 52 51 VMHeap(); 53 52 54 SmallPage* allocateSmallPage(); 55 MediumPage* allocateMediumPage(); 53 SmallPage* allocateSmallPage(std::lock_guard<StaticMutex>&); 56 54 LargeObject allocateLargeObject(size_t); 57 55 LargeObject allocateLargeObject(size_t, size_t, size_t); 58 56 59 57 void deallocateSmallPage(std::unique_lock<StaticMutex>&, SmallPage*); 60 void deallocateMediumPage(std::unique_lock<StaticMutex>&, MediumPage*);61 58 void deallocateLargeObject(std::unique_lock<StaticMutex>&, LargeObject); 62 59 … … 65 62 66 63 Vector<SmallPage*> m_smallPages; 67 Vector<MediumPage*> m_mediumPages;68 64 SegregatedFreeList m_largeObjects; 69 65 #if BOS(DARWIN) … … 72 68 }; 73 69 74 inline SmallPage* VMHeap::allocateSmallPage( )70 inline SmallPage* VMHeap::allocateSmallPage(std::lock_guard<StaticMutex>& lock) 75 71 { 76 72 if (!m_smallPages.size()) … … 78 74 79 75 SmallPage* page = m_smallPages.pop(); 80 vmAllocatePhysicalPages(page->begin()->begin(), vmPageSize); 81 return page; 82 } 83 84 inline MediumPage* VMHeap::allocateMediumPage() 85 { 86 if (!m_mediumPages.size()) 87 grow(); 88 89 MediumPage* page = m_mediumPages.pop(); 76 page->setHasFreeLines(lock, true); 90 77 vmAllocatePhysicalPages(page->begin()->begin(), vmPageSize); 91 78 return page; … … 125 112 } 126 113 127 inline void VMHeap::deallocateMediumPage(std::unique_lock<StaticMutex>& lock, MediumPage* page)128 {129 lock.unlock();130 vmDeallocatePhysicalPages(page->begin()->begin(), vmPageSize);131 lock.lock();132 133 m_mediumPages.push(page);134 }135 136 114 inline void VMHeap::deallocateLargeObject(std::unique_lock<StaticMutex>& lock, LargeObject largeObject) 137 115 {
Note:
See TracChangeset
for help on using the changeset viewer.