Bug 804303 - Part2: Add ability to dynamically replace or supplement jemalloc implementation. r=jlebar, r=khuey, a=jlebar
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 07 Dec 2012 09:32:24 +0100
changeset 117535 ae773140a8c6d9852bd076f8eca4a61f64d6ba02
parent 117534 4e6a72f7029bae4bb4a8d278b79345ca6428effa
child 117536 a4c1d908de1aab072c06ae4b46781d4a02aabd38
push id28
push userryanvm@gmail.com
push dateFri, 14 Dec 2012 01:37:47 +0000
reviewersjlebar, khuey, jlebar
bugs804303
milestone18.0
Bug 804303 - Part2: Add ability to dynamically replace or supplement jemalloc implementation. r=jlebar, r=khuey, a=jlebar
allmakefiles.sh
configure.in
memory/Makefile.in
memory/build/Makefile.in
memory/build/jemalloc_config.c
memory/build/malloc_decls.h
memory/build/mozjemalloc_compat.c
memory/build/mozmemory_wrap.h
memory/build/replace_malloc.c
memory/build/replace_malloc.h
memory/jemalloc/Makefile.in
memory/mozjemalloc/Makefile.in
memory/mozjemalloc/jemalloc.c
memory/replace/defs.mk
memory/replace/dummy/Makefile.in
memory/replace/dummy/dummy_replace_malloc.c
mozglue/build/Makefile.in
mozglue/build/mozglue.def.in
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -66,16 +66,21 @@ if [ ! "$LIBXUL_SDK" ]; then
   fi
   if [ "$MOZ_MEMORY" ]; then
     add_makefiles "
       memory/Makefile
       memory/mozjemalloc/Makefile
       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
       other-licenses/skia-npapi/Makefile
       mozglue/android/Makefile
     "
   fi
   if [ "$MOZ_LINKER" ]; then
--- a/configure.in
+++ b/configure.in
@@ -7034,18 +7034,91 @@ else
     dnl And we need mozglue symbols to be exported.
     MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS -rdynamic"
   fi
   if test "$MOZ_LINKER" = 1; then
     MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS $ZLIB_LIBS"
   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=
        break])
     if test -n "$MOZ_NATIVE_JEMALLOC"; then
       MOZ_MEMORY=1
       AC_DEFINE(MOZ_MEMORY)
       AC_DEFINE(MOZ_JEMALLOC3)
@@ -8994,30 +9067,37 @@ MOZ_CRASHREPORTER=${MOZ_CRASHREPORTER} \
 if cmp -s ./mozinfo.json.tmp ./mozinfo.json; then
   rm ./mozinfo.json.tmp
 else
   mv -f ./mozinfo.json.tmp ./mozinfo.json
 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
       # See memory/build/mozmemory_wrap.h for details.
       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=
     if test -n "$_WRAP_MALLOC"; then
       JEMALLOC_WRAPPER=__wrap_
     fi
     for mangle in ${MANGLE}; do
       if test -n "$MANGLED"; then
--- a/memory/Makefile.in
+++ b/memory/Makefile.in
@@ -14,9 +14,13 @@ DIRS += mozjemalloc
 ifdef MOZ_JEMALLOC3
 ifndef MOZ_NATIVE_JEMALLOC
 DIRS += jemalloc
 endif
 endif
 
 DIRS += build
 
+ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
+DIRS += replace/dummy
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/memory/build/Makefile.in
+++ b/memory/build/Makefile.in
@@ -39,9 +39,24 @@ endif
 
 ifndef MOZ_NATIVE_JEMALLOC
 SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,jemalloc,$(DEPTH)/memory/jemalloc)
 endif
 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
--- a/memory/build/jemalloc_config.c
+++ b/memory/build/jemalloc_config.c
@@ -1,14 +1,16 @@
 /* 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_JEMALLOC3
 
+#define MOZ_JEMALLOC_IMPL
+
 #include "mozmemory_wrap.h"
 #include "mozilla/Types.h"
 
 /* Override some jemalloc defaults */
 MFBT_DATA const char * je_(malloc_conf) = "narenas:1,lg_chunk:20";
 
 #ifdef ANDROID
 #include <android/log.h>
--- a/memory/build/malloc_decls.h
+++ b/memory/build/malloc_decls.h
@@ -8,29 +8,52 @@
  *   - function name
  *   - return type
  *   - argument types
  */
 
 #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)
 MALLOC_DECL(calloc, void *, size_t, size_t)
 MALLOC_DECL(realloc, void *, void *, size_t)
 MALLOC_DECL(free, void, void *)
 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
