From 5cd3519571c464e9bdff5824fed5303cba2394e6 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 22 Sep 2017 07:22:38 +0900 Subject: [PATCH] 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. --HG-- extra : rebase_source : e301eac77c6bd8247c09d369074ecb8d7b5a1a2f --- memory/build/fallback.cpp | 28 ++++++++++++++++++++++ memory/build/malloc_decls.h | 41 ++++++++++++++++++++++++++++++-- memory/build/moz.build | 13 ++++++---- memory/build/mozjemalloc.cpp | 19 +++++++++++++-- memory/build/mozjemalloc.h | 23 +++++++++++++++++- memory/build/mozjemalloc_types.h | 2 ++ memory/build/mozmemory.h | 17 ++++++++----- memory/build/mozmemory_wrap.h | 4 ---- memory/moz.build | 13 ++++------ 9 files changed, 133 insertions(+), 27 deletions(-) create mode 100644 memory/build/fallback.cpp diff --git a/memory/build/fallback.cpp b/memory/build/fallback.cpp new file mode 100644 index 000000000000..ae1372da534a --- /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::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \ + } +#define MALLOC_FUNCS MALLOC_FUNCS_ARENA +#include "malloc_decls.h" diff --git a/memory/build/malloc_decls.h b/memory/build/malloc_decls.h index 805c3ab35781..8357474af052 100644 --- a/memory/build/malloc_decls.h +++ b/memory/build/malloc_decls.h @@ -22,13 +22,19 @@ # 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 @@ -101,6 +107,37 @@ MALLOC_DECL(jemalloc_thread_local_arena, void, bool) 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 diff --git a/memory/build/moz.build b/memory/build/moz.build index 6477f23872f6..227725ec5b71 100644 --- a/memory/build/moz.build +++ b/memory/build/moz.build @@ -20,10 +20,15 @@ if CONFIG['MOZ_REPLACE_MALLOC']: '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']): diff --git a/memory/build/mozjemalloc.cpp b/memory/build/mozjemalloc.cpp index ff7abf26bc82..fdeaf3b59d14 100644 --- a/memory/build/mozjemalloc.cpp +++ b/memory/build/mozjemalloc.cpp @@ -5131,6 +5131,15 @@ MozJemalloc::jemalloc_free_dirty_pages(void) 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::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \ + } +#define MALLOC_FUNCS MALLOC_FUNCS_ARENA +#include "malloc_decls.h" + /* * End non-standard functions. */ @@ -5327,7 +5336,6 @@ 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* @@ -5374,6 +5382,13 @@ replace_malloc_init_funcs() if (!replace_malloc_table.valloc && replace_malloc_table.memalign) { replace_malloc_table.valloc = AlignedAllocator::valloc; } + if (!replace_malloc_table.moz_create_arena && replace_malloc_table.malloc) { +#define MALLOC_DECL(name, ...) \ + replace_malloc_table.name = DummyArenaAllocator::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; \ @@ -5403,7 +5418,7 @@ replace_malloc_init_funcs() 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" /******************************************************************************/ diff --git a/memory/build/mozjemalloc.h b/memory/build/mozjemalloc.h index b3da5bbe511c..bb8b66cbd2ed 100644 --- a/memory/build/mozjemalloc.h +++ b/memory/build/mozjemalloc.h @@ -26,13 +26,14 @@ #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 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" @@ -51,3 +52,23 @@ 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 +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" +}; diff --git a/memory/build/mozjemalloc_types.h b/memory/build/mozjemalloc_types.h index dc45e7a17654..7ac6f3d072a8 100644 --- a/memory/build/mozjemalloc_types.h +++ b/memory/build/mozjemalloc_types.h @@ -50,6 +50,8 @@ extern "C" { 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 diff --git a/memory/build/mozmemory.h b/memory/build/mozmemory.h index f17ed7cea9b5..ddfe0dc1947d 100644 --- a/memory/build/mozmemory.h +++ b/memory/build/mozmemory.h @@ -16,22 +16,20 @@ * - 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 -#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 @@ -54,4 +52,11 @@ static inline size_t _malloc_good_size(size_t size) { #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 */ diff --git a/memory/build/mozmemory_wrap.h b/memory/build/mozmemory_wrap.h index 30a7416fd5d7..18e7e4bc4d8f 100644 --- a/memory/build/mozmemory_wrap.h +++ b/memory/build/mozmemory_wrap.h @@ -88,10 +88,6 @@ * 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. diff --git a/memory/moz.build b/memory/moz.build index 8a75d9ca4b4a..547f9a4a0fbc 100644 --- a/memory/moz.build +++ b/memory/moz.build @@ -8,6 +8,7 @@ with Files("**"): BUG_COMPONENT = ("Core", "Memory Allocator") DIRS += [ + 'build', 'mozalloc', 'fallible', ] @@ -15,12 +16,8 @@ DIRS += [ 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']