8d48bab9353e7ae373492e7c5fe699348501395d
[pdfium.git] / core / src / fxcrt / fx_basic_memmgr_mini.cpp
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_
10 static 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
23 static 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
36 void FXMEM_SetConfig(const FX_MEMCONFIG* memConfig)
37 {
38     g_MemConfig = *memConfig;
39 }
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 static void* FixedAlloc(FXMEM_SystemMgr* pMgr, size_t size, int flags)
44 {
45     return ((CFXMEM_FixedMgr*)pMgr->user)->Alloc(size);
46 }
47 static 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 }
51 static void* FixedRealloc(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags)
52 {
53     return ((CFXMEM_FixedMgr*)pMgr->user)->Realloc(pointer, size);
54 }
55 static 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 }
59 static void  FixedFree(FXMEM_SystemMgr* pMgr, void* pointer, int flags)
60 {
61     ((CFXMEM_FixedMgr*)pMgr->user)->Free(pointer);
62 }
63 static void  FixedPurge(FXMEM_SystemMgr* pMgr)
64 {
65     ((CFXMEM_FixedMgr*)pMgr->user)->Purge();
66 }
67 static void FixedCollectAll(FXMEM_SystemMgr* pMgr)
68 {
69     ((CFXMEM_FixedMgr*)pMgr->user)->FreeAll();
70 }
71 #define FIXEDMEM_MINIMUMSIZE    (1024 * 1024 * 8)
72 FXMEM_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 }
92 FXMEM_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 }
112 size_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
119 const 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 };
127 const 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 }
143 FXMEM_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 }
156 FX_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 }
167 void 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 }
177 void 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 }
187 FX_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 }
203 FX_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 }
228 FX_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 }
295 void 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 }
330 void 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 }
340 FX_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 }
354 FX_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 }
369 FX_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 }
375 void 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 }
381 void 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 }
408 FX_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 }
424 size_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 }
438 FX_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 }
450 void 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 }
468 void 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 }
490 FX_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 }
505 FX_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 }
532 FX_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 }
568 FX_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 }
607 FX_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 }
645 size_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 }
656 FX_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 }
674 FX_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 }
684 FX_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 }
727 void 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 }
741 void 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 }
755 void 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 }
768 void 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 }
787 extern 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 };
805 extern 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 };