// We only use a custom allocator on linux (for now) // The allocator we chose is 'dlmalloc' (doug lea's malloc). // It's a good allocator for single-threaded programs. // It needs to be configured by setting a bunch of defines. // #ifdef __linux__ // We need this to define dlmalloc, not malloc. #define USE_DL_PREFIX 1 // We don't need mspaces. #define ONLY_MSPACES 0 #define MSPACES 0 // We don't need mallinfo #define NO_MALLINFO 1 // We don't need dlmalloc_inspect_all #define MALLOC_INSPECT_ALL 0 // Disable locking. The entire engine is single-threaded. #define USE_LOCKS 0 // This allocator can use sbrk to obtain RAM. We're going to // emulate sbrk, in order to put it in a different memory region // than the system malloc, which also uses sbrk. #define HAVE_MORECORE 1 #define MORECORE emulated_sbrk #define MORECORE_CANNOT_TRIM 1 // We won't let the memory allocator use mmap. This is because // opening the replay log may be implemented in stdio using mmap. // So using mmap might trigger different results under replay. #define HAVE_MMAP 0 // Fix a warning in dlmalloc. #define MAX_RELEASE_CHECK_RATE INT_MAX // Don't generate random seeds, or time-based seeds. #define USE_DEV_RANDOM 0 #define LACKS_TIME_H 1 // Don't export any dlmalloc functions. #define DLMALLOC_EXPORT static inline #include #include #include #include static char *emulated_sbrk_base; static intptr_t emulated_sbrk_used; static intptr_t emulated_sbrk_limit; // We assume that the increments are already aligned to the system // page size, because dlmalloc does that for us. // // Our emulated sbrk cannot trim the memory size. It can only grow. // static void *emulated_sbrk(intptr_t increment) { if (emulated_sbrk_base == 0) { emulated_sbrk_limit = intptr_t(64) * 1024 * 1024 * 1024; void *map = mmap(nullptr, emulated_sbrk_limit, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); assert(map != MAP_FAILED); assert(map != nullptr); emulated_sbrk_base = (char *)map; emulated_sbrk_used = 0; } int64_t old_used = emulated_sbrk_used; int64_t new_used = emulated_sbrk_used + increment; if (new_used > emulated_sbrk_limit) { return (void *)(-1); } assert(new_used >= old_used); emulated_sbrk_used = new_used; if (new_used > old_used) { int status = mprotect(emulated_sbrk_base + old_used, new_used - old_used, PROT_READ | PROT_WRITE); assert(status == 0); } return emulated_sbrk_base + old_used; } #include "../../ext/dlmalloc.c" namespace eng { static uint32_t hash; void *malloc(size_t size) { void *result = dlmalloc(size); hash += uint32_t(uintptr_t(result)) + 0x83748374; hash += hash << 10; hash ^= hash >> 6; hash += uint32_t(size) + 0x85893489; hash += hash << 10; hash ^= hash >> 6; return result; } void *realloc(void *p, size_t size) { void *result = dlrealloc(p, size); hash += uint32_t(uintptr_t(p)) + 0x74741912; hash += hash << 10; hash ^= hash >> 6; hash += uint32_t(uintptr_t(result)) + 0x68843823; hash += hash << 10; hash ^= hash >> 6; hash += uint32_t(size) + 0x81444120; hash += hash << 10; hash ^= hash >> 6; return result; } void free(void *p) { hash += uint32_t(uintptr_t(p)) + 0x87823448; dlfree(p); } int memhash() { return (hash & 0x3FFFFFFF) | 0x40000000; } } // namespace eng #endif // ifdef __linux__