Bug 804303 part 2 - Add ability to dynamically replace or supplement jemalloc implementation. r=jlebar,r=khuey

This commit is contained in:
Mike Hommey 2012-12-07 09:32:24 +01:00
Родитель c51f5d814d
Коммит e9c6d8bfe1
18 изменённых файлов: 935 добавлений и 31 удалений

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

@ -71,6 +71,11 @@ if [ ! "$LIBXUL_SDK" ]; then
memory/build/Makefile
"
fi
if [ "$MOZ_REPLACE_MALLOC_LINKAGE" = "dummy library" ]; then
add_makefiles "
memory/replace/dummy/Makefile
"
fi
if [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then
add_makefiles "
other-licenses/android/Makefile

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

@ -7039,8 +7039,81 @@ else
fi
fi
dnl ========================================================
dnl = Enable dynamic replacement of malloc implementation
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(replace-malloc,
[ --enable-replace-malloc Enable ability to dynamically replace the malloc implementation],
MOZ_REPLACE_MALLOC=1,
MOZ_REPLACE_MALLOC= )
if test -n "$MOZ_REPLACE_MALLOC" -a -z "$MOZ_MEMORY"; then
dnl We don't want to enable jemalloc unconditionally because it may be a
dnl deliberate choice not to enable it (bug 702250, for instance)
AC_MSG_ERROR([--enable-replace-malloc requires --enable-jemalloc])
elif test -n "$MOZ_REPLACE_MALLOC"; then
MOZ_NATIVE_JEMALLOC=
dnl Replace-malloc Mac linkage quirks
if test -n "$MACOSX_DEPLOYMENT_TARGET"; then
AC_CACHE_CHECK([how to do weak dynamic linking],
ac_cv_weak_dynamic_linking,
[echo 'extern void foo() __attribute__((weak_import));int bar() { if (foo) foo(); return 0; }' > conftest.c
if AC_TRY_COMMAND([${CC-cc} -o conftest${DLL_SUFFIX} $CFLAGS -dynamiclib $LDFLAGS -Wl,-U,_foo conftest.c $LIBS 1>&5]) &&
test -s conftest${DLL_SUFFIX}; then
dnl There are several ways the linker can put link edit rules in a binary:
dnl - classic info only (for OSX < 10.6)
dnl - dyld info only
dnl - both
if otool -l conftest${DLL_SUFFIX} 2> /dev/null | grep "LC_DYLD_INFO_ONLY" > /dev/null; then
_CLASSIC_INFO=
else
_CLASSIC_INFO=1
fi
if otool -l conftest${DLL_SUFFIX} 2> /dev/null | grep "LC_DYLD_INFO" > /dev/null; then
_DYLD_INFO=1
else
_DYLD_INFO=
fi
dnl With classic info, we need to build with -flat_namespace.
dnl With dyld info, Xcode 4.5 does the right thing without additional flags,
dnl but Xcode < 4.5 requires a dummy library and -flat_namespace because it
dnl forgets to set the weak flag in the dyld info.
dnl See http://glandium.org/blog/?p=2764 for more details.
dnl
dnl Values for ac_cv_weak_dynamic_linking, and subsequently
dnl MOZ_REPLACE_MALLOC_LINKAGE are thus:
dnl - "flat namespace" when -flat_namespace alone is needed
dnl - "dummy library" when a dummy library and -flat_namespace are needed
dnl - "compiler support" when nothing is needed
if test -n "$_DYLD_INFO" && dyldinfo -bind conftest${DLL_SUFFIX} 2> /dev/null | grep "_foo (weak import)" > /dev/null; then
if test -n "$_CLASSIC_INFO"; then
ac_cv_weak_dynamic_linking="flat namespace"
else
ac_cv_weak_dynamic_linking="compiler support"
fi
else
if test -n "$_DYLD_INFO"; then
ac_cv_weak_dynamic_linking="dummy library"
else
ac_cv_weak_dynamic_linking="flat namespace"
fi
fi
else
AC_ERROR([couldn't compile a simple C file])
fi
rm -rf conftest*])
MOZ_REPLACE_MALLOC_LINKAGE="$ac_cv_weak_dynamic_linking"
fi
fi
AC_SUBST(MOZ_REPLACE_MALLOC)
AC_SUBST(MOZ_REPLACE_MALLOC_LINKAGE)
dnl ========================================================
dnl = Jemalloc build setup
dnl ========================================================
if test -z "$MOZ_MEMORY"; then
if test -n "$MOZ_JEMALLOC3"; then
if test -n "$MOZ_JEMALLOC3" -a -z "$MOZ_REPLACE_MALLOC"; then
MOZ_NATIVE_JEMALLOC=1
AC_CHECK_FUNCS(mallctl nallocm,,
[MOZ_NATIVE_JEMALLOC=
@ -8994,8 +9067,13 @@ fi
# Run jemalloc configure script
if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_JEMALLOC3" -a "$MOZ_MEMORY" ; then
if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" -a "$MOZ_JEMALLOC3"; then
ac_configure_args="$_SUBDIR_CONFIG_ARGS --build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_"
if test -n "$MOZ_REPLACE_MALLOC"; then
# When using replace_malloc, we always want memalign and valloc exported from jemalloc.
ac_configure_args="$ac_configure_args ac_cv_func_memalign=yes"
ac_configure_args="$ac_configure_args ac_cv_func_valloc=yes"
fi
case "${OS_ARCH}" in
WINNT|Darwin)
# We want jemalloc functions to be kept hidden on both Mac and Windows
@ -9003,11 +9081,13 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_JEMALLOC3" -a "$MOZ_MEMORY" ; then
ac_configure_args="$ac_configure_args --without-export"
;;
esac
case "$OS_ARCH" in
Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
MANGLE="malloc posix_memalign aligned_alloc calloc realloc free memalign valloc malloc_usable_size"
;;
esac
if test -z "$MOZ_REPLACE_MALLOC"; then
case "$OS_ARCH" in
Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
MANGLE="malloc posix_memalign aligned_alloc calloc realloc free memalign valloc malloc_usable_size"
;;
esac
fi
if test -n "$MANGLE"; then
MANGLED=
JEMALLOC_WRAPPER=

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

@ -19,4 +19,8 @@ endif
DIRS += build
ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
DIRS += replace/dummy
endif
include $(topsrcdir)/config/rules.mk

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

@ -44,4 +44,19 @@ else
SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,jemalloc,$(DEPTH)/memory/mozjemalloc)
endif
ifdef MOZ_REPLACE_MALLOC
DEFINES += -DMOZ_REPLACE_MALLOC
CSRCS += replace_malloc.c
EXPORTS += \
replace_malloc.h \
malloc_decls.h \
$(NULL)
# The zone allocator for OSX needs some jemalloc internal functions
ifeq (Darwin,$(OS_TARGET))
LOCAL_INCLUDES += -I$(topsrcdir)/memory/jemalloc/src/include
endif
endif
include $(topsrcdir)/config/rules.mk

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

@ -4,6 +4,8 @@
#ifdef MOZ_JEMALLOC3
#define MOZ_JEMALLOC_IMPL
#include "mozmemory_wrap.h"
#include "mozilla/Types.h"

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

@ -13,14 +13,30 @@
#ifndef malloc_decls_h
# define malloc_decls_h
# include "jemalloc_types.h"
# ifdef __linux__
typedef void * usable_ptr_t;
# else
typedef const void * usable_ptr_t;
# endif
# define MALLOC_FUNCS_MALLOC 1
# define MALLOC_FUNCS_JEMALLOC 2
# define MALLOC_FUNCS_INIT 4
# define MALLOC_FUNCS_ALL (MALLOC_FUNCS_INIT | MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
#endif /* malloc_decls_h */
#ifndef MALLOC_FUNCS
# define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
#endif
#ifdef MALLOC_DECL
# if MALLOC_FUNCS & MALLOC_FUNCS_INIT
MALLOC_DECL(init, void, const malloc_table_t *)
# endif
# if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC
MALLOC_DECL(malloc, void *, size_t)
MALLOC_DECL(posix_memalign, int, void **, size_t, size_t)
MALLOC_DECL(aligned_alloc, void *, size_t, size_t)
@ -31,6 +47,13 @@ MALLOC_DECL(memalign, void *, size_t, size_t)
MALLOC_DECL(valloc, void *, size_t)
MALLOC_DECL(malloc_usable_size, size_t, usable_ptr_t)
MALLOC_DECL(malloc_good_size, size_t, size_t)
# endif
# if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC
MALLOC_DECL(jemalloc_stats, void, jemalloc_stats_t *)
MALLOC_DECL(jemalloc_purge_freed_pages, void, void)
MALLOC_DECL(jemalloc_free_dirty_pages, void, void)
# endif
#endif /* MALLOC_DECL */
#undef MALLOC_DECL
#undef MALLOC_FUNCS

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

@ -6,6 +6,8 @@
# error Should only compile this file when building with jemalloc 3
#endif
#define MOZ_JEMALLOC_IMPL
#include "mozmemory_wrap.h"
#include "jemalloc_types.h"
#include "mozilla/Types.h"

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

@ -94,12 +94,31 @@
* third-party code, doesn't, but instead has an elaborate way to mangle
* individual functions. See under "Run jemalloc configure script" in
* $(topsrcdir)/configure.in.
*
*
* When building with replace-malloc support, the above still holds, but
* the malloc implementation and jemalloc specific functions are the
* replace-malloc functions from replace_malloc.c.
*
* The actual jemalloc/mozjemalloc implementation is prefixed with "je_".
*
* Thus, when MOZ_REPLACE_MALLOC is defined, the "_impl" suffixed macros
* expand to "je_" prefixed function when building mozjemalloc or
* jemalloc3/mozjemalloc_compat, where MOZ_JEMALLOC_IMPL is defined.
*
* In other cases, the "_impl" suffixed macros follow the original scheme,
* except on Windows and MacOSX, where they would expand to "je_" prefixed
* functions. Instead, they are left unmodified (malloc_impl expands to
* malloc_impl).
*/
#ifndef MOZ_MEMORY
# error Should only include mozmemory_wrap.h when MOZ_MEMORY is set.
#endif
#if defined(MOZ_JEMALLOC_IMPL) && !defined(MOZ_MEMORY_IMPL)
# define MOZ_MEMORY_IMPL
#endif
#if defined(MOZ_MEMORY_IMPL) && !defined(IMPL_MFBT)
# ifdef MFBT_API /* mozilla/Types.h was already included */
# error mozmemory_wrap.h has to be included before mozilla/Types.h when MOZ_MEMORY_IMPL is set and IMPL_MFBT is not.
@ -111,22 +130,33 @@
#if !defined(MOZ_NATIVE_JEMALLOC)
# ifdef MOZ_MEMORY_IMPL
# define MOZ_JEMALLOC_API MFBT_API
# ifdef XP_WIN
# define mozmem_malloc_impl(a) je_ ## a
# define mozmem_dup_impl(a) wrap_ ## a
# elif defined(XP_DARWIN)
# define mozmem_malloc_impl(a) je_ ## a
# if defined(MOZ_JEMALLOC_IMPL) && defined(MOZ_REPLACE_MALLOC)
# define mozmem_malloc_impl(a) je_ ## a
# define mozmem_jemalloc_impl(a) je_ ## a
# else
# define MOZ_MEMORY_API MFBT_API
# if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
# define MOZ_WRAP_NEW_DELETE
# define MOZ_JEMALLOC_API MFBT_API
# if (defined(XP_WIN) || defined(XP_DARWIN))
# if defined(MOZ_REPLACE_MALLOC)
# define mozmem_malloc_impl(a) a ## _impl
# else
# define mozmem_malloc_impl(a) je_ ## a
# endif
# else
# define MOZ_MEMORY_API MFBT_API
# if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
# define MOZ_WRAP_NEW_DELETE
# endif
# endif
# endif
# ifdef XP_WIN
# define mozmem_dup_impl(a) wrap_ ## a
# endif
# endif
# if defined(MOZ_WIDGET_ANDROID)
# define mozmem_malloc_impl(a) __wrap_ ## a
# ifndef mozmem_malloc_impl
# define mozmem_malloc_impl(a) __wrap_ ## a
# endif
# define mozmem_dup_impl(a) __wrap_ ## a
# endif

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

@ -0,0 +1,505 @@
/* 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/. */
#ifndef MOZ_MEMORY
# error Should not compile this file when MOZ_MEMORY is not set
#endif
#ifndef MOZ_REPLACE_MALLOC
# error Should not compile this file when replace-malloc is disabled
#endif
#ifdef MOZ_NATIVE_JEMALLOC
# error Should not compile this file when we want to use native jemalloc
#endif
#include "mozmemory_wrap.h"
/* Declare all je_* functions */
#define MALLOC_DECL(name, return_type, ...) \
return_type je_ ## name(__VA_ARGS__);
#include "malloc_decls.h"
#include "mozilla/Likely.h"
/*
* Windows doesn't come with weak imports as they are possible with
* LD_PRELOAD or DYLD_INSERT_LIBRARIES on Linux/OSX. On this platform,
* the replacement functions are defined as variable pointers to the
* function resolved with GetProcAddress() instead of weak definitions
* of functions. On Android, the same needs to happen as well, because
* the Android linker doesn't handle weak linking with non LD_PRELOADed
* libraries, but LD_PRELOADing is not very convenient on Android, with
* the zygote.
*/
#ifdef XP_DARWIN
# define MOZ_REPLACE_WEAK __attribute__((weak_import))
#elif defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID)
# define MOZ_NO_REPLACE_FUNC_DECL
#elif defined(__GNUC__)
# define MOZ_REPLACE_WEAK __attribute__((weak))
#endif
#include "replace_malloc.h"
#define MALLOC_DECL(name, return_type, ...) \
je_ ## name,
static const malloc_table_t malloc_table = {
#include "malloc_decls.h"
};
#ifdef MOZ_NO_REPLACE_FUNC_DECL
# define MALLOC_DECL(name, return_type, ...) \
typedef return_type (replace_ ## name ## _impl_t)(__VA_ARGS__); \
replace_ ## name ## _impl_t *replace_ ## name = NULL;
# define MALLOC_FUNCS MALLOC_FUNCS_ALL
# include "malloc_decls.h"
# ifdef XP_WIN
# include <windows.h>
static void
replace_malloc_init_funcs()
{
char replace_malloc_lib[1024];
if (GetEnvironmentVariableA("MOZ_REPLACE_MALLOC_LIB", (LPSTR)&replace_malloc_lib,
sizeof(replace_malloc_lib)) > 0) {
HMODULE handle = LoadLibraryA(replace_malloc_lib);
if (handle) {
#define MALLOC_DECL(name, ...) \
replace_ ## name = (replace_ ## name ## _impl_t *) GetProcAddress(handle, "replace_" # name);
# define MALLOC_FUNCS MALLOC_FUNCS_ALL
#include "malloc_decls.h"
}
}
}
# elif defined(MOZ_WIDGET_ANDROID)
# include <dlfcn.h>
static void
replace_malloc_init_funcs()
{
char *replace_malloc_lib = getenv("MOZ_REPLACE_MALLOC_LIB");
if (replace_malloc_lib && *replace_malloc_lib) {
void *handle = dlopen(replace_malloc_lib, RTLD_LAZY);
if (handle) {
#define MALLOC_DECL(name, ...) \
replace_ ## name = (replace_ ## name ## _impl_t *) dlsym(handle, "replace_" # name);
# define MALLOC_FUNCS MALLOC_FUNCS_ALL
#include "malloc_decls.h"
}
}
}
# else
# error No implementation for replace_malloc_init_funcs()
# endif
#endif /* MOZ_NO_REPLACE_FUNC_DECL */
/*
* Below is the malloc implementation overriding jemalloc and calling the
* replacement functions if they exist.
*/
/*
* On OSX, MOZ_MEMORY_API is defined to nothing, because malloc functions
* are meant to have hidden visibility. But since the functions are only
* used locally in the zone allocator further below, we can allow the
* compiler to optimize more by switching to static.
*/
#ifdef XP_DARWIN
#undef MOZ_MEMORY_API
#define MOZ_MEMORY_API static
#endif
/*
* Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
* specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
*/
#define MALLOC_DECL(name, return_type, ...) \
MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
#include "malloc_decls.h"
#define MALLOC_DECL(name, return_type, ...) \
MOZ_JEMALLOC_API return_type name ## _impl(__VA_ARGS__);
#define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
#include "malloc_decls.h"
static int replace_malloc_initialized = 0;
static void
init()
{
#ifdef MOZ_NO_REPLACE_FUNC_DECL
replace_malloc_init_funcs();
#endif
// Set this *before* calling replace_init, otherwise if replace_init calls
// malloc() we'll get an infinite loop.
replace_malloc_initialized = 1;
if (replace_init)
replace_init(&malloc_table);
}
void*
malloc_impl(size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_malloc))
return je_malloc(size);
return replace_malloc(size);
}
int
posix_memalign_impl(void **memptr, size_t alignment, size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_posix_memalign))
return je_posix_memalign(memptr, alignment, size);
return replace_posix_memalign(memptr, alignment, size);
}
void*
aligned_alloc_impl(size_t alignment, size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_aligned_alloc))
return je_aligned_alloc(alignment, size);
return replace_aligned_alloc(alignment, size);
}
void*
calloc_impl(size_t num, size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_calloc))
return je_calloc(num, size);
return replace_calloc(num, size);
}
void*
realloc_impl(void *ptr, size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_realloc))
return je_realloc(ptr, size);
return replace_realloc(ptr, size);
}
void
free_impl(void *ptr)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_free))
je_free(ptr);
else
replace_free(ptr);
}
void*
memalign_impl(size_t alignment, size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_memalign))
return je_memalign(alignment, size);
return replace_memalign(alignment, size);
}
void*
valloc_impl(size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_valloc))
return je_valloc(size);
return replace_valloc(size);
}
size_t
malloc_usable_size_impl(usable_ptr_t ptr)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_malloc_usable_size))
return je_malloc_usable_size(ptr);
return replace_malloc_usable_size(ptr);
}
size_t
malloc_good_size_impl(size_t size)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_malloc_good_size))
return je_malloc_good_size(size);
return replace_malloc_good_size(size);
}
void
jemalloc_stats_impl(jemalloc_stats_t *stats)
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_jemalloc_stats))
je_jemalloc_stats(stats);
else
replace_jemalloc_stats(stats);
}
void
jemalloc_purge_freed_pages_impl()
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_jemalloc_purge_freed_pages))
je_jemalloc_purge_freed_pages();
else
replace_jemalloc_purge_freed_pages();
}
void
jemalloc_free_dirty_pages_impl()
{
if (MOZ_UNLIKELY(!replace_malloc_initialized))
init();
if (MOZ_LIKELY(!replace_jemalloc_free_dirty_pages))
je_jemalloc_free_dirty_pages();
else
replace_jemalloc_free_dirty_pages();
}
/* The following comment and definitions are from jemalloc.c: */
#if defined(__GLIBC__) && !defined(__UCLIBC__)
/*
* glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
* to inconsistently reference libc's malloc(3)-compatible functions
* (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
*
* These definitions interpose hooks in glibc. The functions are actually
* passed an extra argument for the caller return address, which will be
* ignored.
*/
typedef void (* __free_hook_type)(void *ptr);
typedef void *(* __malloc_hook_type)(size_t size);
typedef void *(* __realloc_hook_type)(void *ptr, size_t size);
typedef void *(* __memalign_hook_type)(size_t alignment, size_t size);
MOZ_MEMORY_API __free_hook_type __free_hook = free_impl;
MOZ_MEMORY_API __malloc_hook_type __malloc_hook = malloc_impl;
MOZ_MEMORY_API __realloc_hook_type __realloc_hook = realloc_impl;
MOZ_MEMORY_API __memalign_hook_type __memalign_hook = memalign_impl;
#endif
/*
* The following is a OSX zone allocator implementation.
* /!\ WARNING. It assumes the underlying malloc implementation's
* malloc_usable_size returns 0 when the given pointer is not owned by
* the allocator. Sadly, OSX does call zone_size with pointers not
* owned by the allocator.
*/
#ifdef XP_DARWIN
#include <stdlib.h>
#include <malloc/malloc.h>
#include "mozilla/Assertions.h"
static size_t
zone_size(malloc_zone_t *zone, void *ptr)
{
return malloc_usable_size_impl(ptr);
}
static void *
zone_malloc(malloc_zone_t *zone, size_t size)
{
return malloc_impl(size);
}
static void *
zone_calloc(malloc_zone_t *zone, size_t num, size_t size)
{
return calloc_impl(num, size);
}
static void *
zone_realloc(malloc_zone_t *zone, void *ptr, size_t size)
{
if (malloc_usable_size_impl(ptr))
return realloc_impl(ptr, size);
return realloc(ptr, size);
}
static void
zone_free(malloc_zone_t *zone, void *ptr)
{
if (malloc_usable_size_impl(ptr)) {
free_impl(ptr);
return;
}
free(ptr);
}
static void
zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
{
size_t current_size = malloc_usable_size_impl(ptr);
if (current_size) {
MOZ_ASSERT(current_size == size);
free_impl(ptr);
return;
}
free(ptr);
}
static void *
zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
{
void *ptr;
if (posix_memalign_impl(&ptr, alignment, size) == 0)
return ptr;
return NULL;
}
static void *
zone_valloc(malloc_zone_t *zone, size_t size)
{
return valloc_impl(size);
}
static void *
zone_destroy(malloc_zone_t *zone)
{
/* This function should never be called. */
MOZ_CRASH();
}
static size_t
zone_good_size(malloc_zone_t *zone, size_t size)
{
return malloc_good_size_impl(size);
}
#ifdef MOZ_JEMALLOC
#include "jemalloc/internal/jemalloc_internal.h"
static void
zone_force_lock(malloc_zone_t *zone)
{
/* /!\ This calls into jemalloc. It works because we're linked in the
* same library. Stolen from jemalloc's zone.c. */
if (isthreaded)
jemalloc_prefork();
}
static void
zone_force_unlock(malloc_zone_t *zone)
{
/* /!\ This calls into jemalloc. It works because we're linked in the
* same library. Stolen from jemalloc's zone.c. */
if (isthreaded)
jemalloc_postfork_parent();
}
#else
#define JEMALLOC_ZONE_VERSION 6
/* Empty implementations are needed, because fork() calls zone->force_(un)lock
* unconditionally. */
static void
zone_force_lock(malloc_zone_t *zone)
{
}
static void
zone_force_unlock(malloc_zone_t *zone)
{
}
#endif
static malloc_zone_t zone;
static struct malloc_introspection_t zone_introspect;
__attribute__((constructor)) void
register_zone(void)
{
zone.size = (void *)zone_size;
zone.malloc = (void *)zone_malloc;
zone.calloc = (void *)zone_calloc;
zone.valloc = (void *)zone_valloc;
zone.free = (void *)zone_free;
zone.realloc = (void *)zone_realloc;
zone.destroy = (void *)zone_destroy;
zone.zone_name = "replace_malloc_zone";
zone.batch_malloc = NULL;
zone.batch_free = NULL;
zone.introspect = &zone_introspect;
zone.version = JEMALLOC_ZONE_VERSION;
zone.memalign = zone_memalign;
zone.free_definite_size = zone_free_definite_size;
#if (JEMALLOC_ZONE_VERSION >= 8)
zone.pressure_relief = NULL;
#endif
zone_introspect.enumerator = NULL;
zone_introspect.good_size = (void *)zone_good_size;
zone_introspect.check = NULL;
zone_introspect.print = NULL;
zone_introspect.log = NULL;
zone_introspect.force_lock = (void *)zone_force_lock;
zone_introspect.force_unlock = (void *)zone_force_unlock;
zone_introspect.statistics = NULL;
zone_introspect.zone_locked = NULL;
#if (JEMALLOC_ZONE_VERSION >= 7)
zone_introspect.enable_discharge_checking = NULL;
zone_introspect.disable_discharge_checking = NULL;
zone_introspect.discharge = NULL;
#ifdef __BLOCKS__
zone_introspect.enumerate_discharged_pointers = NULL;
#else
zone_introspect.enumerate_unavailable_without_blocks = NULL;
#endif
#endif
/*
* The default purgeable zone is created lazily by OSX's libc. It uses
* the default zone when it is created for "small" allocations
* (< 15 KiB), but assumes the default zone is a scalable_zone. This
* obviously fails when the default zone is the jemalloc zone, so
* malloc_default_purgeable_zone is called beforehand so that the
* default purgeable zone is created when the default zone is still
* a scalable_zone. As purgeable zones only exist on >= 10.6, we need
* to check for the existence of malloc_default_purgeable_zone() at
* run time.
*/
malloc_default_purgeable_zone();
/* Register the custom zone. At this point it won't be the default. */
malloc_zone_register(&zone);
/*
* Unregister and reregister the default zone. On OSX >= 10.6,
* unregistering takes the last registered zone and places it at the
* location of the specified zone. Unregistering the default zone thus
* makes the last registered one the default. On OSX < 10.6,
* unregistering shifts all registered zones. The first registered zone
* then becomes the default.
*/
do {
malloc_zone_t *default_zone = malloc_default_zone();
malloc_zone_unregister(default_zone);
malloc_zone_register(default_zone);
} while (malloc_default_zone() != &zone);
}
#endif

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

