[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:
Greg Roth 2018-07-17 12:46:57 -06:00 коммит произвёл Ehsan
Родитель 41e6028c9e
Коммит c24c9de9f8
5 изменённых файлов: 109 добавлений и 23 удалений

Просмотреть файл

@ -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(