git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / lzma-22.01 / src / Alloc.c
CommitLineData
9e052883 1/* Alloc.c -- Memory allocation functions\r
22021-07-13 : Igor Pavlov : Public domain */\r
3\r
4#include "Precomp.h"\r
5\r
6#include <stdio.h>\r
7\r
8#ifdef _WIN32\r
648db22b 9#include <windows.h>\r
9e052883 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
19\r
20#include <stdio.h>\r
21int g_allocCount = 0;\r
22int g_allocCountMid = 0;\r
23int g_allocCountBig = 0;\r
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 PrintAddr(p)\r
126\r
127#endif\r
128\r
129\r
130\r
131void *MyAlloc(size_t size)\r
132{\r
133 if (size == 0)\r
134 return NULL;\r
135 PRINT_ALLOC("Alloc ", g_allocCount, size, NULL);\r
136 #ifdef _SZ_ALLOC_DEBUG\r
137 {\r
138 void *p = malloc(size);\r
139 // PRINT_ALLOC("Alloc ", g_allocCount, size, p);\r
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
149 PRINT_FREE("Free ", g_allocCount, address);\r
150 \r
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
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
164}\r
165\r
166void MidFree(void *address)\r
167{\r
168 PRINT_FREE("Free-Mid", g_allocCountMid, address);\r
169\r
170 if (!address)\r
171 return;\r
172 VirtualFree(address, 0, MEM_RELEASE);\r
173}\r
174\r
175#ifdef _7ZIP_LARGE_PAGES\r
176\r
177#ifdef MEM_LARGE_PAGES\r
178 #define MY__MEM_LARGE_PAGES MEM_LARGE_PAGES\r
179#else\r
180 #define MY__MEM_LARGE_PAGES 0x20000000\r
181#endif\r
182\r
183extern\r
184SIZE_T g_LargePageSize;\r
185SIZE_T g_LargePageSize = 0;\r
186typedef SIZE_T (WINAPI *GetLargePageMinimumP)(VOID);\r
187\r
188#endif // _7ZIP_LARGE_PAGES\r
189\r
190void SetLargePageSize()\r
191{\r
192 #ifdef _7ZIP_LARGE_PAGES\r
193 SIZE_T size;\r
194 GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)\r
195 GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");\r
196 if (!largePageMinimum)\r
197 return;\r
198 size = largePageMinimum();\r
199 if (size == 0 || (size & (size - 1)) != 0)\r
200 return;\r
201 g_LargePageSize = size;\r
202 #endif\r
203}\r
204\r
205\r
206void *BigAlloc(size_t size)\r
207{\r
208 if (size == 0)\r
209 return NULL;\r
210\r
211 PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);\r
212 \r
213 #ifdef _7ZIP_LARGE_PAGES\r
214 {\r
215 SIZE_T ps = g_LargePageSize;\r
216 if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))\r
217 {\r
218 size_t size2;\r
219 ps--;\r
220 size2 = (size + ps) & ~ps;\r
221 if (size2 >= size)\r
222 {\r
223 void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MY__MEM_LARGE_PAGES, PAGE_READWRITE);\r
224 if (res)\r
225 return res;\r
226 }\r
227 }\r
228 }\r
229 #endif\r
230\r
231 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);\r
232}\r
233\r
234void BigFree(void *address)\r
235{\r
236 PRINT_FREE("Free-Big", g_allocCountBig, address);\r
237 \r
238 if (!address)\r
239 return;\r
240 VirtualFree(address, 0, MEM_RELEASE);\r
241}\r
242\r
243#endif\r
244\r
245\r
246static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }\r
247static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }\r
248const ISzAlloc g_Alloc = { SzAlloc, SzFree };\r
249\r
250#ifdef _WIN32\r
251static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }\r
252static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }\r
253static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }\r
254static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }\r
255const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };\r
256const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };\r
257#endif\r
258\r
259/*\r
260 uintptr_t : <stdint.h> C99 (optional)\r
261 : unsupported in VS6\r
262*/\r
263\r
264#ifdef _WIN32\r
265 typedef UINT_PTR UIntPtr;\r
266#else\r
267 /*\r
268 typedef uintptr_t UIntPtr;\r
269 */\r
270 typedef ptrdiff_t UIntPtr;\r
271#endif\r
272\r
273\r
274#define ADJUST_ALLOC_SIZE 0\r
275/*\r
276#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)\r
277*/\r
278/*\r
279 Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if\r
280 MyAlloc() can return address that is NOT multiple of sizeof(void *).\r
281*/\r
282\r
283\r
284/*\r
285#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))\r
286*/\r
287#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))\r
288\r
289\r
290#if !defined(_WIN32) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)\r
291 #define USE_posix_memalign\r
292#endif\r
293\r
294#ifndef USE_posix_memalign\r
295#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)\r
296#endif\r
297\r
298/*\r
299 This posix_memalign() is for test purposes only.\r
300 We also need special Free() function instead of free(),\r
301 if this posix_memalign() is used.\r
302*/\r
303\r
304/*\r
305static int posix_memalign(void **ptr, size_t align, size_t size)\r
306{\r
307 size_t newSize = size + align;\r
308 void *p;\r
309 void *pAligned;\r
310 *ptr = NULL;\r
311 if (newSize < size)\r
312 return 12; // ENOMEM\r
313 p = MyAlloc(newSize);\r
314 if (!p)\r
315 return 12; // ENOMEM\r
316 pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);\r
317 ((void **)pAligned)[-1] = p;\r
318 *ptr = pAligned;\r
319 return 0;\r
320}\r
321*/\r
322\r
323/*\r
324 ALLOC_ALIGN_SIZE >= sizeof(void *)\r
325 ALLOC_ALIGN_SIZE >= cache_line_size\r
326*/\r
327\r
328#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)\r
329\r
330static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)\r
331{\r
332 #ifndef USE_posix_memalign\r
333 \r
334 void *p;\r
335 void *pAligned;\r
336 size_t newSize;\r
337 UNUSED_VAR(pp);\r
338\r
339 /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned\r
340 block to prevent cache line sharing with another allocated blocks */\r
341\r
342 newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;\r
343 if (newSize < size)\r
344 return NULL;\r
345\r
346 p = MyAlloc(newSize);\r
347 \r
348 if (!p)\r
349 return NULL;\r
350 pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);\r
351\r
352 Print(" size="); PrintHex(size, 8);\r
353 Print(" a_size="); PrintHex(newSize, 8);\r
354 Print(" ptr="); PrintAddr(p);\r
355 Print(" a_ptr="); PrintAddr(pAligned);\r
356 PrintLn();\r
357\r
358 ((void **)pAligned)[-1] = p;\r
359\r
360 return pAligned;\r
361\r
362 #else\r
363\r
364 void *p;\r
365 UNUSED_VAR(pp);\r
366 if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))\r
367 return NULL;\r
368\r
369 Print(" posix_memalign="); PrintAddr(p);\r
370 PrintLn();\r
371\r
372 return p;\r
373\r
374 #endif\r
375}\r
376\r
377\r
378static void SzAlignedFree(ISzAllocPtr pp, void *address)\r
379{\r
380 UNUSED_VAR(pp);\r
381 #ifndef USE_posix_memalign\r
382 if (address)\r
383 MyFree(((void **)address)[-1]);\r
384 #else\r
385 free(address);\r
386 #endif\r
387}\r
388\r
389\r
390const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };\r
391\r
392\r
393\r
394#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))\r
395\r
396/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */\r
397#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]\r
398/*\r
399#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]\r
400*/\r
401\r
402static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)\r
403{\r
404 CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);\r
405 void *adr;\r
406 void *pAligned;\r
407 size_t newSize;\r
408 size_t extra;\r
409 size_t alignSize = (size_t)1 << p->numAlignBits;\r
410\r
411 if (alignSize < sizeof(void *))\r
412 alignSize = sizeof(void *);\r
413 \r
414 if (p->offset >= alignSize)\r
415 return NULL;\r
416\r
417 /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned\r
418 block to prevent cache line sharing with another allocated blocks */\r
419 extra = p->offset & (sizeof(void *) - 1);\r
420 newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;\r
421 if (newSize < size)\r
422 return NULL;\r
423\r
424 adr = ISzAlloc_Alloc(p->baseAlloc, newSize);\r
425 \r
426 if (!adr)\r
427 return NULL;\r
428\r
429 pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +\r
430 alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;\r
431\r
432 PrintLn();\r
433 Print("- Aligned: ");\r
434 Print(" size="); PrintHex(size, 8);\r
435 Print(" a_size="); PrintHex(newSize, 8);\r
436 Print(" ptr="); PrintAddr(adr);\r
437 Print(" a_ptr="); PrintAddr(pAligned);\r
438 PrintLn();\r
439\r
440 REAL_BLOCK_PTR_VAR(pAligned) = adr;\r
441\r
442 return pAligned;\r
443}\r
444\r
445\r
446static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)\r
447{\r
448 if (address)\r
449 {\r
450 CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);\r
451 PrintLn();\r
452 Print("- Aligned Free: ");\r
453 PrintLn();\r
454 ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));\r
455 }\r
456}\r
457\r
458\r
459void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)\r
460{\r
461 p->vt.Alloc = AlignOffsetAlloc_Alloc;\r
462 p->vt.Free = AlignOffsetAlloc_Free;\r
463}\r