OLD | NEW |
| (Empty) |
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 "xfa/src/fgas/crt/fgas_memory.h" | |
8 | |
9 #include <algorithm> | |
10 | |
11 namespace { | |
12 | |
13 class CFX_DefStore : public IFX_MEMAllocator, public CFX_Target { | |
14 public: | |
15 CFX_DefStore() {} | |
16 ~CFX_DefStore() {} | |
17 virtual void Release() { delete this; } | |
18 virtual void* Alloc(size_t size) { return FX_Alloc(uint8_t, size); } | |
19 virtual void Free(void* pBlock) { FX_Free(pBlock); } | |
20 virtual size_t GetBlockSize() const { return 0; } | |
21 virtual size_t GetDefChunkSize() const { return 0; } | |
22 virtual size_t SetDefChunkSize(size_t size) { return 0; } | |
23 virtual size_t GetCurrentDataSize() const { return 0; } | |
24 }; | |
25 | |
26 #if _FX_OS_ != _FX_ANDROID_ | |
27 #pragma pack(push, 1) | |
28 #endif | |
29 struct FX_STATICSTORECHUNK { | |
30 FX_STATICSTORECHUNK* pNextChunk; | |
31 size_t iChunkSize; | |
32 size_t iFreeSize; | |
33 }; | |
34 #if _FX_OS_ != _FX_ANDROID_ | |
35 #pragma pack(pop) | |
36 #endif | |
37 | |
38 class CFX_StaticStore : public IFX_MEMAllocator, public CFX_Target { | |
39 public: | |
40 CFX_StaticStore(size_t iDefChunkSize = 4096); | |
41 ~CFX_StaticStore(); | |
42 virtual void Release() { delete this; } | |
43 virtual void* Alloc(size_t size); | |
44 virtual void Free(void* pBlock) {} | |
45 virtual size_t GetBlockSize() const { return 0; } | |
46 virtual size_t GetDefChunkSize() const { return m_iDefChunkSize; } | |
47 virtual size_t SetDefChunkSize(size_t size); | |
48 virtual size_t GetCurrentDataSize() const { return m_iAllocatedSize; } | |
49 | |
50 protected: | |
51 size_t m_iAllocatedSize; | |
52 size_t m_iDefChunkSize; | |
53 FX_STATICSTORECHUNK* m_pChunk; | |
54 FX_STATICSTORECHUNK* m_pLastChunk; | |
55 FX_STATICSTORECHUNK* AllocChunk(size_t size); | |
56 FX_STATICSTORECHUNK* FindChunk(size_t size); | |
57 }; | |
58 | |
59 #if _FX_OS_ != _FX_ANDROID_ | |
60 #pragma pack(push, 1) | |
61 #endif | |
62 struct FX_FIXEDSTORECHUNK { | |
63 uint8_t* FirstFlag() { return reinterpret_cast<uint8_t*>(this + 1); } | |
64 uint8_t* FirstBlock() { return FirstFlag() + iChunkSize; } | |
65 | |
66 FX_FIXEDSTORECHUNK* pNextChunk; | |
67 size_t iChunkSize; | |
68 size_t iFreeNum; | |
69 }; | |
70 #if _FX_OS_ != _FX_ANDROID_ | |
71 #pragma pack(pop) | |
72 #endif | |
73 | |
74 class CFX_FixedStore : public IFX_MEMAllocator, public CFX_Target { | |
75 public: | |
76 CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk); | |
77 virtual ~CFX_FixedStore(); | |
78 virtual void Release() { delete this; } | |
79 virtual void* Alloc(size_t size); | |
80 virtual void Free(void* pBlock); | |
81 virtual size_t GetBlockSize() const { return m_iBlockSize; } | |
82 virtual size_t GetDefChunkSize() const { return m_iDefChunkSize; } | |
83 virtual size_t SetDefChunkSize(size_t iChunkSize); | |
84 virtual size_t GetCurrentDataSize() const { return 0; } | |
85 | |
86 protected: | |
87 FX_FIXEDSTORECHUNK* AllocChunk(); | |
88 | |
89 size_t m_iBlockSize; | |
90 size_t m_iDefChunkSize; | |
91 FX_FIXEDSTORECHUNK* m_pChunk; | |
92 }; | |
93 | |
94 #if _FX_OS_ != _FX_ANDROID_ | |
95 #pragma pack(push, 1) | |
96 #endif | |
97 struct FX_DYNAMICSTOREBLOCK { | |
98 uint8_t* Data() { return reinterpret_cast<uint8_t*>(this + 1); } | |
99 FX_DYNAMICSTOREBLOCK* NextBlock() { | |
100 return reinterpret_cast<FX_DYNAMICSTOREBLOCK*>(Data() + iBlockSize); | |
101 } | |
102 size_t iBlockSize; | |
103 FX_BOOL bUsed; | |
104 }; | |
105 | |
106 struct FX_DYNAMICSTORECHUNK { | |
107 FX_DYNAMICSTOREBLOCK* FirstBlock() { | |
108 return reinterpret_cast<FX_DYNAMICSTOREBLOCK*>(this + 1); | |
109 } | |
110 FX_DYNAMICSTORECHUNK* pNextChunk; | |
111 size_t iChunkSize; | |
112 size_t iFreeSize; | |
113 }; | |
114 #if _FX_OS_ != _FX_ANDROID_ | |
115 #pragma pack(pop) | |
116 #endif | |
117 | |
118 class CFX_DynamicStore : public IFX_MEMAllocator, public CFX_Target { | |
119 public: | |
120 CFX_DynamicStore(size_t iDefChunkSize = 4096); | |
121 virtual ~CFX_DynamicStore(); | |
122 virtual void Release() { delete this; } | |
123 virtual void* Alloc(size_t size); | |
124 virtual void Free(void* pBlock); | |
125 virtual size_t GetBlockSize() const { return 0; } | |
126 virtual size_t GetDefChunkSize() const { return m_iDefChunkSize; } | |
127 virtual size_t SetDefChunkSize(size_t size); | |
128 virtual size_t GetCurrentDataSize() const { return 0; } | |
129 | |
130 protected: | |
131 FX_DYNAMICSTORECHUNK* AllocChunk(size_t size); | |
132 | |
133 size_t m_iDefChunkSize; | |
134 FX_DYNAMICSTORECHUNK* m_pChunk; | |
135 }; | |
136 | |
137 } // namespace | |
138 | |
139 #define FX_4BYTEALIGN(size) (((size) + 3) / 4 * 4) | |
140 | |
141 IFX_MEMAllocator* FX_CreateAllocator(FX_ALLOCTYPE eType, | |
142 size_t chunkSize, | |
143 size_t blockSize) { | |
144 switch (eType) { | |
145 case FX_ALLOCTYPE_Dynamic: | |
146 return new CFX_DynamicStore(chunkSize); | |
147 case FX_ALLOCTYPE_Default: | |
148 return new CFX_DefStore(); | |
149 case FX_ALLOCTYPE_Static: | |
150 return new CFX_StaticStore(chunkSize); | |
151 case FX_ALLOCTYPE_Fixed: | |
152 return new CFX_FixedStore(blockSize, chunkSize); | |
153 default: | |
154 return NULL; | |
155 } | |
156 } | |
157 CFX_StaticStore::CFX_StaticStore(size_t iDefChunkSize) | |
158 : m_iAllocatedSize(0), | |
159 m_iDefChunkSize(iDefChunkSize), | |
160 m_pChunk(NULL), | |
161 m_pLastChunk(NULL) { | |
162 FXSYS_assert(m_iDefChunkSize != 0); | |
163 } | |
164 CFX_StaticStore::~CFX_StaticStore() { | |
165 FX_STATICSTORECHUNK* pChunk = m_pChunk; | |
166 while (pChunk) { | |
167 FX_STATICSTORECHUNK* pNext = pChunk->pNextChunk; | |
168 FX_Free(pChunk); | |
169 pChunk = pNext; | |
170 } | |
171 } | |
172 FX_STATICSTORECHUNK* CFX_StaticStore::AllocChunk(size_t size) { | |
173 FXSYS_assert(size != 0); | |
174 FX_STATICSTORECHUNK* pChunk = (FX_STATICSTORECHUNK*)FX_Alloc( | |
175 uint8_t, sizeof(FX_STATICSTORECHUNK) + size); | |
176 pChunk->iChunkSize = size; | |
177 pChunk->iFreeSize = size; | |
178 pChunk->pNextChunk = NULL; | |
179 if (m_pLastChunk == NULL) { | |
180 m_pChunk = pChunk; | |
181 } else { | |
182 m_pLastChunk->pNextChunk = pChunk; | |
183 } | |
184 m_pLastChunk = pChunk; | |
185 return pChunk; | |
186 } | |
187 FX_STATICSTORECHUNK* CFX_StaticStore::FindChunk(size_t size) { | |
188 FXSYS_assert(size != 0); | |
189 if (m_pLastChunk == NULL || m_pLastChunk->iFreeSize < size) { | |
190 return AllocChunk(std::max(m_iDefChunkSize, size)); | |
191 } | |
192 return m_pLastChunk; | |
193 } | |
194 void* CFX_StaticStore::Alloc(size_t size) { | |
195 size = FX_4BYTEALIGN(size); | |
196 FXSYS_assert(size != 0); | |
197 FX_STATICSTORECHUNK* pChunk = FindChunk(size); | |
198 FXSYS_assert(pChunk->iFreeSize >= size); | |
199 uint8_t* p = (uint8_t*)pChunk; | |
200 p += sizeof(FX_STATICSTORECHUNK) + pChunk->iChunkSize - pChunk->iFreeSize; | |
201 pChunk->iFreeSize -= size; | |
202 m_iAllocatedSize += size; | |
203 return p; | |
204 } | |
205 size_t CFX_StaticStore::SetDefChunkSize(size_t size) { | |
206 FXSYS_assert(size != 0); | |
207 size_t v = m_iDefChunkSize; | |
208 m_iDefChunkSize = size; | |
209 return v; | |
210 } | |
211 CFX_FixedStore::CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk) | |
212 : m_iBlockSize(FX_4BYTEALIGN(iBlockSize)), | |
213 m_iDefChunkSize(FX_4BYTEALIGN(iBlockNumsInChunk)), | |
214 m_pChunk(NULL) { | |
215 FXSYS_assert(m_iBlockSize != 0 && m_iDefChunkSize != 0); | |
216 } | |
217 CFX_FixedStore::~CFX_FixedStore() { | |
218 FX_FIXEDSTORECHUNK* pChunk = m_pChunk; | |
219 while (pChunk) { | |
220 FX_FIXEDSTORECHUNK* pNext = pChunk->pNextChunk; | |
221 FX_Free(pChunk); | |
222 pChunk = pNext; | |
223 } | |
224 } | |
225 FX_FIXEDSTORECHUNK* CFX_FixedStore::AllocChunk() { | |
226 int32_t iTotalSize = sizeof(FX_FIXEDSTORECHUNK) + m_iDefChunkSize + | |
227 m_iBlockSize * m_iDefChunkSize; | |
228 FX_FIXEDSTORECHUNK* pChunk = | |
229 (FX_FIXEDSTORECHUNK*)FX_Alloc(uint8_t, iTotalSize); | |
230 if (pChunk == NULL) { | |
231 return NULL; | |
232 } | |
233 FXSYS_memset(pChunk->FirstFlag(), 0, m_iDefChunkSize); | |
234 pChunk->pNextChunk = m_pChunk; | |
235 pChunk->iChunkSize = m_iDefChunkSize; | |
236 pChunk->iFreeNum = m_iDefChunkSize; | |
237 m_pChunk = pChunk; | |
238 return pChunk; | |
239 } | |
240 void* CFX_FixedStore::Alloc(size_t size) { | |
241 if (size > m_iBlockSize) { | |
242 return NULL; | |
243 } | |
244 FX_FIXEDSTORECHUNK* pChunk = m_pChunk; | |
245 while (pChunk != NULL) { | |
246 if (pChunk->iFreeNum > 0) { | |
247 break; | |
248 } | |
249 pChunk = pChunk->pNextChunk; | |
250 } | |
251 if (pChunk == NULL) { | |
252 pChunk = AllocChunk(); | |
253 } | |
254 FXSYS_assert(pChunk != NULL); | |
255 uint8_t* pFlags = pChunk->FirstFlag(); | |
256 size_t i = 0; | |
257 for (; i < pChunk->iChunkSize; i++) | |
258 if (pFlags[i] == 0) { | |
259 break; | |
260 } | |
261 FXSYS_assert(i < pChunk->iChunkSize); | |
262 pFlags[i] = 1; | |
263 pChunk->iFreeNum--; | |
264 return pChunk->FirstBlock() + i * m_iBlockSize; | |
265 } | |
266 void CFX_FixedStore::Free(void* pBlock) { | |
267 FXSYS_assert(pBlock != NULL); | |
268 FX_FIXEDSTORECHUNK* pPrior = NULL; | |
269 FX_FIXEDSTORECHUNK* pChunk = m_pChunk; | |
270 uint8_t* pStart = NULL; | |
271 uint8_t* pEnd; | |
272 while (pChunk != NULL) { | |
273 pStart = pChunk->FirstBlock(); | |
274 if (pBlock >= pStart) { | |
275 pEnd = pStart + m_iBlockSize * pChunk->iChunkSize; | |
276 if (pBlock < pEnd) { | |
277 break; | |
278 } | |
279 } | |
280 pPrior = pChunk, pChunk = pChunk->pNextChunk; | |
281 } | |
282 FXSYS_assert(pChunk != NULL); | |
283 size_t iPos = ((uint8_t*)pBlock - pStart) / m_iBlockSize; | |
284 FXSYS_assert(iPos < pChunk->iChunkSize); | |
285 uint8_t* pFlags = pChunk->FirstFlag(); | |
286 if (pFlags[iPos] == 0) { | |
287 return; | |
288 } | |
289 pFlags[iPos] = 0; | |
290 pChunk->iFreeNum++; | |
291 if (pChunk->iFreeNum == pChunk->iChunkSize) { | |
292 if (pPrior == NULL) { | |
293 m_pChunk = pChunk->pNextChunk; | |
294 } else { | |
295 pPrior->pNextChunk = pChunk->pNextChunk; | |
296 } | |
297 FX_Free(pChunk); | |
298 } | |
299 } | |
300 size_t CFX_FixedStore::SetDefChunkSize(size_t iChunkSize) { | |
301 FXSYS_assert(iChunkSize != 0); | |
302 size_t v = m_iDefChunkSize; | |
303 m_iDefChunkSize = FX_4BYTEALIGN(iChunkSize); | |
304 return v; | |
305 } | |
306 CFX_DynamicStore::CFX_DynamicStore(size_t iDefChunkSize) | |
307 : m_iDefChunkSize(iDefChunkSize), m_pChunk(NULL) { | |
308 FXSYS_assert(m_iDefChunkSize != 0); | |
309 } | |
310 CFX_DynamicStore::~CFX_DynamicStore() { | |
311 FX_DYNAMICSTORECHUNK* pChunk = m_pChunk; | |
312 while (pChunk) { | |
313 FX_DYNAMICSTORECHUNK* pNext = pChunk->pNextChunk; | |
314 FX_Free(pChunk); | |
315 pChunk = pNext; | |
316 } | |
317 } | |
318 FX_DYNAMICSTORECHUNK* CFX_DynamicStore::AllocChunk(size_t size) { | |
319 FXSYS_assert(size != 0); | |
320 FX_DYNAMICSTORECHUNK* pChunk = (FX_DYNAMICSTORECHUNK*)FX_Alloc( | |
321 uint8_t, | |
322 sizeof(FX_DYNAMICSTORECHUNK) + sizeof(FX_DYNAMICSTOREBLOCK) * 2 + size); | |
323 if (pChunk == NULL) { | |
324 return NULL; | |
325 } | |
326 pChunk->iChunkSize = size; | |
327 pChunk->iFreeSize = size; | |
328 FX_DYNAMICSTOREBLOCK* pBlock = pChunk->FirstBlock(); | |
329 pBlock->iBlockSize = size; | |
330 pBlock->bUsed = FALSE; | |
331 pBlock = pBlock->NextBlock(); | |
332 pBlock->iBlockSize = 0; | |
333 pBlock->bUsed = TRUE; | |
334 if (m_pChunk != NULL && size >= m_iDefChunkSize) { | |
335 FX_DYNAMICSTORECHUNK* pLast = m_pChunk; | |
336 while (pLast->pNextChunk != NULL) { | |
337 pLast = pLast->pNextChunk; | |
338 } | |
339 pLast->pNextChunk = pChunk; | |
340 pChunk->pNextChunk = NULL; | |
341 } else { | |
342 pChunk->pNextChunk = m_pChunk; | |
343 m_pChunk = pChunk; | |
344 } | |
345 return pChunk; | |
346 } | |
347 void* CFX_DynamicStore::Alloc(size_t size) { | |
348 size = FX_4BYTEALIGN(size); | |
349 FXSYS_assert(size != 0); | |
350 FX_DYNAMICSTORECHUNK* pChunk = m_pChunk; | |
351 FX_DYNAMICSTOREBLOCK* pBlock = NULL; | |
352 while (pChunk != NULL) { | |
353 if (pChunk->iFreeSize >= size) { | |
354 pBlock = pChunk->FirstBlock(); | |
355 FX_BOOL bFind = FALSE; | |
356 while (pBlock->iBlockSize != 0) { | |
357 if (!pBlock->bUsed && pBlock->iBlockSize >= size) { | |
358 bFind = TRUE; | |
359 break; | |
360 } | |
361 pBlock = pBlock->NextBlock(); | |
362 } | |
363 if (bFind) { | |
364 break; | |
365 } | |
366 } | |
367 pChunk = pChunk->pNextChunk; | |
368 } | |
369 if (pChunk == NULL) { | |
370 pChunk = AllocChunk(std::max(m_iDefChunkSize, size)); | |
371 pBlock = pChunk->FirstBlock(); | |
372 } | |
373 FXSYS_assert(pChunk != NULL && pBlock != NULL); | |
374 size_t m = size + sizeof(FX_DYNAMICSTOREBLOCK); | |
375 pBlock->bUsed = TRUE; | |
376 if (pBlock->iBlockSize > m) { | |
377 size_t n = pBlock->iBlockSize; | |
378 pBlock->iBlockSize = size; | |
379 FX_DYNAMICSTOREBLOCK* pNextBlock = pBlock->NextBlock(); | |
380 pNextBlock->bUsed = FALSE; | |
381 pNextBlock->iBlockSize = n - size - sizeof(FX_DYNAMICSTOREBLOCK); | |
382 pChunk->iFreeSize -= size + sizeof(FX_DYNAMICSTOREBLOCK); | |
383 } else { | |
384 pChunk->iFreeSize -= pBlock->iBlockSize; | |
385 } | |
386 return pBlock->Data(); | |
387 } | |
388 void CFX_DynamicStore::Free(void* pBlock) { | |
389 FXSYS_assert(pBlock != NULL); | |
390 FX_DYNAMICSTORECHUNK* pPriorChunk = NULL; | |
391 FX_DYNAMICSTORECHUNK* pChunk = m_pChunk; | |
392 while (pChunk != NULL) { | |
393 if (pBlock > pChunk && | |
394 pBlock <= ((uint8_t*)pChunk + sizeof(FX_DYNAMICSTORECHUNK) + | |
395 pChunk->iChunkSize)) { | |
396 break; | |
397 } | |
398 pPriorChunk = pChunk, pChunk = pChunk->pNextChunk; | |
399 } | |
400 FXSYS_assert(pChunk != NULL); | |
401 FX_DYNAMICSTOREBLOCK* pPriorBlock = NULL; | |
402 FX_DYNAMICSTOREBLOCK* pFindBlock = pChunk->FirstBlock(); | |
403 while (pFindBlock->iBlockSize != 0) { | |
404 if (pBlock == (void*)pFindBlock->Data()) { | |
405 break; | |
406 } | |
407 pPriorBlock = pFindBlock; | |
408 pFindBlock = pFindBlock->NextBlock(); | |
409 } | |
410 FXSYS_assert(pFindBlock->iBlockSize != 0 && pFindBlock->bUsed && | |
411 pBlock == (void*)pFindBlock->Data()); | |
412 pFindBlock->bUsed = FALSE; | |
413 pChunk->iFreeSize += pFindBlock->iBlockSize; | |
414 if (pPriorBlock == NULL) { | |
415 pPriorBlock = pChunk->FirstBlock(); | |
416 } else if (pPriorBlock->bUsed) { | |
417 pPriorBlock = pFindBlock; | |
418 } | |
419 pFindBlock = pPriorBlock; | |
420 size_t sizeFree = 0; | |
421 size_t sizeBlock = 0; | |
422 while (pFindBlock->iBlockSize != 0 && !pFindBlock->bUsed) { | |
423 if (pFindBlock != pPriorBlock) { | |
424 sizeFree += sizeof(FX_DYNAMICSTOREBLOCK); | |
425 sizeBlock += sizeof(FX_DYNAMICSTOREBLOCK); | |
426 } | |
427 sizeBlock += pFindBlock->iBlockSize; | |
428 pFindBlock = pFindBlock->NextBlock(); | |
429 } | |
430 pPriorBlock->iBlockSize = sizeBlock; | |
431 pChunk->iFreeSize += sizeFree; | |
432 if (pChunk->iFreeSize == pChunk->iChunkSize) { | |
433 if (pPriorChunk == NULL) { | |
434 m_pChunk = pChunk->pNextChunk; | |
435 } else { | |
436 pPriorChunk->pNextChunk = pChunk->pNextChunk; | |
437 } | |
438 FX_Free(pChunk); | |
439 } | |
440 } | |
441 size_t CFX_DynamicStore::SetDefChunkSize(size_t size) { | |
442 FXSYS_assert(size != 0); | |
443 size_t v = m_iDefChunkSize; | |
444 m_iDefChunkSize = size; | |
445 return v; | |
446 } | |
OLD | NEW |