Changeset 243688 in webkit
- Timestamp:
- Mar 31, 2019, 11:51:11 PM (7 years ago)
- Location:
- trunk/Source
- Files:
-
- 21 edited
-
JavaScriptCore/ChangeLog (modified) (1 diff)
-
JavaScriptCore/heap/AlignedMemoryAllocator.h (modified) (1 diff)
-
JavaScriptCore/heap/CompleteSubspace.cpp (modified) (2 diffs)
-
JavaScriptCore/heap/CompleteSubspace.h (modified) (1 diff)
-
JavaScriptCore/heap/FastMallocAlignedMemoryAllocator.cpp (modified) (1 diff)
-
JavaScriptCore/heap/FastMallocAlignedMemoryAllocator.h (modified) (1 diff)
-
JavaScriptCore/heap/GigacageAlignedMemoryAllocator.cpp (modified) (1 diff)
-
JavaScriptCore/heap/GigacageAlignedMemoryAllocator.h (modified) (1 diff)
-
JavaScriptCore/heap/IsoAlignedMemoryAllocator.cpp (modified) (1 diff)
-
JavaScriptCore/heap/IsoAlignedMemoryAllocator.h (modified) (1 diff)
-
JavaScriptCore/heap/LargeAllocation.cpp (modified) (2 diffs)
-
JavaScriptCore/heap/LargeAllocation.h (modified) (4 diffs)
-
JavaScriptCore/heap/MarkedSpace.cpp (modified) (2 diffs)
-
JavaScriptCore/heap/WeakSet.h (modified) (2 diffs)
-
JavaScriptCore/runtime/Butterfly.h (modified) (1 diff)
-
JavaScriptCore/runtime/ButterflyInlines.h (modified) (1 diff)
-
JavaScriptCore/runtime/JSObject.cpp (modified) (3 diffs)
-
WTF/ChangeLog (modified) (1 diff)
-
WTF/wtf/FastMalloc.h (modified) (1 diff)
-
WTF/wtf/Gigacage.cpp (modified) (2 diffs)
-
WTF/wtf/Gigacage.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r243683 r243688 1 2019-03-31 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] Butterfly allocation from LargeAllocation should try "realloc" behavior if collector thread is not active 4 https://bugs.webkit.org/show_bug.cgi?id=196160 5 6 Reviewed by Saam Barati. 7 8 "realloc" can be effective in terms of peak/current memory footprint when realloc succeeds because, 9 10 1. It does not allocate additional memory while expanding a vector 11 2. It does not deallocate an old memory, just reusing the current memory by expanding, so that memory footprint is tight even before scavenging 12 13 We found that we can "realloc" large butterflies in certain conditions are met because, 14 15 1. If it goes to LargeAllocation, this memory region is never reused until GC sweeps it. 16 2. Butterflies are owned by owner JSObjects, so we know the lifetime of Butterflies. 17 18 This patch attempts to use "realloc" onto butterflies if, 19 20 1. Butterflies are allocated in LargeAllocation kind 21 2. Concurrent collector is not active 22 3. Butterflies do not have property storage 23 24 The condition (2) is required to avoid deallocating butterflies while the concurrent collector looks into it. The condition (3) is 25 also required to avoid deallocating butterflies while the concurrent compiler looks into it. 26 27 We also change LargeAllocation mechanism to using "malloc" and "free" instead of "posix_memalign". This allows us to use "realloc" 28 safely in all the platforms. Since LargeAllocation uses alignment to distinguish LargeAllocation and MarkedBlock, we manually adjust 29 16B alignment by allocating 8B more memory in "malloc". 30 31 Speedometer2 and JetStream2 are neutral. RAMification shows about 1% progression (even in some of JIT tests). 32 33 * heap/AlignedMemoryAllocator.h: 34 * heap/CompleteSubspace.cpp: 35 (JSC::CompleteSubspace::tryAllocateSlow): 36 (JSC::CompleteSubspace::reallocateLargeAllocationNonVirtual): 37 * heap/CompleteSubspace.h: 38 * heap/FastMallocAlignedMemoryAllocator.cpp: 39 (JSC::FastMallocAlignedMemoryAllocator::tryAllocateMemory): 40 (JSC::FastMallocAlignedMemoryAllocator::freeMemory): 41 (JSC::FastMallocAlignedMemoryAllocator::tryReallocateMemory): 42 * heap/FastMallocAlignedMemoryAllocator.h: 43 * heap/GigacageAlignedMemoryAllocator.cpp: 44 (JSC::GigacageAlignedMemoryAllocator::tryAllocateMemory): 45 (JSC::GigacageAlignedMemoryAllocator::freeMemory): 46 (JSC::GigacageAlignedMemoryAllocator::tryReallocateMemory): 47 * heap/GigacageAlignedMemoryAllocator.h: 48 * heap/IsoAlignedMemoryAllocator.cpp: 49 (JSC::IsoAlignedMemoryAllocator::tryAllocateMemory): 50 (JSC::IsoAlignedMemoryAllocator::freeMemory): 51 (JSC::IsoAlignedMemoryAllocator::tryReallocateMemory): 52 * heap/IsoAlignedMemoryAllocator.h: 53 * heap/LargeAllocation.cpp: 54 (JSC::isAlignedForLargeAllocation): 55 (JSC::LargeAllocation::tryCreate): 56 (JSC::LargeAllocation::tryReallocate): 57 (JSC::LargeAllocation::LargeAllocation): 58 (JSC::LargeAllocation::destroy): 59 * heap/LargeAllocation.h: 60 (JSC::LargeAllocation::indexInSpace): 61 (JSC::LargeAllocation::setIndexInSpace): 62 (JSC::LargeAllocation::basePointer const): 63 * heap/MarkedSpace.cpp: 64 (JSC::MarkedSpace::sweepLargeAllocations): 65 (JSC::MarkedSpace::prepareForConservativeScan): 66 * heap/WeakSet.h: 67 (JSC::WeakSet::isTriviallyDestructible const): 68 * runtime/Butterfly.h: 69 * runtime/ButterflyInlines.h: 70 (JSC::Butterfly::reallocArrayRightIfPossible): 71 * runtime/JSObject.cpp: 72 (JSC::JSObject::ensureLengthSlow): 73 1 74 2019-03-31 Sam Weinig <weinig@apple.com> 2 75 -
trunk/Source/JavaScriptCore/heap/AlignedMemoryAllocator.h
r226822 r243688 51 51 void registerSubspace(Subspace*); 52 52 53 // Some of derived memory allocators do not have these features because they do not use them. 54 // For example, IsoAlignedMemoryAllocator does not have "realloc" feature since it never extends / shrinks the allocated memory region. 55 virtual void* tryAllocateMemory(size_t) = 0; 56 virtual void freeMemory(void*) = 0; 57 virtual void* tryReallocateMemory(void*, size_t) = 0; 58 53 59 private: 54 60 SinglyLinkedListWithTail<BlockDirectory> m_directories; -
trunk/Source/JavaScriptCore/heap/CompleteSubspace.cpp
r241927 r243688 141 141 142 142 size = WTF::roundUpToMultipleOf<MarkedSpace::sizeStep>(size); 143 LargeAllocation* allocation = LargeAllocation::tryCreate(vm.heap, size, this );143 LargeAllocation* allocation = LargeAllocation::tryCreate(vm.heap, size, this, m_space.m_largeAllocations.size()); 144 144 if (!allocation) 145 145 return nullptr; 146 146 147 147 m_space.m_largeAllocations.append(allocation); 148 ASSERT(allocation->indexInSpace() == m_space.m_largeAllocations.size() - 1); 148 149 vm.heap.didAllocate(size); 149 150 m_space.m_capacity += size; … … 154 155 } 155 156 157 void* CompleteSubspace::reallocateLargeAllocationNonVirtual(VM& vm, HeapCell* oldCell, size_t size, GCDeferralContext* deferralContext, AllocationFailureMode failureMode) 158 { 159 if (validateDFGDoesGC) 160 RELEASE_ASSERT(vm.heap.expectDoesGC()); 161 162 // The following conditions are met in Butterfly for example. 163 ASSERT(oldCell->isLargeAllocation()); 164 165 LargeAllocation* oldAllocation = &oldCell->largeAllocation(); 166 ASSERT(oldAllocation->cellSize() <= size); 167 ASSERT(oldAllocation->weakSet().isTriviallyDestructible()); 168 ASSERT(oldAllocation->attributes().destruction == DoesNotNeedDestruction); 169 ASSERT(oldAllocation->attributes().cellKind == HeapCell::Auxiliary); 170 ASSERT(size > MarkedSpace::largeCutoff); 171 172 sanitizeStackForVM(&vm); 173 174 if (size <= Options::largeAllocationCutoff() 175 && size <= MarkedSpace::largeCutoff) { 176 dataLog("FATAL: attampting to allocate small object using large allocation.\n"); 177 dataLog("Requested allocation size: ", size, "\n"); 178 RELEASE_ASSERT_NOT_REACHED(); 179 } 180 181 vm.heap.collectIfNecessaryOrDefer(deferralContext); 182 183 size = WTF::roundUpToMultipleOf<MarkedSpace::sizeStep>(size); 184 size_t difference = size - oldAllocation->cellSize(); 185 unsigned oldIndexInSpace = oldAllocation->indexInSpace(); 186 if (oldAllocation->isOnList()) 187 oldAllocation->remove(); 188 189 LargeAllocation* allocation = oldAllocation->tryReallocate(size, this); 190 if (!allocation) { 191 RELEASE_ASSERT(failureMode != AllocationFailureMode::Assert); 192 m_largeAllocations.append(oldAllocation); 193 return nullptr; 194 } 195 ASSERT(oldIndexInSpace == allocation->indexInSpace()); 196 197 m_space.m_largeAllocations[oldIndexInSpace] = allocation; 198 vm.heap.didAllocate(difference); 199 m_space.m_capacity += difference; 200 201 m_largeAllocations.append(allocation); 202 203 return allocation->cell(); 204 } 205 156 206 } // namespace JSC 157 207 -
trunk/Source/JavaScriptCore/heap/CompleteSubspace.h
r232132 r243688 45 45 void* allocate(VM&, size_t, GCDeferralContext*, AllocationFailureMode) override; 46 46 void* allocateNonVirtual(VM&, size_t, GCDeferralContext*, AllocationFailureMode); 47 void* reallocateLargeAllocationNonVirtual(VM&, HeapCell*, size_t, GCDeferralContext*, AllocationFailureMode); 47 48 48 49 static ptrdiff_t offsetOfAllocatorForSizeStep() { return OBJECT_OFFSETOF(CompleteSubspace, m_allocatorForSizeStep); } -
trunk/Source/JavaScriptCore/heap/FastMallocAlignedMemoryAllocator.cpp
r220352 r243688 55 55 } 56 56 57 void* FastMallocAlignedMemoryAllocator::tryAllocateMemory(size_t size) 58 { 59 return FastMalloc::tryMalloc(size); 60 } 61 62 void FastMallocAlignedMemoryAllocator::freeMemory(void* pointer) 63 { 64 FastMalloc::free(pointer); 65 } 66 67 void* FastMallocAlignedMemoryAllocator::tryReallocateMemory(void* pointer, size_t size) 68 { 69 return FastMalloc::tryRealloc(pointer, size); 70 } 71 57 72 } // namespace JSC 58 73 -
trunk/Source/JavaScriptCore/heap/FastMallocAlignedMemoryAllocator.h
r220352 r243688 39 39 40 40 void dump(PrintStream&) const override; 41 42 void* tryAllocateMemory(size_t) override; 43 void freeMemory(void*) override; 44 void* tryReallocateMemory(void*, size_t) override; 41 45 }; 42 46 -
trunk/Source/JavaScriptCore/heap/GigacageAlignedMemoryAllocator.cpp
r220352 r243688 53 53 } 54 54 55 void* GigacageAlignedMemoryAllocator::tryAllocateMemory(size_t size) 56 { 57 return Gigacage::tryMalloc(m_kind, size); 58 } 59 60 void GigacageAlignedMemoryAllocator::freeMemory(void* pointer) 61 { 62 Gigacage::free(m_kind, pointer); 63 } 64 65 void* GigacageAlignedMemoryAllocator::tryReallocateMemory(void* pointer, size_t size) 66 { 67 return Gigacage::tryRealloc(m_kind, pointer, size); 68 } 69 55 70 } // namespace JSC 56 71 -
trunk/Source/JavaScriptCore/heap/GigacageAlignedMemoryAllocator.h
r220352 r243688 41 41 void dump(PrintStream&) const override; 42 42 43 void* tryAllocateMemory(size_t) override; 44 void freeMemory(void*) override; 45 void* tryReallocateMemory(void*, size_t) override; 46 43 47 private: 44 48 Gigacage::Kind m_kind; -
trunk/Source/JavaScriptCore/heap/IsoAlignedMemoryAllocator.cpp
r230187 r243688 89 89 } 90 90 91 void* IsoAlignedMemoryAllocator::tryAllocateMemory(size_t) 92 { 93 RELEASE_ASSERT_NOT_REACHED(); 94 } 95 96 void IsoAlignedMemoryAllocator::freeMemory(void*) 97 { 98 RELEASE_ASSERT_NOT_REACHED(); 99 } 100 101 void* IsoAlignedMemoryAllocator::tryReallocateMemory(void*, size_t) 102 { 103 RELEASE_ASSERT_NOT_REACHED(); 104 } 105 91 106 } // namespace JSC 92 107 -
trunk/Source/JavaScriptCore/heap/IsoAlignedMemoryAllocator.h
r240216 r243688 40 40 void dump(PrintStream&) const override; 41 41 42 void* tryAllocateMemory(size_t) override; 43 void freeMemory(void*) override; 44 void* tryReallocateMemory(void*, size_t) override; 45 42 46 private: 43 47 Vector<void*> m_blocks; -
trunk/Source/JavaScriptCore/heap/LargeAllocation.cpp
r243667 r243688 35 35 namespace JSC { 36 36 37 LargeAllocation* LargeAllocation::tryCreate(Heap& heap, size_t size, Subspace* subspace) 37 static inline bool isAlignedForLargeAllocation(void* memory) 38 { 39 uintptr_t allocatedPointer = bitwise_cast<uintptr_t>(memory); 40 return !(allocatedPointer & (LargeAllocation::alignment - 1)); 41 } 42 43 LargeAllocation* LargeAllocation::tryCreate(Heap& heap, size_t size, Subspace* subspace, unsigned indexInSpace) 38 44 { 39 45 if (validateDFGDoesGC) 40 46 RELEASE_ASSERT(heap.expectDoesGC()); 41 47 42 size_t allocationSize = headerSize() + size; 48 size_t adjustedAlignmentAllocationSize = headerSize() + size + halfAlignment; 49 static_assert(halfAlignment == 8, "We assume that memory returned by malloc has alignment >= 8."); 43 50 44 void* space = subspace->alignedMemoryAllocator()->tryAllocateAlignedMemory(alignment, allocationSize); 51 // We must use tryAllocateMemory instead of tryAllocateAlignedMemory since we want to use "realloc" feature. 52 void* space = subspace->alignedMemoryAllocator()->tryAllocateMemory(adjustedAlignmentAllocationSize); 45 53 if (!space) 46 54 return nullptr; 55 56 bool adjustedAlignment = false; 57 if (!isAlignedForLargeAllocation(space)) { 58 space = bitwise_cast<void*>(bitwise_cast<uintptr_t>(space) + halfAlignment); 59 adjustedAlignment = true; 60 ASSERT(isAlignedForLargeAllocation(space)); 61 } 47 62 48 63 if (scribbleFreeCells()) 49 64 scribble(space, size); 50 return new (NotNull, space) LargeAllocation(heap, size, subspace); 51 } 52 53 LargeAllocation::LargeAllocation(Heap& heap, size_t size, Subspace* subspace) 65 return new (NotNull, space) LargeAllocation(heap, size, subspace, indexInSpace, adjustedAlignment); 66 } 67 68 LargeAllocation* LargeAllocation::tryReallocate(size_t size, Subspace* subspace) 69 { 70 size_t adjustedAlignmentAllocationSize = headerSize() + size + halfAlignment; 71 static_assert(halfAlignment == 8, "We assume that memory returned by malloc has alignment >= 8."); 72 73 ASSERT(subspace == m_subspace); 74 75 unsigned oldCellSize = m_cellSize; 76 bool oldAdjustedAlignment = m_adjustedAlignment; 77 void* oldBasePointer = basePointer(); 78 79 void* newBasePointer = subspace->alignedMemoryAllocator()->tryReallocateMemory(oldBasePointer, adjustedAlignmentAllocationSize); 80 if (!newBasePointer) 81 return nullptr; 82 83 LargeAllocation* newAllocation = bitwise_cast<LargeAllocation*>(newBasePointer); 84 bool newAdjustedAlignment = false; 85 if (!isAlignedForLargeAllocation(newBasePointer)) { 86 newAdjustedAlignment = true; 87 newAllocation = bitwise_cast<LargeAllocation*>(bitwise_cast<uintptr_t>(newBasePointer) + halfAlignment); 88 ASSERT(isAlignedForLargeAllocation(static_cast<void*>(newAllocation))); 89 } 90 91 // We have 4 patterns. 92 // oldAdjustedAlignment = true newAdjustedAlignment = true => Do nothing. 93 // oldAdjustedAlignment = true newAdjustedAlignment = false => Shift forward by halfAlignment 94 // oldAdjustedAlignment = false newAdjustedAlignment = true => Shift backward by halfAlignment 95 // oldAdjustedAlignment = false newAdjustedAlignment = false => Do nothing. 96 97 if (oldAdjustedAlignment != newAdjustedAlignment) { 98 if (oldAdjustedAlignment) { 99 ASSERT(!newAdjustedAlignment); 100 ASSERT(newAllocation == newBasePointer); 101 // Old [ 8 ][ content ] 102 // Now [ ][ content ] 103 // New [ content ]... 104 memmove(newBasePointer, bitwise_cast<char*>(newBasePointer) + halfAlignment, oldCellSize + LargeAllocation::headerSize()); 105 } else { 106 ASSERT(newAdjustedAlignment); 107 ASSERT(newAllocation != newBasePointer); 108 ASSERT(newAllocation == bitwise_cast<void*>(bitwise_cast<char*>(newBasePointer) + halfAlignment)); 109 // Old [ content ] 110 // Now [ content ][ ] 111 // New [ 8 ][ content ] 112 memmove(bitwise_cast<char*>(newBasePointer) + halfAlignment, newBasePointer, oldCellSize + LargeAllocation::headerSize()); 113 } 114 } 115 116 newAllocation->m_cellSize = size; 117 newAllocation->m_adjustedAlignment = newAdjustedAlignment; 118 return newAllocation; 119 } 120 121 LargeAllocation::LargeAllocation(Heap& heap, size_t size, Subspace* subspace, unsigned indexInSpace, bool adjustedAlignment) 54 122 : m_cellSize(size) 123 , m_indexInSpace(indexInSpace) 55 124 , m_isNewlyAllocated(true) 56 125 , m_hasValidCell(true) 126 , m_adjustedAlignment(adjustedAlignment) 57 127 , m_attributes(subspace->attributes()) 58 128 , m_subspace(subspace) … … 116 186 { 117 187 AlignedMemoryAllocator* allocator = m_subspace->alignedMemoryAllocator(); 188 void* basePointer = this->basePointer(); 118 189 this->~LargeAllocation(); 119 allocator->free AlignedMemory(this);190 allocator->freeMemory(basePointer); 120 191 } 121 192 -
trunk/Source/JavaScriptCore/heap/LargeAllocation.h
r226822 r243688 40 40 class LargeAllocation : public BasicRawSentinelNode<LargeAllocation> { 41 41 public: 42 static LargeAllocation* tryCreate(Heap&, size_t, Subspace*); 42 static LargeAllocation* tryCreate(Heap&, size_t, Subspace*, unsigned indexInSpace); 43 44 LargeAllocation* tryReallocate(size_t, Subspace*); 43 45 44 46 ~LargeAllocation(); … … 66 68 VM* vm() const { return m_weakSet.vm(); } 67 69 WeakSet& weakSet() { return m_weakSet; } 70 71 unsigned indexInSpace() { return m_indexInSpace; } 72 void setIndexInSpace(unsigned indexInSpace) { m_indexInSpace = indexInSpace; } 68 73 69 74 void shrink(); … … 141 146 void dump(PrintStream&) const; 142 147 143 private:144 LargeAllocation(Heap&, size_t, Subspace*);145 146 148 static const unsigned alignment = MarkedBlock::atomSize; 147 149 static const unsigned halfAlignment = alignment / 2; 148 150 151 private: 152 LargeAllocation(Heap&, size_t, Subspace*, unsigned indexInSpace, bool adjustedAlignment); 153 149 154 static unsigned headerSize(); 155 156 void* basePointer() const; 150 157 151 158 size_t m_cellSize; 152 bool m_isNewlyAllocated; 153 bool m_hasValidCell; 159 unsigned m_indexInSpace { 0 }; 160 bool m_isNewlyAllocated : 1; 161 bool m_hasValidCell : 1; 162 bool m_adjustedAlignment : 1; 154 163 Atomic<bool> m_isMarked; 155 164 CellAttributes m_attributes; … … 163 172 } 164 173 174 inline void* LargeAllocation::basePointer() const 175 { 176 if (m_adjustedAlignment) 177 return bitwise_cast<char*>(this) - halfAlignment; 178 return bitwise_cast<void*>(this); 179 } 180 165 181 } // namespace JSC 166 182 -
trunk/Source/JavaScriptCore/heap/MarkedSpace.cpp
r240965 r243688 251 251 continue; 252 252 } 253 allocation->setIndexInSpace(dstIndex); 253 254 m_largeAllocations[dstIndex++] = allocation; 254 255 } … … 328 329 return a < b; 329 330 }); 331 unsigned index = m_largeAllocationsOffsetForThisCollection; 332 for (auto* start = m_largeAllocationsForThisCollectionBegin; start != m_largeAllocationsForThisCollectionEnd; ++start, ++index) { 333 (*start)->setIndexInSpace(index); 334 ASSERT(m_largeAllocations[index] == *start); 335 ASSERT(m_largeAllocations[index]->indexInSpace() == index); 336 } 330 337 } 331 338 -
trunk/Source/JavaScriptCore/heap/WeakSet.h
r210844 r243688 53 53 54 54 bool isEmpty() const; 55 bool isTriviallyDestructible() const; 55 56 56 57 void visit(SlotVisitor&); … … 97 98 } 98 99 100 inline bool WeakSet::isTriviallyDestructible() const 101 { 102 if (!m_blocks.isEmpty()) 103 return false; 104 if (isOnList()) 105 return false; 106 return true; 107 } 108 99 109 inline void WeakSet::deallocate(WeakImpl* weakImpl) 100 110 { -
trunk/Source/JavaScriptCore/runtime/Butterfly.h
r239324 r243688 223 223 Butterfly* growArrayRight(VM&, JSObject* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much. 224 224 Butterfly* growArrayRight(VM&, JSObject* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes); 225 226 Butterfly* reallocArrayRightIfPossible(VM&, GCDeferralContext&, JSObject* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much. 227 225 228 Butterfly* resizeArray(VM&, JSObject* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes); 226 229 Butterfly* resizeArray(VM&, JSObject* intendedOwner, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header. -
trunk/Source/JavaScriptCore/runtime/ButterflyInlines.h
r232951 r243688 195 195 } 196 196 197 inline Butterfly* Butterfly::reallocArrayRightIfPossible( 198 VM& vm, GCDeferralContext& deferralContext, JSObject* intendedOwner, Structure* oldStructure, size_t propertyCapacity, 199 bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, 200 size_t newIndexingPayloadSizeInBytes) 201 { 202 ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure)); 203 ASSERT_UNUSED(intendedOwner, hadIndexingHeader == oldStructure->hasIndexingHeader(intendedOwner)); 204 205 void* theBase = base(0, propertyCapacity); 206 size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes); 207 size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes); 208 ASSERT(newSize >= oldSize); 209 210 // We can eagerly destroy butterfly backed by LargeAllocation if (1) concurrent collector is not active and (2) the butterfly does not contain any property storage. 211 // This is because during deallocation concurrent collector can access butterfly and DFG concurrent compilers accesses properties. 212 // Objects with no properties are common in arrays, and we are focusing on very large array crafted by repeating Array#push, so... that's fine! 213 bool canRealloc = !propertyCapacity && !vm.heap.mutatorShouldBeFenced() && bitwise_cast<HeapCell*>(theBase)->isLargeAllocation(); 214 if (canRealloc) { 215 void* newBase = vm.jsValueGigacageAuxiliarySpace.reallocateLargeAllocationNonVirtual(vm, bitwise_cast<HeapCell*>(theBase), newSize, &deferralContext, AllocationFailureMode::ReturnNull); 216 if (!newBase) 217 return nullptr; 218 return fromBase(newBase, 0, propertyCapacity); 219 } 220 221 void* newBase = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, newSize, &deferralContext, AllocationFailureMode::ReturnNull); 222 if (!newBase) 223 return nullptr; 224 memcpy(newBase, theBase, oldSize); 225 return fromBase(newBase, 0, propertyCapacity); 226 } 227 197 228 inline Butterfly* Butterfly::resizeArray( 198 229 VM& vm, JSObject* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, -
trunk/Source/JavaScriptCore/runtime/JSObject.cpp
r243299 r243688 31 31 #include "ErrorConstructor.h" 32 32 #include "Exception.h" 33 #include "GCDeferralContextInlines.h" 33 34 #include "GetterSetter.h" 34 35 #include "HeapSnapshotBuilder.h" … … 3358 3359 unsigned propertyCapacity = structure->outOfLineCapacity(); 3359 3360 3361 GCDeferralContext deferralContext(vm.heap); 3362 DisallowGC disallowGC; 3360 3363 unsigned availableOldLength = 3361 3364 Butterfly::availableContiguousVectorLength(propertyCapacity, oldVectorLength); … … 3369 3372 newVectorLength = Butterfly::optimalContiguousVectorLength( 3370 3373 propertyCapacity, std::min(length * 2, MAX_STORAGE_VECTOR_LENGTH)); 3371 butterfly = butterfly-> growArrayRight(3372 vm, this, structure, propertyCapacity, true,3374 butterfly = butterfly->reallocArrayRightIfPossible( 3375 vm, deferralContext, this, structure, propertyCapacity, true, 3373 3376 oldVectorLength * sizeof(EncodedJSValue), 3374 3377 newVectorLength * sizeof(EncodedJSValue)); -
trunk/Source/WTF/ChangeLog
r243682 r243688 1 2019-03-31 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] Butterfly allocation from LargeAllocation should try "realloc" behavior if collector thread is not active 4 https://bugs.webkit.org/show_bug.cgi?id=196160 5 6 Reviewed by Saam Barati. 7 8 * wtf/FastMalloc.h: 9 (WTF::FastMalloc::tryRealloc): 10 * wtf/Gigacage.cpp: 11 (Gigacage::tryRealloc): 12 * wtf/Gigacage.h: 13 1 14 2019-03-31 Andy Estes <aestes@apple.com> 2 15 -
trunk/Source/WTF/wtf/FastMalloc.h
r237577 r243688 202 202 203 203 static void* realloc(void* p, size_t size) { return fastRealloc(p, size); } 204 205 static void* tryRealloc(void* p, size_t size) 206 { 207 auto result = tryFastRealloc(p, size); 208 void* realResult; 209 if (result.getValue(realResult)) 210 return realResult; 211 return nullptr; 212 } 204 213 205 214 static void free(void* p) { fastFree(p); } -
trunk/Source/WTF/wtf/Gigacage.cpp
r240175 r243688 40 40 { 41 41 return FastMalloc::tryMalloc(size); 42 } 43 44 void* tryRealloc(Kind, void* pointer, size_t size) 45 { 46 return FastMalloc::tryRealloc(pointer, size); 42 47 } 43 48 … … 90 95 { 91 96 void* result = bmalloc::api::tryMalloc(size, bmalloc::heapKind(kind)); 97 WTF::compilerFence(); 98 return result; 99 } 100 101 void* tryRealloc(Kind kind, void* pointer, size_t size) 102 { 103 void* result = bmalloc::api::tryRealloc(pointer, size, bmalloc::heapKind(kind)); 92 104 WTF::compilerFence(); 93 105 return result; -
trunk/Source/WTF/wtf/Gigacage.h
r240175 r243688 121 121 inline void alignedFree(Kind, void* p) { fastAlignedFree(p); } 122 122 WTF_EXPORT_PRIVATE void* tryMalloc(Kind, size_t size); 123 WTF_EXPORT_PRIVATE void* tryRealloc(Kind, void*, size_t); 123 124 inline void free(Kind, void* p) { fastFree(p); } 124 125 … … 135 136 WTF_EXPORT_PRIVATE void alignedFree(Kind, void*); 136 137 WTF_EXPORT_PRIVATE void* tryMalloc(Kind, size_t); 138 WTF_EXPORT_PRIVATE void* tryRealloc(Kind, void*, size_t); 137 139 WTF_EXPORT_PRIVATE void free(Kind, void*); 138 140
Note:
See TracChangeset
for help on using the changeset viewer.