Bug 1052573 - Add an API for allocation in separate arenas. r=njn
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 22 Sep 2017 07:22:38 +0900
changeset 382476 a531623c4ec56359d7c6012f62e897318eeb2aa9
parent 382475 14342971a6c8c2a63e8378e2582e016271ac9d1d
child 382477 14dac365b5f6e32b3caab3ab4bd2a75856374c72
push id95346
push userkwierso@gmail.com
push dateFri, 22 Sep 2017 22:06:27 +0000
treeherdermozilla-inbound@bec1b493c91e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1052573
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1052573 - Add an API for allocation in separate arenas. r=njn The implementation is not doing anything just yet. This will be done in a followup bug.
memory/build/fallback.cpp
memory/build/malloc_decls.h
memory/build/moz.build
memory/build/mozjemalloc.cpp
memory/build/mozjemalloc.h
memory/build/mozjemalloc_types.h
memory/build/mozmemory.h
memory/build/mozmemory_wrap.h
memory/moz.build
new file mode 100644
--- /dev/null
+++ b/memory/build/fallback.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "mozmemory.h"
+#include "mozjemalloc.h"
+
+struct SystemMalloc {
+#define MALLOC_DECL(name, return_type, ...) \
+  static inline return_type \
+  name(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
+  { \
+    return ::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
+  }
+#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC_BASE
+#include "malloc_decls.h"
+};
+
+#define MALLOC_DECL(name, return_type, ...) \
+  MOZ_JEMALLOC_API return_type \
+  name(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
+  { \
+    return DummyArenaAllocator<SystemMalloc>::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
+  }
+#define MALLOC_FUNCS MALLOC_FUNCS_ARENA
+#include "malloc_decls.h"
--- a/memory/build/malloc_decls.h
+++ b/memory/build/malloc_decls.h
@@ -17,23 +17,29 @@
 
 #  define MALLOC_FUNCS_MALLOC_BASE 1
 #  define MALLOC_FUNCS_MALLOC_EXTRA 2
 #  define MALLOC_FUNCS_MALLOC (MALLOC_FUNCS_MALLOC_BASE | \
                                MALLOC_FUNCS_MALLOC_EXTRA)
 #  define MALLOC_FUNCS_JEMALLOC 4
 #  define MALLOC_FUNCS_INIT 8
 #  define MALLOC_FUNCS_BRIDGE 16
+#  define MALLOC_FUNCS_ARENA_BASE 32
+#  define MALLOC_FUNCS_ARENA_ALLOC 64
+#  define MALLOC_FUNCS_ARENA (MALLOC_FUNCS_ARENA_BASE | \
+                              MALLOC_FUNCS_ARENA_ALLOC)
 #  define MALLOC_FUNCS_ALL (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE | \
-                            MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
+                            MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC | \
+                            MALLOC_FUNCS_ARENA)
 
 #endif /* malloc_decls_h */
 
 #ifndef MALLOC_FUNCS
-#  define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
+#  define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC | \
+                        MALLOC_FUNCS_ARENA)
 #endif
 
 #ifdef MALLOC_DECL
 #  if MALLOC_FUNCS & MALLOC_FUNCS_INIT
 MALLOC_DECL(init, void, const malloc_table_t *)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_BRIDGE
 MALLOC_DECL(get_bridge, struct ReplaceMallocBridge*)
