]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/LzmaCompress/Sdk/C/Alloc.c
BaseTools Lzma: Update LZMA SDK version to 18.05
[mirror_edk2.git] / BaseTools / Source / C / LzmaCompress / Sdk / C / Alloc.c
CommitLineData
30fdf114 1/* Alloc.c -- Memory allocation functions\r
5ec5a236 22018-04-27 : Igor Pavlov : Public domain */\r
c4ab09ef
LG
3\r
4#include "Precomp.h"\r
30fdf114 5\r
5ec5a236
LG
6#include <stdio.h>\r
7\r
30fdf114
LG
8#ifdef _WIN32\r
9#include <windows.h>\r
10#endif\r
11#include <stdlib.h>\r
12\r
13#include "Alloc.h"\r
14\r
15/* #define _SZ_ALLOC_DEBUG */\r
16\r
17/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */\r
18#ifdef _SZ_ALLOC_DEBUG\r
5ec5a236 19\r
30fdf114
LG
20#include <stdio.h>\r
21int g_allocCount = 0;\r
22int g_allocCountMid = 0;\r
23int g_allocCountBig = 0;\r
5ec5a236
LG
24\r
25\r
26#define CONVERT_INT_TO_STR(charType, tempSize) \\r
27 unsigned char temp[tempSize]; unsigned i = 0; \\r
28 while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \\r
29 *s++ = (charType)('0' + (unsigned)val); \\r
30 while (i != 0) { i--; *s++ = temp[i]; } \\r
31 *s = 0;\r
32\r
33static void ConvertUInt64ToString(UInt64 val, char *s)\r
34{\r
35 CONVERT_INT_TO_STR(char, 24);\r
36}\r
37\r
38#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))\r
39\r
40static void ConvertUInt64ToHex(UInt64 val, char *s)\r
41{\r
42 UInt64 v = val;\r
43 unsigned i;\r
44 for (i = 1;; i++)\r
45 {\r
46 v >>= 4;\r
47 if (v == 0)\r
48 break;\r
49 }\r
50 s[i] = 0;\r
51 do\r
52 {\r
53 unsigned t = (unsigned)(val & 0xF);\r
54 val >>= 4;\r
55 s[--i] = GET_HEX_CHAR(t);\r
56 }\r
57 while (i);\r
58}\r
59\r
60#define DEBUG_OUT_STREAM stderr\r
61\r
62static void Print(const char *s)\r
63{\r
64 fputs(s, DEBUG_OUT_STREAM);\r
65}\r
66\r
67static void PrintAligned(const char *s, size_t align)\r
68{\r
69 size_t len = strlen(s);\r
70 for(;;)\r
71 {\r
72 fputc(' ', DEBUG_OUT_STREAM);\r
73 if (len >= align)\r
74 break;\r
75 ++len;\r
76 }\r
77 Print(s);\r
78}\r
79\r
80static void PrintLn()\r
81{\r
82 Print("\n");\r
83}\r
84\r
85static void PrintHex(UInt64 v, size_t align)\r
86{\r
87 char s[32];\r
88 ConvertUInt64ToHex(v, s);\r
89 PrintAligned(s, align);\r
90}\r
91\r
92static void PrintDec(UInt64 v, size_t align)\r
93{\r
94 char s[32];\r
95 ConvertUInt64ToString(v, s);\r
96 PrintAligned(s, align);\r
97}\r
98\r
99static void PrintAddr(void *p)\r
100{\r
101 PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);\r
102}\r
103\r
104\r
105#define PRINT_ALLOC(name, cnt, size, ptr) \\r
106 Print(name " "); \\r
107 PrintDec(cnt++, 10); \\r
108 PrintHex(size, 10); \\r
109 PrintAddr(ptr); \\r
110 PrintLn();\r
111 \r
112#define PRINT_FREE(name, cnt, ptr) if (ptr) { \\r
113 Print(name " "); \\r
114 PrintDec(--cnt, 10); \\r
115 PrintAddr(ptr); \\r
116 PrintLn(); }\r
117 \r
118#else\r
119\r
120#define PRINT_ALLOC(name, cnt, size, ptr)\r
121#define PRINT_FREE(name, cnt, ptr)\r
122#define Print(s)\r
123#define PrintLn()\r
124#define PrintHex(v, align)\r
125#define PrintDec(v, align)\r
126#define PrintAddr(p)\r
127\r
30fdf114
LG
128#endif\r
129\r
5ec5a236
LG
130\r
131\r
30fdf114
LG
132void *MyAlloc(size_t size)\r
133{\r
134 if (size == 0)\r
5ec5a236 135 return NULL;\r
30fdf114
LG
136 #ifdef _SZ_ALLOC_DEBUG\r
137 {\r
138 void *p = malloc(size);\r
5ec5a236 139 PRINT_ALLOC("Alloc ", g_allocCount, size, p);\r
30fdf114
LG
140 return p;\r
141 }\r
142 #else\r
143 return malloc(size);\r
144 #endif\r
145}\r
146\r
147void MyFree(void *address)\r
148{\r
5ec5a236
LG
149 PRINT_FREE("Free ", g_allocCount, address);\r
150 \r
30fdf114
LG
151 free(address);\r
152}\r
153\r
154#ifdef _WIN32\r
155\r
156void *MidAlloc(size_t size)\r
157{\r
158 if (size == 0)\r
5ec5a236
LG
159 return NULL;\r
160 \r
161 PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL);\r
162 \r
163 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);\r
30fdf114
LG
164}\r
165\r
166void MidFree(void *address)\r
167{\r
5ec5a236
LG
168 PRINT_FREE("Free-Mid", g_allocCountMid, address);\r
169\r
170 if (!address)\r
30fdf114
LG
171 return;\r
172 VirtualFree(address, 0, MEM_RELEASE);\r
173}\r
174\r
175#ifndef MEM_LARGE_PAGES\r
176#undef _7ZIP_LARGE_PAGES\r
177#endif\r
178\r
179#ifdef _7ZIP_LARGE_PAGES\r
180SIZE_T g_LargePageSize = 0;\r
181typedef SIZE_T (WINAPI *GetLargePageMinimumP)();\r
182#endif\r
183\r
184void SetLargePageSize()\r
185{\r
186 #ifdef _7ZIP_LARGE_PAGES\r
5ec5a236 187 SIZE_T size;\r
30fdf114
LG
188 GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)\r
189 GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");\r
5ec5a236 190 if (!largePageMinimum)\r
30fdf114
LG
191 return;\r
192 size = largePageMinimum();\r
193 if (size == 0 || (size & (size - 1)) != 0)\r
194 return;\r
195 g_LargePageSize = size;\r
196 #endif\r
197}\r
198\r
199\r
200void *BigAlloc(size_t size)\r
201{\r
202 if (size == 0)\r
5ec5a236
LG
203 return NULL;\r
204\r
205 PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);\r
30fdf114
LG
206 \r
207 #ifdef _7ZIP_LARGE_PAGES\r
30fdf114 208 {\r
5ec5a236
LG
209 SIZE_T ps = g_LargePageSize;\r
210 if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))\r
211 {\r
212 size_t size2;\r
213 ps--;\r
214 size2 = (size + ps) & ~ps;\r
215 if (size2 >= size)\r
216 {\r
217 void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);\r
218 if (res)\r
219 return res;\r
220 }\r
221 }\r
30fdf114
LG
222 }\r
223 #endif\r
5ec5a236
LG
224\r
225 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);\r
30fdf114
LG
226}\r
227\r
228void BigFree(void *address)\r
229{\r
5ec5a236 230 PRINT_FREE("Free-Big", g_allocCountBig, address);\r
30fdf114 231 \r
5ec5a236 232 if (!address)\r
30fdf114
LG
233 return;\r
234 VirtualFree(address, 0, MEM_RELEASE);\r
235}\r
236\r
237#endif\r
c4ab09ef
LG
238\r
239\r
5ec5a236
LG
240static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }\r
241static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }\r
242const ISzAlloc g_Alloc = { SzAlloc, SzFree };\r
243\r
244static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }\r
245static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }\r
246const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };\r
247\r
248static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }\r
249static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }\r
250const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };\r
251\r
252\r
253/*\r
254 uintptr_t : <stdint.h> C99 (optional)\r
255 : unsupported in VS6\r
256*/\r
257\r
258#ifdef _WIN32\r
259 typedef UINT_PTR UIntPtr;\r
260#else\r
261 /*\r
262 typedef uintptr_t UIntPtr;\r
263 */\r
264 typedef ptrdiff_t UIntPtr;\r
265#endif\r
266\r
267\r
268#define ADJUST_ALLOC_SIZE 0\r
269/*\r
270#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)\r
271*/\r
272/*\r
273 Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if\r
274 MyAlloc() can return address that is NOT multiple of sizeof(void *).\r
275*/\r
276\r
277\r
278/*\r
279#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))\r
280*/\r
281#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))\r
282\r
283#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)\r
284\r
285\r
286#if (_POSIX_C_SOURCE >= 200112L) && !defined(_WIN32)\r
287 #define USE_posix_memalign\r
288#endif\r
289\r
290/*\r
291 This posix_memalign() is for test purposes only.\r
292 We also need special Free() function instead of free(),\r
293 if this posix_memalign() is used.\r
294*/\r
295\r
296/*\r
297static int posix_memalign(void **ptr, size_t align, size_t size)\r
298{\r
299 size_t newSize = size + align;\r
300 void *p;\r
301 void *pAligned;\r
302 *ptr = NULL;\r
303 if (newSize < size)\r
304 return 12; // ENOMEM\r
305 p = MyAlloc(newSize);\r
306 if (!p)\r
307 return 12; // ENOMEM\r
308 pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);\r
309 ((void **)pAligned)[-1] = p;\r
310 *ptr = pAligned;\r
311 return 0;\r
312}\r
313*/\r
314\r
315/*\r
316 ALLOC_ALIGN_SIZE >= sizeof(void *)\r
317 ALLOC_ALIGN_SIZE >= cache_line_size\r
318*/\r
319\r
320#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)\r
321\r
322static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)\r
323{\r
324 #ifndef USE_posix_memalign\r
325 \r
326 void *p;\r
327 void *pAligned;\r
328 size_t newSize;\r
329 UNUSED_VAR(pp);\r
330\r
331 /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned\r
332 block to prevent cache line sharing with another allocated blocks */\r
333\r
334 newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;\r
335 if (newSize < size)\r
336 return NULL;\r
337\r
338 p = MyAlloc(newSize);\r
339 \r
340 if (!p)\r
341 return NULL;\r
342 pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);\r
343\r
344 Print(" size="); PrintHex(size, 8);\r
345 Print(" a_size="); PrintHex(newSize, 8);\r
346 Print(" ptr="); PrintAddr(p);\r
347 Print(" a_ptr="); PrintAddr(pAligned);\r
348 PrintLn();\r
349\r
350 ((void **)pAligned)[-1] = p;\r
351\r
352 return pAligned;\r
353\r
354 #else\r
355\r
356 void *p;\r
357 UNUSED_VAR(pp);\r
358 if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))\r
359 return NULL;\r
360\r
361 Print(" posix_memalign="); PrintAddr(p);\r
362 PrintLn();\r
363\r
364 return p;\r
365\r
366 #endif\r
367}\r
368\r
369\r
370static void SzAlignedFree(ISzAllocPtr pp, void *address)\r
371{\r
372 UNUSED_VAR(pp);\r
373 #ifndef USE_posix_memalign\r
374 if (address)\r
375 MyFree(((void **)address)[-1]);\r
376 #else\r
377 free(address);\r
378 #endif\r
379}\r
380\r
381\r
382const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };\r
383\r
384\r
385\r
386#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))\r
387\r
388/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */\r
389#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]\r
390/*\r
391#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]\r
392*/\r
393\r
394static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)\r
395{\r
396 CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);\r
397 void *adr;\r
398 void *pAligned;\r
399 size_t newSize;\r
400 size_t extra;\r
401 size_t alignSize = (size_t)1 << p->numAlignBits;\r
402\r
403 if (alignSize < sizeof(void *))\r
404 alignSize = sizeof(void *);\r
405 \r
406 if (p->offset >= alignSize)\r
407 return NULL;\r
408\r
409 /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned\r
410 block to prevent cache line sharing with another allocated blocks */\r
411 extra = p->offset & (sizeof(void *) - 1);\r
412 newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;\r
413 if (newSize < size)\r
414 return NULL;\r
c4ab09ef 415\r
5ec5a236
LG
416 adr = ISzAlloc_Alloc(p->baseAlloc, newSize);\r
417 \r
418 if (!adr)\r
419 return NULL;\r
420\r
421 pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +\r
422 alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;\r
423\r
424 PrintLn();\r
425 Print("- Aligned: ");\r
426 Print(" size="); PrintHex(size, 8);\r
427 Print(" a_size="); PrintHex(newSize, 8);\r
428 Print(" ptr="); PrintAddr(adr);\r
429 Print(" a_ptr="); PrintAddr(pAligned);\r
430 PrintLn();\r
431\r
432 REAL_BLOCK_PTR_VAR(pAligned) = adr;\r
433\r
434 return pAligned;\r
435}\r
436\r
437\r
438static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)\r
439{\r
440 if (address)\r
441 {\r
442 CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);\r
443 PrintLn();\r
444 Print("- Aligned Free: ");\r
445 PrintLn();\r
446 ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));\r
447 }\r
448}\r
449\r
450\r
451void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)\r
452{\r
453 p->vt.Alloc = AlignOffsetAlloc_Alloc;\r
454 p->vt.Free = AlignOffsetAlloc_Free;\r
455}\r