Blender V5.0
BLI_memarena.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
16
17#include <cstdlib>
18#include <cstring>
19
20#include "MEM_guardedalloc.h"
21
22#include "BLI_asan.h"
23#include "BLI_memarena.h"
24#include "BLI_utildefines.h"
25
26#ifdef WITH_MEM_VALGRIND
27# include "valgrind/memcheck.h"
28#else
29# define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) UNUSED_VARS(pool, rzB, is_zeroed)
30# define VALGRIND_DESTROY_MEMPOOL(pool) UNUSED_VARS(pool)
31# define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) UNUSED_VARS(pool, addr, size)
32# define VALGRIND_MOVE_MEMPOOL(pool_a, pool_b) UNUSED_VARS(pool_a, pool_b)
33#endif
34
35#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
36
37struct MemBuf {
40};
41
42struct MemArena {
44 const char *name;
46
48 size_t align;
49
51};
52
54{
55 while (mb != nullptr) {
56 MemBuf *mb_next = mb->next;
57
58 /* Unpoison memory because #MEM_freeN might overwrite it. */
60
61 MEM_freeN(mb);
62 mb = mb_next;
63 }
64}
65
66MemArena *BLI_memarena_new(const size_t bufsize, const char *name)
67{
68 MemArena *ma = MEM_callocN<MemArena>("memarena");
69 ma->bufsize = bufsize;
70 ma->align = 8;
71 ma->name = name;
72
73 VALGRIND_CREATE_MEMPOOL(ma, 0, false);
74
75 return ma;
76}
77
79{
80 ma->use_calloc = true;
81}
82
84{
85 ma->use_calloc = false;
86}
87
88void BLI_memarena_use_align(MemArena *ma, const size_t align)
89{
90 /* Align must be a power of two. */
91 BLI_assert((align & (align - 1)) == 0);
92
93 ma->align = align;
94}
95
97{
99
101
102 MEM_freeN(ma);
103}
104
106#define PADUP(num, amt) (((num) + ((amt) - 1)) & ~((amt) - 1))
107
110{
111 uchar *tmp;
112
113 tmp = (uchar *)PADUP(intptr_t(ma->curbuf), int(ma->align));
114 ma->cursize -= size_t(tmp - ma->curbuf);
115 ma->curbuf = tmp;
116}
117
119{
120 void *ptr;
121
122 /* Ensure proper alignment by rounding size up to multiple of 8. */
123 size = PADUP(size, ma->align);
124
125 if (UNLIKELY(size > ma->cursize)) {
126 if (size > ma->bufsize - (ma->align - 1)) {
127 ma->cursize = PADUP(size + 1, ma->align);
128 }
129 else {
130 ma->cursize = ma->bufsize;
131 }
132
133 MemBuf *mb;
134 if (ma->use_calloc) {
135 mb = static_cast<MemBuf *>(MEM_callocN(sizeof(*mb) + ma->cursize, ma->name));
136 }
137 else {
138 mb = static_cast<MemBuf *>(MEM_mallocN(sizeof(*mb) + ma->cursize, ma->name));
139 }
140 ma->curbuf = mb->data;
141 mb->next = ma->bufs;
142 ma->bufs = mb;
143
145
147 }
148
149 ptr = ma->curbuf;
150 ma->curbuf += size;
151 ma->cursize -= size;
152
154
156
157 return ptr;
158}
159
161{
162 void *ptr;
163
164 /* No need to use this function call if we're calloc'ing by default. */
165 BLI_assert(ma->use_calloc == false);
166
168 BLI_assert(ptr != nullptr);
169 memset(ptr, 0, size);
170
171 return ptr;
172}
173
175{
176 /* Memory arenas must be compatible. */
177 BLI_assert(ma_dst != ma_src);
178 BLI_assert(ma_dst->align == ma_src->align);
179 BLI_assert(ma_dst->use_calloc == ma_src->use_calloc);
180 BLI_assert(ma_dst->bufsize == ma_src->bufsize);
181
182 if (ma_src->bufs == nullptr) {
183 return;
184 }
185
186 if (UNLIKELY(ma_dst->bufs == nullptr)) {
187 BLI_assert(ma_dst->curbuf == nullptr);
188 ma_dst->bufs = ma_src->bufs;
189 ma_dst->curbuf = ma_src->curbuf;
190 ma_dst->cursize = ma_src->cursize;
191 }
192 else {
193 /* Keep the 'ma_dst->curbuf' for simplicity.
194 * Insert buffers after the first. */
195 if (ma_dst->bufs->next != nullptr) {
196 /* Loop over `ma_src` instead of `ma_dst` since it's likely the destination is larger
197 * when used for accumulating from multiple sources. */
198 MemBuf *mb_src = ma_src->bufs;
199 while (mb_src->next) {
200 mb_src = mb_src->next;
201 }
202 mb_src->next = ma_dst->bufs->next;
203 }
204 ma_dst->bufs->next = ma_src->bufs;
205 }
206
207 ma_src->bufs = nullptr;
208 ma_src->curbuf = nullptr;
209 ma_src->cursize = 0;
210
211 VALGRIND_MOVE_MEMPOOL(ma_src, ma_dst);
212 VALGRIND_CREATE_MEMPOOL(ma_src, 0, false);
213}
214
216{
217 if (ma->bufs) {
218 if (ma->bufs->next) {
220 ma->bufs->next = nullptr;
221 }
222
223 const uchar *curbuf_prev = ma->curbuf;
224 ma->curbuf = ma->bufs->data;
226
227 /* restore to original size */
228 const size_t curbuf_used = size_t(curbuf_prev - ma->curbuf);
229 ma->cursize += curbuf_used;
230
231 if (ma->use_calloc) {
232 memset(ma->curbuf, 0, curbuf_used);
233 }
235 }
236
238 VALGRIND_CREATE_MEMPOOL(ma, 0, false);
239}
#define BLI_asan_unpoison(addr, size)
Definition BLI_asan.h:36
#define BLI_asan_poison(addr, size)
Definition BLI_asan.h:31
#define BLI_assert(a)
Definition BLI_assert.h:46
static void memarena_curbuf_align(MemArena *ma)
#define PADUP(num, amt)
void BLI_memarena_use_calloc(MemArena *ma)
#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
void * BLI_memarena_calloc(MemArena *ma, size_t size)
static void memarena_buf_free_all(MemBuf *mb)
MemArena * BLI_memarena_new(const size_t bufsize, const char *name)
#define VALGRIND_MOVE_MEMPOOL(pool_a, pool_b)
#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)
void BLI_memarena_use_malloc(MemArena *ma)
void BLI_memarena_use_align(MemArena *ma, const size_t align)
#define VALGRIND_DESTROY_MEMPOOL(pool)
void BLI_memarena_free(MemArena *ma)
void * BLI_memarena_alloc(MemArena *ma, size_t size)
void BLI_memarena_clear(MemArena *ma)
unsigned char uchar
unsigned int uint
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
const char * name
MemBuf * bufs
uchar * curbuf
const char * name
size_t align
bool use_calloc
size_t cursize
size_t bufsize
uchar data[0]
MemBuf * next
PointerRNA * ptr
Definition wm_files.cc:4238