summaryrefslogtreecommitdiffstats
path: root/memory/build/mozjemalloc.h
blob: df3fbc31b367dea948da07c1154600ffb4984e46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* -*- 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/. */

#ifndef mozjemalloc_h
#define mozjemalloc_h

#include <errno.h>

#include "mozjemalloc_types.h"
#include "mozilla/MacroArgs.h"

// Macro helpers

#define MACRO_CALL(a, b) a b
// Can't use macros recursively, so we need another one doing the same as above.
#define MACRO_CALL2(a, b) a b

#define ARGS_HELPER(name, ...)                                     \
  MACRO_CALL2(MOZ_PASTE_PREFIX_AND_ARG_COUNT(name, ##__VA_ARGS__), \
              (__VA_ARGS__))
#define TYPED_ARGS0()
#define TYPED_ARGS1(t1) t1 arg1
#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

size_t GetKernelPageSize();

// Implement the set of alignment functions in terms of memalign.
template <void* (*memalign)(size_t, size_t)>
struct AlignedAllocator {
  static inline int posix_memalign(void** aMemPtr, size_t aAlignment,
                                   size_t aSize) {
    void* result;

    // alignment must be a power of two and a multiple of sizeof(void*)
    if (((aAlignment - 1) & aAlignment) != 0 || aAlignment < sizeof(void*)) {
      return EINVAL;
    }

    // The 0-->1 size promotion is done in the memalign() call below
    result = memalign(aAlignment, aSize);

    if (!result) {
      return ENOMEM;
    }

    *aMemPtr = result;
    return 0;
  }

  static inline void* aligned_alloc(size_t aAlignment, size_t aSize) {
    if (aSize % aAlignment) {
      return nullptr;
    }
    return memalign(aAlignment, aSize);
  }

  static inline void* valloc(size_t aSize) {
    return memalign(GetKernelPageSize(), aSize);
  }
};

// These classes each implement the same interface.  Writing out the
// interface for each one rather than using inheritance makes things more
// explicit.
//
// Note: compilers are expected to be able to optimize out `this`.

// The MozJemalloc allocator
struct MozJemalloc {
#  define MALLOC_DECL(name, return_type, ...) \
    static inline return_type name(__VA_ARGS__);
#  include "malloc_decls.h"
};

#  ifdef MOZ_PHC
struct MozJemallocPHC : public MozJemalloc {
#    define MALLOC_DECL(name, return_type, ...) \
      static return_type name(__VA_ARGS__);
#    define MALLOC_FUNCS MALLOC_FUNCS_MALLOC_BASE
#    include "malloc_decls.h"

  static inline int posix_memalign(void** aMemPtr, size_t aAlignment,
                                   size_t aSize) {
    return AlignedAllocator<memalign>::posix_memalign(aMemPtr, aAlignment,
                                                      aSize);
  }

  static inline void* aligned_alloc(size_t aAlignment, size_t aSize) {
    return AlignedAllocator<memalign>::aligned_alloc(aAlignment, aSize);
  }

  static inline void* valloc(size_t aSize) {
    return AlignedAllocator<memalign>::valloc(aSize);
  }

  static size_t malloc_usable_size(usable_ptr_t);

  static void jemalloc_stats_internal(jemalloc_stats_t*, jemalloc_bin_stats_t*);

  static void jemalloc_ptr_info(const void*, jemalloc_ptr_info_t*);

#    define MALLOC_DECL(name, return_type, ...) \
      static return_type name(__VA_ARGS__);
#    define MALLOC_FUNCS MALLOC_FUNCS_ARENA_ALLOC
#    include "malloc_decls.h"
};
#  endif

#  ifdef MOZ_REPLACE_MALLOC
// The replace-malloc allocator
struct ReplaceMalloc {
#    define MALLOC_DECL(name, return_type, ...) \
      static return_type name(__VA_ARGS__);
#    include "malloc_decls.h"
};
#  endif

#  ifdef MOZ_PHC
using CanonicalMalloc = MozJemallocPHC;
#  else
using CanonicalMalloc = MozJemalloc;
#  endif

#  ifdef MOZ_REPLACE_MALLOC
using DefaultMalloc = ReplaceMalloc;
#  else
using DefaultMalloc = CanonicalMalloc;
#  endif

// Poison - write "poison" to cells upon deallocation.
constexpr uint8_t kAllocPoison = 0xe5;

// Junk - write this junk value to freshly allocated cells.
constexpr uint8_t kAllocJunk = 0xe4;

#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_with_params(arena_params_t*) { return 0; }

  static void moz_dispose_arena(arena_id_t) {}

  static void moz_set_max_dirty_page_modifier(int32_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"
};

#endif