| // 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 |