/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef MOZ_JEMALLOC4 #define MOZ_JEMALLOC_IMPL /* mozmemory_wrap.h needs to be included before MFBT headers */ #include "mozmemory_wrap.h" #include #include "mozilla/Types.h" #if defined(MOZ_NATIVE_JEMALLOC) #include MALLOC_H #else #define DLLEXPORT #include "jemalloc/jemalloc.h" #endif #ifdef XP_WIN #include #endif #ifdef XP_DARWIN #include #endif /* Override some jemalloc defaults */ #ifdef DEBUG #define MOZ_MALLOC_BUILD_OPTIONS ",junk:true" #else #define MOZ_MALLOC_BUILD_OPTIONS ",junk:free" #endif #define MOZ_MALLOC_OPTIONS "narenas:1,tcache:false" MFBT_DATA const char* je_(malloc_conf) = MOZ_MALLOC_OPTIONS MOZ_MALLOC_BUILD_OPTIONS; #ifdef ANDROID #include static void _je_malloc_message(void* cbopaque, const char* s) { __android_log_print(ANDROID_LOG_INFO, "GeckoJemalloc", "%s", s); } void (*je_(malloc_message))(void*, const char* s) = _je_malloc_message; #endif /* Jemalloc supports hooks that are called on chunk * allocate/deallocate/commit/decommit/purge/etc. * * We currently only hook commit, decommit and purge. We do this to tweak * the way chunks are handled so that RSS stays lower than it normally * would with the default jemalloc uses. * This somewhat matches the behavior of mozjemalloc, except it doesn't * rely on a double purge on mac, instead purging directly. (Yes, this * means we can get rid of jemalloc_purge_freed_pages at some point) * * The default for jemalloc is to do the following: * - commit, decommit: nothing * - purge: MEM_RESET on Windows, MADV_FREE on Mac/BSD, MADV_DONTNEED on Linux * * The hooks we setup do the following: * on Windows: * - commit: MEM_COMMIT * - decommit: MEM_DECOMMIT * on Mac: * - purge: mmap new anonymous memory on top of the chunk * * We only set the above hooks, others are left with the default. */ #if defined(XP_WIN) || defined(XP_DARWIN) class JemallocInit { public: JemallocInit() { chunk_hooks_t hooks; size_t hooks_len; unsigned narenas; size_t mib[3]; size_t size; size = sizeof(narenas); je_(mallctl)("arenas.narenas", &narenas, &size, nullptr, 0); size = sizeof(mib) / sizeof(mib[0]); je_(mallctlnametomib)("arena.0.chunk_hooks", mib, &size); /* Set the hooks on all the existing arenas. */ for (unsigned arena = 0; arena < narenas; arena++) { mib[1] = arena; hooks_len = sizeof(hooks); je_(mallctlbymib)(mib, size, &hooks, &hooks_len, nullptr, 0); #ifdef XP_WIN hooks.commit = CommitHook; hooks.decommit = DecommitHook; #endif #ifdef XP_DARWIN hooks.purge = PurgeHook; #endif je_(mallctlbymib)(mib, size, nullptr, nullptr, &hooks, hooks_len); } } private: #ifdef XP_WIN static bool CommitHook(void* chunk, size_t size, size_t offset, size_t length, unsigned arena_ind) { void* addr = reinterpret_cast( reinterpret_cast(chunk) + static_cast(offset)); if (!VirtualAlloc(addr, length, MEM_COMMIT, PAGE_READWRITE)) return true; return false; } static bool DecommitHook(void* chunk, size_t size, size_t offset, size_t length, unsigned arena_ind) { void* addr = reinterpret_cast( reinterpret_cast(chunk) + static_cast(offset)); if (!VirtualFree(addr, length, MEM_DECOMMIT)) MOZ_CRASH(); return false; } #endif #ifdef XP_DARWIN static bool PurgeHook(void* chunk, size_t size, size_t offset, size_t length, unsigned arena_ind) { void* addr = reinterpret_cast( reinterpret_cast(chunk) + static_cast(offset)); void* new_addr = mmap(addr, length, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); return (new_addr != addr); } #endif }; /* For the static constructor from the class above */ JemallocInit gJemallocInit; #endif #else #include #endif /* MOZ_JEMALLOC4 */ /* Provide an abort function for use in jemalloc code */ extern "C" void moz_abort() { MOZ_CRASH(); }