1 /*************************************************************************/
2 /* memory.h */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #ifndef MEMORY_H
31 #define MEMORY_H
32
33 #include "os/memory_pool_dynamic.h"
34 #include "os/memory_pool_static.h"
35 #include "safe_refcount.h"
36 #include <stddef.h>
37
38 /**
39 @author Juan Linietsky <reduzio@gmail.com>
40 */
41
42 class MID {
43
44 struct Data {
45
46 SafeRefCount refcount;
47 MemoryPoolDynamic::ID id;
48 };
49
50 mutable Data *data;
51
unref()52 void unref() {
53
54 if (!data)
55 return;
56 if (data->refcount.unref()) {
57
58 if (data->id != MemoryPoolDynamic::INVALID_ID)
59 MemoryPoolDynamic::get_singleton()->free(data->id);
60 MemoryPoolStatic::get_singleton()->free(data);
61 }
62
63 data = NULL;
64 }
65
ref(Data * p_data)66 void ref(Data *p_data) {
67
68 if (data == p_data)
69 return;
70 unref();
71
72 if (p_data && p_data->refcount.ref())
73 data = p_data;
74 }
75
76 friend class MID_Lock;
77
lock()78 inline void lock() {
79
80 if (data && data->id != MemoryPoolDynamic::INVALID_ID)
81 MemoryPoolDynamic::get_singleton()->lock(data->id);
82 }
unlock()83 inline void unlock() {
84
85 if (data && data->id != MemoryPoolDynamic::INVALID_ID)
86 MemoryPoolDynamic::get_singleton()->unlock(data->id);
87 }
88
get()89 inline void *get() {
90
91 if (data && data->id != MemoryPoolDynamic::INVALID_ID)
92 return MemoryPoolDynamic::get_singleton()->get(data->id);
93
94 return NULL;
95 }
96
_resize(size_t p_size)97 Error _resize(size_t p_size) {
98
99 if (p_size == 0 && (!data || data->id == MemoryPoolDynamic::INVALID_ID))
100 return OK;
101 if (p_size && !data) {
102 // create data because we'll need it
103 data = (Data *)MemoryPoolStatic::get_singleton()->alloc(sizeof(Data), "MID::Data");
104 ERR_FAIL_COND_V(!data, ERR_OUT_OF_MEMORY);
105 data->refcount.init();
106 data->id = MemoryPoolDynamic::INVALID_ID;
107 }
108
109 if (p_size == 0 && data && data->id == MemoryPoolDynamic::INVALID_ID) {
110
111 MemoryPoolDynamic::get_singleton()->free(data->id);
112 data->id = MemoryPoolDynamic::INVALID_ID;
113 }
114
115 if (p_size > 0) {
116
117 if (data->id == MemoryPoolDynamic::INVALID_ID) {
118
119 data->id = MemoryPoolDynamic::get_singleton()->alloc(p_size, "Unnamed MID");
120 ERR_FAIL_COND_V(data->id == MemoryPoolDynamic::INVALID_ID, ERR_OUT_OF_MEMORY);
121
122 } else {
123
124 MemoryPoolDynamic::get_singleton()->realloc(data->id, p_size);
125 ERR_FAIL_COND_V(data->id == MemoryPoolDynamic::INVALID_ID, ERR_OUT_OF_MEMORY);
126 }
127 }
128
129 return OK;
130 }
131 friend class Memory;
132
MID(MemoryPoolDynamic::ID p_id)133 MID(MemoryPoolDynamic::ID p_id) {
134
135 data = (Data *)MemoryPoolStatic::get_singleton()->alloc(sizeof(Data), "MID::Data");
136 data->refcount.init();
137 data->id = p_id;
138 }
139
140 public:
is_valid()141 bool is_valid() const { return data; }
142 operator bool() const { return data; }
143
get_size()144 size_t get_size() const { return (data && data->id != MemoryPoolDynamic::INVALID_ID) ? MemoryPoolDynamic::get_singleton()->get_size(data->id) : 0; }
resize(size_t p_size)145 Error resize(size_t p_size) { return _resize(p_size); }
146 inline void operator=(const MID &p_mid) { ref(p_mid.data); }
is_locked()147 inline bool is_locked() const { return (data && data->id != MemoryPoolDynamic::INVALID_ID) ? MemoryPoolDynamic::get_singleton()->is_locked(data->id) : false; }
MID(const MID & p_mid)148 inline MID(const MID &p_mid) {
149 data = NULL;
150 ref(p_mid.data);
151 }
MID()152 inline MID() { data = NULL; }
~MID()153 ~MID() { unref(); }
154 };
155
156 class MID_Lock {
157
158 MID mid;
159
160 public:
data()161 void *data() { return mid.get(); }
162
163 void operator=(const MID_Lock &p_lock) {
164 mid.unlock();
165 mid = p_lock.mid;
166 mid.lock();
167 }
MID_Lock(const MID & p_mid)168 inline MID_Lock(const MID &p_mid) {
169 mid = p_mid;
170 mid.lock();
171 }
MID_Lock(const MID_Lock & p_lock)172 inline MID_Lock(const MID_Lock &p_lock) {
173 mid = p_lock.mid;
174 mid.lock();
175 }
MID_Lock()176 MID_Lock() {}
~MID_Lock()177 ~MID_Lock() { mid.unlock(); }
178 };
179
180 class Memory {
181
182 Memory();
183
184 public:
185 static void *alloc_static(size_t p_bytes, const char *p_descr = "");
186 static void *realloc_static(void *p_memory, size_t p_bytes);
187 static void free_static(void *p_ptr);
188 static size_t get_static_mem_available();
189 static size_t get_static_mem_usage();
190 static size_t get_static_mem_max_usage();
191 static void dump_static_mem_to_file(const char *p_file);
192
193 static MID alloc_dynamic(size_t p_bytes, const char *p_descr = "");
194 static Error realloc_dynamic(MID p_mid, size_t p_bytes);
195
196 static size_t get_dynamic_mem_available();
197 static size_t get_dynamic_mem_usage();
198 };
199
200 template <class T>
201 struct MemAalign {
get_alignMemAalign202 static _FORCE_INLINE_ int get_align() { return DEFAULT_ALIGNMENT; }
203 };
204
205 class DefaultAllocator {
206 public:
alloc(size_t p_memory)207 _FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, ""); }
free(void * p_ptr)208 _FORCE_INLINE_ static void free(void *p_ptr) { return Memory::free_static(p_ptr); }
209 };
210
211 void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
212 void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
213
214 void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
215
216 #ifdef DEBUG_MEMORY_ENABLED
217
218 #define memalloc(m_size) Memory::alloc_static(m_size, __FILE__ ":" __STR(__LINE__) ", memalloc.")
219 #define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size)
220 #define memfree(m_size) Memory::free_static(m_size)
221
222 #else
223
224 #define memalloc(m_size) Memory::alloc_static(m_size)
225 #define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size)
226 #define memfree(m_size) Memory::free_static(m_size)
227
228 #endif
229
230 #ifdef DEBUG_MEMORY_ENABLED
231 #define dynalloc(m_size) Memory::alloc_dynamic(m_size, __FILE__ ":" __STR(__LINE__) ", type: DYNAMIC")
232 #define dynrealloc(m_mem, m_size) m_mem.resize(m_size)
233
234 #else
235
236 #define dynalloc(m_size) Memory::alloc_dynamic(m_size)
237 #define dynrealloc(m_mem, m_size) m_mem.resize(m_size)
238
239 #endif
240
postinitialize_handler(void *)241 _ALWAYS_INLINE_ void postinitialize_handler(void *) {}
242
243 template <class T>
_post_initialize(T * p_obj)244 _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
245
246 postinitialize_handler(p_obj);
247 return p_obj;
248 }
249
250 #ifdef DEBUG_MEMORY_ENABLED
251
252 #define memnew(m_class) _post_initialize(new (__FILE__ ":" __STR(__LINE__) ", memnew type: " __STR(m_class)) m_class)
253
254 #else
255
256 #define memnew(m_class) _post_initialize(new ("") m_class)
257
258 #endif
259
new(size_t p_size,void * p_pointer,size_t check,const char * p_description)260 _ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
261 // void *failptr=0;
262 // ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */
263
264 return p_pointer;
265 }
266
267 #define memnew_allocator(m_class, m_allocator) _post_initialize(new (m_allocator::alloc) m_class)
268 #define memnew_placement(m_placement, m_class) _post_initialize(new (m_placement, sizeof(m_class), "") m_class)
269
predelete_handler(void *)270 _ALWAYS_INLINE_ bool predelete_handler(void *) {
271 return true;
272 }
273
274 template <class T>
memdelete(T * p_class)275 void memdelete(T *p_class) {
276
277 if (!predelete_handler(p_class))
278 return; // doesn't want to be deleted
279 p_class->~T();
280 Memory::free_static(p_class);
281 }
282
283 template <class T, class A>
memdelete_allocator(T * p_class)284 void memdelete_allocator(T *p_class) {
285
286 if (!predelete_handler(p_class))
287 return; // doesn't want to be deleted
288 p_class->~T();
289 A::free(p_class);
290 }
291
292 #define memdelete_notnull(m_v) \
293 { \
294 if (m_v) memdelete(m_v); \
295 }
296 #ifdef DEBUG_MEMORY_ENABLED
297
298 #define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count, __FILE__ ":" __STR(__LINE__) ", memnew_arr type: " _STR(m_class))
299
300 #else
301
302 #define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
303
304 #endif
305
306 template <typename T>
307 T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
308
309 if (p_elements == 0)
310 return 0;
311 /** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the
312 same strategy used by std::vector, and the DVector class, so it should be safe.*/
313
314 size_t len = sizeof(T) * p_elements;
315 unsigned int *mem = (unsigned int *)Memory::alloc_static(len + MAX(sizeof(size_t), DEFAULT_ALIGNMENT), p_descr);
316 T *failptr = 0; //get rid of a warning
317 ERR_FAIL_COND_V(!mem, failptr);
318 *mem = p_elements;
319 mem = (unsigned int *)(((uint8_t *)mem) + MAX(sizeof(size_t), DEFAULT_ALIGNMENT));
320 T *elems = (T *)mem;
321
322 /* call operator new */
323 for (size_t i = 0; i < p_elements; i++) {
324 new (&elems[i], sizeof(T), p_descr) T;
325 }
326
327 return (T *)mem;
328 }
329
330 /**
331 * Wonders of having own array functions, you can actually check the length of
332 * an allocated-with memnew_arr() array
333 */
334
335 template <typename T>
memarr_len(const T * p_class)336 size_t memarr_len(const T *p_class) {
337
338 uint8_t *ptr = ((uint8_t *)p_class) - MAX(sizeof(size_t), DEFAULT_ALIGNMENT);
339 return *(size_t *)ptr;
340 }
341
342 template <typename T>
memdelete_arr(T * p_class)343 void memdelete_arr(T *p_class) {
344
345 unsigned int *elems = (unsigned int *)(((uint8_t *)p_class) - MAX(sizeof(size_t), DEFAULT_ALIGNMENT));
346
347 for (unsigned int i = 0; i < *elems; i++) {
348
349 p_class[i].~T();
350 };
351 Memory::free_static(elems);
352 }
353
354 struct _GlobalNil {
355
356 int color;
357 _GlobalNil *right;
358 _GlobalNil *left;
359 _GlobalNil *parent;
360
361 _GlobalNil();
362 };
363
364 struct _GlobalNilClass {
365
366 static _GlobalNil _nil;
367 };
368
369 #endif
370