[linux-port] Unix Heap* allocation implementation (#1428)
Heap allocation functions were previously partially implemented via a few macros that provided some of the functionality. This replaces those macros with a more expansive implementation of the interface as defined in Microsoft documents. Simple structs are used to store pointer and size implementation, enabling queries of allocation sized from pointers, putting an upper limit on the total amount of memory allocated by the given heap, retrieving a default heap for the process, and freeing of all heap memory at the time of heap destruction. Most flags are unsupported save ZERO_MEMORY. Heap creation includes an initial size that is meant to preallocate memory and make latter allocations more efficient. This does not support that. Still for the usages in the code base, this should appear externally to be a fully functional implementation. Includes a macro for CaptureStackBackTrace as well for CompilerTest
This commit is contained in:
Родитель
41e6028c9e
Коммит
c24c9de9f8
|
@ -32,6 +32,7 @@
|
|||
#include <typeinfo>
|
||||
#include <vector>
|
||||
#endif // __cplusplus
|
||||
#include <execinfo.h>
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
@ -44,15 +45,6 @@
|
|||
#define CoTaskMemAlloc malloc
|
||||
#define CoTaskMemFree free
|
||||
|
||||
// Windows-specific heap functions. Use malloc/realloc/free instead.
|
||||
#define HeapAlloc(hHeap,dwFlags, nBytes) malloc(nBytes)
|
||||
#define HeapReAlloc(hHeap, dwFlags, voidPtr, nBytes) realloc(voidPtr, nBytes)
|
||||
#define HeapFree(hHeap, dwFlags, voidPtr) free(voidPtr)
|
||||
#define HeapCreate(flags, nBytes, maxSize) malloc(nBytes)
|
||||
|
||||
#define SysFreeString free
|
||||
#define SysAllocStringLen(ptr, size) (wchar_t*)realloc(ptr, (size + 1)*sizeof(wchar_t))
|
||||
|
||||
#define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
#define _countof(a) (sizeof(a) / sizeof(*(a)))
|
||||
|
@ -154,7 +146,8 @@
|
|||
#define STREAM_SEEK_CUR 1
|
||||
#define STREAM_SEEK_END 2
|
||||
|
||||
#define HEAP_NO_SERIALIZE 1
|
||||
#define HEAP_NO_SERIALIZE 0x1
|
||||
#define HEAP_ZERO_MEMORY 0x8
|
||||
|
||||
#define MB_ERR_INVALID_CHARS 0x00000008 // error for invalid chars
|
||||
|
||||
|
@ -191,6 +184,9 @@
|
|||
#define OutputDebugStringA(msg) fputs(msg, stderr)
|
||||
#define OutputDebugFormatA(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
#define CaptureStackBackTrace(FramesToSkip, FramesToCapture, BackTrace, BackTraceHash)\
|
||||
backtrace(BackTrace, FramesToCapture)
|
||||
|
||||
// Event Tracing for Windows (ETW) provides application programmers the ability
|
||||
// to start and stop event tracing sessions, instrument an application to
|
||||
// provide trace events, and consume trace events.
|
||||
|
|
|
@ -56,6 +56,15 @@ BOOL WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer,
|
|||
|
||||
BOOL CloseHandle(_In_ HANDLE hObject);
|
||||
|
||||
// Windows-specific heap functions
|
||||
HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize , SIZE_T dwMaximumSize);
|
||||
BOOL HeapDestroy(HANDLE heap);
|
||||
LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T nBytes);
|
||||
LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
|
||||
BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
|
||||
SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
|
||||
HANDLE GetProcessHeap();
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // LLVM_SUPPORT_WINFUNCTIONS_H
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#define CP_UTF16 1200
|
||||
|
||||
#ifdef _WIN32
|
||||
struct HeapMalloc : public IMalloc {
|
||||
public:
|
||||
ULONG STDMETHODCALLTYPE AddRef() {
|
||||
|
@ -80,9 +79,6 @@ public:
|
|||
{
|
||||
}
|
||||
};
|
||||
#else
|
||||
typedef IMalloc HeapMalloc;
|
||||
#endif
|
||||
|
||||
static HeapMalloc g_HeapMalloc;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
@ -240,4 +241,97 @@ BOOL CloseHandle(_In_ HANDLE hObject) {
|
|||
return !close(fd);
|
||||
}
|
||||
|
||||
// Half-hearted implementation of a heap structure
|
||||
// Enables size queries, maximum allocation limit, and collective free at heap destruction
|
||||
// Does not perform any preallocation or allocation organization.
|
||||
// Does not respect any flags except for HEAP_ZERO_MEMORY
|
||||
struct SimpleAllocation {
|
||||
LPVOID ptr;
|
||||
SIZE_T size;
|
||||
};
|
||||
|
||||
struct SimpleHeap {
|
||||
std::map<LPCVOID, SimpleAllocation> allocs;
|
||||
SIZE_T maxSize, curSize;
|
||||
};
|
||||
|
||||
HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize , SIZE_T dwMaximumSize) {
|
||||
SimpleHeap *simpHeap = new SimpleHeap;
|
||||
simpHeap->maxSize = dwMaximumSize;
|
||||
simpHeap->curSize = 0;
|
||||
return (HANDLE)simpHeap;
|
||||
}
|
||||
|
||||
BOOL HeapDestroy(HANDLE hHeap) {
|
||||
SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
|
||||
|
||||
for (auto it = simpHeap->allocs.begin(), e = simpHeap->allocs.end(); it != e; it++)
|
||||
free(it->second.ptr);
|
||||
|
||||
delete simpHeap;
|
||||
return true;
|
||||
}
|
||||
|
||||
LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) {
|
||||
LPVOID ptr = nullptr;
|
||||
SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
|
||||
|
||||
if (simpHeap->maxSize && simpHeap->curSize + dwBytes > simpHeap->maxSize)
|
||||
return nullptr;
|
||||
|
||||
if (dwFlags == HEAP_ZERO_MEMORY)
|
||||
ptr = calloc(1, dwBytes);
|
||||
else
|
||||
ptr = malloc(dwBytes);
|
||||
|
||||
simpHeap->allocs[ptr] = {ptr, dwBytes};
|
||||
simpHeap->curSize += dwBytes;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) {
|
||||
LPVOID ptr = nullptr;
|
||||
SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
|
||||
SIZE_T oSize = simpHeap->allocs[lpMem].size;
|
||||
|
||||
if (simpHeap->maxSize && simpHeap->curSize - oSize + dwBytes > simpHeap->maxSize)
|
||||
return nullptr;
|
||||
|
||||
ptr = realloc(lpMem, dwBytes);
|
||||
if (dwFlags == HEAP_ZERO_MEMORY && oSize < dwBytes)
|
||||
memset((char*)ptr + oSize, 0, dwBytes - oSize);
|
||||
|
||||
simpHeap->allocs.erase(lpMem);
|
||||
simpHeap->curSize -= oSize;
|
||||
|
||||
simpHeap->allocs[ptr] = {ptr, dwBytes};
|
||||
simpHeap->curSize += dwBytes;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
|
||||
SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
|
||||
SIZE_T oSize = simpHeap->allocs[lpMem].size;
|
||||
|
||||
free(lpMem);
|
||||
|
||||
simpHeap->allocs.erase(lpMem);
|
||||
simpHeap->curSize -= oSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) {
|
||||
SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
|
||||
return simpHeap->allocs[lpMem].size;
|
||||
}
|
||||
|
||||
static SimpleHeap g_processHeap;
|
||||
|
||||
HANDLE GetProcessHeap() {
|
||||
return (HANDLE)&g_processHeap;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
|
|
@ -142,16 +142,7 @@ public:
|
|||
/* [annotation][in] */
|
||||
_In_opt_ _Post_writable_byte_size_(return) void *pv)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HeapSize(m_Handle, 0, pv);
|
||||
#else
|
||||
// Note: There is no way to get the size of the dynamically allocated memory
|
||||
// from the pointer in Linux. Therefore, we'd need to add a member variable
|
||||
// to this class to keep track of the size. Not needed yet.
|
||||
assert(false &&
|
||||
"Can't get the size of dynamically allocated memory from pointer.");
|
||||
return 0;
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
virtual int STDMETHODCALLTYPE DidAlloc(
|
||||
|
|
Загрузка…
Ссылка в новой задаче