| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /* Alloc.c -- Memory allocation functions
- 2024-02-18 : Igor Pavlov : Public domain */
- #include "Precomp.h"
- #ifdef _WIN32
- #include "7zWindows.h"
- #endif
- #include <stdlib.h>
- #include "Alloc.h"
- #if defined(Z7_LARGE_PAGES) && defined(_WIN32) && \
- (!defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502) // < Win2003 (xp-64)
- #define Z7_USE_DYN_GetLargePageMinimum
- #endif
- // for debug:
- #if 0
- #if defined(__CHERI__) && defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16)
- // #pragma message("=== Z7_ALLOC_NO_OFFSET_ALLOCATOR === ")
- #define Z7_ALLOC_NO_OFFSET_ALLOCATOR
- #endif
- #endif
- // #define SZ_ALLOC_DEBUG
- /* #define SZ_ALLOC_DEBUG */
- /* use SZ_ALLOC_DEBUG to debug alloc/free operations */
- #ifdef SZ_ALLOC_DEBUG
- #include <string.h>
- #include <stdio.h>
- static int g_allocCount = 0;
- #ifdef _WIN32
- static int g_allocCountMid = 0;
- static int g_allocCountBig = 0;
- #endif
- #define CONVERT_INT_TO_STR(charType, tempSize) \
- char temp[tempSize]; unsigned i = 0; \
- while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \
- *s++ = (charType)('0' + (unsigned)val); \
- while (i != 0) { i--; *s++ = temp[i]; } \
- *s = 0;
- static void ConvertUInt64ToString(UInt64 val, char *s)
- {
- CONVERT_INT_TO_STR(char, 24)
- }
- #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
- static void ConvertUInt64ToHex(UInt64 val, char *s)
- {
- UInt64 v = val;
- unsigned i;
- for (i = 1;; i++)
- {
- v >>= 4;
- if (v == 0)
- break;
- }
- s[i] = 0;
- do
- {
- unsigned t = (unsigned)(val & 0xF);
- val >>= 4;
- s[--i] = GET_HEX_CHAR(t);
- }
- while (i);
- }
- #define DEBUG_OUT_STREAM stderr
- static void Print(const char *s)
- {
- fputs(s, DEBUG_OUT_STREAM);
- }
- static void PrintAligned(const char *s, size_t align)
- {
- size_t len = strlen(s);
- for(;;)
- {
- fputc(' ', DEBUG_OUT_STREAM);
- if (len >= align)
- break;
- ++len;
- }
- Print(s);
- }
- static void PrintLn(void)
- {
- Print("\n");
- }
- static void PrintHex(UInt64 v, size_t align)
- {
- char s[32];
- ConvertUInt64ToHex(v, s);
- PrintAligned(s, align);
- }
- static void PrintDec(int v, size_t align)
- {
- char s[32];
- ConvertUInt64ToString((unsigned)v, s);
- PrintAligned(s, align);
- }
- static void PrintAddr(void *p)
- {
- PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
- }
- #define PRINT_REALLOC(name, cnt, size, ptr) { \
- Print(name " "); \
- if (!ptr) PrintDec(cnt++, 10); \
- PrintHex(size, 10); \
- PrintAddr(ptr); \
- PrintLn(); }
- #define PRINT_ALLOC(name, cnt, size, ptr) { \
- Print(name " "); \
- PrintDec(cnt++, 10); \
- PrintHex(size, 10); \
- PrintAddr(ptr); \
- PrintLn(); }
-
- #define PRINT_FREE(name, cnt, ptr) if (ptr) { \
- Print(name " "); \
- PrintDec(--cnt, 10); \
- PrintAddr(ptr); \
- PrintLn(); }
-
- #else
- #ifdef _WIN32
- #define PRINT_ALLOC(name, cnt, size, ptr)
- #endif
- #define PRINT_FREE(name, cnt, ptr)
- #define Print(s)
- #define PrintLn()
- #ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
- #define PrintHex(v, align)
- #endif
- #define PrintAddr(p)
- #endif
- /*
- by specification:
- malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free()
- realloc(NULL, size) : the call is equivalent to malloc(size)
- realloc(non_NULL, 0) : the call is equivalent to free(ptr)
- in main compilers:
- malloc(0) : returns non_NULL
- realloc(NULL, 0) : returns non_NULL
- realloc(non_NULL, 0) : returns NULL
- */
- void *MyAlloc(size_t size)
- {
- if (size == 0)
- return NULL;
- // PRINT_ALLOC("Alloc ", g_allocCount, size, NULL)
- #ifdef SZ_ALLOC_DEBUG
- {
- void *p = malloc(size);
- if (p)
- {
- PRINT_ALLOC("Alloc ", g_allocCount, size, p)
- }
- return p;
- }
- #else
- return malloc(size);
- #endif
- }
- void MyFree(void *address)
- {
- PRINT_FREE("Free ", g_allocCount, address)
-
- free(address);
- }
- void *MyRealloc(void *address, size_t size)
- {
- if (size == 0)
- {
- MyFree(address);
- return NULL;
- }
- // PRINT_REALLOC("Realloc ", g_allocCount, size, address)
- #ifdef SZ_ALLOC_DEBUG
- {
- void *p = realloc(address, size);
- if (p)
- {
- PRINT_REALLOC("Realloc ", g_allocCount, size, address)
- }
- return p;
- }
- #else
- return realloc(address, size);
- #endif
- }
- #ifdef _WIN32
- void *MidAlloc(size_t size)
- {
- if (size == 0)
- return NULL;
- #ifdef SZ_ALLOC_DEBUG
- {
- void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
- if (p)
- {
- PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p)
- }
- return p;
- }
- #else
- return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
- #endif
- }
- void MidFree(void *address)
- {
- PRINT_FREE("Free-Mid", g_allocCountMid, address)
- if (!address)
- return;
- VirtualFree(address, 0, MEM_RELEASE);
- }
- #ifdef Z7_LARGE_PAGES
- #ifdef MEM_LARGE_PAGES
- #define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES
- #else
- #define MY_MEM_LARGE_PAGES 0x20000000
- #endif
- extern
- SIZE_T g_LargePageSize;
- SIZE_T g_LargePageSize = 0;
- typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
- void SetLargePageSize(void)
- {
- SIZE_T size;
- #ifdef Z7_USE_DYN_GetLargePageMinimum
- Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
- const
- Func_GetLargePageMinimum fn =
- (Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
- "GetLargePageMinimum");
- if (!fn)
- return;
- size = fn();
- #else
- size = GetLargePageMinimum();
- #endif
- if (size == 0 || (size & (size - 1)) != 0)
- return;
- g_LargePageSize = size;
- }
- #endif // Z7_LARGE_PAGES
- void *BigAlloc(size_t size)
- {
- if (size == 0)
- return NULL;
- PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL)
- #ifdef Z7_LARGE_PAGES
- {
- SIZE_T ps = g_LargePageSize;
- if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
- {
- size_t size2;
- ps--;
- size2 = (size + ps) & ~ps;
- if (size2 >= size)
- {
- void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE);
- if (p)
- {
- PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p)
- return p;
- }
- }
- }
- }
- #endif
- return MidAlloc(size);
- }
- void BigFree(void *address)
- {
- PRINT_FREE("Free-Big", g_allocCountBig, address)
- MidFree(address);
- }
- #endif // _WIN32
- static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); }
- static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); }
- const ISzAlloc g_Alloc = { SzAlloc, SzFree };
- #ifdef _WIN32
- static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); }
- static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); }
- static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); }
- static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); }
- const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
- const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
- #endif
- #ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
- #define ADJUST_ALLOC_SIZE 0
- /*
- #define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
- */
- /*
- Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
- MyAlloc() can return address that is NOT multiple of sizeof(void *).
- */
- /*
- uintptr_t : <stdint.h> C99 (optional)
- : unsupported in VS6
- */
- typedef
- #ifdef _WIN32
- UINT_PTR
- #elif 1
- uintptr_t
- #else
- ptrdiff_t
- #endif
- MY_uintptr_t;
- #if 0 \
- || (defined(__CHERI__) \
- || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ > 8))
- // for 128-bit pointers (cheri):
- #define MY_ALIGN_PTR_DOWN(p, align) \
- ((void *)((char *)(p) - ((size_t)(MY_uintptr_t)(p) & ((align) - 1))))
- #else
- #define MY_ALIGN_PTR_DOWN(p, align) \
- ((void *)((((MY_uintptr_t)(p)) & ~((MY_uintptr_t)(align) - 1))))
- #endif
- #endif
- #if !defined(_WIN32) \
- && (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
- || defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
- #define USE_posix_memalign
- #endif
- #ifndef USE_posix_memalign
- #define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
- #endif
- /*
- This posix_memalign() is for test purposes only.
- We also need special Free() function instead of free(),
- if this posix_memalign() is used.
- */
- /*
- static int posix_memalign(void **ptr, size_t align, size_t size)
- {
- size_t newSize = size + align;
- void *p;
- void *pAligned;
- *ptr = NULL;
- if (newSize < size)
- return 12; // ENOMEM
- p = MyAlloc(newSize);
- if (!p)
- return 12; // ENOMEM
- pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
- ((void **)pAligned)[-1] = p;
- *ptr = pAligned;
- return 0;
- }
- */
- /*
- ALLOC_ALIGN_SIZE >= sizeof(void *)
- ALLOC_ALIGN_SIZE >= cache_line_size
- */
- #define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
- void *z7_AlignedAlloc(size_t size)
- {
- #ifndef USE_posix_memalign
-
- void *p;
- void *pAligned;
- size_t newSize;
- /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
- block to prevent cache line sharing with another allocated blocks */
- newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
- if (newSize < size)
- return NULL;
- p = MyAlloc(newSize);
-
- if (!p)
- return NULL;
- pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
- Print(" size="); PrintHex(size, 8);
- Print(" a_size="); PrintHex(newSize, 8);
- Print(" ptr="); PrintAddr(p);
- Print(" a_ptr="); PrintAddr(pAligned);
- PrintLn();
- ((void **)pAligned)[-1] = p;
- return pAligned;
- #else
- void *p;
- if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
- return NULL;
- Print(" posix_memalign="); PrintAddr(p);
- PrintLn();
- return p;
- #endif
- }
- void z7_AlignedFree(void *address)
- {
- #ifndef USE_posix_memalign
- if (address)
- MyFree(((void **)address)[-1]);
- #else
- free(address);
- #endif
- }
- static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
- {
- UNUSED_VAR(pp)
- return z7_AlignedAlloc(size);
- }
- static void SzAlignedFree(ISzAllocPtr pp, void *address)
- {
- UNUSED_VAR(pp)
- #ifndef USE_posix_memalign
- if (address)
- MyFree(((void **)address)[-1]);
- #else
- free(address);
- #endif
- }
- const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
- /* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
- #ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
- #if 1
- #define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
- #define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
- #else
- // we can use this simplified code,
- // if (CAlignOffsetAlloc::offset == (k * sizeof(void *))
- #define REAL_BLOCK_PTR_VAR(p) (((void **)(p))[-1])
- #endif
- #endif
- #if 0
- #ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR
- #include <stdio.h>
- static void PrintPtr(const char *s, const void *p)
- {
- const Byte *p2 = (const Byte *)&p;
- unsigned i;
- printf("%s %p ", s, p);
- for (i = sizeof(p); i != 0;)
- {
- i--;
- printf("%02x", p2[i]);
- }
- printf("\n");
- }
- #endif
- #endif
- static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
- {
- #if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR)
- UNUSED_VAR(pp)
- return z7_AlignedAlloc(size);
- #else
- const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
- void *adr;
- void *pAligned;
- size_t newSize;
- size_t extra;
- size_t alignSize = (size_t)1 << p->numAlignBits;
- if (alignSize < sizeof(void *))
- alignSize = sizeof(void *);
-
- if (p->offset >= alignSize)
- return NULL;
- /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
- block to prevent cache line sharing with another allocated blocks */
- extra = p->offset & (sizeof(void *) - 1);
- newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
- if (newSize < size)
- return NULL;
- adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
-
- if (!adr)
- return NULL;
- pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
- alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
- #if 0
- printf("\nalignSize = %6x, offset=%6x, size=%8x \n", (unsigned)alignSize, (unsigned)p->offset, (unsigned)size);
- PrintPtr("base", adr);
- PrintPtr("alig", pAligned);
- #endif
- PrintLn();
- Print("- Aligned: ");
- Print(" size="); PrintHex(size, 8);
- Print(" a_size="); PrintHex(newSize, 8);
- Print(" ptr="); PrintAddr(adr);
- Print(" a_ptr="); PrintAddr(pAligned);
- PrintLn();
- REAL_BLOCK_PTR_VAR(pAligned) = adr;
- return pAligned;
- #endif
- }
- static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
- {
- #if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR)
- UNUSED_VAR(pp)
- z7_AlignedFree(address);
- #else
- if (address)
- {
- const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
- PrintLn();
- Print("- Aligned Free: ");
- PrintLn();
- ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
- }
- #endif
- }
- void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
- {
- p->vt.Alloc = AlignOffsetAlloc_Alloc;
- p->vt.Free = AlignOffsetAlloc_Free;
- }
|