Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (243687 => 243688)
--- trunk/Source/_javascript_Core/ChangeLog 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-04-01 06:51:11 UTC (rev 243688)
@@ -1,3 +1,76 @@
+2019-03-31 Yusuke Suzuki <[email protected]>
+
+ [JSC] Butterfly allocation from LargeAllocation should try "realloc" behavior if collector thread is not active
+ https://bugs.webkit.org/show_bug.cgi?id=196160
+
+ Reviewed by Saam Barati.
+
+ "realloc" can be effective in terms of peak/current memory footprint when realloc succeeds because,
+
+ 1. It does not allocate additional memory while expanding a vector
+ 2. It does not deallocate an old memory, just reusing the current memory by expanding, so that memory footprint is tight even before scavenging
+
+ We found that we can "realloc" large butterflies in certain conditions are met because,
+
+ 1. If it goes to LargeAllocation, this memory region is never reused until GC sweeps it.
+ 2. Butterflies are owned by owner JSObjects, so we know the lifetime of Butterflies.
+
+ This patch attempts to use "realloc" onto butterflies if,
+
+ 1. Butterflies are allocated in LargeAllocation kind
+ 2. Concurrent collector is not active
+ 3. Butterflies do not have property storage
+
+ The condition (2) is required to avoid deallocating butterflies while the concurrent collector looks into it. The condition (3) is
+ also required to avoid deallocating butterflies while the concurrent compiler looks into it.
+
+ We also change LargeAllocation mechanism to using "malloc" and "free" instead of "posix_memalign". This allows us to use "realloc"
+ safely in all the platforms. Since LargeAllocation uses alignment to distinguish LargeAllocation and MarkedBlock, we manually adjust
+ 16B alignment by allocating 8B more memory in "malloc".
+
+ Speedometer2 and JetStream2 are neutral. RAMification shows about 1% progression (even in some of JIT tests).
+
+ * heap/AlignedMemoryAllocator.h:
+ * heap/CompleteSubspace.cpp:
+ (JSC::CompleteSubspace::tryAllocateSlow):
+ (JSC::CompleteSubspace::reallocateLargeAllocationNonVirtual):
+ * heap/CompleteSubspace.h:
+ * heap/FastMallocAlignedMemoryAllocator.cpp:
+ (JSC::FastMallocAlignedMemoryAllocator::tryAllocateMemory):
+ (JSC::FastMallocAlignedMemoryAllocator::freeMemory):
+ (JSC::FastMallocAlignedMemoryAllocator::tryReallocateMemory):
+ * heap/FastMallocAlignedMemoryAllocator.h:
+ * heap/GigacageAlignedMemoryAllocator.cpp:
+ (JSC::GigacageAlignedMemoryAllocator::tryAllocateMemory):
+ (JSC::GigacageAlignedMemoryAllocator::freeMemory):
+ (JSC::GigacageAlignedMemoryAllocator::tryReallocateMemory):
+ * heap/GigacageAlignedMemoryAllocator.h:
+ * heap/IsoAlignedMemoryAllocator.cpp:
+ (JSC::IsoAlignedMemoryAllocator::tryAllocateMemory):
+ (JSC::IsoAlignedMemoryAllocator::freeMemory):
+ (JSC::IsoAlignedMemoryAllocator::tryReallocateMemory):
+ * heap/IsoAlignedMemoryAllocator.h:
+ * heap/LargeAllocation.cpp:
+ (JSC::isAlignedForLargeAllocation):
+ (JSC::LargeAllocation::tryCreate):
+ (JSC::LargeAllocation::tryReallocate):
+ (JSC::LargeAllocation::LargeAllocation):
+ (JSC::LargeAllocation::destroy):
+ * heap/LargeAllocation.h:
+ (JSC::LargeAllocation::indexInSpace):
+ (JSC::LargeAllocation::setIndexInSpace):
+ (JSC::LargeAllocation::basePointer const):
+ * heap/MarkedSpace.cpp:
+ (JSC::MarkedSpace::sweepLargeAllocations):
+ (JSC::MarkedSpace::prepareForConservativeScan):
+ * heap/WeakSet.h:
+ (JSC::WeakSet::isTriviallyDestructible const):
+ * runtime/Butterfly.h:
+ * runtime/ButterflyInlines.h:
+ (JSC::Butterfly::reallocArrayRightIfPossible):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::ensureLengthSlow):
+
2019-03-31 Sam Weinig <[email protected]>
Remove more i386 specific configurations
Modified: trunk/Source/_javascript_Core/heap/AlignedMemoryAllocator.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/AlignedMemoryAllocator.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/AlignedMemoryAllocator.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -50,6 +50,12 @@
void registerSubspace(Subspace*);
+ // Some of derived memory allocators do not have these features because they do not use them.
+ // For example, IsoAlignedMemoryAllocator does not have "realloc" feature since it never extends / shrinks the allocated memory region.
+ virtual void* tryAllocateMemory(size_t) = 0;
+ virtual void freeMemory(void*) = 0;
+ virtual void* tryReallocateMemory(void*, size_t) = 0;
+
private:
SinglyLinkedListWithTail<BlockDirectory> m_directories;
SinglyLinkedListWithTail<Subspace> m_subspaces;
Modified: trunk/Source/_javascript_Core/heap/CompleteSubspace.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/CompleteSubspace.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/CompleteSubspace.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -140,11 +140,12 @@
vm.heap.collectIfNecessaryOrDefer(deferralContext);
size = WTF::roundUpToMultipleOf<MarkedSpace::sizeStep>(size);
- LargeAllocation* allocation = LargeAllocation::tryCreate(vm.heap, size, this);
+ LargeAllocation* allocation = LargeAllocation::tryCreate(vm.heap, size, this, m_space.m_largeAllocations.size());
if (!allocation)
return nullptr;
m_space.m_largeAllocations.append(allocation);
+ ASSERT(allocation->indexInSpace() == m_space.m_largeAllocations.size() - 1);
vm.heap.didAllocate(size);
m_space.m_capacity += size;
@@ -153,5 +154,54 @@
return allocation->cell();
}
+void* CompleteSubspace::reallocateLargeAllocationNonVirtual(VM& vm, HeapCell* oldCell, size_t size, GCDeferralContext* deferralContext, AllocationFailureMode failureMode)
+{
+ if (validateDFGDoesGC)
+ RELEASE_ASSERT(vm.heap.expectDoesGC());
+
+ // The following conditions are met in Butterfly for example.
+ ASSERT(oldCell->isLargeAllocation());
+
+ LargeAllocation* oldAllocation = &oldCell->largeAllocation();
+ ASSERT(oldAllocation->cellSize() <= size);
+ ASSERT(oldAllocation->weakSet().isTriviallyDestructible());
+ ASSERT(oldAllocation->attributes().destruction == DoesNotNeedDestruction);
+ ASSERT(oldAllocation->attributes().cellKind == HeapCell::Auxiliary);
+ ASSERT(size > MarkedSpace::largeCutoff);
+
+ sanitizeStackForVM(&vm);
+
+ if (size <= Options::largeAllocationCutoff()
+ && size <= MarkedSpace::largeCutoff) {
+ dataLog("FATAL: attampting to allocate small object using large allocation.\n");
+ dataLog("Requested allocation size: ", size, "\n");
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ vm.heap.collectIfNecessaryOrDefer(deferralContext);
+
+ size = WTF::roundUpToMultipleOf<MarkedSpace::sizeStep>(size);
+ size_t difference = size - oldAllocation->cellSize();
+ unsigned oldIndexInSpace = oldAllocation->indexInSpace();
+ if (oldAllocation->isOnList())
+ oldAllocation->remove();
+
+ LargeAllocation* allocation = oldAllocation->tryReallocate(size, this);
+ if (!allocation) {
+ RELEASE_ASSERT(failureMode != AllocationFailureMode::Assert);
+ m_largeAllocations.append(oldAllocation);
+ return nullptr;
+ }
+ ASSERT(oldIndexInSpace == allocation->indexInSpace());
+
+ m_space.m_largeAllocations[oldIndexInSpace] = allocation;
+ vm.heap.didAllocate(difference);
+ m_space.m_capacity += difference;
+
+ m_largeAllocations.append(allocation);
+
+ return allocation->cell();
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/CompleteSubspace.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/CompleteSubspace.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/CompleteSubspace.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -44,6 +44,7 @@
void* allocate(VM&, size_t, GCDeferralContext*, AllocationFailureMode) override;
void* allocateNonVirtual(VM&, size_t, GCDeferralContext*, AllocationFailureMode);
+ void* reallocateLargeAllocationNonVirtual(VM&, HeapCell*, size_t, GCDeferralContext*, AllocationFailureMode);
static ptrdiff_t offsetOfAllocatorForSizeStep() { return OBJECT_OFFSETOF(CompleteSubspace, m_allocatorForSizeStep); }
Modified: trunk/Source/_javascript_Core/heap/FastMallocAlignedMemoryAllocator.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/FastMallocAlignedMemoryAllocator.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/FastMallocAlignedMemoryAllocator.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -54,5 +54,20 @@
out.print("FastMalloc");
}
+void* FastMallocAlignedMemoryAllocator::tryAllocateMemory(size_t size)
+{
+ return FastMalloc::tryMalloc(size);
+}
+
+void FastMallocAlignedMemoryAllocator::freeMemory(void* pointer)
+{
+ FastMalloc::free(pointer);
+}
+
+void* FastMallocAlignedMemoryAllocator::tryReallocateMemory(void* pointer, size_t size)
+{
+ return FastMalloc::tryRealloc(pointer, size);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/FastMallocAlignedMemoryAllocator.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/FastMallocAlignedMemoryAllocator.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/FastMallocAlignedMemoryAllocator.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -38,6 +38,10 @@
void freeAlignedMemory(void*) override;
void dump(PrintStream&) const override;
+
+ void* tryAllocateMemory(size_t) override;
+ void freeMemory(void*) override;
+ void* tryReallocateMemory(void*, size_t) override;
};
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/GigacageAlignedMemoryAllocator.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/GigacageAlignedMemoryAllocator.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/GigacageAlignedMemoryAllocator.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -52,5 +52,20 @@
out.print(Gigacage::name(m_kind), "Gigacage");
}
+void* GigacageAlignedMemoryAllocator::tryAllocateMemory(size_t size)
+{
+ return Gigacage::tryMalloc(m_kind, size);
+}
+
+void GigacageAlignedMemoryAllocator::freeMemory(void* pointer)
+{
+ Gigacage::free(m_kind, pointer);
+}
+
+void* GigacageAlignedMemoryAllocator::tryReallocateMemory(void* pointer, size_t size)
+{
+ return Gigacage::tryRealloc(m_kind, pointer, size);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/GigacageAlignedMemoryAllocator.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/GigacageAlignedMemoryAllocator.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/GigacageAlignedMemoryAllocator.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -40,6 +40,10 @@
void dump(PrintStream&) const override;
+ void* tryAllocateMemory(size_t) override;
+ void freeMemory(void*) override;
+ void* tryReallocateMemory(void*, size_t) override;
+
private:
Gigacage::Kind m_kind;
};
Modified: trunk/Source/_javascript_Core/heap/IsoAlignedMemoryAllocator.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/IsoAlignedMemoryAllocator.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/IsoAlignedMemoryAllocator.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -88,5 +88,20 @@
out.print("Iso(", RawPointer(this), ")");
}
+void* IsoAlignedMemoryAllocator::tryAllocateMemory(size_t)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void IsoAlignedMemoryAllocator::freeMemory(void*)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void* IsoAlignedMemoryAllocator::tryReallocateMemory(void*, size_t)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/IsoAlignedMemoryAllocator.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/IsoAlignedMemoryAllocator.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/IsoAlignedMemoryAllocator.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -39,6 +39,10 @@
void dump(PrintStream&) const override;
+ void* tryAllocateMemory(size_t) override;
+ void freeMemory(void*) override;
+ void* tryReallocateMemory(void*, size_t) override;
+
private:
Vector<void*> m_blocks;
HashMap<void*, unsigned> m_blockIndices;
Modified: trunk/Source/_javascript_Core/heap/LargeAllocation.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/LargeAllocation.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/LargeAllocation.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -34,26 +34,96 @@
namespace JSC {
-LargeAllocation* LargeAllocation::tryCreate(Heap& heap, size_t size, Subspace* subspace)
+static inline bool isAlignedForLargeAllocation(void* memory)
{
+ uintptr_t allocatedPointer = bitwise_cast<uintptr_t>(memory);
+ return !(allocatedPointer & (LargeAllocation::alignment - 1));
+}
+
+LargeAllocation* LargeAllocation::tryCreate(Heap& heap, size_t size, Subspace* subspace, unsigned indexInSpace)
+{
if (validateDFGDoesGC)
RELEASE_ASSERT(heap.expectDoesGC());
- size_t allocationSize = headerSize() + size;
+ size_t adjustedAlignmentAllocationSize = headerSize() + size + halfAlignment;
+ static_assert(halfAlignment == 8, "We assume that memory returned by malloc has alignment >= 8.");
- void* space = subspace->alignedMemoryAllocator()->tryAllocateAlignedMemory(alignment, allocationSize);
+ // We must use tryAllocateMemory instead of tryAllocateAlignedMemory since we want to use "realloc" feature.
+ void* space = subspace->alignedMemoryAllocator()->tryAllocateMemory(adjustedAlignmentAllocationSize);
if (!space)
return nullptr;
+
+ bool adjustedAlignment = false;
+ if (!isAlignedForLargeAllocation(space)) {
+ space = bitwise_cast<void*>(bitwise_cast<uintptr_t>(space) + halfAlignment);
+ adjustedAlignment = true;
+ ASSERT(isAlignedForLargeAllocation(space));
+ }
if (scribbleFreeCells())
scribble(space, size);
- return new (NotNull, space) LargeAllocation(heap, size, subspace);
+ return new (NotNull, space) LargeAllocation(heap, size, subspace, indexInSpace, adjustedAlignment);
}
-LargeAllocation::LargeAllocation(Heap& heap, size_t size, Subspace* subspace)
+LargeAllocation* LargeAllocation::tryReallocate(size_t size, Subspace* subspace)
+{
+ size_t adjustedAlignmentAllocationSize = headerSize() + size + halfAlignment;
+ static_assert(halfAlignment == 8, "We assume that memory returned by malloc has alignment >= 8.");
+
+ ASSERT(subspace == m_subspace);
+
+ unsigned oldCellSize = m_cellSize;
+ bool oldAdjustedAlignment = m_adjustedAlignment;
+ void* oldBasePointer = basePointer();
+
+ void* newBasePointer = subspace->alignedMemoryAllocator()->tryReallocateMemory(oldBasePointer, adjustedAlignmentAllocationSize);
+ if (!newBasePointer)
+ return nullptr;
+
+ LargeAllocation* newAllocation = bitwise_cast<LargeAllocation*>(newBasePointer);
+ bool newAdjustedAlignment = false;
+ if (!isAlignedForLargeAllocation(newBasePointer)) {
+ newAdjustedAlignment = true;
+ newAllocation = bitwise_cast<LargeAllocation*>(bitwise_cast<uintptr_t>(newBasePointer) + halfAlignment);
+ ASSERT(isAlignedForLargeAllocation(static_cast<void*>(newAllocation)));
+ }
+
+ // We have 4 patterns.
+ // oldAdjustedAlignment = true newAdjustedAlignment = true => Do nothing.
+ // oldAdjustedAlignment = true newAdjustedAlignment = false => Shift forward by halfAlignment
+ // oldAdjustedAlignment = false newAdjustedAlignment = true => Shift backward by halfAlignment
+ // oldAdjustedAlignment = false newAdjustedAlignment = false => Do nothing.
+
+ if (oldAdjustedAlignment != newAdjustedAlignment) {
+ if (oldAdjustedAlignment) {
+ ASSERT(!newAdjustedAlignment);
+ ASSERT(newAllocation == newBasePointer);
+ // Old [ 8 ][ content ]
+ // Now [ ][ content ]
+ // New [ content ]...
+ memmove(newBasePointer, bitwise_cast<char*>(newBasePointer) + halfAlignment, oldCellSize + LargeAllocation::headerSize());
+ } else {
+ ASSERT(newAdjustedAlignment);
+ ASSERT(newAllocation != newBasePointer);
+ ASSERT(newAllocation == bitwise_cast<void*>(bitwise_cast<char*>(newBasePointer) + halfAlignment));
+ // Old [ content ]
+ // Now [ content ][ ]
+ // New [ 8 ][ content ]
+ memmove(bitwise_cast<char*>(newBasePointer) + halfAlignment, newBasePointer, oldCellSize + LargeAllocation::headerSize());
+ }
+ }
+
+ newAllocation->m_cellSize = size;
+ newAllocation->m_adjustedAlignment = newAdjustedAlignment;
+ return newAllocation;
+}
+
+LargeAllocation::LargeAllocation(Heap& heap, size_t size, Subspace* subspace, unsigned indexInSpace, bool adjustedAlignment)
: m_cellSize(size)
+ , m_indexInSpace(indexInSpace)
, m_isNewlyAllocated(true)
, m_hasValidCell(true)
+ , m_adjustedAlignment(adjustedAlignment)
, m_attributes(subspace->attributes())
, m_subspace(subspace)
, m_weakSet(heap.vm(), *this)
@@ -115,8 +185,9 @@
void LargeAllocation::destroy()
{
AlignedMemoryAllocator* allocator = m_subspace->alignedMemoryAllocator();
+ void* basePointer = this->basePointer();
this->~LargeAllocation();
- allocator->freeAlignedMemory(this);
+ allocator->freeMemory(basePointer);
}
void LargeAllocation::dump(PrintStream& out) const
Modified: trunk/Source/_javascript_Core/heap/LargeAllocation.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/LargeAllocation.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/LargeAllocation.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -39,7 +39,9 @@
class LargeAllocation : public BasicRawSentinelNode<LargeAllocation> {
public:
- static LargeAllocation* tryCreate(Heap&, size_t, Subspace*);
+ static LargeAllocation* tryCreate(Heap&, size_t, Subspace*, unsigned indexInSpace);
+
+ LargeAllocation* tryReallocate(size_t, Subspace*);
~LargeAllocation();
@@ -65,6 +67,9 @@
Heap* heap() const { return m_weakSet.heap(); }
VM* vm() const { return m_weakSet.vm(); }
WeakSet& weakSet() { return m_weakSet; }
+
+ unsigned indexInSpace() { return m_indexInSpace; }
+ void setIndexInSpace(unsigned indexInSpace) { m_indexInSpace = indexInSpace; }
void shrink();
@@ -140,17 +145,21 @@
void dump(PrintStream&) const;
-private:
- LargeAllocation(Heap&, size_t, Subspace*);
-
static const unsigned alignment = MarkedBlock::atomSize;
static const unsigned halfAlignment = alignment / 2;
+private:
+ LargeAllocation(Heap&, size_t, Subspace*, unsigned indexInSpace, bool adjustedAlignment);
+
static unsigned headerSize();
+
+ void* basePointer() const;
size_t m_cellSize;
- bool m_isNewlyAllocated;
- bool m_hasValidCell;
+ unsigned m_indexInSpace { 0 };
+ bool m_isNewlyAllocated : 1;
+ bool m_hasValidCell : 1;
+ bool m_adjustedAlignment : 1;
Atomic<bool> m_isMarked;
CellAttributes m_attributes;
Subspace* m_subspace;
@@ -162,5 +171,12 @@
return ((sizeof(LargeAllocation) + halfAlignment - 1) & ~(halfAlignment - 1)) | halfAlignment;
}
+inline void* LargeAllocation::basePointer() const
+{
+ if (m_adjustedAlignment)
+ return bitwise_cast<char*>(this) - halfAlignment;
+ return bitwise_cast<void*>(this);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/MarkedSpace.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -250,6 +250,7 @@
allocation->destroy();
continue;
}
+ allocation->setIndexInSpace(dstIndex);
m_largeAllocations[dstIndex++] = allocation;
}
m_largeAllocations.shrink(dstIndex);
@@ -327,6 +328,12 @@
[&] (LargeAllocation* a, LargeAllocation* b) {
return a < b;
});
+ unsigned index = m_largeAllocationsOffsetForThisCollection;
+ for (auto* start = m_largeAllocationsForThisCollectionBegin; start != m_largeAllocationsForThisCollectionEnd; ++start, ++index) {
+ (*start)->setIndexInSpace(index);
+ ASSERT(m_largeAllocations[index] == *start);
+ ASSERT(m_largeAllocations[index]->indexInSpace() == index);
+ }
}
void MarkedSpace::prepareForMarking()
Modified: trunk/Source/_javascript_Core/heap/WeakSet.h (243687 => 243688)
--- trunk/Source/_javascript_Core/heap/WeakSet.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/heap/WeakSet.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -52,6 +52,7 @@
VM* vm() const;
bool isEmpty() const;
+ bool isTriviallyDestructible() const;
void visit(SlotVisitor&);
@@ -96,6 +97,15 @@
return true;
}
+inline bool WeakSet::isTriviallyDestructible() const
+{
+ if (!m_blocks.isEmpty())
+ return false;
+ if (isOnList())
+ return false;
+ return true;
+}
+
inline void WeakSet::deallocate(WeakImpl* weakImpl)
{
weakImpl->setState(WeakImpl::Deallocated);
Modified: trunk/Source/_javascript_Core/runtime/Butterfly.h (243687 => 243688)
--- trunk/Source/_javascript_Core/runtime/Butterfly.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/runtime/Butterfly.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -222,6 +222,9 @@
static Butterfly* createOrGrowPropertyStorage(Butterfly*, VM&, JSObject* intendedOwner, Structure*, size_t oldPropertyCapacity, size_t newPropertyCapacity);
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.
Butterfly* growArrayRight(VM&, JSObject* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes);
+
+ 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.
+
Butterfly* resizeArray(VM&, JSObject* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
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.
Butterfly* unshift(Structure*, size_t numberOfSlots);
Modified: trunk/Source/_javascript_Core/runtime/ButterflyInlines.h (243687 => 243688)
--- trunk/Source/_javascript_Core/runtime/ButterflyInlines.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/runtime/ButterflyInlines.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -194,6 +194,37 @@
newIndexingPayloadSizeInBytes);
}
+inline Butterfly* Butterfly::reallocArrayRightIfPossible(
+ VM& vm, GCDeferralContext& deferralContext, JSObject* intendedOwner, Structure* oldStructure, size_t propertyCapacity,
+ bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes,
+ size_t newIndexingPayloadSizeInBytes)
+{
+ ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure));
+ ASSERT_UNUSED(intendedOwner, hadIndexingHeader == oldStructure->hasIndexingHeader(intendedOwner));
+
+ void* theBase = base(0, propertyCapacity);
+ size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes);
+ size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes);
+ ASSERT(newSize >= oldSize);
+
+ // 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.
+ // This is because during deallocation concurrent collector can access butterfly and DFG concurrent compilers accesses properties.
+ // 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!
+ bool canRealloc = !propertyCapacity && !vm.heap.mutatorShouldBeFenced() && bitwise_cast<HeapCell*>(theBase)->isLargeAllocation();
+ if (canRealloc) {
+ void* newBase = vm.jsValueGigacageAuxiliarySpace.reallocateLargeAllocationNonVirtual(vm, bitwise_cast<HeapCell*>(theBase), newSize, &deferralContext, AllocationFailureMode::ReturnNull);
+ if (!newBase)
+ return nullptr;
+ return fromBase(newBase, 0, propertyCapacity);
+ }
+
+ void* newBase = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, newSize, &deferralContext, AllocationFailureMode::ReturnNull);
+ if (!newBase)
+ return nullptr;
+ memcpy(newBase, theBase, oldSize);
+ return fromBase(newBase, 0, propertyCapacity);
+}
+
inline Butterfly* Butterfly::resizeArray(
VM& vm, JSObject* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader,
size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader,
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (243687 => 243688)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -30,6 +30,7 @@
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "Exception.h"
+#include "GCDeferralContextInlines.h"
#include "GetterSetter.h"
#include "HeapSnapshotBuilder.h"
#include "IndexingHeaderInlines.h"
@@ -3357,6 +3358,8 @@
Structure* structure = this->structure(vm);
unsigned propertyCapacity = structure->outOfLineCapacity();
+ GCDeferralContext deferralContext(vm.heap);
+ DisallowGC disallowGC;
unsigned availableOldLength =
Butterfly::availableContiguousVectorLength(propertyCapacity, oldVectorLength);
Butterfly* newButterfly = nullptr;
@@ -3368,8 +3371,8 @@
} else {
newVectorLength = Butterfly::optimalContiguousVectorLength(
propertyCapacity, std::min(length * 2, MAX_STORAGE_VECTOR_LENGTH));
- butterfly = butterfly->growArrayRight(
- vm, this, structure, propertyCapacity, true,
+ butterfly = butterfly->reallocArrayRightIfPossible(
+ vm, deferralContext, this, structure, propertyCapacity, true,
oldVectorLength * sizeof(EncodedJSValue),
newVectorLength * sizeof(EncodedJSValue));
if (!butterfly)
Modified: trunk/Source/WTF/ChangeLog (243687 => 243688)
--- trunk/Source/WTF/ChangeLog 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/WTF/ChangeLog 2019-04-01 06:51:11 UTC (rev 243688)
@@ -1,3 +1,16 @@
+2019-03-31 Yusuke Suzuki <[email protected]>
+
+ [JSC] Butterfly allocation from LargeAllocation should try "realloc" behavior if collector thread is not active
+ https://bugs.webkit.org/show_bug.cgi?id=196160
+
+ Reviewed by Saam Barati.
+
+ * wtf/FastMalloc.h:
+ (WTF::FastMalloc::tryRealloc):
+ * wtf/Gigacage.cpp:
+ (Gigacage::tryRealloc):
+ * wtf/Gigacage.h:
+
2019-03-31 Andy Estes <[email protected]>
[iOS] WebKit should consult the navigation response policy delegate before previewing a QuickLook document
Modified: trunk/Source/WTF/wtf/FastMalloc.h (243687 => 243688)
--- trunk/Source/WTF/wtf/FastMalloc.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/WTF/wtf/FastMalloc.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -201,6 +201,15 @@
}
static void* realloc(void* p, size_t size) { return fastRealloc(p, size); }
+
+ static void* tryRealloc(void* p, size_t size)
+ {
+ auto result = tryFastRealloc(p, size);
+ void* realResult;
+ if (result.getValue(realResult))
+ return realResult;
+ return nullptr;
+ }
static void free(void* p) { fastFree(p); }
};
Modified: trunk/Source/WTF/wtf/Gigacage.cpp (243687 => 243688)
--- trunk/Source/WTF/wtf/Gigacage.cpp 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/WTF/wtf/Gigacage.cpp 2019-04-01 06:51:11 UTC (rev 243688)
@@ -41,6 +41,11 @@
return FastMalloc::tryMalloc(size);
}
+void* tryRealloc(Kind, void* pointer, size_t size)
+{
+ return FastMalloc::tryRealloc(pointer, size);
+}
+
void* tryAllocateZeroedVirtualPages(Kind, size_t requestedSize)
{
size_t size = roundUpToMultipleOf(WTF::pageSize(), requestedSize);
@@ -93,6 +98,13 @@
return result;
}
+void* tryRealloc(Kind kind, void* pointer, size_t size)
+{
+ void* result = bmalloc::api::tryRealloc(pointer, size, bmalloc::heapKind(kind));
+ WTF::compilerFence();
+ return result;
+}
+
void free(Kind kind, void* p)
{
if (!p)
Modified: trunk/Source/WTF/wtf/Gigacage.h (243687 => 243688)
--- trunk/Source/WTF/wtf/Gigacage.h 2019-04-01 06:42:31 UTC (rev 243687)
+++ trunk/Source/WTF/wtf/Gigacage.h 2019-04-01 06:51:11 UTC (rev 243688)
@@ -120,6 +120,7 @@
inline void* tryAlignedMalloc(Kind, size_t alignment, size_t size) { return tryFastAlignedMalloc(alignment, size); }
inline void alignedFree(Kind, void* p) { fastAlignedFree(p); }
WTF_EXPORT_PRIVATE void* tryMalloc(Kind, size_t size);
+WTF_EXPORT_PRIVATE void* tryRealloc(Kind, void*, size_t);
inline void free(Kind, void* p) { fastFree(p); }
WTF_EXPORT_PRIVATE void* tryAllocateZeroedVirtualPages(Kind, size_t size);
@@ -134,6 +135,7 @@
WTF_EXPORT_PRIVATE void* tryAlignedMalloc(Kind, size_t alignment, size_t size);
WTF_EXPORT_PRIVATE void alignedFree(Kind, void*);
WTF_EXPORT_PRIVATE void* tryMalloc(Kind, size_t);
+WTF_EXPORT_PRIVATE void* tryRealloc(Kind, void*, size_t);
WTF_EXPORT_PRIVATE void free(Kind, void*);
WTF_EXPORT_PRIVATE void* tryAllocateZeroedVirtualPages(Kind, size_t size);