Title: [199453] releases/WebKitGTK/webkit-2.12/Source/bmalloc
Revision
199453
Author
[email protected]
Date
2016-04-13 02:39:26 -0700 (Wed, 13 Apr 2016)

Log Message

Merge r199115 - bmalloc: handle aligned allocations on the fast path
https://bugs.webkit.org/show_bug.cgi?id=156302

Reviewed by Michael Saboff.

This helps keep the _javascript_Core GC on the fast path, and it also
helps avoid fragmentation on our website stress test:

    nimlang                      209,584kB            198,076kB      ^ 1.06x smaller

* bmalloc/Allocator.cpp:
(bmalloc::Allocator::allocate): Because we arrange for power-of-two size
classes to allocate at power-of-two alignments, we can allocate any
small aligned request on the small path.

* bmalloc/Chunk.h:
(bmalloc::Chunk::bytes):
(bmalloc::Chunk::lines):
(bmalloc::Chunk::pages):
(bmalloc::Chunk::boundaryTags):
(bmalloc::Chunk::objectType): Moved some code around to provide better
API.

(bmalloc::Chunk::Chunk): Moved this code to VMHeap.

(bmalloc::Chunk::offset):
(bmalloc::Chunk::object): Use our new bytes() helper function.

* bmalloc/VMHeap.cpp:
(bmalloc::VMHeap::allocateChunk): Moved code here from Chunk.

(bmalloc::VMHeap::allocateSmallChunk): Ensure that power-of-two page
sizes always begin allocation at the same alignment. Power-of-two object
sizes always request power-of-two page sizes (since that's the least
wasteful option), so if we also ensure that power-of-two page sizes get
power-of-two alignment, then everything is aligned for all small objects.

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.12/Source/bmalloc/ChangeLog (199452 => 199453)


--- releases/WebKitGTK/webkit-2.12/Source/bmalloc/ChangeLog	2016-04-13 09:39:10 UTC (rev 199452)
+++ releases/WebKitGTK/webkit-2.12/Source/bmalloc/ChangeLog	2016-04-13 09:39:26 UTC (rev 199453)
@@ -1,3 +1,42 @@
+2016-04-06  Geoffrey Garen  <[email protected]>
+
+        bmalloc: handle aligned allocations on the fast path
+        https://bugs.webkit.org/show_bug.cgi?id=156302
+
+        Reviewed by Michael Saboff.
+
+        This helps keep the _javascript_Core GC on the fast path, and it also
+        helps avoid fragmentation on our website stress test:
+
+            nimlang                      209,584kB            198,076kB      ^ 1.06x smaller
+
+        * bmalloc/Allocator.cpp:
+        (bmalloc::Allocator::allocate): Because we arrange for power-of-two size
+        classes to allocate at power-of-two alignments, we can allocate any
+        small aligned request on the small path.
+
+        * bmalloc/Chunk.h:
+        (bmalloc::Chunk::bytes):
+        (bmalloc::Chunk::lines):
+        (bmalloc::Chunk::pages):
+        (bmalloc::Chunk::boundaryTags):
+        (bmalloc::Chunk::objectType): Moved some code around to provide better
+        API.
+
+        (bmalloc::Chunk::Chunk): Moved this code to VMHeap.
+
+        (bmalloc::Chunk::offset):
+        (bmalloc::Chunk::object): Use our new bytes() helper function.
+
+        * bmalloc/VMHeap.cpp:
+        (bmalloc::VMHeap::allocateChunk): Moved code here from Chunk.
+
+        (bmalloc::VMHeap::allocateSmallChunk): Ensure that power-of-two page
+        sizes always begin allocation at the same alignment. Power-of-two object
+        sizes always request power-of-two page sizes (since that's the least
+        wasteful option), so if we also ensure that power-of-two page sizes get
+        power-of-two alignment, then everything is aligned for all small objects.
+
 2016-04-03  Geoffrey Garen  <[email protected]>
 
         bmalloc: segregate small and large objects again, and allocate more objects on the small path

Modified: releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/Allocator.cpp (199452 => 199453)


--- releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/Allocator.cpp	2016-04-13 09:39:10 UTC (rev 199452)
+++ releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/Allocator.cpp	2016-04-13 09:39:26 UTC (rev 199453)
@@ -77,16 +77,13 @@
             return nullptr;
         return result;
     }
