1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../include/fxcrt/fx_ext.h"
8#include "mem_int.h"
9#ifdef _FPDFAPI_MINI_
10static FX_MEMCONFIG g_MemConfig = {
11    1,
12    5,
13    8,
14    4,
15    12,
16    8,
17    2,
18    4,
19    32,
20    64,
21};
22#else
23static FX_MEMCONFIG g_MemConfig = {
24    1,
25    8,
26    24,
27    8,
28    32,
29    16,
30    4,
31    8,
32    128,
33    64,
34};
35#endif
36void FXMEM_SetConfig(const FX_MEMCONFIG* memConfig)
37{
38    g_MemConfig = *memConfig;
39}
40#ifdef __cplusplus
41extern "C" {
42#endif
43static void* FixedAlloc(FXMEM_SystemMgr* pMgr, size_t size, int flags)
44{
45    return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);
46}
47static void* FixedAllocDebug(FXMEM_SystemMgr* pMgr, size_t size, int flags, FX_LPCSTR file, int line)
48{
49    return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);
50}
51static void* FixedRealloc(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags)
52{
53    return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);
54}
55static void* FixedReallocDebug(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags, FX_LPCSTR file, int line)
56{
57    return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);
58}
59static void  FixedFree(FXMEM_SystemMgr* pMgr, void* pointer, int flags)
60{
61    ((CFXMEM_FixedMgr*)pMgr->user)->Free(pointer);
62}
63static void  FixedPurge(FXMEM_SystemMgr* pMgr)
64{
65    ((CFXMEM_FixedMgr*)pMgr->user)->Purge();
66}
67static void FixedCollectAll(FXMEM_SystemMgr* pMgr)
68{
69    ((CFXMEM_FixedMgr*)pMgr->user)->FreeAll();
70}
71#define FIXEDMEM_MINIMUMSIZE	(1024 * 1024 * 8)
72FXMEM_FoxitMgr* FXMEM_CreateMemoryMgr(size_t size, FX_BOOL extensible)
73{
74    if (size < FIXEDMEM_MINIMUMSIZE) {
75        size = FIXEDMEM_MINIMUMSIZE;
76    }
77    FX_LPVOID pMemory = malloc(size);
78    if (!pMemory) {
79        return NULL;
80    }
81    CFixedMgr_Proxy* pProxy = (CFixedMgr_Proxy*)pMemory;
82    size_t offsetSize = (sizeof(CFixedMgr_Proxy) + 15) / 16 * 16;
83    FXMEM_FoxitMgr* pFoxitMgr = pProxy->Initialize((FX_LPBYTE)pProxy + offsetSize, size - offsetSize, extensible);
84    if (!pFoxitMgr) {
85        free(pMemory);
86        return NULL;
87    }
88    g_pDefFoxitMgr = (CFX_MemoryMgr*)pFoxitMgr;
89    g_pDefFoxitMgr->m_pExternalMemory = pMemory;
90    return pFoxitMgr;
91}
92FXMEM_FoxitMgr* FXMEM_CreateFixedMgr(void* pMemory, size_t size, FXMEM_SystemMgr2* pSystemMgr)
93{
94    if (pMemory == NULL || size < FX_FIXEDMEM_PAGESIZE) {
95        return NULL;
96    }
97    if (!pSystemMgr && size >= FIXEDMEM_PROXYSIZE_1) {
98        CFixedMgr_Proxy* pProxy = (CFixedMgr_Proxy*)pMemory;
99        size_t offsetSize = (sizeof(CFixedMgr_Proxy) + 15) / 16 * 16;
100        return pProxy->Initialize((FX_LPBYTE)pProxy + offsetSize, size - offsetSize, FALSE);
101    }
102    CFXMEM_FixedMgr* pHeader = (CFXMEM_FixedMgr*)pMemory;
103    pHeader->Initialize(size);
104    pHeader->m_pExtender = pSystemMgr;
105    CFX_MemoryMgr* p = (CFX_MemoryMgr*)pHeader->Alloc(sizeof(CFX_MemoryMgr));
106    if (p == NULL) {
107        return NULL;
108    }
109    p->Init(&pHeader->m_SystemMgr);
110    return (FXMEM_FoxitMgr*)p;
111}
112size_t FXMEM_GetBlockSizeInFixedMgr(FXMEM_FoxitMgr* pFoxitMgr, void* ptr)
113{
114    return pFoxitMgr ? ((CFXMEM_FixedMgr*)((CFX_MemoryMgr*)pFoxitMgr)->m_pSystemMgr->user)->GetSize(ptr) : 0;
115}
116#ifdef __cplusplus
117}
118#endif
119const FX_MEMCONFIG g_ProxyMgr_MemConfigs[6] = {
120    {1,      2,      4,      0,      2,      2,   2,       0,       0,     0},
121    {1,      4,      8,      0,      2,      2,   2,       0,       0,     0},
122    {1,      4,      16,     4,      8,      8,   2,       1,       16,    16},
123    {1,      8,      24,     4,      12,     12,  4,       2,       32,    16},
124    {1,      8,      24,     8,      16,     16,  4,       2,       64,    32},
125    {1,      8,      24,     8,      24,     32,  4,       2,       128,   64},
126};
127const FX_MEMCONFIG*	FixedMgr_GetConfig(size_t nSize)
128{
129    int index = 5;
130    if (nSize <= FIXEDMEM_PROXYSIZE_0) {
131        index = 0;
132    } else if (nSize <= FIXEDMEM_PROXYSIZE_1) {
133        index = 1;
134    } else if (nSize <= FIXEDMEM_PROXYSIZE_2) {
135        index = 2;
136    } else if (nSize <= FIXEDMEM_PROXYSIZE_3) {
137        index = 3;
138    } else if (nSize <= FIXEDMEM_PROXYSIZE_4) {
139        index = 4;
140    }
141    return &g_ProxyMgr_MemConfigs[index];
142}
143FXMEM_FoxitMgr* CFixedMgr_Proxy::Initialize(FX_LPVOID pBuffer, size_t nSize, FX_BOOL bExtensible)
144{
145    FXSYS_assert(pBuffer != NULL && nSize >= FIXEDMEM_PROXYSIZE_1 - sizeof(CFixedMgr_Proxy));
146    FXMEM_SetConfig(FixedMgr_GetConfig(nSize));
147    m_SystemMgr.More = &CFixedMgr_Proxy::Common_More;
148    m_SystemMgr.Free = &CFixedMgr_Proxy::Common_Free;
149    m_pFixedPage = (CFXMEM_Page*)((FX_LPBYTE)pBuffer + FIXEDMEM_PROXYSIZE_0);
150    m_pFixedPage->Initialize(nSize - FIXEDMEM_PROXYSIZE_0);
151    m_pBuffer = pBuffer;
152    m_nSize = nSize;
153    m_bExtensible = bExtensible;
154    return FXMEM_CreateFixedMgr(pBuffer, FIXEDMEM_PROXYSIZE_0, &m_SystemMgr);
155}
156FX_BOOL CFixedMgr_Proxy::Common_More(FXMEM_SystemMgr2* pMgr, size_t alloc_size, void** new_memory, size_t* new_size)
157{
158    CFixedMgr_Proxy* pProxyMgr = (CFixedMgr_Proxy*)pMgr;
159    FXSYS_assert(pProxyMgr != NULL && pProxyMgr->m_pFixedPage != NULL);
160    *new_size = alloc_size;
161    *new_memory = pProxyMgr->m_pFixedPage->Alloc(alloc_size);
162    if (*new_memory == NULL && pProxyMgr->m_bExtensible) {
163        *new_memory = malloc(alloc_size);
164    }
165    return *new_memory != NULL;
166}
167void CFixedMgr_Proxy::Common_Free(FXMEM_SystemMgr2* pMgr, void* memory)
168{
169    CFixedMgr_Proxy* pProxyMgr = (CFixedMgr_Proxy*)pMgr;
170    FXSYS_assert(pProxyMgr != NULL && pProxyMgr->m_pFixedPage != NULL);
171    if (memory > pProxyMgr->m_pBuffer && memory < (FX_LPBYTE)pProxyMgr->m_pBuffer + pProxyMgr->m_nSize) {
172        pProxyMgr->m_pFixedPage->Free(memory);
173    } else if (pProxyMgr->m_bExtensible) {
174        free(memory);
175    }
176}
177void CFXMEM_Page::Initialize(size_t size)
178{
179    CFXMEM_Block *pFirstBlock = (CFXMEM_Block*)(this + 1);
180    m_nAvailSize = size - sizeof(CFXMEM_Page) - sizeof(CFXMEM_Block);
181    pFirstBlock->m_nBlockSize = m_nAvailSize;
182    pFirstBlock->m_pNextBlock = NULL;
183    m_AvailHead.m_nBlockSize = m_nAvailSize;
184    m_AvailHead.m_pNextBlock = pFirstBlock;
185    m_pLimitPos = (CFXMEM_Block*)((FX_LPBYTE)this + size);
186}
187FX_LPVOID CFXMEM_Page::Alloc(CFXMEM_Block* pPrevBlock, CFXMEM_Block* pNextBlock, size_t size, size_t oldsize)
188{
189    size_t gap = pNextBlock->m_nBlockSize - size;
190    if (gap <= 64 + sizeof(CFXMEM_Block)) {
191        pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
192        m_nAvailSize -= pNextBlock->m_nBlockSize;
193    } else {
194        m_nAvailSize -= size + sizeof(CFXMEM_Block);
195        pNextBlock->m_nBlockSize = size;
196        CFXMEM_Block *pNewBlock = (CFXMEM_Block*)((FX_LPBYTE)(pNextBlock + 1) + size);
197        pNewBlock->m_nBlockSize = gap - sizeof(CFXMEM_Block);
198        pNewBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
199        pPrevBlock->m_pNextBlock = pNewBlock;
200    }
201    return (FX_LPVOID)(pNextBlock + 1);
202}
203FX_LPVOID CFXMEM_Page::Alloc(size_t size)
204{
205    size_t oldsize = size;
206#if _FX_WORDSIZE_ == _FX_W64_
207    size = (size + 31) / 32 * 32;
208#else
209    size = (size + 7) / 8 * 8;
210#endif
211    if (m_nAvailSize < size) {
212        return NULL;
213    }
214    CFXMEM_Block *pNextBlock;
215    CFXMEM_Block *pPrevBlock = &m_AvailHead;
216    while (TRUE) {
217        pNextBlock = pPrevBlock->m_pNextBlock;
218        if (!pNextBlock) {
219            return NULL;
220        }
221        if (pNextBlock->m_nBlockSize >= size) {
222            break;
223        }
224        pPrevBlock = pNextBlock;
225    }
226    return Alloc(pPrevBlock, pNextBlock, size, oldsize);
227}
228FX_LPVOID CFXMEM_Page::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)
229{
230    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
231    size_t oldnewSize = newSize;
232#if _FX_WORDSIZE_ == _FX_W64_
233    newSize = (newSize + 31) / 32 * 32;
234#else
235    newSize = (newSize + 7) / 8 * 8;
236#endif
237    CFXMEM_Block *pPrevBlock = &m_AvailHead;
238    CFXMEM_Block *pNextBlock, *pPrevPrev;
239    CFXMEM_Block *pBlock = (CFXMEM_Block*)p - 1;
240    pPrevPrev = NULL;
241    while (TRUE) {
242        pNextBlock = pPrevBlock->m_pNextBlock;
243        if (pNextBlock == NULL || pNextBlock > pBlock) {
244            break;
245        }
246        if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
247            m_nAvailSize += sizeof(CFXMEM_Block);
248            pPrevBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
249            pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
250        } else {
251            pPrevPrev = pPrevBlock;
252            pPrevBlock = pNextBlock;
253        }
254    }
255    if (pNextBlock) {
256        CFXMEM_Block* pCurBlock = pNextBlock->m_pNextBlock;
257        while ((FX_LPBYTE)pCurBlock == (FX_LPBYTE)(pNextBlock + 1) + pNextBlock->m_nBlockSize) {
258            m_nAvailSize += sizeof(CFXMEM_Block);
259            pNextBlock->m_nBlockSize += pCurBlock->m_nBlockSize + sizeof(CFXMEM_Block);
260            pCurBlock = pCurBlock->m_pNextBlock;
261            pNextBlock->m_pNextBlock = pCurBlock;
262        }
263    }
264    size_t size = 0;
265    FX_DWORD dwFlags = 0;
266    if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
267        size += pPrevBlock->m_nBlockSize + oldSize + sizeof(CFXMEM_Block);
268        dwFlags |= 0x10;
269    }
270    if (pNextBlock && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)p + oldSize) {
271        size += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
272        dwFlags |= 0x01;
273    }
274    if (size >= newSize) {
275        m_nAvailSize += pBlock->m_nBlockSize;
276        CFXMEM_Block* pCurBlock = pBlock;
277        if (dwFlags & 0x10) {
278            pCurBlock = pPrevBlock;
279            m_nAvailSize += sizeof(CFXMEM_Block);
280            pCurBlock->m_nBlockSize += pBlock->m_nBlockSize + sizeof(CFXMEM_Block);
281            pPrevBlock = pPrevPrev;
282        }
283        if (dwFlags & 0x01) {
284            m_nAvailSize += sizeof(CFXMEM_Block);
285            pCurBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
286            pCurBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
287        }
288        if (pCurBlock != pBlock) {
289            FXSYS_memmove32((FX_LPVOID)(pCurBlock + 1), p, oldSize);
290        }
291        return Alloc(pPrevBlock, pCurBlock, newSize, oldnewSize);
292    }
293    return NULL;
294}
295void CFXMEM_Page::Free(FX_LPVOID p)
296{
297    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
298    CFXMEM_Block *pPrevBlock = &m_AvailHead;
299    CFXMEM_Block *pNextBlock;
300    CFXMEM_Block *pBlock = (CFXMEM_Block*)p - 1;
301    m_nAvailSize += pBlock->m_nBlockSize;
302    while (TRUE) {
303        pNextBlock = pPrevBlock->m_pNextBlock;
304        if (pNextBlock == NULL || pNextBlock > pBlock) {
305            break;
306        }
307        if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
308            m_nAvailSize += sizeof(CFXMEM_Block);
309            pPrevBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
310            pPrevBlock->m_pNextBlock = pNextBlock->m_pNextBlock;
311        } else {
312            pPrevBlock = pNextBlock;
313        }
314    }
315    while ((FX_LPBYTE)pNextBlock == (FX_LPBYTE)(pBlock + 1) + pBlock->m_nBlockSize) {
316        m_nAvailSize += sizeof(CFXMEM_Block);
317        pBlock->m_nBlockSize += pNextBlock->m_nBlockSize + sizeof(CFXMEM_Block);
318        pNextBlock = pNextBlock->m_pNextBlock;
319    }
320    pBlock->m_pNextBlock = pNextBlock;
321    if (pPrevBlock != &m_AvailHead && (FX_LPBYTE)pBlock == (FX_LPBYTE)(pPrevBlock + 1) + pPrevBlock->m_nBlockSize) {
322        m_nAvailSize += sizeof(CFXMEM_Block);
323        pPrevBlock->m_nBlockSize += pBlock->m_nBlockSize + sizeof(CFXMEM_Block);
324        pPrevBlock->m_pNextBlock = pBlock->m_pNextBlock;
325    } else {
326        FXSYS_assert(pPrevBlock != pBlock);
327        pPrevBlock->m_pNextBlock = pBlock;
328    }
329}
330void CFXMEM_Pages::Initialize(FX_LPBYTE pStart, size_t pageSize, size_t pages)
331{
332    m_pStartPage = m_pCurPage = (CFXMEM_Page*)pStart;
333    m_nPageSize = pageSize;
334    for (size_t n = 0; n < pages; n++) {
335        ((CFXMEM_Page*)pStart)->Initialize(pageSize);
336        pStart += pageSize;
337    }
338    m_pLimitPos = (CFXMEM_Page*)pStart;
339}
340FX_BOOL CFXMEM_Pages::IsEmpty() const
341{
342    if (m_pStartPage >= m_pLimitPos) {
343        return TRUE;
344    }
345    FX_LPBYTE pPage = (FX_LPBYTE)m_pStartPage;
346    while (pPage < (FX_LPBYTE)m_pLimitPos) {
347        if (!((CFXMEM_Page*)pPage)->IsEmpty()) {
348            return FALSE;
349        }
350        pPage += m_nPageSize;
351    }
352    return TRUE;
353}
354FX_LPVOID CFXMEM_Pages::Alloc(size_t size)
355{
356    CFXMEM_Page *pCurPage = m_pCurPage;
357    do {
358        FX_LPVOID p = m_pCurPage->Alloc(size);
359        if (p) {
360            return p;
361        }
362        m_pCurPage = (CFXMEM_Page*)((FX_LPBYTE)m_pCurPage + m_nPageSize);
363        if (m_pCurPage == m_pLimitPos) {
364            m_pCurPage = m_pStartPage;
365        }
366    } while (m_pCurPage != pCurPage);
367    return NULL;
368}
369FX_LPVOID CFXMEM_Pages::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)
370{
371    FXSYS_assert (p > (FX_LPVOID)m_pStartPage && p < (FX_LPVOID)m_pLimitPos);
372    CFXMEM_Page* pPage = (CFXMEM_Page*)((FX_LPBYTE)m_pStartPage + ((FX_LPBYTE)p - (FX_LPBYTE)m_pStartPage) / m_nPageSize * m_nPageSize);
373    return pPage->Realloc(p, oldSize, newSize);
374}
375void CFXMEM_Pages::Free(FX_LPVOID p)
376{
377    FXSYS_assert (p > (FX_LPVOID)m_pStartPage && p < (FX_LPVOID)m_pLimitPos);
378    CFXMEM_Page* pPage = (CFXMEM_Page*)((FX_LPBYTE)m_pStartPage + ((FX_LPBYTE)p - (FX_LPBYTE)m_pStartPage) / m_nPageSize * m_nPageSize);
379    pPage->Free(p);
380}
381void CFXMEM_Pool::Initialize(const FX_MEMCONFIG* pMemConfig, size_t size, size_t pageNum8Bytes, size_t pageNum16Bytes, size_t pageNum32Bytes, size_t pageNumMid)
382{
383    m_pPrevPool = NULL;
384    m_pNextPool = NULL;
385    m_bAlone = FALSE;
386    FX_LPBYTE pPage = (FX_LPBYTE)this + sizeof(CFXMEM_Pool);
387    size -= sizeof(CFXMEM_Pool);
388    m_8BytesPages.Initialize(pPage, pageNum8Bytes);
389    pPage += pageNum8Bytes * FX_FIXEDMEM_PAGESIZE;
390    size -= pageNum8Bytes * FX_FIXEDMEM_PAGESIZE;
391    m_16BytesPages.Initialize(pPage, pageNum16Bytes);
392    pPage += pageNum16Bytes * FX_FIXEDMEM_PAGESIZE;
393    size -= pageNum16Bytes * FX_FIXEDMEM_PAGESIZE;
394    m_32BytesPages.Initialize(pPage, pageNum32Bytes);
395    pPage += pageNum32Bytes * FX_FIXEDMEM_PAGESIZE;
396    size -= pageNum32Bytes * FX_FIXEDMEM_PAGESIZE;
397    m_MidPages.Initialize(pPage, pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE, pageNumMid);
398    pPage += pageNumMid * pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE;
399    size -= pageNumMid * pMemConfig->nPageSize_Mid * FX_FIXEDMEM_PAGESIZE;
400    if (size < FX_FIXEDMEM_MIDBLOCKSIZE) {
401        m_pLargePage = NULL;
402    } else {
403        m_pLargePage = (CFXMEM_Page*)pPage;
404        m_pLargePage->Initialize(size);
405    }
406    m_pLimitPos = pPage + size;
407}
408FX_BOOL CFXMEM_Pool::IsEmpty() const
409{
410    if (!m_8BytesPages.IsEmpty()) {
411        return FALSE;
412    }
413    if (!m_16BytesPages.IsEmpty()) {
414        return FALSE;
415    }
416    if (!m_32BytesPages.IsEmpty()) {
417        return FALSE;
418    }
419    if (!m_MidPages.IsEmpty()) {
420        return FALSE;
421    }
422    return !m_pLargePage || m_pLargePage->IsEmpty();
423}
424size_t CFXMEM_Pool::GetSize(FX_LPVOID p) const
425{
426    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
427    if (p < (FX_LPVOID)m_8BytesPages.m_pLimitPos) {
428        return 8;
429    }
430    if (p < (FX_LPVOID)m_16BytesPages.m_pLimitPos) {
431        return 16;
432    }
433    if (p < (FX_LPVOID)m_32BytesPages.m_pLimitPos) {
434        return 32;
435    }
436    return ((CFXMEM_Block*)p - 1)->m_nBlockSize;
437}
438FX_LPVOID CFXMEM_Pool::Realloc(FX_LPVOID p, size_t oldSize, size_t newSize)
439{
440    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
441    if (p > (FX_LPVOID)m_32BytesPages.m_pLimitPos) {
442        if (p < (FX_LPVOID)m_MidPages.m_pLimitPos) {
443            return m_MidPages.Realloc(p, oldSize, newSize);
444        } else if (m_pLargePage) {
445            return m_pLargePage->Realloc(p, oldSize, newSize);
446        }
447    }
448    return NULL;
449}
450void CFXMEM_Pool::Free(FX_LPVOID p)
451{
452    FXSYS_assert(p > (FX_LPVOID)this && p < (FX_LPVOID)m_pLimitPos);
453    if (p < (FX_LPVOID)m_32BytesPages.m_pLimitPos) {
454        if (p < (FX_LPVOID)m_8BytesPages.m_pLimitPos) {
455            m_8BytesPages.Free(p);
456        } else if (p < (FX_LPVOID)m_16BytesPages.m_pLimitPos) {
457            m_16BytesPages.Free(p);
458        } else {
459            m_32BytesPages.Free(p);
460        }
461        return;
462    } else if (p < (FX_LPVOID)m_MidPages.m_pLimitPos) {
463        m_MidPages.Free(p);
464    } else {
465        m_pLargePage->Free(p);
466    }
467}
468void CFXMEM_FixedMgr::Initialize(size_t size)
469{
470    m_MemConfig = g_MemConfig;
471    FXSYS_memset32(&m_SystemMgr, 0, sizeof m_SystemMgr);
472    m_SystemMgr.Alloc = FixedAlloc;
473    m_SystemMgr.AllocDebug = FixedAllocDebug;
474    m_SystemMgr.Free = FixedFree;
475    m_SystemMgr.Realloc = FixedRealloc;
476    m_SystemMgr.ReallocDebug = FixedReallocDebug;
477    m_SystemMgr.CollectAll = FixedCollectAll;
478    m_SystemMgr.Purge = FixedPurge;
479    m_SystemMgr.user = this;
480    size -= sizeof(CFXMEM_FixedMgr);
481    size_t nMidPages = 0;
482    if (m_MemConfig.nPageSize_Mid) {
483        nMidPages = (size - (m_MemConfig.nPageNum_Init8 + m_MemConfig.nPageNum_Init16 + m_MemConfig.nPageNum_Init32) * FX_FIXEDMEM_PAGESIZE) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);
484        if (nMidPages > m_MemConfig.nPageNum_InitMid) {
485            nMidPages = m_MemConfig.nPageNum_InitMid;
486        }
487    }
488    m_FirstPool.Initialize(&m_MemConfig, size, m_MemConfig.nPageNum_Init8, m_MemConfig.nPageNum_Init16, m_MemConfig.nPageNum_Init32, nMidPages);
489}
490FX_LPVOID CFXMEM_FixedMgr::Alloc16(CFXMEM_Pool **pp32Pool, size_t size)
491{
492    CFXMEM_Pool *pPool = &m_FirstPool;
493    do {
494        CFXMEM_16BytesPages &pages = pPool->m_16BytesPages;
495        if (pages.HasFreeBlock()) {
496            return pages.Alloc(size);
497        }
498        if (pp32Pool && pPool->m_32BytesPages.HasFreeBlock()) {
499            *pp32Pool = pPool;
500        }
501        pPool = pPool->m_pNextPool;
502    } while(pPool);
503    return NULL;
504}
505FX_LPVOID CFXMEM_FixedMgr::Alloc32(size_t size)
506{
507    if (size <= 8) {
508        CFXMEM_8BytesPages &pages = m_FirstPool.m_8BytesPages;
509        if (pages.HasFreeBlock()) {
510            return pages.Alloc(size);
511        }
512    }
513    CFXMEM_Pool *p32BytesPool;
514    if (size <= 16) {
515        p32BytesPool = NULL;
516        FX_LPVOID p = Alloc16(&p32BytesPool, size);
517        if (p) {
518            return p;
519        }
520    } else {
521        p32BytesPool = &m_FirstPool;
522    }
523    while (p32BytesPool) {
524        CFXMEM_32BytesPages &pages = p32BytesPool->m_32BytesPages;
525        if (pages.HasFreeBlock()) {
526            return pages.Alloc(size);
527        }
528        p32BytesPool = p32BytesPool->m_pNextPool;
529    }
530    return NULL;
531}
532FX_LPVOID CFXMEM_FixedMgr::AllocSmall(size_t size)
533{
534    FX_LPVOID p = Alloc32(size);
535    if (p) {
536        return p;
537    }
538    if (!m_pExtender) {
539        return NULL;
540    }
541    size_t requiredSize = (m_MemConfig.nPageNum_More16 + m_MemConfig.nPageNum_More32) * FX_FIXEDMEM_PAGESIZE;
542    if (!requiredSize) {
543        return NULL;
544    }
545    CFXMEM_Pool *pNewPool = NULL;
546    requiredSize += sizeof(CFXMEM_Pool);
547    size_t newSize = requiredSize;
548    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {
549        return NULL;
550    }
551    size_t nMidPages = 0;
552    if (m_MemConfig.nPageSize_Mid) {
553        nMidPages = (newSize - requiredSize) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);
554        if (nMidPages > m_MemConfig.nPageNum_MoreMid) {
555            nMidPages = m_MemConfig.nPageNum_MoreMid;
556        }
557    }
558    pNewPool->Initialize(&m_MemConfig, newSize, 0, m_MemConfig.nPageNum_More16, m_MemConfig.nPageNum_More32, nMidPages);
559    pNewPool->m_pPrevPool = &m_FirstPool;
560    CFXMEM_Pool *pPool = m_FirstPool.m_pNextPool;
561    pNewPool->m_pNextPool = pPool;
562    if (pPool) {
563        pPool->m_pPrevPool = pNewPool;
564    }
565    m_FirstPool.m_pNextPool = pNewPool;
566    return Alloc32(size);
567}
568FX_LPVOID CFXMEM_FixedMgr::AllocMid(size_t size)
569{
570    CFXMEM_Pool *pPool = &m_FirstPool;
571    do {
572        CFXMEM_Pages &pages = pPool->m_MidPages;
573        if (pages.m_pLimitPos > pages.m_pStartPage) {
574            FX_LPVOID p = pages.Alloc(size);
575            if (p) {
576                return p;
577            }
578        }
579        pPool = pPool->m_pNextPool;
580    } while(pPool);
581    if (!m_pExtender) {
582        return NULL;
583    }
584    size_t newSize = m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE * m_MemConfig.nPageNum_MoreMid;
585    if (!newSize) {
586        return NULL;
587    }
588    CFXMEM_Pool *pNewPool = NULL;
589    newSize += sizeof(CFXMEM_Pool);
590    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {
591        return NULL;
592    }
593    size_t nMidPages = (newSize - sizeof(CFXMEM_Pool)) / (m_MemConfig.nPageSize_Mid * FX_FIXEDMEM_PAGESIZE);
594    if (nMidPages > m_MemConfig.nPageNum_MoreMid) {
595        nMidPages = m_MemConfig.nPageNum_MoreMid;
596    }
597    pNewPool->Initialize(&m_MemConfig, newSize, 0, 0, 0, nMidPages);
598    pNewPool->m_pPrevPool = &m_FirstPool;
599    pPool = m_FirstPool.m_pNextPool;
600    pNewPool->m_pNextPool = pPool;
601    if (pPool) {
602        pPool->m_pPrevPool = pNewPool;
603    }
604    m_FirstPool.m_pNextPool = pNewPool;
605    return pNewPool->m_MidPages.Alloc(size);
606}
607FX_LPVOID CFXMEM_FixedMgr::AllocLarge(size_t size)
608{
609    CFXMEM_Pool *pPool = &m_FirstPool;
610    do {
611        if (!pPool->m_bAlone && pPool->m_pLargePage) {
612            FX_LPVOID p = pPool->m_pLargePage->Alloc(size);
613            if (p) {
614                return p;
615            }
616        }
617        pPool = pPool->m_pNextPool;
618    } while(pPool);
619    if (!m_pExtender || !m_MemConfig.nPageSize_Large) {
620        return NULL;
621    }
622    CFXMEM_Pool *pNewPool = NULL;
623#if _FX_WORDSIZE_ == _FX_W64_
624    size_t newSize = ((size + 31) / 32 * 32 + sizeof(CFXMEM_Pool) + sizeof(CFXMEM_Page) + sizeof(CFXMEM_Block) + 4095) / 4096 * 4096;
625#else
626    size_t newSize = (size + 7) / 8 * 8 + sizeof(CFXMEM_Pool) + sizeof(CFXMEM_Page) + sizeof(CFXMEM_Block);
627#endif
628    if (newSize < m_MemConfig.nPageSize_Large * FX_FIXEDMEM_PAGESIZE) {
629        newSize = m_MemConfig.nPageSize_Large * FX_FIXEDMEM_PAGESIZE;
630    }
631    if (!m_pExtender->More(m_pExtender, newSize, (void**)&pNewPool, &newSize)) {
632        return NULL;
633    }
634    pNewPool->Initialize(&m_MemConfig, newSize, 0, 0, 0, 0);
635    pNewPool->m_bAlone = size >= m_MemConfig.nPageSize_Alone * FX_FIXEDMEM_PAGESIZE;
636    pNewPool->m_pPrevPool = &m_FirstPool;
637    pPool = m_FirstPool.m_pNextPool;
638    pNewPool->m_pNextPool = pPool;
639    if (pPool) {
640        pPool->m_pPrevPool = pNewPool;
641    }
642    m_FirstPool.m_pNextPool = pNewPool;
643    return pNewPool->m_pLargePage->Alloc(size);
644}
645size_t CFXMEM_FixedMgr::GetSize(FX_LPVOID p) const
646{
647    const CFXMEM_Pool *pFind = &m_FirstPool;
648    do {
649        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {
650            return pFind->GetSize(p);
651        }
652        pFind = pFind->m_pNextPool;
653    } while (pFind);
654    return 0;
655}
656FX_LPVOID CFXMEM_FixedMgr::Alloc(size_t size)
657{
658    FX_LPVOID p;
659    if (size <= 32) {
660        p = AllocSmall(size);
661        if (p) {
662            return p;
663        }
664    }
665    if (size <= FX_FIXEDMEM_MIDBLOCKSIZE) {
666        p = AllocMid(size);
667        if (p) {
668            return p;
669        }
670    }
671    p = AllocLarge(size);
672    return p;
673}
674FX_LPVOID CFXMEM_FixedMgr::ReallocSmall(CFXMEM_Pool* pPool, FX_LPVOID p, size_t oldSize, size_t newSize)
675{
676    FX_LPVOID np = AllocSmall(newSize);
677    if (!np) {
678        return NULL;
679    }
680    FXSYS_memcpy32(np, p, oldSize);
681    pPool->Free(p);
682    return np;
683}
684FX_LPVOID CFXMEM_FixedMgr::Realloc(FX_LPVOID p, size_t newSize)
685{
686    if (!p) {
687        return Alloc(newSize);
688    }
689    size_t oldSize = 0;
690    CFXMEM_Pool *pFind = &m_FirstPool;
691    do {
692        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {
693            oldSize = pFind->GetSize(p);
694            if (oldSize >= newSize) {
695                return p;
696            }
697            break;
698        }
699        pFind = pFind->m_pNextPool;
700    } while (pFind);
701    if (!oldSize || !pFind) {
702        return Alloc(newSize);
703    }
704    FX_LPVOID np = NULL;
705    if (newSize <= 32) {
706        np = ReallocSmall(pFind, p, oldSize, newSize);
707        if (np) {
708            return np;
709        }
710    }
711    if (newSize <= FX_FIXEDMEM_MIDBLOCKSIZE) {
712        np = pFind->Realloc(p, oldSize, newSize);
713        if (np) {
714            return np;
715        }
716    }
717    np = Alloc(newSize);
718    if (np) {
719        FXSYS_memcpy32(np, p, oldSize);
720        pFind->Free(p);
721    }
722    if (pFind->m_bAlone && pFind->IsEmpty()) {
723        FreePool(pFind);
724    }
725    return np;
726}
727void CFXMEM_FixedMgr::Free(FX_LPVOID p)
728{
729    CFXMEM_Pool *pFind = &m_FirstPool;
730    do {
731        if (p > (FX_LPVOID)pFind && p < pFind->m_pLimitPos) {
732            pFind->Free(p);
733            if (pFind->m_bAlone && pFind->IsEmpty()) {
734                FreePool(pFind);
735            }
736            return;
737        }
738        pFind = pFind->m_pNextPool;
739    } while (pFind);
740}
741void CFXMEM_FixedMgr::FreePool(CFXMEM_Pool* pPool)
742{
743    FXSYS_assert(pPool->m_bAlone && pPool->IsEmpty());
744    FXSYS_assert(m_pExtender != NULL);
745    CFXMEM_Pool* pPrevPool = pPool->m_pPrevPool;
746    CFXMEM_Pool* pNextPool = pPool->m_pNextPool;
747    if (pPrevPool) {
748        pPrevPool->m_pNextPool = pNextPool;
749    }
750    if (pNextPool) {
751        pNextPool->m_pPrevPool = pPrevPool;
752    }
753    m_pExtender->Free(m_pExtender, pPool);
754}
755void CFXMEM_FixedMgr::FreeAll()
756{
757    if (!m_pExtender) {
758        return;
759    }
760    CFXMEM_Pool* pPool = m_FirstPool.m_pNextPool;
761    while (pPool) {
762        CFXMEM_Pool* pPrevPool = pPool;
763        pPool = pPool->m_pNextPool;
764        m_pExtender->Free(m_pExtender, pPrevPool);
765    }
766    m_FirstPool.m_pNextPool = NULL;
767}
768void CFXMEM_FixedMgr::Purge()
769{
770    if (!m_pExtender) {
771        return;
772    }
773    CFXMEM_Pool* pPool = m_FirstPool.m_pNextPool;
774    while (pPool) {
775        CFXMEM_Pool* pNextPool = pPool->m_pNextPool;
776        if (pPool->IsEmpty()) {
777            CFXMEM_Pool* pPrevPool = pPool->m_pPrevPool;
778            pPrevPool->m_pNextPool = pNextPool;
779            if (pNextPool) {
780                pNextPool->m_pPrevPool = pPrevPool;
781            }
782            m_pExtender->Free(m_pExtender, pPool);
783        }
784        pPool = pNextPool;
785    }
786}
787extern const FX_BYTE OneLeadPos[256] = {
788    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
789    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
790    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
791    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
792    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
793    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
794    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
795    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
796    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
797    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
798    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
799    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
800    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
801    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
802    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
803    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
804};
805extern const FX_BYTE ZeroLeadPos[256] = {
806    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
807    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
808    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
809    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
810    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
811    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
812    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
813    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
814    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
815    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
816    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
817    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
818    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
819    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
820    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
821    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
822};
823