blob: 0f17dc8a7edb2777171c2808ffbccdd302af2c4c [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include <algorithm>
#include "xfa/src/fgas/src/fgas_base.h"
#include "fx_memory.h"
#define FX_4BYTEALIGN(size) (((size) + 3) / 4 * 4)
IFX_MEMAllocator* FX_CreateAllocator(FX_ALLOCTYPE eType,
size_t chunkSize,
size_t blockSize) {
switch (eType) {
#ifndef _FXEMB
case FX_ALLOCTYPE_Dynamic:
return new CFX_DynamicStore(chunkSize);
#endif
case FX_ALLOCTYPE_Default:
return new CFX_DefStore();
case FX_ALLOCTYPE_Static:
return new CFX_StaticStore(chunkSize);
case FX_ALLOCTYPE_Fixed:
return new CFX_FixedStore(blockSize, chunkSize);
default:
return NULL;
}
}
CFX_StaticStore::CFX_StaticStore(size_t iDefChunkSize)
: m_iAllocatedSize(0),
m_iDefChunkSize(iDefChunkSize),
m_pChunk(NULL),
m_pLastChunk(NULL) {
FXSYS_assert(m_iDefChunkSize != 0);
}
CFX_StaticStore::~CFX_StaticStore() {
FX_LPSTATICSTORECHUNK pChunk, pNext;
pChunk = m_pChunk;
while (pChunk != NULL) {
pNext = pChunk->pNextChunk;
FX_Free(pChunk);
pChunk = pNext;
}
}
FX_LPSTATICSTORECHUNK CFX_StaticStore::AllocChunk(size_t size) {
FXSYS_assert(size != 0);
FX_LPSTATICSTORECHUNK pChunk = (FX_LPSTATICSTORECHUNK)FX_Alloc(
uint8_t, sizeof(FX_STATICSTORECHUNK) + size);
pChunk->iChunkSize = size;
pChunk->iFreeSize = size;
pChunk->pNextChunk = NULL;
if (m_pLastChunk == NULL) {
m_pChunk = pChunk;
} else {
m_pLastChunk->pNextChunk = pChunk;
}
m_pLastChunk = pChunk;
return pChunk;
}
FX_LPSTATICSTORECHUNK CFX_StaticStore::FindChunk(size_t size) {
FXSYS_assert(size != 0);
if (m_pLastChunk == NULL || m_pLastChunk->iFreeSize < size) {
return AllocChunk(std::max(m_iDefChunkSize, size));
}
return m_pLastChunk;
}
void* CFX_StaticStore::Alloc(size_t size) {
size = FX_4BYTEALIGN(size);
FXSYS_assert(size != 0);
FX_LPSTATICSTORECHUNK pChunk = FindChunk(size);
FXSYS_assert(pChunk != NULL && pChunk->iFreeSize >= size);
uint8_t* p = (uint8_t*)pChunk;
p += sizeof(FX_STATICSTORECHUNK) + pChunk->iChunkSize - pChunk->iFreeSize;
pChunk->iFreeSize -= size;
m_iAllocatedSize += size;
return p;
}
size_t CFX_StaticStore::SetDefChunkSize(size_t size) {
FXSYS_assert(size != 0);
size_t v = m_iDefChunkSize;
m_iDefChunkSize = size;
return v;
}
CFX_FixedStore::CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk)
: m_iBlockSize(FX_4BYTEALIGN(iBlockSize)),
m_iDefChunkSize(FX_4BYTEALIGN(iBlockNumsInChunk)),
m_pChunk(NULL) {
FXSYS_assert(m_iBlockSize != 0 && m_iDefChunkSize != 0);
}
CFX_FixedStore::~CFX_FixedStore() {
FX_LPFIXEDSTORECHUNK pChunk, pNext;
pChunk = m_pChunk;
while (pChunk != NULL) {
pNext = pChunk->pNextChunk;
FX_Free(pChunk);
pChunk = pNext;
}
}
FX_LPFIXEDSTORECHUNK CFX_FixedStore::AllocChunk() {
int32_t iTotalSize = sizeof(FX_FIXEDSTORECHUNK) + m_iDefChunkSize +
m_iBlockSize * m_iDefChunkSize;
FX_LPFIXEDSTORECHUNK pChunk =
(FX_LPFIXEDSTORECHUNK)FX_Alloc(uint8_t, iTotalSize);
if (pChunk == NULL) {
return NULL;
}
FXSYS_memset(pChunk->FirstFlag(), 0, m_iDefChunkSize);
pChunk->pNextChunk = m_pChunk;
pChunk->iChunkSize = m_iDefChunkSize;
pChunk->iFreeNum = m_iDefChunkSize;
m_pChunk = pChunk;
return pChunk;
}
void* CFX_FixedStore::Alloc(size_t size) {
if (size > m_iBlockSize) {
return NULL;
}
FX_LPFIXEDSTORECHUNK pChunk = m_pChunk;
while (pChunk != NULL) {
if (pChunk->iFreeNum > 0) {
break;
}
pChunk = pChunk->pNextChunk;
}
if (pChunk == NULL) {
pChunk = AllocChunk();
}
FXSYS_assert(pChunk != NULL);
uint8_t* pFlags = pChunk->FirstFlag();
size_t i = 0;
for (; i < pChunk->iChunkSize; i++)
if (pFlags[i] == 0) {
break;
}
FXSYS_assert(i < pChunk->iChunkSize);
pFlags[i] = 1;
pChunk->iFreeNum--;
return pChunk->FirstBlock() + i * m_iBlockSize;
}
void CFX_FixedStore::Free(void* pBlock) {
FXSYS_assert(pBlock != NULL);
FX_LPFIXEDSTORECHUNK pPrior, pChunk;
pPrior = NULL, pChunk = m_pChunk;
uint8_t* pStart = NULL;
uint8_t* pEnd;
while (pChunk != NULL) {
pStart = pChunk->FirstBlock();
if (pBlock >= pStart) {
pEnd = pStart + m_iBlockSize * pChunk->iChunkSize;
if (pBlock < pEnd) {
break;
}
}
pPrior = pChunk, pChunk = pChunk->pNextChunk;
}
FXSYS_assert(pChunk != NULL);
size_t iPos = ((uint8_t*)pBlock - pStart) / m_iBlockSize;
FXSYS_assert(iPos < pChunk->iChunkSize);
uint8_t* pFlags = pChunk->FirstFlag();
if (pFlags[iPos] == 0) {
return;
}
pFlags[iPos] = 0;
pChunk->iFreeNum++;
if (pChunk->iFreeNum == pChunk->iChunkSize) {
if (pPrior == NULL) {
m_pChunk = pChunk->pNextChunk;
} else {
pPrior->pNextChunk = pChunk->pNextChunk;
}
FX_Free(pChunk);
}
}
size_t CFX_FixedStore::SetDefChunkSize(size_t iChunkSize) {
FXSYS_assert(iChunkSize != 0);
size_t v = m_iDefChunkSize;
m_iDefChunkSize = FX_4BYTEALIGN(iChunkSize);
return v;
}
#ifndef _FXEMB
CFX_DynamicStore::CFX_DynamicStore(size_t iDefChunkSize)
: m_iDefChunkSize(iDefChunkSize), m_pChunk(NULL) {
FXSYS_assert(m_iDefChunkSize != 0);
}
CFX_DynamicStore::~CFX_DynamicStore() {
FX_LPDYNAMICSTORECHUNK pChunk, pNext;
pChunk = m_pChunk;
while (pChunk != NULL) {
pNext = pChunk->pNextChunk;
FX_Free(pChunk);
pChunk = pNext;
}
}
FX_LPDYNAMICSTORECHUNK CFX_DynamicStore::AllocChunk(size_t size) {
FXSYS_assert(size != 0);
FX_LPDYNAMICSTORECHUNK pChunk = (FX_LPDYNAMICSTORECHUNK)FX_Alloc(
uint8_t,
sizeof(FX_DYNAMICSTORECHUNK) + sizeof(FX_DYNAMICSTOREBLOCK) * 2 + size);
if (pChunk == NULL) {
return NULL;
}
pChunk->iChunkSize = size;
pChunk->iFreeSize = size;
FX_LPDYNAMICSTOREBLOCK pBlock = pChunk->FirstBlock();
pBlock->iBlockSize = size;
pBlock->bUsed = FALSE;
pBlock = pBlock->NextBlock();
pBlock->iBlockSize = 0;
pBlock->bUsed = TRUE;
if (m_pChunk != NULL && size >= m_iDefChunkSize) {
FX_LPDYNAMICSTORECHUNK pLast = m_pChunk;
while (pLast->pNextChunk != NULL) {
pLast = pLast->pNextChunk;
}
pLast->pNextChunk = pChunk;
pChunk->pNextChunk = NULL;
} else {
pChunk->pNextChunk = m_pChunk;
m_pChunk = pChunk;
}
return pChunk;
}
void* CFX_DynamicStore::Alloc(size_t size) {
size = FX_4BYTEALIGN(size);
FXSYS_assert(size != 0);
FX_LPDYNAMICSTORECHUNK pChunk = m_pChunk;
FX_LPDYNAMICSTOREBLOCK pBlock = NULL;
while (pChunk != NULL) {
if (pChunk->iFreeSize >= size) {
pBlock = pChunk->FirstBlock();
FX_BOOL bFind = FALSE;
while (pBlock->iBlockSize != 0) {
if (!pBlock->bUsed && pBlock->iBlockSize >= size) {
bFind = TRUE;
break;
}
pBlock = pBlock->NextBlock();
}
if (bFind) {
break;
}
}
pChunk = pChunk->pNextChunk;
}
if (pChunk == NULL) {
pChunk = AllocChunk(std::max(m_iDefChunkSize, size));
pBlock = pChunk->FirstBlock();
}
FXSYS_assert(pChunk != NULL && pBlock != NULL);
size_t m = size + sizeof(FX_DYNAMICSTOREBLOCK);
pBlock->bUsed = TRUE;
if (pBlock->iBlockSize > m) {
size_t n = pBlock->iBlockSize;
pBlock->iBlockSize = size;
FX_LPDYNAMICSTOREBLOCK pNextBlock = pBlock->NextBlock();
pNextBlock->bUsed = FALSE;
pNextBlock->iBlockSize = n - size - sizeof(FX_DYNAMICSTOREBLOCK);
pChunk->iFreeSize -= size + sizeof(FX_DYNAMICSTOREBLOCK);
} else {
pChunk->iFreeSize -= pBlock->iBlockSize;
}
return pBlock->Data();
}
void CFX_DynamicStore::Free(void* pBlock) {
FXSYS_assert(pBlock != NULL);
FX_LPDYNAMICSTORECHUNK pPriorChunk, pChunk;
pPriorChunk = NULL, pChunk = m_pChunk;
while (pChunk != NULL) {
if (pBlock > pChunk &&
pBlock <= ((uint8_t*)pChunk + sizeof(FX_DYNAMICSTORECHUNK) +
pChunk->iChunkSize)) {
break;
}
pPriorChunk = pChunk, pChunk = pChunk->pNextChunk;
}
FXSYS_assert(pChunk != NULL);
FX_LPDYNAMICSTOREBLOCK pPriorBlock, pFindBlock;
pPriorBlock = NULL, pFindBlock = pChunk->FirstBlock();
while (pFindBlock->iBlockSize != 0) {
if (pBlock == (void*)pFindBlock->Data()) {
break;
}
pPriorBlock = pFindBlock;
pFindBlock = pFindBlock->NextBlock();
}
FXSYS_assert(pFindBlock->iBlockSize != 0 && pFindBlock->bUsed &&
pBlock == (void*)pFindBlock->Data());
pFindBlock->bUsed = FALSE;
pChunk->iFreeSize += pFindBlock->iBlockSize;
if (pPriorBlock == NULL) {
pPriorBlock = pChunk->FirstBlock();
} else if (pPriorBlock->bUsed) {
pPriorBlock = pFindBlock;
}
pFindBlock = pPriorBlock;
size_t sizeFree = 0;
size_t sizeBlock = 0;
while (pFindBlock->iBlockSize != 0 && !pFindBlock->bUsed) {
if (pFindBlock != pPriorBlock) {
sizeFree += sizeof(FX_DYNAMICSTOREBLOCK);
sizeBlock += sizeof(FX_DYNAMICSTOREBLOCK);
}
sizeBlock += pFindBlock->iBlockSize;
pFindBlock = pFindBlock->NextBlock();
}
pPriorBlock->iBlockSize = sizeBlock;
pChunk->iFreeSize += sizeFree;
if (pChunk->iFreeSize == pChunk->iChunkSize) {
if (pPriorChunk == NULL) {
m_pChunk = pChunk->pNextChunk;
} else {
pPriorChunk->pNextChunk = pChunk->pNextChunk;
}
FX_Free(pChunk);
}
}
size_t CFX_DynamicStore::SetDefChunkSize(size_t size) {
FXSYS_assert(size != 0);
size_t v = m_iDefChunkSize;
m_iDefChunkSize = size;
return v;
}
#endif