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.
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']