blob: e682eb326cc13f0c592fa837f673da19c98656b5 [file] [log] [blame]
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef AlignedMemoryAllocator_h
#define AlignedMemoryAllocator_h
#include <wtf/Bitmap.h>
#include <wtf/PageReservation.h>
namespace JSC {
struct AlignedMemoryAllocatorConstants {
// Set sane defaults if -D<flagname=value> wasn't provided via compiler args
#if defined(JSCCOLLECTOR_VIRTUALMEM_RESERVATION)
// Keep backwards compatibility with symbian build system
static const size_t virtualMemoryReservation = JSCCOLLECTOR_VIRTUALMEM_RESERVATION;
#elif defined(__WINS__)
// Emulator has limited virtual address space
static const size_t virtualMemoryReservation = 0x400000;
#else
// HW has plenty of virtual addresses
static const size_t virtualMemoryReservation = 0x8000000;
#endif
};
template<size_t blockSize> class AlignedMemory;
template<size_t blockSize> class AlignedMemoryAllocator;
#if HAVE(PAGE_ALLOCATE_ALIGNED)
template<size_t blockSize>
class AlignedMemoryAllocator;
template<size_t blockSize>
class AlignedMemory {
public:
void deallocate();
void* base();
private:
friend class AlignedMemoryAllocator<blockSize>;
AlignedMemory(PageAllocation);
PageAllocation m_allocation;
};
template<size_t blockSize>
class AlignedMemoryAllocator {
public:
void destroy();
AlignedMemory<blockSize> allocate();
};
template<size_t blockSize>
inline void AlignedMemoryAllocator<blockSize>::destroy()
{
}
template<size_t blockSize>
inline AlignedMemory<blockSize> AlignedMemoryAllocator<blockSize>::allocate()
{
return AlignedMemory<blockSize>(PageAllocation::allocateAligned(blockSize, PageAllocation::JSGCHeapPages));
}
template<size_t blockSize>
inline void AlignedMemory<blockSize>::deallocate()
{
m_allocation.deallocate();
}
template<size_t blockSize>
inline void* AlignedMemory<blockSize>::base()
{
return m_allocation.base();
}
template<size_t blockSize>
inline AlignedMemory<blockSize>::AlignedMemory(PageAllocation allocation)
: m_allocation(allocation)
{
}
#else
template<size_t blockSize>
class AlignedMemory {
public:
void deallocate();
void* base();
private:
friend class AlignedMemoryAllocator<blockSize>;
AlignedMemory(void* base, AlignedMemoryAllocator<blockSize>* allocator);
void* m_base;
AlignedMemoryAllocator<blockSize>* m_allocator;
};
template<size_t blockSize>
class AlignedMemoryAllocator {
public:
AlignedMemoryAllocator();
~AlignedMemoryAllocator();
void destroy();
AlignedMemory<blockSize> allocate();
void free(AlignedMemory<blockSize>);
private:
static const size_t reservationSize = AlignedMemoryAllocatorConstants::virtualMemoryReservation;
static const size_t bitmapSize = reservationSize / blockSize;
PageReservation m_reservation;
size_t m_nextFree;
uintptr_t m_reservationBase;
WTF::Bitmap<bitmapSize> m_bitmap;
};
template<size_t blockSize>
AlignedMemoryAllocator<blockSize>::AlignedMemoryAllocator()
: m_reservation(PageReservation::reserve(reservationSize + blockSize, PageAllocation::JSGCHeapPages))
, m_nextFree(0)
{
// check that blockSize and reservationSize are powers of two
ASSERT(!(blockSize & (blockSize - 1)));
ASSERT(!(reservationSize & (reservationSize - 1)));
// check that blockSize is a multiple of pageSize and that
// reservationSize is a multiple of blockSize
ASSERT(!(blockSize & (PageAllocation::pageSize() - 1)));
ASSERT(!(reservationSize & (blockSize - 1)));
ASSERT(m_reservation);
m_reservationBase = reinterpret_cast<uintptr_t>(m_reservation.base());
m_reservationBase = (m_reservationBase + blockSize) & ~(blockSize - 1);
}
template<size_t blockSize>
AlignedMemoryAllocator<blockSize>::~AlignedMemoryAllocator()
{
destroy();
m_reservation.deallocate();
}
template<size_t blockSize>
inline void AlignedMemoryAllocator<blockSize>::destroy()
{
for (unsigned i = 0; i < bitmapSize; ++i) {
if (m_bitmap.get(i)) {
void* blockAddress = reinterpret_cast<void*>(m_reservationBase + m_nextFree * blockSize);
m_reservation.decommit(blockAddress, blockSize);
m_bitmap.clear(i);
}
}
}
template<size_t blockSize>
AlignedMemory<blockSize> AlignedMemoryAllocator<blockSize>::allocate()
{
while (m_nextFree < bitmapSize) {
if (!m_bitmap.get(m_nextFree)) {
void* blockAddress = reinterpret_cast<void*>(m_reservationBase + m_nextFree * blockSize);
m_reservation.commit(blockAddress, blockSize);
m_bitmap.set(m_nextFree);
++m_nextFree;
return AlignedMemory<blockSize>(blockAddress, this);
}
m_bitmap.advanceToNextFreeBit(m_nextFree);
}
if (m_bitmap.isFull())
return AlignedMemory<blockSize>(0, this);
m_nextFree = 0;
return allocate();
}
template<size_t blockSize>
void AlignedMemoryAllocator<blockSize>::free(AlignedMemory<blockSize> allocation)
{
ASSERT(allocation.base());
m_reservation.decommit(allocation.base(), blockSize);
size_t diff = (reinterpret_cast<uintptr_t>(allocation.base()) - m_reservationBase);
ASSERT(!(diff & (blockSize - 1)));
size_t i = diff / blockSize;
ASSERT(m_bitmap.get(i));
m_bitmap.clear(i);
}
template<size_t blockSize>
inline void AlignedMemory<blockSize>::deallocate()
{
m_allocator->free(*this);
}
template<size_t blockSize>
inline void* AlignedMemory<blockSize>::base()
{
return m_base;
}
template<size_t blockSize>
AlignedMemory<blockSize>::AlignedMemory(void* base, AlignedMemoryAllocator<blockSize>* allocator)
: m_base(base)
, m_allocator(allocator)
{
}
#endif
}
#endif