@ -0,0 +1,139 @@
/* 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/. */
#ifndef replace_malloc_h
#define replace_malloc_h
/*
* The replace_malloc facility allows an external library to replace or
* supplement the jemalloc implementation.
*
* The external library may be hooked by setting one of the following
* environment variables to the library path:
* - LD_PRELOAD on Linux,
* - DYLD_INSERT_LIBRARIES on OSX,
* - MOZ_REPLACE_MALLOC_LIB on Windows and Android.
*
* An initialization function is called before any malloc replacement
* function, and has the following declaration:
*
* void replace_init(const malloc_table_t *)
*
* The const malloc_table_t pointer given to that function is a table
* containing pointers to the original jemalloc implementation, so that
* replacement functions can call them back if they need to. The pointer
* itself can safely be kept around (no need to copy the table itself).
*
* The functions to be implemented in the external library are of the form:
*
* void *replace_malloc(size_t size)
* {
* // Fiddle with the size if necessary.
* // orig->malloc doesn't have to be called if the external library
* // provides its own allocator, but in this case it will have to
* // implement all functions.
* void *ptr = orig->malloc(size);
* // Do whatever you want with the ptr.
* return ptr;
* }
*
* where "orig" is the pointer obtained from replace_init.
*
* See malloc_decls.h for a list of functions that can be replaced this
* way. The implementations are all in the form:
* return_type replace_name(arguments [,...])
*
* They don't all need to be provided.
*
* Building a replace-malloc library is like rocket science. It can end up
* with things blowing up, especially when trying to use complex types, and
* even more especially when these types come from XPCOM or other parts of the
* Mozilla codebase.
* It is recommended to add the following to a replace-malloc implementation's
* Makefile.in:
* MOZ_GLUE_LDFLAGS = # Don't link against mozglue
* WRAP_LDFLAGS = # Never wrap malloc function calls with -Wl,--wrap
* STL_FLAGS = # Avoid STL wrapping
*
* If your replace-malloc implementation lives under memory/replace, these
* are taken care of by memory/replace/defs.mk.
*/
/* Implementing a replace-malloc library is incompatible with using mozalloc. */
#define MOZ_NO_MOZALLOC 1
#include "mozilla/Types.h"
MOZ_BEGIN_EXTERN_C
#define MALLOC_DECL(name, return_type, ...) \
typedef return_type(name ## _impl_t)(__VA_ARGS__);
#include "malloc_decls.h"
#define MALLOC_DECL(name, return_type, ...) \
name ## _impl_t * name;
typedef struct {
#include "malloc_decls.h"
} malloc_table_t;
/* MOZ_NO_REPLACE_FUNC_DECL and MOZ_REPLACE_WEAK are only defined in
* replace_malloc.c. Normally including this header will add function
* definitions. */
#ifndef MOZ_NO_REPLACE_FUNC_DECL
# ifndef MOZ_REPLACE_WEAK
# define MOZ_REPLACE_WEAK
# endif
# define MALLOC_DECL(name, return_type, ...) \
MOZ_EXPORT return_type replace_ ## name(__VA_ARGS__) MOZ_REPLACE_WEAK;
# define MALLOC_FUNCS MALLOC_FUNCS_ALL
# include "malloc_decls.h"
#endif /* MOZ_NO_REPLACE_FUNC_DECL */
/*
* posix_memalign, aligned_alloc, memalign and valloc all implement some
* kind of aligned memory allocation. For convenience, replace_posix_memalign,
* replace_aligned_alloc and replace_valloc can be automatically derived from
* memalign when MOZ_REPLACE_ONLY_MEMALIGN is defined before including this
* header. PAGE_SIZE also needs to be defined to the appropriate expression.
*/
#ifdef MOZ_REPLACE_ONLY_MEMALIGN
#include <errno.h>
int replace_posix_memalign(void **ptr, size_t alignment, size_t size)
{
if (size == 0) {
*ptr = NULL;
return 0;
}
/* alignment must be a power of two and a multiple of sizeof(void *) */
if (((alignment - 1) & alignment) != 0 || (alignment % sizeof(void *)))
return EINVAL;
*ptr = replace_memalign(alignment, size);
return *ptr ? 0 : ENOMEM;
}
void *replace_aligned_alloc(size_t alignment, size_t size)
{
/* size should be a multiple of alignment */
if (size % alignment)
return NULL;
return replace_memalign(alignment, size);
}
void *replace_valloc(size_t size)
{
return replace_memalign(PAGE_SIZE, size);
}
#endif
MOZ_END_EXTERN_C
#endif /* replace_malloc_h */

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

@ -20,7 +20,9 @@ DIST_INSTALL = 1
endif
CSRCS := $(notdir $(wildcard $(srcdir)/src/src/*.c))
ifneq ($(OS_TARGET),Darwin)
# Only OSX needs the zone allocation implementation, but only if
# replace-malloc is not enabled.
ifneq ($(OS_TARGET)$(MOZ_REPLACE_MALLOC),Darwin)
CSRCS := $(filter-out zone.c,$(CSRCS))
endif

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

@ -44,6 +44,10 @@ endif
DEFINES += -Dabort=moz_abort
DEFINES += -DMOZ_MEMORY_IMPL
ifdef MOZ_REPLACE_MALLOC
DEFINES += -DMOZ_REPLACE_MALLOC
endif
DEFINES += -DMOZ_JEMALLOC_IMPL
include $(topsrcdir)/config/rules.mk

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

@ -1472,6 +1472,7 @@ static void _malloc_postfork(void);
* of malloc_zone_t adapted into osx_zone_types.h.
*/
#ifndef MOZ_REPLACE_MALLOC
#include "osx_zone_types.h"
#define LEOPARD_MALLOC_ZONE_T_VERSION 3
@ -1489,6 +1490,10 @@ static malloc_introspection_t * const ozone_introspect =
(malloc_introspection_t*)(&l_ozone_introspect);
static void szone2ozone(malloc_zone_t *zone, size_t size);
static size_t zone_version_size(int version);
#else
static const bool osx_use_jemalloc = true;
#endif
#endif
/*
@ -6176,7 +6181,7 @@ MALLOC_OUT:
}
#endif
#ifdef MOZ_MEMORY_DARWIN
#if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
/*
* Overwrite the default memory allocator to use jemalloc everywhere.
*/
@ -6255,7 +6260,7 @@ malloc_shutdown()
*
* This means that NO_MAC_JEMALLOC doesn't work on i386.
*/
#if defined(MOZ_MEMORY_DARWIN) && !defined(__i386__)
#if defined(MOZ_MEMORY_DARWIN) && !defined(__i386__) && !defined(MOZ_REPLACE_MALLOC)
#define DARWIN_ONLY(A) if (!osx_use_jemalloc) { A; }
#else
#define DARWIN_ONLY(A)
@ -6316,6 +6321,7 @@ RETURN:
* Exported Symbols) in http://www.akkadia.org/drepper/dsohowto.pdf.
*/
#ifndef MOZ_REPLACE_MALLOC
#if defined(__GNUC__) && !defined(MOZ_MEMORY_DARWIN)
#define MOZ_MEMORY_ELF
#endif
@ -6333,7 +6339,7 @@ __attribute__((noinline))
__attribute__((visibility ("hidden")))
#endif
#endif
#endif /* MOZ_REPLACE_MALLOC */
#ifdef MOZ_MEMORY_ELF
#define MEMALIGN memalign_internal
@ -6594,7 +6600,7 @@ free_impl(void *ptr)
*/
/* This was added by Mozilla for use by SQLite. */
#ifdef MOZ_MEMORY_DARWIN
#if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
static
#else
MOZ_MEMORY_API
@ -6935,8 +6941,9 @@ _malloc_postfork(void)
# include <dlfcn.h>
#endif
#ifdef MOZ_MEMORY_DARWIN
#if defined(MOZ_MEMORY_DARWIN)
#if !defined(MOZ_REPLACE_MALLOC)
static void *
zone_malloc(malloc_zone_t *zone, size_t size)
{
@ -7156,6 +7163,7 @@ szone2ozone(malloc_zone_t *default_zone, size_t size)
l_ozone_introspect.m13 = NULL;
}
}
#endif
__attribute__((constructor))
void
@ -7165,7 +7173,18 @@ jemalloc_darwin_init(void)
abort();
}
#elif defined(__GLIBC__) && !defined(__UCLIBC__)
#endif
/*
* is_malloc(malloc_impl) is some macro magic to detect if malloc_impl is
* defined as "malloc" in mozmemory_wrap.h
*/
#define malloc_is_malloc 1
#define is_malloc_(a) malloc_is_ ## a
#define is_malloc(a) is_malloc_(a)
#if !defined(MOZ_MEMORY_DARWIN) && (is_malloc(malloc_impl) == 1)
# if defined(__GLIBC__) && !defined(__UCLIBC__)
/*
* glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
* to inconsistently reference libc's malloc(3)-compatible functions
@ -7175,18 +7194,19 @@ jemalloc_darwin_init(void)
* passed an extra argument for the caller return address, which will be
* ignored.
*/
MOZ_MEMORY_API void (*__free_hook)(void *ptr) = free;
MOZ_MEMORY_API void *(*__malloc_hook)(size_t size) = malloc;
MOZ_MEMORY_API void *(*__realloc_hook)(void *ptr, size_t size) = realloc;
MOZ_MEMORY_API void (*__free_hook)(void *ptr) = free_impl;
MOZ_MEMORY_API void *(*__malloc_hook)(size_t size) = malloc_impl;
MOZ_MEMORY_API void *(*__realloc_hook)(void *ptr, size_t size) = realloc_impl;
MOZ_MEMORY_API void *(*__memalign_hook)(size_t alignment, size_t size) = MEMALIGN;
#elif defined(RTLD_DEEPBIND)
# elif defined(RTLD_DEEPBIND)
/*
* XXX On systems that support RTLD_GROUP or DF_1_GROUP, do their
* implementations permit similar inconsistencies? Should STV_SINGLETON
* visibility be used for interposition where available?
*/
# error "Interposing malloc is unsafe on this system without libc malloc hooks."
# error "Interposing malloc is unsafe on this system without libc malloc hooks."
# endif
#endif
#ifdef MOZ_MEMORY_WINDOWS

