зеркало из https://github.com/mozilla/gecko-dev.git
Bug 616310 - JM: reduce fragmentation in ExecutableAllocator. r=jseward.
This commit is contained in:
Родитель
98b52d4461
Коммит
c91ab0b8ab
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче