Bug 1401875 - Replace MALLOC_DECL_VOID with a clever use of templates. r=njn
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 21 Sep 2017 15:27:12 +0900
changeset 431692 4f561b9294aec40e8219bfe46a3ea4e73dbde9e2
parent 431691 1c88655364bef6ed5fdcd4ab2c6e564da529cff1
child 431693 58e2fc0076b728539fdfb632ae314bd911338759
push id7785
push userryanvm@gmail.com
push dateThu, 21 Sep 2017 13:39:55 +0000
treeherdermozilla-beta@06d4034a8a03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1401875
milestone57.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 1401875 - Replace MALLOC_DECL_VOID with a clever use of templates. r=njn This effectively means malloc_hook_table_t is now C++ only, which is not a big problem. This also makes some functions use a return construct with functions that don't return a value (such as free). While that is not allowed in ISO C, it's allowed in C++, so the simplification is welcome (although, retrospectively, it turns out C compilers don't complain about it without -pedantic).
memory/build/malloc_decls.h
memory/build/mozjemalloc.cpp
memory/build/replace_malloc_bridge.h
--- a/memory/build/malloc_decls.h
+++ b/memory/build/malloc_decls.h
@@ -24,40 +24,36 @@
 
 #endif /* malloc_decls_h */
 
 #ifndef MALLOC_FUNCS
 #  define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
 #endif
 
 #ifdef MALLOC_DECL
-#  ifndef MALLOC_DECL_VOID
-#    define MALLOC_DECL_VOID(func, ...) MALLOC_DECL(func, void, __VA_ARGS__)
-#  endif
-
 #  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*)
 #  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_VOID(free, void *)
+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_VOID(jemalloc_stats, jemalloc_stats_t *)
+MALLOC_DECL(jemalloc_stats, void, jemalloc_stats_t *)
 /*
  * On some operating systems (Mac), we use madvise(MADV_FREE) to hand pages
  * back to the operating system.  On Mac, the operating system doesn't take
  * this memory back immediately; instead, the OS takes it back only when the
  * machine is running out of physical memory.
  *
  * This is great from the standpoint of efficiency, but it makes measuring our
  * actual RSS difficult, because pages which we've MADV_FREE'd shouldn't count
@@ -73,35 +69,34 @@ MALLOC_DECL_VOID(jemalloc_stats, jemallo
  *
  * This function is also expensive in that the next time we go to access a page
  * which we've just explicitly decommitted, the operating system has to attach
  * to it a physical page!  If we hadn't run this function, the OS would have
  * less work to do.
  *
  * If MALLOC_DOUBLE_PURGE is not defined, this function does nothing.
  */
-MALLOC_DECL_VOID(jemalloc_purge_freed_pages)
+MALLOC_DECL(jemalloc_purge_freed_pages, void)
 
 /*
  * Free all unused dirty pages in all arenas. Calling this function will slow
  * down subsequent allocations so it is recommended to use it only when
  * memory needs to be reclaimed at all costs (see bug 805855). This function
  * provides functionality similar to mallctl("arenas.purge") in jemalloc 3.
  */
-MALLOC_DECL_VOID(jemalloc_free_dirty_pages)
+MALLOC_DECL(jemalloc_free_dirty_pages, void)
 
 /*
  * Opt in or out of a thread local arena (bool argument is whether to opt-in
  * (true) or out (false)).
  */
-MALLOC_DECL_VOID(jemalloc_thread_local_arena, bool)
+MALLOC_DECL(jemalloc_thread_local_arena, void, bool)
 
 /*
  * Provide information about any allocation enclosing the given address.
  */
-MALLOC_DECL_VOID(jemalloc_ptr_info, const void*, jemalloc_ptr_info_t*)
+MALLOC_DECL(jemalloc_ptr_info, void, const void*, jemalloc_ptr_info_t*)
 #  endif
 
-#  undef MALLOC_DECL_VOID
 #endif /* MALLOC_DECL */
 
 #undef MALLOC_DECL
 #undef MALLOC_FUNCS
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -5211,21 +5211,16 @@ void
 #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
 
-#define GENERIC_MALLOC_DECL(name, return_type, ...) \
-  GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ##__VA_ARGS__)
-#define GENERIC_MALLOC_DECL_VOID(name, ...) \
-  GENERIC_MALLOC_DECL_HELPER(name, , void, ##__VA_ARGS__)
-
 /******************************************************************************/
 #ifdef MOZ_REPLACE_MALLOC
 
 /*
  * 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
@@ -5326,33 +5321,28 @@ init()
   // 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);
   }
 }
 
-#define GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ...) \
+#define MALLOC_DECL(name, return_type, ...) \
   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_DECL(...) MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
-#define MALLOC_DECL_VOID(...) MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
 #define MALLOC_FUNCS (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC)
 #include "malloc_decls.h"
 
-#undef GENERIC_MALLOC_DECL_HELPER
-
 MOZ_JEMALLOC_API struct ReplaceMallocBridge*
 get_bridge(void)
 {
   if (MOZ_UNLIKELY(!replace_malloc_initialized))
     init();
   if (MOZ_LIKELY(!replace_get_bridge))
     return nullptr;
   return replace_get_bridge();
@@ -5398,36 +5388,34 @@ replace_malloc_init_funcs()
   }
 #include "malloc_decls.h"
 }
 
 #endif /* MOZ_REPLACE_MALLOC */
 /******************************************************************************/
 /* Definition of all the _impl functions */
 
-#define GENERIC_MALLOC_DECL_HELPER2(name, name_impl, return, return_type, ...) \
+#define GENERIC_MALLOC_DECL2(name, name_impl, return_type, ...) \
   return_type name_impl(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
   { \
     return DefaultMalloc::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
   }
 
-#define GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ...) \
-  GENERIC_MALLOC_DECL_HELPER2(name, name##_impl, return, return_type, ##__VA_ARGS__)
+#define GENERIC_MALLOC_DECL(name, return_type, ...) \
+  GENERIC_MALLOC_DECL2(name, name##_impl, return_type, ##__VA_ARGS__)
 
 #define MALLOC_DECL(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
-#define MALLOC_DECL_VOID(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
 #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
 #include "malloc_decls.h"
 
-#undef GENERIC_MALLOC_DECL_HELPER
-#define GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ...) \
-  GENERIC_MALLOC_DECL_HELPER2(name, name, return, return_type, ##__VA_ARGS__)
+#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_DECL_VOID(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
 #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
 #include "malloc_decls.h"
 /******************************************************************************/
 
 #ifdef HAVE_DLOPEN
 #  include <dlfcn.h>
 #endif
 
--- a/memory/build/replace_malloc_bridge.h
+++ b/memory/build/replace_malloc_bridge.h
@@ -67,45 +67,59 @@ MFBT_API ReplaceMallocBridge* get_bridge
 
 #define MALLOC_DECL(name, return_type, ...) \
   name ## _impl_t * name;
 
 typedef struct {
 #include "malloc_decls.h"
 } malloc_table_t;
 
+MOZ_END_EXTERN_C
+
+#ifdef __cplusplus
 
 /* Table of malloc hook functions.
  * Those functions are called with the arguments and results of malloc
  * functions after they are called.
  *   e.g. void* (*malloc_hook)(void*, size_t), etc.
  * They can either return the result they're given, or alter it before
  * returning it.
  * The hooks corresponding to functions, like free(void*), that return no
  * value, don't take an extra argument.
  * The table must at least contain a pointer for malloc_hook and free_hook
  * functions. They will be used as fallback if no pointer is given for
  * other allocation functions, like calloc_hook.
  */
+namespace mozilla {
+namespace detail {
+template <typename R, typename... Args>
+struct AllocHookType {
+  using Type = R (*)(R, Args...);
+};
+
+template <typename... Args>
+struct AllocHookType<void, Args...>
+{
+  using Type = void (*)(Args...);
+};
+
+} // namespace detail
+} // namespace mozilla
+
 #define MALLOC_DECL(name, return_type, ...) \
-  return_type (*name ## _hook)(return_type, __VA_ARGS__);
-#define MALLOC_DECL_VOID(name, ...) \
-  void (*name ## _hook)(__VA_ARGS__);
+  typename mozilla::detail::AllocHookType<return_type, ##__VA_ARGS__>::Type \
+    name ## _hook;
 
 typedef struct {
 #include "malloc_decls.h"
   /* Like free_hook, but called before realloc_hook. free_hook is called
    * instead of not given. */
   void (*realloc_hook_before)(void* aPtr);
 } malloc_hook_table_t;
 
-MOZ_END_EXTERN_C
-
-#ifdef __cplusplus
-
 namespace mozilla {
 namespace dmd {
 struct DMDFuncs;
 } // namespace dmd
 
 /* Callbacks to register debug file handles for Poison IO interpose.
  * See Mozilla(|Un)RegisterDebugHandle in xpcom/build/PoisonIOInterposer.h */
 struct DebugFdRegistry