@@ -96,12 +102,43 @@ MALLOC_DECL(jemalloc_free_dirty_pages, v
 MALLOC_DECL(jemalloc_thread_local_arena, void, bool)
 
 /*
  * Provide information about any allocation enclosing the given address.
  */
 MALLOC_DECL(jemalloc_ptr_info, void, const void*, jemalloc_ptr_info_t*)
 #  endif
 
+#  if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_BASE
+/*
+ * Creates a separate arena, and returns its id, valid to use with moz_arena_*
+ * functions.
+ */
+MALLOC_DECL(moz_create_arena, arena_id_t)
+
+/*
+ * Dispose of the given arena. Subsequent uses of the arena will fail.
+ */
+MALLOC_DECL(moz_dispose_arena, void, arena_id_t)
+#  endif
+
+#  if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_ALLOC
+/*
+ * Same as the functions without the moz_arena_ prefix, but using arenas
+ * created with moz_create_arena.
+ * The contract, even if not enforced at runtime in some configurations,
+ * is that moz_arena_realloc and moz_arena_free will crash if the wrong
+ * arena id is given. All functions will crash if the arena id is invalid.
+ * Although discouraged, plain realloc and free can still be used on
+ * pointers allocated with these functions. Realloc will properly keep
+ * new pointers in the same arena as the original.
+ */
+MALLOC_DECL(moz_arena_malloc, void*, arena_id_t, size_t)
+MALLOC_DECL(moz_arena_calloc, void*, arena_id_t, size_t, size_t)
+MALLOC_DECL(moz_arena_realloc, void*, arena_id_t, void*, size_t)
+MALLOC_DECL(moz_arena_free, void, arena_id_t, void*)
+MALLOC_DECL(moz_arena_memalign, void*, arena_id_t, size_t, size_t)
+#  endif
+
 #endif /* MALLOC_DECL */
 
 #undef MALLOC_DECL
 #undef MALLOC_FUNCS
--- a/memory/build/moz.build
+++ b/memory/build/moz.build
@@ -15,20 +15,25 @@ LIBRARY_DEFINES['MOZ_HAS_MOZGLUE'] = Tru
 DEFINES['MOZ_MEMORY_IMPL'] = True
 
 if CONFIG['MOZ_REPLACE_MALLOC']:
     EXPORTS += [
         'replace_malloc.h',
         'replace_malloc_bridge.h',
     ]
 
-UNIFIED_SOURCES += [
-    'mozjemalloc.cpp',
-    'mozmemory_wrap.cpp',
-]
+if CONFIG['MOZ_MEMORY']:
+    UNIFIED_SOURCES += [
+        'mozjemalloc.cpp',
+        'mozmemory_wrap.cpp',
+    ]
+else:
+    UNIFIED_SOURCES += [
+        'fallback.cpp',
+    ]
 
 if CONFIG['OS_TARGET'] == 'Darwin' and (CONFIG['MOZ_REPLACE_MALLOC'] or
         CONFIG['MOZ_MEMORY']):
     SOURCES += [
         'zone.c',
     ]
 
 Library('memory')
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -5126,16 +5126,25 @@ MozJemalloc::jemalloc_free_dirty_pages(v
       malloc_spin_lock(&arena->mLock);
       arena->Purge(true);
       malloc_spin_unlock(&arena->mLock);
     }
   }
   malloc_spin_unlock(&arenas_lock);
 }
 