--- a/memory/build/mozjemalloc_compat.c
+++ b/memory/build/mozjemalloc_compat.c
@@ -1,16 +1,18 @@
 /* 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_JEMALLOC3
 #  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"
 
 #if defined(MOZ_NATIVE_JEMALLOC)
 
 MOZ_IMPORT_API int
 je_(mallctl)(const char*, void*, size_t*, void*, size_t);
--- a/memory/build/mozmemory_wrap.h
+++ b/memory/build/mozmemory_wrap.h
@@ -89,49 +89,79 @@
  * That is, the implementation declaration for e.g. strdup would look like:
  *   char* strdup_impl(const char *)
  * That implementation would call malloc by using "malloc_impl".
  *
  * While mozjemalloc uses these "_impl" suffixed helpers, jemalloc3, being
  * 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.
 #  endif
 #  define IMPL_MFBT
 #endif
 
 #include "mozilla/Types.h"
 
 #if !defined(MOZ_NATIVE_JEMALLOC)
 #  ifdef MOZ_MEMORY_IMPL
-#    define MOZ_JEMALLOC_API MFBT_API
+#    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_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_malloc_impl(a)   je_ ## a
 #      define mozmem_dup_impl(a)      wrap_ ## a
-#    elif defined(XP_DARWIN)
-#      define mozmem_malloc_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
-#      endif
 #    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
 
 /* All other jemalloc3 functions are prefixed with "je_", except when
  * building against an unprefixed system jemalloc library */
 #  define je_(a) je_ ## a
 #else /* defined(MOZ_NATIVE_JEMALLOC) */
 #  define je_(a) a
new file mode 100644
--- /dev/null
+++ b/memory/build/replace_malloc.c
@@ -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
new file mode 100644
--- /dev/null
+++ b/memory/build/replace_malloc.h
@@ -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 */
--- a/memory/jemalloc/Makefile.in
+++ b/memory/jemalloc/Makefile.in
@@ -15,17 +15,19 @@ LIBRARY_NAME = jemalloc
 FORCE_STATIC_LIB = 1
 
 ifdef MOZ_GLUE_PROGRAM_LDFLAGS
 SDK_LIBRARY = $(REAL_LIBRARY)
 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
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir)/src/include \
   -Isrc/include \
--- a/memory/mozjemalloc/Makefile.in
+++ b/memory/mozjemalloc/Makefile.in
@@ -39,11 +39,15 @@ LOCAL_INCLUDES += -I$(topsrcdir)/memory/
 # helps us catch memory errors.  See bug 764192 for details on what
 # MOZ_TEMP_INVESTIGATION is for.
 ifeq (,$(filter release esr,$(MOZ_UPDATE_CHANNEL)))
 DEFINES	+= -DMOZ_JEMALLOC_HARD_ASSERTS -DMOZ_TEMP_INVESTIGATION
 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
--- a/memory/mozjemalloc/jemalloc.c
+++ b/memory/mozjemalloc/jemalloc.c
@@ -1467,16 +1467,17 @@ static void	_malloc_postfork(void);
  *     10.7 or later, or 10.5.
  *
  * FIXME:
  *   When later versions of OSX come out (10.8 and up), we need to check their
  *   malloc_zone_t versions. If they're greater than 8, we need a new version
  *   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
 #define SNOW_LEOPARD_MALLOC_ZONE_T_VERSION 6
 #define LION_MALLOC_ZONE_T_VERSION 8
 
 static bool osx_use_jemalloc = false;
 
