Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/os/memory.cpp
9903 views
1
/**************************************************************************/
2
/* memory.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
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
31
#include "memory.h"
32
33
#include "core/templates/safe_refcount.h"
34
35
#include <cstdlib>
36
37
void *operator new(size_t p_size, const char *p_description) {
38
return Memory::alloc_static(p_size, false);
39
}
40
41
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) {
42
return p_allocfunc(p_size);
43
}
44
45
#ifdef _MSC_VER
46
void operator delete(void *p_mem, const char *p_description) {
47
CRASH_NOW_MSG("Call to placement delete should not happen.");
48
}
49
50
void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) {
51
CRASH_NOW_MSG("Call to placement delete should not happen.");
52
}
53
54
void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) {
55
CRASH_NOW_MSG("Call to placement delete should not happen.");
56
}
57
#endif
58
59
#ifdef DEBUG_ENABLED
60
SafeNumeric<uint64_t> Memory::mem_usage;
61
SafeNumeric<uint64_t> Memory::max_usage;
62
#endif
63
64
void *Memory::alloc_aligned_static(size_t p_bytes, size_t p_alignment) {
65
DEV_ASSERT(is_power_of_2(p_alignment));
66
67
void *p1, *p2;
68
if ((p1 = (void *)malloc(p_bytes + p_alignment - 1 + sizeof(uint32_t))) == nullptr) {
69
return nullptr;
70
}
71
72
p2 = (void *)(((uintptr_t)p1 + sizeof(uint32_t) + p_alignment - 1) & ~((p_alignment)-1));
73
*((uint32_t *)p2 - 1) = (uint32_t)((uintptr_t)p2 - (uintptr_t)p1);
74
return p2;
75
}
76
77
void *Memory::realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment) {
78
if (p_memory == nullptr) {
79
return alloc_aligned_static(p_bytes, p_alignment);
80
}
81
82
void *ret = alloc_aligned_static(p_bytes, p_alignment);
83
if (ret) {
84
memcpy(ret, p_memory, p_prev_bytes);
85
}
86
free_aligned_static(p_memory);
87
return ret;
88
}
89
90
void Memory::free_aligned_static(void *p_memory) {
91
uint32_t offset = *((uint32_t *)p_memory - 1);
92
void *p = (void *)((uint8_t *)p_memory - offset);
93
free(p);
94
}
95
96
template <bool p_ensure_zero>
97
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
98
#ifdef DEBUG_ENABLED
99
bool prepad = true;
100
#else
101
bool prepad = p_pad_align;
102
#endif
103
104
void *mem;
105
if constexpr (p_ensure_zero) {
106
mem = calloc(1, p_bytes + (prepad ? DATA_OFFSET : 0));
107
} else {
108
mem = malloc(p_bytes + (prepad ? DATA_OFFSET : 0));
109
}
110
111
ERR_FAIL_NULL_V(mem, nullptr);
112
113
if (prepad) {
114
uint8_t *s8 = (uint8_t *)mem;
115
116
uint64_t *s = (uint64_t *)(s8 + SIZE_OFFSET);
117
*s = p_bytes;
118
119
#ifdef DEBUG_ENABLED
120
uint64_t new_mem_usage = mem_usage.add(p_bytes);
121
max_usage.exchange_if_greater(new_mem_usage);
122
#endif
123
return s8 + DATA_OFFSET;
124
} else {
125
return mem;
126
}
127
}
128
129
template void *Memory::alloc_static<true>(size_t p_bytes, bool p_pad_align);
130
template void *Memory::alloc_static<false>(size_t p_bytes, bool p_pad_align);
131
132
void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
133
if (p_memory == nullptr) {
134
return alloc_static(p_bytes, p_pad_align);
135
}
136
137
uint8_t *mem = (uint8_t *)p_memory;
138
139
#ifdef DEBUG_ENABLED
140
bool prepad = true;
141
#else
142
bool prepad = p_pad_align;
143
#endif
144
145
if (prepad) {
146
mem -= DATA_OFFSET;
147
uint64_t *s = (uint64_t *)(mem + SIZE_OFFSET);
148
149
#ifdef DEBUG_ENABLED
150
if (p_bytes > *s) {
151
uint64_t new_mem_usage = mem_usage.add(p_bytes - *s);
152
max_usage.exchange_if_greater(new_mem_usage);
153
} else {
154
mem_usage.sub(*s - p_bytes);
155
}
156
#endif
157
158
if (p_bytes == 0) {
159
free(mem);
160
return nullptr;
161
} else {
162
*s = p_bytes;
163
164
mem = (uint8_t *)realloc(mem, p_bytes + DATA_OFFSET);
165
ERR_FAIL_NULL_V(mem, nullptr);
166
167
s = (uint64_t *)(mem + SIZE_OFFSET);
168
169
*s = p_bytes;
170
171
return mem + DATA_OFFSET;
172
}
173
} else {
174
mem = (uint8_t *)realloc(mem, p_bytes);
175
176
ERR_FAIL_COND_V(mem == nullptr && p_bytes > 0, nullptr);
177
178
return mem;
179
}
180
}
181
182
void Memory::free_static(void *p_ptr, bool p_pad_align) {
183
ERR_FAIL_NULL(p_ptr);
184
185
uint8_t *mem = (uint8_t *)p_ptr;
186
187
#ifdef DEBUG_ENABLED
188
bool prepad = true;
189
#else
190
bool prepad = p_pad_align;
191
#endif
192
193
if (prepad) {
194
mem -= DATA_OFFSET;
195
196
#ifdef DEBUG_ENABLED
197
uint64_t *s = (uint64_t *)(mem + SIZE_OFFSET);
198
mem_usage.sub(*s);
199
#endif
200
201
free(mem);
202
} else {
203
free(mem);
204
}
205
}
206
207
uint64_t Memory::get_mem_available() {
208
return -1; // 0xFFFF...
209
}
210
211
uint64_t Memory::get_mem_usage() {
212
#ifdef DEBUG_ENABLED
213
return mem_usage.get();
214
#else
215
return 0;
216
#endif
217
}
218
219
uint64_t Memory::get_mem_max_usage() {
220
#ifdef DEBUG_ENABLED
221
return max_usage.get();
222
#else
223
return 0;
224
#endif
225
}
226
227
_GlobalNil::_GlobalNil() {
228
left = this;
229
right = this;
230
parent = this;
231
}
232
233
_GlobalNil _GlobalNilClass::_nil;
234
235