+#define MALLOC_DECL(name, return_type, ...) \
+  template<> inline return_type \
+  MozJemalloc::name(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
+  { \
+    return DummyArenaAllocator<MozJemalloc>::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
+  }
+#define MALLOC_FUNCS MALLOC_FUNCS_ARENA
+#include "malloc_decls.h"
+
 /*
  * End non-standard functions.
  */
 /******************************************************************************/
 /*
  * Begin library-private functions, used by threading libraries for protection
  * of malloc during fork().  These functions are only called if the program is
  * running in threaded mode, so there is no need to check whether the program
@@ -5322,17 +5331,16 @@ init()
   template<> inline return_type \
   ReplaceMalloc::name(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
   { \
     if (MOZ_UNLIKELY(!replace_malloc_initialized)) { \
       init(); \
     } \
     return replace_malloc_table.name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
   }
-#define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
 #include "malloc_decls.h"
 
 MOZ_JEMALLOC_API struct ReplaceMallocBridge*
 get_bridge(void)
 {
   if (MOZ_UNLIKELY(!replace_malloc_initialized))
     init();
   if (MOZ_LIKELY(!replace_get_bridge))
@@ -5369,16 +5377,23 @@ replace_malloc_init_funcs()
     replace_malloc_table.posix_memalign = AlignedAllocator<ReplaceMalloc::memalign>::posix_memalign;
   }
   if (!replace_malloc_table.aligned_alloc && replace_malloc_table.memalign) {
     replace_malloc_table.aligned_alloc = AlignedAllocator<ReplaceMalloc::memalign>::aligned_alloc;
   }
   if (!replace_malloc_table.valloc && replace_malloc_table.memalign) {
     replace_malloc_table.valloc = AlignedAllocator<ReplaceMalloc::memalign>::valloc;
   }
+  if (!replace_malloc_table.moz_create_arena && replace_malloc_table.malloc) {
+#define MALLOC_DECL(name, ...) \
+    replace_malloc_table.name = DummyArenaAllocator<ReplaceMalloc>::name;
+#define MALLOC_FUNCS MALLOC_FUNCS_ARENA
+#include "malloc_decls.h"
+  }
+
 #define MALLOC_DECL(name, ...) \
   if (!replace_malloc_table.name) { \
     replace_malloc_table.name = MozJemalloc::name; \
   }
 #include "malloc_decls.h"
 }
 
 #endif /* MOZ_REPLACE_MALLOC */
@@ -5398,17 +5413,17 @@ replace_malloc_init_funcs()
 #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
 #include "malloc_decls.h"
 
 #undef GENERIC_MALLOC_DECL
 #define GENERIC_MALLOC_DECL(name, return_type, ...) \
   GENERIC_MALLOC_DECL2(name, name, return_type, ##__VA_ARGS__)
 
 #define MALLOC_DECL(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
-#define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
+#define MALLOC_FUNCS (MALLOC_FUNCS_JEMALLOC | MALLOC_FUNCS_ARENA)
 #include "malloc_decls.h"
 /******************************************************************************/
 
 #ifdef HAVE_DLOPEN
 #  include <dlfcn.h>
 #endif
 
 #if defined(__GLIBC__) && !defined(__UCLIBC__)
--- a/memory/build/mozjemalloc.h
+++ b/memory/build/mozjemalloc.h
@@ -21,23 +21,24 @@
 #define TYPED_ARGS2(t1, t2) TYPED_ARGS1(t1), t2 arg2
 #define TYPED_ARGS3(t1, t2, t3) TYPED_ARGS2(t1, t2), t3 arg3
 
 #define ARGS0()
 #define ARGS1(t1) arg1
 #define ARGS2(t1, t2) ARGS1(t1), arg2
 #define ARGS3(t1, t2, t3) ARGS2(t1, t2), arg3
 
+#ifdef MOZ_MEMORY
+
 /* Generic interface exposing the whole public allocator API
  * This facilitates the implementation of things like replace-malloc.
  * Note: compilers are expected to be able to optimize out `this`.
  */
 template <typename T>
 struct Allocator: public T {
-#define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
 #define MALLOC_DECL(name, return_type, ...) \
   static return_type name(__VA_ARGS__);
 #include "malloc_decls.h"
 };
 
 /* The MozJemalloc allocator */
 struct MozJemallocBase {};
 typedef Allocator<MozJemallocBase> MozJemalloc;
@@ -46,8 +47,28 @@ typedef Allocator<MozJemallocBase> MozJe
 /* The replace-malloc allocator */
 struct ReplaceMallocBase {};
 typedef Allocator<ReplaceMallocBase> ReplaceMalloc;
 
 typedef ReplaceMalloc DefaultMalloc;
 #else
 typedef MozJemalloc DefaultMalloc;
 #endif
+
+#endif /* MOZ_MEMORY */
+
+/* Dummy implementation of the moz_arena_* API, falling back to a given
+ * implementation of the base allocator. */
+template <typename T>
+struct DummyArenaAllocator {
+  static arena_id_t moz_create_arena(void) { return 0; }
+
+  static void moz_dispose_arena(arena_id_t) { }
+
+#define MALLOC_DECL(name, return_type, ...) \
+  static return_type \
+  moz_arena_ ## name(arena_id_t, ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
+  { \
+    return T::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
+  }
+#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC_BASE
+#include "malloc_decls.h"
+};
--- a/memory/build/mozjemalloc_types.h
+++ b/memory/build/mozjemalloc_types.h
@@ -45,16 +45,18 @@ extern "C" {
 #endif
 
 #ifndef MALLOC_USABLE_SIZE_CONST_PTR
 #define MALLOC_USABLE_SIZE_CONST_PTR const
 #endif
 
 typedef MALLOC_USABLE_SIZE_CONST_PTR void* usable_ptr_t;
 
+typedef size_t arena_id_t;
+
 /*
  * jemalloc_stats() is not a stable interface.  When using jemalloc_stats_t, be
  * sure that the compiled results of jemalloc.c are in sync with this header
  * file.
  */
 typedef struct {
 	/*
 	 * Run-time configuration settings.
--- a/memory/build/mozmemory.h
+++ b/memory/build/mozmemory.h
@@ -11,32 +11,30 @@
  *   - malloc_good_size (used to be called je_malloc_usable_in_advance)
  *   - jemalloc_stats
  *   - jemalloc_purge_freed_pages
  *   - jemalloc_free_dirty_pages
  *   - jemalloc_thread_local_arena
  *   - jemalloc_ptr_info
  */
 
-#ifndef MOZ_MEMORY
-#  error Should not include mozmemory.h when MOZ_MEMORY is not set
+#ifdef MALLOC_H
+#include MALLOC_H
 #endif
-
 #include "mozmemory_wrap.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Types.h"
 #include "mozjemalloc_types.h"
 
+#ifdef MOZ_MEMORY
 /*
  * On OSX, malloc/malloc.h contains the declaration for malloc_good_size,
  * which will call back in jemalloc, through the zone allocator so just use it.
  */
-#ifdef XP_DARWIN
-#  include <malloc/malloc.h>
-#else
+#ifndef XP_DARWIN
 MOZ_MEMORY_API size_t malloc_good_size_impl(size_t size);
 
 /* Note: the MOZ_GLUE_IN_PROGRAM ifdef below is there to avoid -Werror turning
  * the protective if into errors. MOZ_GLUE_IN_PROGRAM is what triggers MFBT_API
  * to use weak imports. */
 
 static inline size_t _malloc_good_size(size_t size) {
 #  if defined(MOZ_GLUE_IN_PROGRAM) && !defined(IMPL_MFBT)
@@ -49,9 +47,16 @@ static inline size_t _malloc_good_size(s
 #  define malloc_good_size _malloc_good_size
 #endif
 
 #define MALLOC_DECL(name, return_type, ...) \
   MOZ_JEMALLOC_API return_type name(__VA_ARGS__);
 #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
 #include "malloc_decls.h"
 
+#endif
+
+#define MALLOC_DECL(name, return_type, ...) \
+  MOZ_JEMALLOC_API return_type name(__VA_ARGS__);
+#define MALLOC_FUNCS MALLOC_FUNCS_ARENA
+#include "malloc_decls.h"
+
 #endif /* mozmemory_h */
--- a/memory/build/mozmemory_wrap.h
+++ b/memory/build/mozmemory_wrap.h
@@ -83,20 +83,16 @@
  *
  * Within libmozglue (when MOZ_MEMORY_IMPL is defined), all the functions
  * should be suffixed with "_impl" both for declarations and use.
  * 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".
  */
 
-#ifndef MOZ_MEMORY
-#  error Should only include mozmemory_wrap.h when MOZ_MEMORY is set.
-#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"
--- a/memory/moz.build
+++ b/memory/moz.build
@@ -3,24 +3,21 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "Memory Allocator")
 
 DIRS += [
+    'build',
     'mozalloc',
     'fallible',
 ]
 
 if not CONFIG['JS_STANDALONE']:
     DIRS += ['volatile']
 
-if CONFIG['MOZ_MEMORY']:
-    # NB: gtest dir is included in toolkit/toolkit.build due to its dependency
-    # on libxul.
-    DIRS += [
-        'build',
-    ]
+# NB: gtest dir is included in toolkit/toolkit.build due to its dependency
+# on libxul.
 
-    if CONFIG['MOZ_REPLACE_MALLOC']:
-        DIRS += ['replace']
+if CONFIG['MOZ_REPLACE_MALLOC']:
+    DIRS += ['replace']