| /* 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 <mozilla/Assertions.h> |
| #include "mozilla/Types.h" |
| |
| #if defined(MOZ_NATIVE_JEMALLOC) |
| #include MALLOC_H |
| #else |
| #define DLLEXPORT |
| #include "jemalloc/jemalloc.h" |
| #endif |
| |
| #ifdef XP_WIN |
| #include <windows.h> |
| #endif |
| #ifdef XP_DARWIN |
| #include <sys/mman.h> |
| #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 <android/log.h> |
| |
| 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<void*>( |
| reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(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<void*>( |
| reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(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<void*>( |
| reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(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 <mozilla/Assertions.h> |
| #endif /* MOZ_JEMALLOC4 */ |
| |
| /* Provide an abort function for use in jemalloc code */ |
| extern "C" void moz_abort() { |
| MOZ_CRASH(); |
| } |