bmalloc: page size should be configurable at runtime
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Mar 2016 02:22:47 +0000 (02:22 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Mar 2016 02:22:47 +0000 (02:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155993

Reviewed by Andreas Kling.

This is a memory win on 32bit iOS devices, since their page sizes are
4kB and not 16kB.

It's also a step toward supporting 64bit iOS devices that have a
16kB/4kB virtual/physical page size split.

* bmalloc/Chunk.h: Align to largeAlignment since 2 * smallMax isn't
required by the boundary tag allocator.

(bmalloc::Chunk::page): Account for the slide when accessing a page.
Each SmallPage hashes 4kB of memory. When we want to allocate a region
of memory larger than 4kB, we store our metadata in the first SmallPage
in the region and we assign a slide to the remaining SmallPages, so
they forward to that first SmallPage when accessed.

NOTE: We could use a less flexible technique that just hashed by
vmPageSize() instead of 4kB at runtime, with no slide, but I think we'll
be able to use this slide technique to make even more page sizes
dynamically at runtime, which should save some memory and simplify
the allocator.

(bmalloc::SmallPage::begin): It's invalid to access a SmallPage with
a slide, since such SmallPages do not contain meaningful data.

(bmalloc::SmallPage::end): Account for smallPageCount when computing
the size of a page.

(bmalloc::Chunk::pageBegin): Deleted.
(bmalloc::Chunk::pageEnd): Deleted.
(bmalloc::Object::pageBegin): Deleted.

* bmalloc/Heap.cpp:
(bmalloc::Heap::Heap): Cache vmPageSize because computing it might require
a syscall.

(bmalloc::Heap::initializeLineMetadata): Line metadata is a vector instead
of a 2D array because we don't know how much metadata we'll need until
we know the page size.

(bmalloc::Heap::scavengeSmallPage): Be sure to revert the slide when
deallocating a page. Otherwise, the next attempt to allocate the page
will slide when initializing it, sliding to nowhere.

(bmalloc::Heap::allocateSmallBumpRanges): Account for vector change to
line metadata.

(bmalloc::Heap::allocateSmallPage): Initialize slide and smallPageCount
since they aren't constant anymore.

(bmalloc::Heap::allocateLarge):
(bmalloc::Heap::splitAndAllocate):
(bmalloc::Heap::tryAllocateXLarge):
(bmalloc::Heap::shrinkXLarge): Adopt dynamic page size.

* bmalloc/Heap.h:

* bmalloc/Sizes.h: smallPageSize is no longer equal to the VM page
size -- it's just the smallest VM page size we're interested in supporting.

* bmalloc/SmallPage.h:
(bmalloc::SmallPage::slide):
(bmalloc::SmallPage::setSlide):
(bmalloc::SmallPage::smallPageCount):
(bmalloc::SmallPage::setSmallPageCount):
(bmalloc::SmallPage::ref):
(bmalloc::SmallPage::deref): Support slide and small page count as
dynamic values. This doesn't increase metadata size since sizeof(SmallPage)
rounds up to alignment anyway.

* bmalloc/VMAllocate.h:
(bmalloc::vmPageSize):
(bmalloc::vmPageShift):
(bmalloc::vmSize):
(bmalloc::vmValidate):
(bmalloc::tryVMAllocate):
(bmalloc::vmDeallocatePhysicalPagesSloppy):
(bmalloc::vmAllocatePhysicalPagesSloppy): Treat page size as a variable.

* bmalloc/Vector.h:
(bmalloc::Vector::initialCapacity):
(bmalloc::Vector<T>::insert):
(bmalloc::Vector<T>::grow):
(bmalloc::Vector<T>::shrink):
(bmalloc::Vector<T>::shrinkCapacity):
(bmalloc::Vector<T>::growCapacity): Treat page size as a variable.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198821 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/bmalloc/ChangeLog
Source/bmalloc/bmalloc/Chunk.h
Source/bmalloc/bmalloc/Heap.cpp
Source/bmalloc/bmalloc/Heap.h
Source/bmalloc/bmalloc/Sizes.h
Source/bmalloc/bmalloc/SmallPage.h
Source/bmalloc/bmalloc/VMAllocate.h
Source/bmalloc/bmalloc/Vector.h

index 010263b..ac62718 100644 (file)
@@ -1,3 +1,96 @@
+2016-03-29  Geoffrey Garen  <ggaren@apple.com>
+
+        bmalloc: page size should be configurable at runtime
+        https://bugs.webkit.org/show_bug.cgi?id=155993
+
+        Reviewed by Andreas Kling.
+
+        This is a memory win on 32bit iOS devices, since their page sizes are
+        4kB and not 16kB.
+
+        It's also a step toward supporting 64bit iOS devices that have a
+        16kB/4kB virtual/physical page size split.
+
+        * bmalloc/Chunk.h: Align to largeAlignment since 2 * smallMax isn't
+        required by the boundary tag allocator.
+
+        (bmalloc::Chunk::page): Account for the slide when accessing a page.
+        Each SmallPage hashes 4kB of memory. When we want to allocate a region
+        of memory larger than 4kB, we store our metadata in the first SmallPage
+        in the region and we assign a slide to the remaining SmallPages, so
+        they forward to that first SmallPage when accessed.
+
+        NOTE: We could use a less flexible technique that just hashed by
+        vmPageSize() instead of 4kB at runtime, with no slide, but I think we'll
+        be able to use this slide technique to make even more page sizes
+        dynamically at runtime, which should save some memory and simplify
+        the allocator.
+
+        (bmalloc::SmallPage::begin): It's invalid to access a SmallPage with
+        a slide, since such SmallPages do not contain meaningful data.
+
+        (bmalloc::SmallPage::end): Account for smallPageCount when computing
+        the size of a page.
+
+        (bmalloc::Chunk::pageBegin): Deleted.
+        (bmalloc::Chunk::pageEnd): Deleted.
+        (bmalloc::Object::pageBegin): Deleted.
+
+        * bmalloc/Heap.cpp:
+        (bmalloc::Heap::Heap): Cache vmPageSize because computing it might require
+        a syscall.
+
+        (bmalloc::Heap::initializeLineMetadata): Line metadata is a vector instead
+        of a 2D array because we don't know how much metadata we'll need until
+        we know the page size.
+
+        (bmalloc::Heap::scavengeSmallPage): Be sure to revert the slide when
+        deallocating a page. Otherwise, the next attempt to allocate the page
+        will slide when initializing it, sliding to nowhere.
+
+        (bmalloc::Heap::allocateSmallBumpRanges): Account for vector change to
+        line metadata.
+
+        (bmalloc::Heap::allocateSmallPage): Initialize slide and smallPageCount
+        since they aren't constant anymore.
+
+        (bmalloc::Heap::allocateLarge):
+        (bmalloc::Heap::splitAndAllocate):
+        (bmalloc::Heap::tryAllocateXLarge):
+        (bmalloc::Heap::shrinkXLarge): Adopt dynamic page size.
+
+        * bmalloc/Heap.h:
+
+        * bmalloc/Sizes.h: smallPageSize is no longer equal to the VM page
+        size -- it's just the smallest VM page size we're interested in supporting.
+
+        * bmalloc/SmallPage.h:
+        (bmalloc::SmallPage::slide):
+        (bmalloc::SmallPage::setSlide):
+        (bmalloc::SmallPage::smallPageCount):
+        (bmalloc::SmallPage::setSmallPageCount):
+        (bmalloc::SmallPage::ref):
+        (bmalloc::SmallPage::deref): Support slide and small page count as
+        dynamic values. This doesn't increase metadata size since sizeof(SmallPage)
+        rounds up to alignment anyway.
+
+        * bmalloc/VMAllocate.h:
+        (bmalloc::vmPageSize):
+        (bmalloc::vmPageShift):
+        (bmalloc::vmSize):
+        (bmalloc::vmValidate):
+        (bmalloc::tryVMAllocate):
+        (bmalloc::vmDeallocatePhysicalPagesSloppy):
+        (bmalloc::vmAllocatePhysicalPagesSloppy): Treat page size as a variable.
+
+        * bmalloc/Vector.h:
+        (bmalloc::Vector::initialCapacity):
+        (bmalloc::Vector<T>::insert):
+        (bmalloc::Vector<T>::grow):
+        (bmalloc::Vector<T>::shrink):
+        (bmalloc::Vector<T>::shrinkCapacity):
+        (bmalloc::Vector<T>::growCapacity): Treat page size as a variable.
+
 2016-03-29  David Kilzer  <ddkilzer@apple.com>
 
         bmalloc: add logging for mmap() failures
index fc5c3e1..4a5c824 100644 (file)
@@ -53,9 +53,6 @@ public:
     SmallPage* page(size_t offset);
     SmallLine* line(size_t offset);
 
-    SmallPage* pageBegin() { return Object(m_memory).page(); }
-    SmallPage* pageEnd() { return m_pages.end(); }
-    
     SmallLine* lines() { return m_lines.begin(); }
     SmallPage* pages() { return m_pages.begin(); }
 
@@ -81,15 +78,12 @@ private:
     // We use the X's for boundary tags and the O's for edge sentinels.
 
     std::array<SmallLine, chunkSize / smallLineSize> m_lines;
-    std::array<SmallPage, chunkSize / vmPageSize> m_pages;
+    std::array<SmallPage, chunkSize / smallPageSize> m_pages;
     std::array<BoundaryTag, boundaryTagCount> m_boundaryTags;
-    char m_memory[] __attribute__((aligned(2 * smallMax + 0)));
+    char m_memory[] __attribute__((aligned(largeAlignment + 0)));
 };
 
 static_assert(sizeof(Chunk) + largeMax <= chunkSize, "largeMax is too big");
-static_assert(
-    sizeof(Chunk) % vmPageSize + 2 * smallMax <= vmPageSize,
-    "the first page of object memory in a small chunk must be able to allocate smallMax");
 
 inline Chunk::Chunk(std::lock_guard<StaticMutex>& lock)
 {
@@ -165,8 +159,9 @@ inline void* Chunk::object(size_t offset)
 
 inline SmallPage* Chunk::page(size_t offset)
 {
-    size_t pageNumber = offset / vmPageSize;
-    return &m_pages[pageNumber];
+    size_t pageNumber = offset / smallPageSize;
+    SmallPage* page = &m_pages[pageNumber];
+    return page - page->slide();
 }
 
 inline SmallLine* Chunk::line(size_t offset)
@@ -190,15 +185,17 @@ inline char* SmallLine::end()
 
 inline SmallLine* SmallPage::begin()
 {
+    BASSERT(!m_slide);
     Chunk* chunk = Chunk::get(this);
     size_t pageNumber = this - chunk->pages();
-    size_t lineNumber = pageNumber * smallLineCount;
+    size_t lineNumber = pageNumber * smallPageLineCount;
     return &chunk->lines()[lineNumber];
 }
 
 inline SmallLine* SmallPage::end()
 {
-    return begin() + smallLineCount;
+    BASSERT(!m_slide);
+    return begin() + m_smallPageCount * smallPageLineCount;
 }
 
 inline Object::Object(void* object)
@@ -219,11 +216,6 @@ inline void* Object::begin()
     return m_chunk->object(m_offset);
 }
 
-inline void* Object::pageBegin()
-{
-    return m_chunk->object(roundDownToMultipleOf(vmPageSize, m_offset));
-}
-
 inline SmallLine* Object::line()
 {
     return m_chunk->line(m_offset);
index 0365a5f..9037a90 100644 (file)
@@ -35,7 +35,8 @@
 namespace bmalloc {
 
 Heap::Heap(std::lock_guard<StaticMutex>&)
-    : m_largeObjects(VMState::HasPhysical::True)
+    : m_vmPageSize(vmPageSize())
+    , m_largeObjects(VMState::HasPhysical::True)
     , m_isAllocatingPages(false)
     , m_scavenger(*this, &Heap::concurrentScavenge)
 {
@@ -46,13 +47,16 @@ void Heap::initializeLineMetadata()
 {
     // We assume that m_smallLineMetadata is zero-filled.
 
+    size_t smallLineCount = m_vmPageSize / smallLineSize;
+    m_smallLineMetadata.grow(sizeClassCount * smallLineCount);
+
     for (size_t sizeClass = 0; sizeClass < sizeClassCount; ++sizeClass) {
         size_t size = objectSize(sizeClass);
-        auto& metadata = m_smallLineMetadata[sizeClass];
+        LineMetadata* pageMetadata = &m_smallLineMetadata[sizeClass * smallLineCount];
 
         size_t object = 0;
         size_t line = 0;
-        while (object < vmPageSize) {
+        while (object < m_vmPageSize) {
             line = object / smallLineSize;
             size_t leftover = object % smallLineSize;
 
@@ -60,15 +64,15 @@ void Heap::initializeLineMetadata()
             size_t remainder;
             divideRoundingUp(smallLineSize - leftover, size, objectCount, remainder);
 
-            metadata[line] = { static_cast<unsigned short>(leftover), static_cast<unsigned short>(objectCount) };
+            pageMetadata[line] = { static_cast<unsigned short>(leftover), static_cast<unsigned short>(objectCount) };
 
             object += objectCount * size;
         }
 
         // Don't allow the last object in a page to escape the page.
-        if (object > vmPageSize) {
-            BASSERT(metadata[line].objectCount);
-            --metadata[line].objectCount;
+        if (object > m_vmPageSize) {
+            BASSERT(pageMetadata[line].objectCount);
+            --pageMetadata[line].objectCount;
         }
     }
 }
@@ -100,7 +104,12 @@ void Heap::scavengeSmallPage(std::lock_guard<StaticMutex>& lock)
 {
     SmallPage* page = m_smallPages.pop();
 
-    // Transform small object page back into a large object.
+    // Revert the slide() value on intermediate SmallPages so they hash to
+    // themselves again.
+    for (size_t i = 1; i < page->smallPageCount(); ++i)
+        page[i].setSlide(0);
+
+    // Revert our small object page back to large object.
     page->setObjectType(ObjectType::Large);
 
     LargeObject largeObject(page->begin()->begin());
@@ -143,13 +152,15 @@ void Heap::allocateSmallBumpRanges(std::lock_guard<StaticMutex>& lock, size_t si
     SmallPage* page = allocateSmallPage(lock, sizeClass);
     SmallLine* lines = page->begin();
     BASSERT(page->hasFreeLines(lock));
+    size_t smallLineCount = m_vmPageSize / smallLineSize;
+    LineMetadata* pageMetadata = &m_smallLineMetadata[sizeClass * smallLineCount];
 
     // Find a free line.
     for (size_t lineNumber = 0; lineNumber < smallLineCount; ++lineNumber) {
         if (lines[lineNumber].refCount(lock))
             continue;
 
-        LineMetadata& lineMetadata = m_smallLineMetadata[sizeClass][lineNumber];
+        LineMetadata& lineMetadata = pageMetadata[lineNumber];
         if (!lineMetadata.objectCount)
             continue;
 
@@ -170,7 +181,7 @@ void Heap::allocateSmallBumpRanges(std::lock_guard<StaticMutex>& lock, size_t si
             if (lines[lineNumber].refCount(lock))
                 break;
 
-            LineMetadata& lineMetadata = m_smallLineMetadata[sizeClass][lineNumber];
+            LineMetadata& lineMetadata = pageMetadata[lineNumber];
             if (!lineMetadata.objectCount)
                 continue;
 
@@ -200,16 +211,24 @@ SmallPage* Heap::allocateSmallPage(std::lock_guard<StaticMutex>& lock, size_t si
         return page;
     }
 
-    size_t unalignedSize = largeMin + vmPageSize - largeAlignment + vmPageSize;
-    LargeObject largeObject = allocateLarge(lock, vmPageSize, vmPageSize, unalignedSize);
-
+    size_t unalignedSize = largeMin + m_vmPageSize - largeAlignment + m_vmPageSize;
+    LargeObject largeObject = allocateLarge(lock, m_vmPageSize, m_vmPageSize, unalignedSize);
+    
     // Transform our large object into a small object page. We deref here
-    // because our small objects will keep their own refcounts on the line.
+    // because our small objects will keep their own line refcounts.
     Object object(largeObject.begin());
     object.line()->deref(lock);
     object.page()->setObjectType(ObjectType::Small);
 
-    object.page()->setSizeClass(sizeClass);
+    SmallPage* page = object.page();
+    page->setSizeClass(sizeClass);
+    page->setSmallPageCount(m_vmPageSize / smallPageSize);
+
+    // Set a slide() value on intermediate SmallPages so they hash to their
+    // vmPageSize-sized page.
+    for (size_t i = 1; i < page->smallPageCount(); ++i)
+        page[i].setSlide(i);
+
     return object.page();
 }
 
@@ -307,7 +326,7 @@ void* Heap::allocateLarge(std::lock_guard<StaticMutex>& lock, size_t size)
     BASSERT(size >= largeMin);
     BASSERT(size == roundUpToMultipleOf<largeAlignment>(size));
     
-    if (size <= vmPageSize)
+    if (size <= m_vmPageSize)
         scavengeSmallPages(lock);
 
     LargeObject largeObject = m_largeObjects.take(size);
@@ -338,7 +357,7 @@ void* Heap::allocateLarge(std::lock_guard<StaticMutex>& lock, size_t alignment,
     BASSERT(alignment >= largeAlignment);
     BASSERT(isPowerOfTwo(alignment));
 
-    if (size <= vmPageSize)
+    if (size <= m_vmPageSize)
         scavengeSmallPages(lock);
 
     LargeObject largeObject = m_largeObjects.take(alignment, size, unalignedSize);
@@ -412,7 +431,7 @@ XLargeRange Heap::splitAndAllocate(XLargeRange& range, size_t alignment, size_t
     // in the allocated list. This is an important optimization because it
     // keeps the free list short, speeding up allocation and merging.
 
-    std::pair<XLargeRange, XLargeRange> allocated = range.split(roundUpToMultipleOf<vmPageSize>(size));
+    std::pair<XLargeRange, XLargeRange> allocated = range.split(roundUpToMultipleOf(m_vmPageSize, size));
     if (allocated.first.vmState().hasVirtual()) {
         vmAllocatePhysicalPagesSloppy(allocated.first.begin(), allocated.first.size());
         allocated.first.setVMState(VMState::Physical);
@@ -429,7 +448,7 @@ void* Heap::tryAllocateXLarge(std::lock_guard<StaticMutex>&, size_t alignment, s
 
     m_isAllocatingPages = true;
 
-    size = std::max(vmPageSize, size);
+    size = std::max(m_vmPageSize, size);
     alignment = roundUpToMultipleOf<xLargeAlignment>(alignment);
 
     XLargeRange range = m_xLargeMap.takeFree(alignment, size);
@@ -456,7 +475,7 @@ void Heap::shrinkXLarge(std::unique_lock<StaticMutex>&, const Range& object, siz
 {
     BASSERT(object.size() > newSize);
 
-    if (object.size() - newSize < vmPageSize)
+    if (object.size() - newSize < m_vmPageSize)
         return;
     
     XLargeRange range = m_xLargeMap.takeAllocated(object.begin());
index 1bf0f3b..e8ee77a 100644 (file)
@@ -93,7 +93,9 @@ private:
     void scavengeLargeObjects(std::unique_lock<StaticMutex>&, std::chrono::milliseconds);
     void scavengeXLargeObjects(std::unique_lock<StaticMutex>&, std::chrono::milliseconds);
 
-    std::array<std::array<LineMetadata, smallLineCount>, sizeClassCount> m_smallLineMetadata;
+    size_t m_vmPageSize;
+
+    Vector<LineMetadata> m_smallLineMetadata;
 
     std::array<List<SmallPage>, sizeClassCount> m_smallPagesWithFreeLines;
 
index 8feff56..ef73536 100644 (file)
@@ -46,14 +46,9 @@ namespace Sizes {
     static const size_t alignment = 8;
     static const size_t alignmentMask = alignment - 1ul;
 
-#if BPLATFORM(IOS)
-    static const size_t vmPageSize = 16 * kB;
-#else
-    static const size_t vmPageSize = 4 * kB;
-#endif
-    
     static const size_t smallLineSize = 256;
-    static const size_t smallLineCount = vmPageSize / smallLineSize;
+    static const size_t smallPageSize = 4 * kB;
+    static const size_t smallPageLineCount = smallPageSize / smallLineSize;
 
     static const size_t smallMax = 1 * kB;
     static const size_t maskSizeClassMax = 512;
index d741240..8a123d2 100644 (file)
@@ -58,10 +58,18 @@ public:
     SmallLine* begin();
     SmallLine* end();
 
+    unsigned char slide() const { return m_slide; }
+    void setSlide(unsigned char slide) { m_slide = slide; }
+
+    unsigned char smallPageCount() const { return m_smallPageCount; }
+    void setSmallPageCount(unsigned char smallPageCount) { m_smallPageCount = smallPageCount; }
+
 private:
     unsigned char m_hasFreeLines: 1;
     unsigned char m_refCount: 7;
     unsigned char m_sizeClass;
+    unsigned char m_smallPageCount;
+    unsigned char m_slide;
     ObjectType m_objectType;
 
 static_assert(
@@ -71,12 +79,14 @@ static_assert(
 
 inline void SmallPage::ref(std::lock_guard<StaticMutex>&)
 {
+    BASSERT(!m_slide);
     ++m_refCount;
     BASSERT(m_refCount);
 }
 
 inline bool SmallPage::deref(std::lock_guard<StaticMutex>&)
 {
+    BASSERT(!m_slide);
     BASSERT(m_refCount);
     --m_refCount;
     return !m_refCount;
index 4ca4d89..08db4a4 100644 (file)
@@ -47,31 +47,35 @@ namespace bmalloc {
 #define BMALLOC_VM_TAG -1
 #endif
 
+inline size_t vmPageSize()
+{
+    return sysconf(_SC_PAGESIZE);
+}
+
+inline size_t vmPageShift()
+{
+    return log2(vmPageSize());
+}
+
 inline size_t vmSize(size_t size)
 {
-    return roundUpToMultipleOf<vmPageSize>(size);
+    return roundUpToMultipleOf(vmPageSize(), size);
 }
 
 inline void vmValidate(size_t vmSize)
 {
-    // We use getpagesize() here instead of vmPageSize because vmPageSize is
-    // allowed to be larger than the OS's true page size.
-
     UNUSED(vmSize);
     BASSERT(vmSize);
-    BASSERT(vmSize == roundUpToMultipleOf(static_cast<size_t>(getpagesize()), vmSize));
+    BASSERT(vmSize == roundUpToMultipleOf(vmPageSize(), vmSize));
 }
 
 inline void vmValidate(void* p, size_t vmSize)
 {
-    // We use getpagesize() here instead of vmPageSize because vmPageSize is
-    // allowed to be larger than the OS's true page size.
-
     vmValidate(vmSize);
     
     UNUSED(p);
     BASSERT(p);
-    BASSERT(p == mask(p, ~(getpagesize() - 1)));
+    BASSERT(p == mask(p, ~(vmPageSize() - 1)));
 }
 
 inline void* tryVMAllocate(size_t vmSize)
@@ -106,10 +110,7 @@ inline void* tryVMAllocate(size_t vmAlignment, size_t vmSize)
     vmValidate(vmSize);
     vmValidate(vmAlignment);
 
-    // We use getpagesize() here instead of vmPageSize because vmPageSize is
-    // allowed to be larger than the OS's true page size.
-
-    size_t mappedSize = vmAlignment - getpagesize() + vmSize;
+    size_t mappedSize = vmAlignment - vmPageSize() + vmSize;
     char* mapped = static_cast<char*>(tryVMAllocate(mappedSize));
     if (!mapped)
         return nullptr;
@@ -159,8 +160,8 @@ inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
 // Trims requests that are un-page-aligned.
 inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
 {
-    char* begin = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p));
-    char* end = roundDownToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
+    char* begin = roundUpToMultipleOf(vmPageSize(), static_cast<char*>(p));
+    char* end = roundDownToMultipleOf(vmPageSize(), static_cast<char*>(p) + size);
 
     if (begin >= end)
         return;
@@ -171,8 +172,8 @@ inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
 // Expands requests that are un-page-aligned.
 inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
 {
-    char* begin = roundDownToMultipleOf<vmPageSize>(static_cast<char*>(p));
-    char* end = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
+    char* begin = roundDownToMultipleOf(vmPageSize(), static_cast<char*>(p));
+    char* end = roundUpToMultipleOf(vmPageSize(), static_cast<char*>(p) + size);
 
     if (begin >= end)
         return;
index 0959e45..d257fc5 100644 (file)
@@ -66,6 +66,7 @@ public:
     
     void insert(iterator, const T&);
 
+    void grow(size_t);
     void shrink(size_t);
 
     void shrinkToFit();
@@ -73,7 +74,7 @@ public:
 private:
     static const size_t growFactor = 2;
     static const size_t shrinkFactor = 4;
-    static const size_t initialCapacity = vmPageSize / sizeof(T);
+    static size_t initialCapacity() { return vmPageSize() / sizeof(T); }
 
     void growCapacity();
     void shrinkCapacity();
@@ -146,11 +147,19 @@ void Vector<T>::insert(iterator it, const T& value)
 }
 
 template<typename T>
+inline void Vector<T>::grow(size_t size)
+{
+    BASSERT(size >= m_size);
+    while (m_size < size)
+        push(T());
+}
+
+template<typename T>
 inline void Vector<T>::shrink(size_t size)
 {
     BASSERT(size <= m_size);
     m_size = size;
-    if (m_capacity > initialCapacity && m_size < m_capacity / shrinkFactor)
+    if (m_size < m_capacity / shrinkFactor && m_capacity > initialCapacity())
         shrinkCapacity();
 }
 
@@ -171,14 +180,14 @@ void Vector<T>::reallocateBuffer(size_t newCapacity)
 template<typename T>
 NO_INLINE void Vector<T>::shrinkCapacity()
 {
-    size_t newCapacity = max(initialCapacity, m_capacity / shrinkFactor);
+    size_t newCapacity = max(initialCapacity(), m_capacity / shrinkFactor);
     reallocateBuffer(newCapacity);
 }
 
 template<typename T>
 NO_INLINE void Vector<T>::growCapacity()
 {
-    size_t newCapacity = max(initialCapacity, m_size * growFactor);
+    size_t newCapacity = max(initialCapacity(), m_size * growFactor);
     reallocateBuffer(newCapacity);
 }