@@ -1484,16 +1485,20 @@ static bool osx_use_jemalloc = false;
 static lion_malloc_zone l_szone;
 static malloc_zone_t * szone = (malloc_zone_t*)(&l_szone);
 
 static lion_malloc_introspection l_ozone_introspect;
 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
 
 /*
  * End function prototypes.
  */
 /******************************************************************************/
 
 /*
@@ -6171,17 +6176,17 @@ MALLOC_OUT:
 	malloc_initialized = true;
 
 #if defined(NEEDS_PTHREAD_MMAP_UNALIGNED_TSD)
 	if (pthread_key_create(&mmap_unaligned_tsd, NULL) != 0) {
 		malloc_printf("<jemalloc>: Error in pthread_key_create()\n");
 	}
 #endif
 
-#ifdef MOZ_MEMORY_DARWIN
+#if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
 	/*
 	* Overwrite the default memory allocator to use jemalloc everywhere.
 	*/
 	default_zone = malloc_default_zone();
 
 	/*
 	 * We only use jemalloc with MacOS 10.6 and 10.7.  jemalloc is disabled
 	 * on 32-bit builds (10.5 and 32-bit 10.6) due to bug 702250, an
@@ -6250,17 +6255,17 @@ malloc_shutdown()
  * when osx_use_jemalloc is not (dynamically) set.
  *
  * Note that we assume jemalloc is enabled on i386.  This is safe because the
  * only i386 versions of MacOS are 10.5 and 10.6, which we support.  We have to
  * do this because madvise isn't in the malloc zone struct for 10.5.
  *
  * 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)
 #endif
 
 MOZ_MEMORY_API void *
 malloc_impl(size_t size)
 {
@@ -6311,16 +6316,17 @@ RETURN:
  * optimized. What we do in here is define two aliasing symbols (they point to
  * the same code): memalign and memalign_internal. The internal version has
  * hidden visibility and is used in every reference from this file.
  *
  * For more information on this technique, see section 2.2.7 (Avoid Using
  * 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
 
 #ifdef MOZ_MEMORY_SOLARIS
 #  ifdef __SUNPRO_C
 void *
 memalign_impl(size_t alignment, size_t size);
@@ -6328,17 +6334,17 @@ memalign_impl(size_t alignment, size_t s
 #  elif (defined(__GNUC__))
 __attribute__((noinline))
 #  endif
 #else
 #if (defined(MOZ_MEMORY_ELF))
 __attribute__((visibility ("hidden")))
 #endif
 #endif
-
+#endif /* MOZ_REPLACE_MALLOC */
 
 #ifdef MOZ_MEMORY_ELF
 #define MEMALIGN memalign_internal
 #else
 #define MEMALIGN memalign_impl
 #endif
 
 #ifndef MOZ_MEMORY_ELF
@@ -6589,17 +6595,17 @@ free_impl(void *ptr)
  * End malloc(3)-compatible functions.
  */
 /******************************************************************************/
 /*
  * Begin non-standard functions.
  */
 
 /* 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
 #endif
 size_t
 malloc_good_size_impl(size_t size)
 {
 	/*
@@ -6930,18 +6936,19 @@ static void
  * End library-private functions.
  */
 /******************************************************************************/
 
 #ifdef HAVE_DLOPEN
 #  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)
 {
 
 	return (malloc_impl(size));
 }
 
 static void *
@@ -7151,47 +7158,60 @@ szone2ozone(malloc_zone_t *default_zone,
     if (default_zone->version >= LION_MALLOC_ZONE_T_VERSION) {
         l_zone->m17 = NULL;
         l_ozone_introspect.m10 = NULL;
         l_ozone_introspect.m11 = NULL;
         l_ozone_introspect.m12 = NULL;
         l_ozone_introspect.m13 = NULL;
     }
 }
+#endif
 
 __attribute__((constructor))
 void
 jemalloc_darwin_init(void)
 {
 	if (malloc_init_hard())
 		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
  * (bug 493541).
  *
  * These definitions interpose hooks in glibc.  The functions are actually
  * 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
 /*
  * In the new style jemalloc integration jemalloc is built as a separate
  * shared library.  Since we're no longer hooking into the CRT binary,
  * we need to initialize the heap at the first opportunity we get.
  * DLL_PROCESS_ATTACH in DllMain is that opportunity.
new file mode 100644
--- /dev/null
+++ b/memory/replace/defs.mk
@@ -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
new file mode 100644
--- /dev/null
+++ b/memory/replace/dummy/Makefile.in
@@ -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
new file mode 100644
--- /dev/null
+++ b/memory/replace/dummy/dummy_replace_malloc.c
@@ -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"
--- a/mozglue/build/Makefile.in
+++ b/mozglue/build/Makefile.in
@@ -43,28 +43,54 @@ endif
 endif
  
 MOZ_GLUE_LDFLAGS = # Don't link against ourselves
 
 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
 
 ifneq (,$(filter -DEFAULTLIB:mozcrt,$(MOZ_GLUE_LDFLAGS)))
 # Don't install the import library if we use mozcrt
 NO_INSTALL_IMPORT_LIBRARY = 1
 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)
 endif
 
 ifeq (android, $(MOZ_WIDGET_TOOLKIT))
 # Add Android specific code
 EXTRA_DSO_LDOPTS += $(MOZ_ZLIB_LIBS)
--- a/mozglue/build/mozglue.def.in
+++ b/mozglue/build/mozglue.def.in
@@ -2,23 +2,33 @@
 ; 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/.
 
 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
   free=je_free
   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
   wcsdup=wrap_wcsdup
   _wcsdup=wrap_wcsdup
   jemalloc_stats
   jemalloc_free_dirty_pages
   ; A hack to work around the CRT (see giant comment in Makefile.in)