Bug 616310 - JM: reduce fragmentation in ExecutableAllocator. r=jseward.

This commit is contained in:
Nicholas Nethercote 2010-12-06 17:16:08 -08:00
Родитель 98b52d4461
Коммит c91ab0b8ab
1 изменённых файлов: 56 добавлений и 24 удалений

Просмотреть файл

@ -55,16 +55,14 @@ extern "C" __declspec(dllimport) void CacheRangeFlush(LPVOID pAddr, DWORD dwLeng
#endif
#define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize)
#if WTF_PLATFORM_WIN_OS || WTF_PLATFORM_WINCE
/*
* In practice, VirtualAlloc allocates in 64K chunks. (Technically, it
* allocates in page chunks, but the starting address is always a multiple
* of 64K, so each allocation uses up 64K of address space.
* On Windows, VirtualAlloc effectively allocates in 64K chunks. (Technically,
* it allocates in page chunks, but the starting address is always a multiple
* of 64K, so each allocation uses up 64K of address space.) So a size less
* than that would be pointless. But it turns out that 64KB is a reasonable
* size for all platforms.
*/
# define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 16)
#else
# define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 4)
#endif
#define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 16)
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
#define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE)
@ -203,15 +201,21 @@ public:
if (!pageSize)
intializePageSize();
allocator->m_smallAllocationPool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
if (!allocator->m_smallAllocationPool) {
ExecutablePool *pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
if (!pool) {
delete allocator;
return NULL;
}
JS_ASSERT(allocator->m_smallAllocationPools.empty());
allocator->m_smallAllocationPools.append(pool);
return allocator;
}
~ExecutableAllocator() { delete m_smallAllocationPool; }
~ExecutableAllocator()
{
for (size_t i = 0; i < m_smallAllocationPools.length(); i++)
delete m_smallAllocationPools[i];
}
// poolForSize returns reference-counted objects. The caller owns a reference
// to the object; i.e., poolForSize increments the count before returning the
@ -220,11 +224,21 @@ public:
ExecutablePool* poolForSize(size_t n)
{
#ifndef DEBUG_STRESS_JSC_ALLOCATOR
// Try to fit in the existing small allocator
if (n < m_smallAllocationPool->available()) {
m_smallAllocationPool->addRef();
return m_smallAllocationPool;
}
// Try to fit in an existing small allocator. Use the pool with the
// least available space that is big enough (best-fit). This is the
// best strategy because (a) it maximizes the chance of the next
// allocation fitting in a small pool, and (b) it minimizes the
// potential waste when a small pool is next abandoned.
ExecutablePool *minPool = NULL;
for (size_t i = 0; i < m_smallAllocationPools.length(); i++) {
ExecutablePool *pool = m_smallAllocationPools[i];
if (n <= pool->available() && (!minPool || pool->available() < minPool->available()))
minPool = pool;
}
if (minPool) {
minPool->addRef();
return minPool;
}
#endif
// If the request is large, we just provide a unshared allocator
@ -237,13 +251,29 @@ public:
return NULL;
// At this point, local |pool| is the owner.
// If the new allocator will result in more free space than in
// the current small allocator, then we will use it instead
if ((pool->available() - n) > m_smallAllocationPool->available()) {
m_smallAllocationPool->release();
m_smallAllocationPool = pool;
pool->addRef();
}
if (m_smallAllocationPools.length() < maxSmallPools) {
// We haven't hit the maximum number of live pools; add the new pool.
m_smallAllocationPools.append(pool);
pool->addRef();
} else {
// Find the pool with the least space.
int iMin = 0;
for (size_t i = 1; i < m_smallAllocationPools.length(); i++)
if (m_smallAllocationPools[i]->available() <
m_smallAllocationPools[iMin]->available())
{
iMin = i;
}
// If the new allocator will result in more free space than the small
// pool with the least space, then we will use it instead
ExecutablePool *minPool = m_smallAllocationPools[iMin];
if ((pool->available() - n) > minPool->available()) {
minPool->release();
m_smallAllocationPools[iMin] = pool;
pool->addRef();
}
}
// Pass ownership to the caller.
return pool;
@ -355,7 +385,9 @@ private:
static void reprotectRegion(void*, size_t, ProtectionSeting);
#endif
ExecutablePool* m_smallAllocationPool;
static const size_t maxSmallPools = 4;
typedef js::Vector<ExecutablePool *, maxSmallPools, js::SystemAllocPolicy > SmallExecPoolVector;
SmallExecPoolVector m_smallAllocationPools;
static void intializePageSize();
};