3
memory/replace/defs.mk Normal file
Просмотреть файл

@ -0,0 +1,3 @@
MOZ_GLUE_LDFLAGS = # Don't link against mozglue
WRAP_LDFLAGS = # Never wrap malloc function calls with -Wl,--wrap
STL_FLAGS = # Avoid STL wrapping

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

@ -0,0 +1,19 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = memory
LIBRARY_NAME = replace_malloc
FORCE_SHARED_LIB = 1
NO_DIST_INSTALL = 1
CSRCS = dummy_replace_malloc.c
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,15 @@
/* 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/. */
#include "mozilla/Types.h"
/*
* Dummy functions for linking purpose on OSX with older XCode.
* See details in configure.in, under "Replace-malloc Mac linkage quirks"
*/
#define MALLOC_FUNCS MALLOC_FUNCS_ALL
#define MALLOC_DECL(name, ...) \
MOZ_EXPORT void replace_ ## name() { }
#include "malloc_decls.h"

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

@ -48,7 +48,7 @@ ifeq (WINNT,$(OS_TARGET))
DEFFILE = mozglue.def
mozglue.def: mozglue.def.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(ACDEFINES) $< > $@
GARBAGE += mozglue.def
@ -60,6 +60,32 @@ endif
EXTRA_DSO_LDOPTS += $(MOZ_ZLIB_LIBS)
endif
ifeq (Darwin_1,$(OS_TARGET)_$(MOZ_REPLACE_MALLOC))
EXTRA_DSO_LDOPTS += \
-Wl,-U,_replace_init \
-Wl,-U,_replace_malloc \
-Wl,-U,_replace_posix_memalign \
-Wl,-U,_replace_aligned_alloc \
-Wl,-U,_replace_calloc \
-Wl,-U,_replace_realloc \
-Wl,-U,_replace_free \
-Wl,-U,_replace_memalign \
-Wl,-U,_replace_valloc \
-Wl,-U,_replace_malloc_usable_size \
-Wl,-U,_replace_malloc_good_size \
-Wl,-U,_replace_jemalloc_stats \
-Wl,-U,_replace_jemalloc_purge_freed_pages \
-Wl,-U,_replace_jemalloc_free_dirty_pages \
$(NULL)
ifneq ($(MOZ_REPLACE_MALLOC_LINKAGE),compiler support)
EXTRA_DSO_LDOPTS += -flat_namespace
endif
ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
EXTRA_DSO_LDOPTS += -Wl,-weak_library,$(DEPTH)/memory/replace/dummy/$(DLL_PREFIX)replace_malloc$(DLL_SUFFIX)
endif
endif
ifeq (Android,$(OS_TARGET))
CPPSRCS += BionicGlue.cpp
SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,android,$(DEPTH)/other-licenses/android)

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

@ -7,6 +7,15 @@ LIBRARY mozglue.dll
EXPORTS
#ifdef MOZ_MEMORY
; symbols that are actually useful
#ifdef MOZ_REPLACE_MALLOC
malloc=malloc_impl
calloc=calloc_impl
realloc=realloc_impl
free=free_impl
posix_memalign=posix_memalign_impl
malloc_usable_size=malloc_usable_size_impl
malloc_good_size=malloc_good_size_impl
#else
malloc=je_malloc
calloc=je_calloc
realloc=je_realloc
@ -14,6 +23,7 @@ EXPORTS
posix_memalign=je_posix_memalign
malloc_usable_size=je_malloc_usable_size
malloc_good_size=je_malloc_good_size
#endif
strndup=wrap_strndup
strdup=wrap_strdup
_strdup=wrap_strdup