-    
-    if (size <= smallMax && alignment <= smallLineSize) {
-        size_t alignmentMask = alignment - 1;
-        while (void* p = allocate(size)) {
-            if (!test(p, alignmentMask))
-                return p;
-            m_deallocator.deallocate(p);
-        }
-    }
 
+    if (!size)
+        size = alignment;
+
+    if (size <= smallMax && alignment <= smallMax)
+        return allocate(roundUpToMultipleOf(alignment, size));
+
     if (size <= largeMax && alignment <= largeMax) {
         size = std::max(largeMin, roundUpToMultipleOf<largeAlignment>(size));
         alignment = roundUpToMultipleOf<largeAlignment>(alignment);

Modified: releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/Chunk.h (199452 => 199453)


--- releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/Chunk.h	2016-04-13 09:39:10 UTC (rev 199452)
+++ releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/Chunk.h	2016-04-13 09:39:26 UTC (rev 199453)
@@ -39,6 +39,23 @@
 namespace bmalloc {
 
 class Chunk {
+    // Our metadata layout includes a left and right edge sentinel.
+    // Metadata takes up enough space to leave at least the first two
+    // boundary tag slots unused.
+    //
+    //      So, boundary tag space looks like this:
+    //
+    //          [OOXXXXX...]
+    //
+    //      And BoundaryTag::get subtracts one, producing:
+    //
+    //          [OXXXXX...O].
+    //
+    // We use the X's for boundary tags and the O's for edge sentinels.
+
+    static const size_t boundaryTagCount = chunkSize / largeMin;
+    static_assert(boundaryTagCount > 2, "Chunk must have space for two sentinel boundary tags");
+
 public:
     static Chunk* get(void*);
 
@@ -53,33 +70,14 @@
     SmallPage* page(size_t offset);
     SmallLine* line(size_t offset);
 
+    char* bytes() { return reinterpret_cast<char*>(this); }
     SmallLine* lines() { return m_lines.begin(); }
     SmallPage* pages() { return m_pages.begin(); }
+    std::array<BoundaryTag, boundaryTagCount>& boundaryTags() { return m_boundaryTags; }
 
-    char* begin() { return roundUpToMultipleOf(vmPageSizePhysical(), m_memory); }
-    char* end() { return reinterpret_cast<char*>(this) + chunkSize; }
-    size_t size() { return end() - begin(); }
-
     ObjectType objectType() { return m_objectType; }
 
 private:
-    static const size_t boundaryTagCount = chunkSize / largeMin;
-    static_assert(boundaryTagCount > 2, "Chunk must have space for two sentinel boundary tags");
-
-    // Our metadata layout includes a left and right edge sentinel.
-    // Metadata takes up enough space to leave at least the first two
-    // boundary tag slots unused.
-    //
-    //      So, boundary tag space looks like this:
-    //
-    //          [OOXXXXX...]
-    //
-    //      And BoundaryTag::get subtracts one, producing:
-    //
-    //          [OXXXXX...O].
-    //
-    // We use the X's for boundary tags and the O's for edge sentinels.
-
     union {
         // The first few bytes of metadata cover the metadata region, so they're
         // not used. We can steal them to store m_objectType.
@@ -93,7 +91,6 @@
         std::array<SmallPage, chunkSize / smallPageSize> m_pages;
         std::array<BoundaryTag, boundaryTagCount> m_boundaryTags;
     };
-    char m_memory[];
 };
 
 static_assert(sizeof(Chunk) + largeMax <= chunkSize, "largeMax is too big");
@@ -104,33 +101,6 @@
 inline Chunk::Chunk(std::lock_guard<StaticMutex>&, ObjectType objectType)
     : m_objectType(objectType)
 {
-    if (objectType != ObjectType::Large)
-        return;
-
-    Range range(begin(), size());
-    BASSERT(range.size() <= largeObjectMax);
-
-    BeginTag* beginTag = Chunk::beginTag(range.begin());
-    beginTag->setRange(range);
-    beginTag->setFree(true);
-    beginTag->setVMState(VMState::Virtual);
-
-    EndTag* endTag = Chunk::endTag(range.begin(), range.size());
-    endTag->init(beginTag);
-
-    // Mark the left and right edges of our range as allocated. This naturally
-    // prevents merging logic from overflowing left (into metadata) or right
-    // (beyond our chunk), without requiring special-case checks.
-
-    EndTag* leftSentinel = beginTag->prev();
-    BASSERT(leftSentinel >= m_boundaryTags.begin());
-    BASSERT(leftSentinel < m_boundaryTags.end());
-    leftSentinel->initSentinel();
-
-    BeginTag* rightSentinel = endTag->next();
-    BASSERT(rightSentinel >= m_boundaryTags.begin());
-    BASSERT(rightSentinel < m_boundaryTags.end());
-    rightSentinel->initSentinel();
 }
 
 inline Chunk* Chunk::get(void* object)
@@ -161,13 +131,13 @@
 inline size_t Chunk::offset(void* object)
 {
     BASSERT(object >= this);
-    BASSERT(object < reinterpret_cast<char*>(this) + chunkSize);
-    return static_cast<char*>(object) - reinterpret_cast<char*>(this);
+    BASSERT(object < bytes() + chunkSize);
+    return static_cast<char*>(object) - bytes();
 }
 
 inline char* Chunk::object(size_t offset)
 {
-    return reinterpret_cast<char*>(this) + offset;
+    return bytes() + offset;
 }
 
 inline SmallPage* Chunk::page(size_t offset)

Modified: releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/VMHeap.cpp (199452 => 199453)


--- releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/VMHeap.cpp	2016-04-13 09:39:10 UTC (rev 199452)
+++ releases/WebKitGTK/webkit-2.12/Source/bmalloc/bmalloc/VMHeap.cpp	2016-04-13 09:39:26 UTC (rev 199453)
@@ -44,7 +44,35 @@
     m_zone.addChunk(chunk);
 #endif
 
-    return LargeObject(chunk->begin());
+    size_t alignment = largeAlignment;
+    size_t metadataSize = roundUpToMultipleOf(alignment, sizeof(Chunk));
+
+    Range range(chunk->bytes() + metadataSize, chunkSize - metadataSize);
+    BASSERT(range.size() <= largeObjectMax);
+
+    BeginTag* beginTag = Chunk::beginTag(range.begin());
+    beginTag->setRange(range);
+    beginTag->setFree(true);
+    beginTag->setVMState(VMState::Virtual);
+
+    EndTag* endTag = Chunk::endTag(range.begin(), range.size());
+    endTag->init(beginTag);
+
+    // Mark the left and right edges of our range as allocated. This naturally
+    // prevents merging logic from overflowing left (into metadata) or right
+    // (beyond our chunk), without requiring special-case checks.
+
+    EndTag* leftSentinel = beginTag->prev();
+    BASSERT(leftSentinel >= chunk->boundaryTags().begin());
+    BASSERT(leftSentinel < chunk->boundaryTags().end());
+    leftSentinel->initSentinel();
+
+    BeginTag* rightSentinel = endTag->next();
+    BASSERT(rightSentinel >= chunk->boundaryTags().begin());
+    BASSERT(rightSentinel < chunk->boundaryTags().end());
+    rightSentinel->initSentinel();
+
+    return LargeObject(range.begin());
 }
 
 void VMHeap::allocateSmallChunk(std::lock_guard<StaticMutex>& lock, size_t pageClass)
@@ -59,9 +87,16 @@
     size_t pageSize = bmalloc::pageSize(pageClass);
     size_t smallPageCount = pageSize / smallPageSize;
 
-    Object begin(chunk->begin());
-    Object end(begin + chunk->size());
+    // If our page size is a power of two, we align to it in order to guarantee
+    // that we can service aligned allocation requests at the same power of two.
+    size_t alignment = vmPageSizePhysical();
+    if (isPowerOfTwo(pageSize))
+        alignment = pageSize;
+    size_t metadataSize = roundUpToMultipleOf(alignment, sizeof(Chunk));
 
+    Object begin(chunk, metadataSize);
+    Object end(chunk, chunkSize);
+
     for (Object it = begin; it + pageSize <= end; it = it + pageSize) {
         SmallPage* page = it.page();
         new (page) SmallPage;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to