Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/lzma/src/Alloc.c
4253 views
1
/* Alloc.c -- Memory allocation functions
2
2024-02-18 : Igor Pavlov : Public domain */
3
4
#include "Precomp.h"
5
6
#ifdef _WIN32
7
#include "7zWindows.h"
8
#endif
9
#include <stdlib.h>
10
11
#include "Alloc.h"
12
13
#if defined(Z7_LARGE_PAGES) && defined(_WIN32) && \
14
(!defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502) // < Win2003 (xp-64)
15
#define Z7_USE_DYN_GetLargePageMinimum
16
#endif
17
18
// for debug:
19
#if 0
20
#if defined(__CHERI__) && defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16)
21
// #pragma message("=== Z7_ALLOC_NO_OFFSET_ALLOCATOR === ")
22
#define Z7_ALLOC_NO_OFFSET_ALLOCATOR
23
#endif
24
#endif
25
26
// #define SZ_ALLOC_DEBUG
27
/* #define SZ_ALLOC_DEBUG */
28
29
/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
30
#ifdef SZ_ALLOC_DEBUG
31
32
#include <string.h>
33
#include <stdio.h>
34
static int g_allocCount = 0;
35
#ifdef _WIN32
36
static int g_allocCountMid = 0;
37
static int g_allocCountBig = 0;
38
#endif
39
40
41
#define CONVERT_INT_TO_STR(charType, tempSize) \
42
char temp[tempSize]; unsigned i = 0; \
43
while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \
44
*s++ = (charType)('0' + (unsigned)val); \
45
while (i != 0) { i--; *s++ = temp[i]; } \
46
*s = 0;
47
48
static void ConvertUInt64ToString(UInt64 val, char *s)
49
{
50
CONVERT_INT_TO_STR(char, 24)
51
}
52
53
#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
54
55
static void ConvertUInt64ToHex(UInt64 val, char *s)
56
{
57
UInt64 v = val;
58
unsigned i;
59
for (i = 1;; i++)
60
{
61
v >>= 4;
62
if (v == 0)
63
break;
64
}
65
s[i] = 0;
66
do
67
{
68
unsigned t = (unsigned)(val & 0xF);
69
val >>= 4;
70
s[--i] = GET_HEX_CHAR(t);
71
}
72
while (i);
73
}
74
75
#define DEBUG_OUT_STREAM stderr
76
77
static void Print(const char *s)
78
{
79
fputs(s, DEBUG_OUT_STREAM);
80
}
81
82
static void PrintAligned(const char *s, size_t align)
83
{
84
size_t len = strlen(s);
85
for(;;)
86
{
87
fputc(' ', DEBUG_OUT_STREAM);
88
if (len >= align)
89
break;
90
++len;
91
}
92
Print(s);
93
}
94
95
static void PrintLn(void)
96
{
97
Print("\n");
98
}
99
100
static void PrintHex(UInt64 v, size_t align)
101
{
102
char s[32];
103
ConvertUInt64ToHex(v, s);
104
PrintAligned(s, align);
105
}
106
107
static void PrintDec(int v, size_t align)
108
{
109
char s[32];
110
ConvertUInt64ToString((unsigned)v, s);
111
PrintAligned(s, align);
112
}
113
114
static void PrintAddr(void *p)
115
{
116
PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
117
}
118
119
120
#define PRINT_REALLOC(name, cnt, size, ptr) { \
121
Print(name " "); \
122
if (!ptr) PrintDec(cnt++, 10); \
123
PrintHex(size, 10); \
124
PrintAddr(ptr); \
125
PrintLn(); }
126
127
#define PRINT_ALLOC(name, cnt, size, ptr) { \
128
Print(name " "); \
129
PrintDec(cnt++, 10); \
130
PrintHex(size, 10); \
131
PrintAddr(ptr); \
132
PrintLn(); }
133
134
#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
135
Print(name " "); \
136
PrintDec(--cnt, 10); \
137
PrintAddr(ptr); \
138
PrintLn(); }
139
140
#else
141
142
#ifdef _WIN32
143
#define PRINT_ALLOC(name, cnt, size, ptr)
144
#endif
145
#define PRINT_FREE(name, cnt, ptr)
146
#define Print(s)
147
#define PrintLn()
148
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
149
#define PrintHex(v, align)
150
#endif
151
#define PrintAddr(p)
152
153
#endif
154
155
156
/*
157
by specification:
158
malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free()
159
realloc(NULL, size) : the call is equivalent to malloc(size)
160
realloc(non_NULL, 0) : the call is equivalent to free(ptr)
161
162
in main compilers:
163
malloc(0) : returns non_NULL
164
realloc(NULL, 0) : returns non_NULL
165
realloc(non_NULL, 0) : returns NULL
166
*/
167
168
169
void *MyAlloc(size_t size)
170
{
171
if (size == 0)
172
return NULL;
173
// PRINT_ALLOC("Alloc ", g_allocCount, size, NULL)
174
#ifdef SZ_ALLOC_DEBUG
175
{
176
void *p = malloc(size);
177
if (p)
178
{
179
PRINT_ALLOC("Alloc ", g_allocCount, size, p)
180
}
181
return p;
182
}
183
#else
184
return malloc(size);
185
#endif
186
}
187
188
void MyFree(void *address)
189
{
190
PRINT_FREE("Free ", g_allocCount, address)
191
192
free(address);
193
}
194
195
void *MyRealloc(void *address, size_t size)
196
{
197
if (size == 0)
198
{
199
MyFree(address);
200
return NULL;
201
}
202
// PRINT_REALLOC("Realloc ", g_allocCount, size, address)
203
#ifdef SZ_ALLOC_DEBUG
204
{
205
void *p = realloc(address, size);
206
if (p)
207
{
208
PRINT_REALLOC("Realloc ", g_allocCount, size, address)
209
}
210
return p;
211
}
212
#else
213
return realloc(address, size);
214
#endif
215
}
216
217
218
#ifdef _WIN32
219
220
void *MidAlloc(size_t size)
221
{
222
if (size == 0)
223
return NULL;
224
#ifdef SZ_ALLOC_DEBUG
225
{
226
void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
227
if (p)
228
{
229
PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p)
230
}
231
return p;
232
}
233
#else
234
return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
235
#endif
236
}
237
238
void MidFree(void *address)
239
{
240
PRINT_FREE("Free-Mid", g_allocCountMid, address)
241
242
if (!address)
243
return;
244
VirtualFree(address, 0, MEM_RELEASE);
245
}
246
247
#ifdef Z7_LARGE_PAGES
248
249
#ifdef MEM_LARGE_PAGES
250
#define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES
251
#else
252
#define MY_MEM_LARGE_PAGES 0x20000000
253
#endif
254
255
extern
256
SIZE_T g_LargePageSize;
257
SIZE_T g_LargePageSize = 0;
258
typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
259
260
void SetLargePageSize(void)
261
{
262
SIZE_T size;
263
#ifdef Z7_USE_DYN_GetLargePageMinimum
264
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
265
266
const
267
Func_GetLargePageMinimum fn =
268
(Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
269
"GetLargePageMinimum");
270
if (!fn)
271
return;
272
size = fn();
273
#else
274
size = GetLargePageMinimum();
275
#endif
276
if (size == 0 || (size & (size - 1)) != 0)
277
return;
278
g_LargePageSize = size;
279
}
280
281
#endif // Z7_LARGE_PAGES
282
283
void *BigAlloc(size_t size)
284
{
285
if (size == 0)
286
return NULL;
287
288
PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL)
289
290
#ifdef Z7_LARGE_PAGES
291
{
292
SIZE_T ps = g_LargePageSize;
293
if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
294
{
295
size_t size2;
296
ps--;
297
size2 = (size + ps) & ~ps;
298
if (size2 >= size)
299
{
300
void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE);
301
if (p)
302
{
303
PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p)
304
return p;
305
}
306
}
307
}
308
}
309
#endif
310
311
return MidAlloc(size);
312
}
313
314
void BigFree(void *address)
315
{
316
PRINT_FREE("Free-Big", g_allocCountBig, address)
317
MidFree(address);
318
}
319
320
#endif // _WIN32
321
322
323
static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); }
324
static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); }
325
const ISzAlloc g_Alloc = { SzAlloc, SzFree };
326
327
#ifdef _WIN32
328
static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); }
329
static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); }
330
static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); }
331
static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); }
332
const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
333
const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
334
#endif
335
336
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
337
338
#define ADJUST_ALLOC_SIZE 0
339
/*
340
#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
341
*/
342
/*
343
Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
344
MyAlloc() can return address that is NOT multiple of sizeof(void *).
345
*/
346
347
/*
348
uintptr_t : <stdint.h> C99 (optional)
349
: unsupported in VS6
350
*/
351
typedef
352
#ifdef _WIN32
353
UINT_PTR
354
#elif 1
355
uintptr_t
356
#else
357
ptrdiff_t
358
#endif
359
MY_uintptr_t;
360
361
#if 0 \
362
|| (defined(__CHERI__) \
363
|| defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ > 8))
364
// for 128-bit pointers (cheri):
365
#define MY_ALIGN_PTR_DOWN(p, align) \
366
((void *)((char *)(p) - ((size_t)(MY_uintptr_t)(p) & ((align) - 1))))
367
#else
368
#define MY_ALIGN_PTR_DOWN(p, align) \
369
((void *)((((MY_uintptr_t)(p)) & ~((MY_uintptr_t)(align) - 1))))
370
#endif
371
372
#endif
373
374
#if !defined(_WIN32) \
375
&& (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
376
|| defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
377
#define USE_posix_memalign
378
#endif
379
380
#ifndef USE_posix_memalign
381
#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
382
#endif
383
384
/*
385
This posix_memalign() is for test purposes only.
386
We also need special Free() function instead of free(),
387
if this posix_memalign() is used.
388
*/
389
390
/*
391
static int posix_memalign(void **ptr, size_t align, size_t size)
392
{
393
size_t newSize = size + align;
394
void *p;
395
void *pAligned;
396
*ptr = NULL;
397
if (newSize < size)
398
return 12; // ENOMEM
399
p = MyAlloc(newSize);
400
if (!p)
401
return 12; // ENOMEM
402
pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
403
((void **)pAligned)[-1] = p;
404
*ptr = pAligned;
405
return 0;
406
}
407
*/
408
409
/*
410
ALLOC_ALIGN_SIZE >= sizeof(void *)
411
ALLOC_ALIGN_SIZE >= cache_line_size
412
*/
413
414
#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
415
416
void *z7_AlignedAlloc(size_t size)
417
{
418
#ifndef USE_posix_memalign
419
420
void *p;
421
void *pAligned;
422
size_t newSize;
423
424
/* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
425
block to prevent cache line sharing with another allocated blocks */
426
427
newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
428
if (newSize < size)
429
return NULL;
430
431
p = MyAlloc(newSize);
432
433
if (!p)
434
return NULL;
435
pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
436
437
Print(" size="); PrintHex(size, 8);
438
Print(" a_size="); PrintHex(newSize, 8);
439
Print(" ptr="); PrintAddr(p);
440
Print(" a_ptr="); PrintAddr(pAligned);
441
PrintLn();
442
443
((void **)pAligned)[-1] = p;
444
445
return pAligned;
446
447
#else
448
449
void *p;
450
if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
451
return NULL;
452
453
Print(" posix_memalign="); PrintAddr(p);
454
PrintLn();
455
456
return p;
457
458
#endif
459
}
460
461
462
void z7_AlignedFree(void *address)
463
{
464
#ifndef USE_posix_memalign
465
if (address)
466
MyFree(((void **)address)[-1]);
467
#else
468
free(address);
469
#endif
470
}
471
472
473
static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
474
{
475
UNUSED_VAR(pp)
476
return z7_AlignedAlloc(size);
477
}
478
479
480
static void SzAlignedFree(ISzAllocPtr pp, void *address)
481
{
482
UNUSED_VAR(pp)
483
#ifndef USE_posix_memalign
484
if (address)
485
MyFree(((void **)address)[-1]);
486
#else
487
free(address);
488
#endif
489
}
490
491
492
const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
493
494
495
496
/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
497
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
498
#if 1
499
#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
500
#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
501
#else
502
// we can use this simplified code,
503
// if (CAlignOffsetAlloc::offset == (k * sizeof(void *))
504
#define REAL_BLOCK_PTR_VAR(p) (((void **)(p))[-1])
505
#endif
506
#endif
507
508
509
#if 0
510
#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
511
#include <stdio.h>
512
static void PrintPtr(const char *s, const void *p)
513
{
514
const Byte *p2 = (const Byte *)&p;
515
unsigned i;
516
printf("%s %p ", s, p);
517
for (i = sizeof(p); i != 0;)
518
{
519
i--;
520
printf("%02x", p2[i]);
521
}
522
printf("\n");
523
}
524
#endif
525
#endif
526
527
528
static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
529
{
530
#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR)
531
UNUSED_VAR(pp)
532
return z7_AlignedAlloc(size);
533
#else
534
const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
535
void *adr;
536
void *pAligned;
537
size_t newSize;
538
size_t extra;
539
size_t alignSize = (size_t)1 << p->numAlignBits;
540
541
if (alignSize < sizeof(void *))
542
alignSize = sizeof(void *);
543
544
if (p->offset >= alignSize)
545
return NULL;
546
547
/* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
548
block to prevent cache line sharing with another allocated blocks */
549
extra = p->offset & (sizeof(void *) - 1);
550
newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
551
if (newSize < size)
552
return NULL;
553
554
adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
555
556
if (!adr)
557
return NULL;
558
559
pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
560
alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
561
562
#if 0
563
printf("\nalignSize = %6x, offset=%6x, size=%8x \n", (unsigned)alignSize, (unsigned)p->offset, (unsigned)size);
564
PrintPtr("base", adr);
565
PrintPtr("alig", pAligned);
566
#endif
567
568
PrintLn();
569
Print("- Aligned: ");
570
Print(" size="); PrintHex(size, 8);
571
Print(" a_size="); PrintHex(newSize, 8);
572
Print(" ptr="); PrintAddr(adr);
573
Print(" a_ptr="); PrintAddr(pAligned);
574
PrintLn();
575
576
REAL_BLOCK_PTR_VAR(pAligned) = adr;
577
578
return pAligned;
579
#endif
580
}
581
582
583
static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
584
{
585
#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR)
586
UNUSED_VAR(pp)
587
z7_AlignedFree(address);
588
#else
589
if (address)
590
{
591
const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
592
PrintLn();
593
Print("- Aligned Free: ");
594
PrintLn();
595
ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
596
}
597
#endif
598
}
599
600
601
void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
602
{
603
p->vt.Alloc = AlignOffsetAlloc_Alloc;
604
p->vt.Free = AlignOffsetAlloc_Free;
605
}
606
607