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