Bug 1052573 - Add an API for allocation in separate arenas. r?njn draft
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 22 Sep 2017 07:22:38 +0900
changeset 669034 c5928f034a11ef9b1a0cbd9eef8d07818c5f437c
parent 668773 3f7b1837627efa6cc01b9d0c59a4e10e49e030b0
child 669297 ef67698e912570cf64ae77065f4eabda9b3fd7aa
push id81192
push userbmo:mh+mozilla@glandium.org
push dateFri, 22 Sep 2017 11:24:31 +0000
reviewersnjn
bugs1052573
milestone58.0a1
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']