CommonLibSSE NG
Loading...
Searching...
No Matches
MemoryManager.h
Go to the documentation of this file.
1#pragma once
2
3#include "RE/S/ScrapHeap.h"
4
5namespace RE
6{
7 namespace CompactingStore
8 {
9 class Store;
10 }
11
12 class BSSmallBlockAllocator;
13 class IMemoryHeap;
14
16 {
17 public:
19 {
20 public:
21 // members
24 std::uint32_t owningThread; // 98
25 std::uint32_t pad; // 9C
26 };
27 static_assert(sizeof(ThreadScrapHeap) == 0xA0);
28
29 [[nodiscard]] static MemoryManager* GetSingleton()
30 {
31 using func_t = decltype(&MemoryManager::GetSingleton);
32 REL::Relocation<func_t> func{ RELOCATION_ID(11045, 11141) };
33 return func();
34 }
35
36 [[nodiscard]] void* Allocate(std::size_t a_size, std::int32_t a_alignment, bool a_alignmentRequired)
37 {
38 using func_t = decltype(&MemoryManager::Allocate);
39 REL::Relocation<func_t> func{ RELOCATION_ID(66859, 68115) };
40 return func(this, a_size, a_alignment, a_alignmentRequired);
41 }
42
43 void Deallocate(void* a_mem, bool a_alignmentRequired)
44 {
45 using func_t = decltype(&MemoryManager::Deallocate);
46 REL::Relocation<func_t> func{ RELOCATION_ID(66861, 68117) };
47 return func(this, a_mem, a_alignmentRequired);
48 }
49
51 {
52 using func_t = decltype(&MemoryManager::GetThreadScrapHeap);
53 REL::Relocation<func_t> func{ RELOCATION_ID(66841, 68088) };
54 return func(this);
55 }
56
57 [[nodiscard]] void* Reallocate(void* a_oldMem, std::size_t a_newSize, std::int32_t a_alignment, bool a_aligned)
58 {
59 using func_t = decltype(&MemoryManager::Reallocate);
60 REL::Relocation<func_t> func{ RELOCATION_ID(66860, 68116) };
61 return func(this, a_oldMem, a_newSize, a_alignment, a_aligned);
62 }
63
65 {
66 using func_t = decltype(&MemoryManager::RegisterMemoryManager);
67 REL::Relocation<func_t> func{ RELOCATION_ID(35199, 36091) };
68 return func(this);
69 }
70
71 // members
72 bool initialized{ false }; // 000
73 std::uint16_t numHeaps{ 0 }; // 002
74 std::uint16_t numPhysicalHeaps{ 0 }; // 004
75 IMemoryHeap** heaps{ nullptr }; // 008
76 bool* allowOtherContextAllocs{ nullptr }; // 010
77 IMemoryHeap* heapsByContext[127]{ nullptr }; // 018
78 ThreadScrapHeap* threadScrapHeap{ nullptr }; // 410
79 IMemoryHeap** physicalHeaps{ nullptr }; // 418
80 IMemoryHeap* bigAllocHeap{ nullptr }; // 420
81 IMemoryHeap* emergencyHeap{ nullptr }; // 428
85 bool specialHeaps{ false }; // 448
86 bool allowPoolUse{ true }; // 449
87 std::uint32_t sysAllocBytes{ 0 }; // 44C
88 std::uint32_t mallocBytes{ 0 }; // 450
89 std::uint32_t alignmentForPools{ 4 }; // 450
90 std::uint32_t mainThreadMemoryProblemPassSignal{ 0 }; // 458
91 std::size_t failedAllocationSize{ 0 }; // 460
92 std::uint32_t numMemoryProblemPassesRun{ 0 }; // 468
93 std::size_t timeOfLastMemoryProblemPass{ 0 }; // 470
94 IMemoryHeap* defaultHeap{ nullptr }; // 478
95 };
96 static_assert(sizeof(MemoryManager) == 0x480);
97
98 inline void* malloc(std::size_t a_size)
99 {
100 auto heap = MemoryManager::GetSingleton();
101 return heap ?
102 heap->Allocate(a_size, 0, false) :
103 nullptr;
104 }
105
106 template <class T>
107 inline T* malloc(std::size_t a_size)
108 {
109 return static_cast<T*>(malloc(a_size));
110 }
111
112 template <class T>
113 inline T* malloc()
114 {
115 return malloc<T>(sizeof(T));
116 }
117
118 inline void* aligned_alloc(std::size_t a_alignment, std::size_t a_size)
119 {
120 auto heap = MemoryManager::GetSingleton();
121 return heap ?
122 heap->Allocate(a_size, static_cast<std::int32_t>(a_alignment), true) :
123 nullptr;
124 }
125
126 template <class T>
127 inline T* aligned_alloc(std::size_t a_alignment, std::size_t a_size)
128 {
129 return static_cast<T*>(aligned_alloc(a_alignment, a_size));
130 }
131
132 template <class T>
133 inline T* aligned_alloc()
134 {
135 return aligned_alloc<T>(alignof(T), sizeof(T));
136 }
137
138 inline void* calloc(std::size_t a_num, std::size_t a_size)
139 {
140 const auto ret = malloc(a_num * a_size);
141 if (ret) {
142 std::memset(ret, 0, a_num * a_size);
143 }
144 return ret;
145 }
146
147 template <class T>
148 inline T* calloc(std::size_t a_num, std::size_t a_size)
149 {
150 return static_cast<T*>(calloc(a_num, a_size));
151 }
152
153 template <class T>
154 inline T* calloc(std::size_t a_num)
155 {
156 return calloc<T>(a_num, sizeof(T));
157 }
158
159 inline void* realloc(void* a_ptr, std::size_t a_newSize)
160 {
161 auto heap = MemoryManager::GetSingleton();
162 return heap ?
163 heap->Reallocate(a_ptr, a_newSize, 0, false) :
164 nullptr;
165 }
166
167 template <class T>
168 inline T* realloc(void* a_ptr, std::size_t a_newSize)
169 {
170 return static_cast<T*>(realloc(a_ptr, a_newSize));
171 }
172
173 inline void* aligned_realloc(void* a_ptr, std::size_t a_newSize, std::size_t a_alignment)
174 {
175 auto heap = MemoryManager::GetSingleton();
176 return heap ?
177 heap->Reallocate(a_ptr, a_newSize, static_cast<std::int32_t>(a_alignment), true) :
178 nullptr;
179 }
180
181 template <class T>
182 inline T* aligned_realloc(void* a_ptr, std::size_t a_newSize, std::size_t a_alignment)
183 {
184 return static_cast<T*>(aligned_realloc(a_ptr, a_newSize, a_alignment));
185 }
186
187 inline void free(void* a_ptr)
188 {
189 auto heap = MemoryManager::GetSingleton();
190 if (heap) {
191 heap->Deallocate(a_ptr, false);
192 }
193 }
194
195 inline void aligned_free(void* a_ptr)
196 {
197 auto heap = MemoryManager::GetSingleton();
198 if (heap) {
199 heap->Deallocate(a_ptr, true);
200 }
201 }
202}
203
204#define TES_HEAP_REDEFINE_NEW() \
205 [[nodiscard]] inline void* operator new(std::size_t a_count) \
206 { \
207 const auto mem = RE::malloc(a_count); \
208 if (mem) { \
209 return mem; \
210 } else { \
211 stl::report_and_fail("out of memory"sv); \
212 } \
213 } \
214 \
215 [[nodiscard]] inline void* operator new[](std::size_t a_count) \
216 { \
217 const auto mem = RE::malloc(a_count); \
218 if (mem) { \
219 return mem; \
220 } else { \
221 stl::report_and_fail("out of memory"sv); \
222 } \
223 } \
224 \
225 [[nodiscard]] constexpr void* operator new(std::size_t, void* a_ptr) noexcept { return a_ptr; } \
226 [[nodiscard]] constexpr void* operator new[](std::size_t, void* a_ptr) noexcept { return a_ptr; } \
227 [[nodiscard]] constexpr void* operator new(std::size_t, std::align_val_t, void* a_ptr) noexcept { return a_ptr; } \
228 [[nodiscard]] constexpr void* operator new[](std::size_t, std::align_val_t, void* a_ptr) noexcept { return a_ptr; } \
229 \
230 inline void operator delete(void* a_ptr) { RE::free(a_ptr); } \
231 inline void operator delete[](void* a_ptr) { RE::free(a_ptr); } \
232 inline void operator delete(void* a_ptr, std::align_val_t) { RE::aligned_free(a_ptr); } \
233 inline void operator delete[](void* a_ptr, std::align_val_t) { RE::aligned_free(a_ptr); } \
234 inline void operator delete(void* a_ptr, std::size_t) { RE::free(a_ptr); } \
235 inline void operator delete[](void* a_ptr, std::size_t) { RE::free(a_ptr); } \
236 inline void operator delete(void* a_ptr, std::size_t, std::align_val_t) { RE::aligned_free(a_ptr); } \
237 inline void operator delete[](void* a_ptr, std::size_t, std::align_val_t) { RE::aligned_free(a_ptr); }
238
239namespace RE
240{
241 // this class is an implementation detail of operator new[]/delete[]
242 template <class T>
244 {
245 public:
246 using value_type = T;
247 using size_type = std::size_t;
248 using difference_type = std::ptrdiff_t;
252 using const_pointer = const value_type*;
255
256 constexpr SimpleArray() noexcept = default;
257
258 explicit SimpleArray(size_type a_count) { resize(a_count); }
259
261 {
262 static_assert(!std::is_trivially_destructible_v<value_type>, "there's no allocation overhead for trivially destructible types");
263 clear();
264 }
265
267
268 [[nodiscard]] reference operator[](size_type a_pos) noexcept
269 {
270 assert(a_pos < size());
271 return _data[a_pos];
272 }
273
274 [[nodiscard]] const_reference operator[](size_type a_pos) const noexcept
275 {
276 assert(a_pos < size());
277 return _data[a_pos];
278 }
279
280 [[nodiscard]] reference front() noexcept { return operator[](0); }
281 [[nodiscard]] const_reference front() const noexcept { return operator[](0); }
282
283 [[nodiscard]] reference back() noexcept { return operator[](size() - 1); }
284 [[nodiscard]] const_reference back() const noexcept { return operator[](size() - 1); }
285
286 [[nodiscard]] pointer data() noexcept { return _data; }
287 [[nodiscard]] const_pointer data() const noexcept { return _data; }
288
289 [[nodiscard]] iterator begin() noexcept { return _data; }
290 [[nodiscard]] const_iterator begin() const noexcept { return _data; }
291 [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
292
293 [[nodiscard]] iterator end() noexcept { return _data ? _data + size() : nullptr; }
294 [[nodiscard]] const_iterator end() const noexcept { return _data ? _data + size() : nullptr; }
295 [[nodiscard]] const_iterator cend() const noexcept { return end(); }
296
297 [[nodiscard]] bool empty() const noexcept { return size() == 0; }
298
299 [[nodiscard]] size_type size() const noexcept { return _data ? *static_cast<const std::size_t*>(get_head()) : 0; }
300
301 void clear()
302 {
303 if (_data) {
304 std::destroy_n(data(), size());
305 free(get_head());
306 _data = nullptr;
307 }
308 }
309
310 void resize(size_type a_count)
311 {
312 const auto oldSize = size();
313 if (oldSize == a_count) {
314 return;
315 }
316
317 const auto newData = [=]() {
318 auto bytes = sizeof(value_type) * a_count;
319 if constexpr (alignof(value_type) > alignof(std::size_t)) {
320 bytes += sizeof(value_type);
321 } else {
322 bytes += sizeof(std::size_t);
323 }
324
325 const auto data = malloc<std::size_t>(bytes);
326 *data = a_count;
327
328 if constexpr (alignof(value_type) > alignof(std::size_t)) {
329 return reinterpret_cast<pointer>(data) + 1;
330 } else {
331 return reinterpret_cast<pointer>(data + 1);
332 }
333 }();
334
335 if (a_count < oldSize) { // shrink
336 std::uninitialized_move_n(data(), a_count, newData);
337 } else { // grow
338 std::uninitialized_move_n(data(), oldSize, newData);
339 std::uninitialized_default_construct_n(newData + oldSize, a_count - oldSize);
340 }
341
342 clear();
343 _data = newData;
344 }
345
346 protected:
347 [[nodiscard]] void* get_head() noexcept
348 {
349 assert(_data != nullptr);
350 if constexpr (alignof(value_type) > alignof(std::size_t)) {
351 return _data - 1;
352 } else {
353 return reinterpret_cast<std::size_t*>(_data) - 1;
354 }
355 }
356
357 [[nodiscard]] const void* get_head() const noexcept
358 {
359 assert(_data != nullptr);
360 if constexpr (alignof(value_type) > alignof(std::size_t)) {
361 return _data - 1;
362 } else {
363 return reinterpret_cast<const std::size_t*>(_data) - 1;
364 }
365 }
366
367 // members
368 pointer _data{ nullptr }; // 0
369 };
370}
#define RELOCATION_ID(a_se, a_ae)
Definition PCH.h:794
Definition BSSmallBlockAllocator.h:61
Definition CompactingStore.h:15
Definition IMemoryHeap.h:31
Definition MemoryManager.h:16
std::uint16_t numHeaps
Definition MemoryManager.h:73
BSSmallBlockAllocator * smallBlockAllocator
Definition MemoryManager.h:82
std::uint32_t mallocBytes
Definition MemoryManager.h:88
IMemoryHeap * defaultHeap
Definition MemoryManager.h:94
std::uint32_t numMemoryProblemPassesRun
Definition MemoryManager.h:92
std::uint16_t numPhysicalHeaps
Definition MemoryManager.h:74
bool specialHeaps
Definition MemoryManager.h:85
CompactingStore::Store * compactingStore
Definition MemoryManager.h:83
std::uint32_t alignmentForPools
Definition MemoryManager.h:89
void Deallocate(void *a_mem, bool a_alignmentRequired)
Definition MemoryManager.h:43
static MemoryManager * GetSingleton()
Definition MemoryManager.h:29
std::size_t failedAllocationSize
Definition MemoryManager.h:91
void * Reallocate(void *a_oldMem, std::size_t a_newSize, std::int32_t a_alignment, bool a_aligned)
Definition MemoryManager.h:57
ThreadScrapHeap * threadScrapHeap
Definition MemoryManager.h:78
bool allowPoolUse
Definition MemoryManager.h:86
std::uint32_t sysAllocBytes
Definition MemoryManager.h:87
IMemoryHeap ** physicalHeaps
Definition MemoryManager.h:79
IMemoryHeap ** heaps
Definition MemoryManager.h:75
IMemoryHeap * bigAllocHeap
Definition MemoryManager.h:80
ScrapHeap * GetThreadScrapHeap()
Definition MemoryManager.h:50
std::uint32_t mainThreadMemoryProblemPassSignal
Definition MemoryManager.h:90
IMemoryHeap * emergencyHeap
Definition MemoryManager.h:81
std::size_t timeOfLastMemoryProblemPass
Definition MemoryManager.h:93
void RegisterMemoryManager()
Definition MemoryManager.h:64
IMemoryHeap * externalHavokAllocator
Definition MemoryManager.h:84
IMemoryHeap * heapsByContext[127]
Definition MemoryManager.h:77
bool * allowOtherContextAllocs
Definition MemoryManager.h:76
bool initialized
Definition MemoryManager.h:72
void * Allocate(std::size_t a_size, std::int32_t a_alignment, bool a_alignmentRequired)
Definition MemoryManager.h:36
Definition ScrapHeap.h:8
Definition MemoryManager.h:244
const_iterator begin() const noexcept
Definition MemoryManager.h:290
const_iterator end() const noexcept
Definition MemoryManager.h:294
size_type size() const noexcept
Definition MemoryManager.h:299
value_type & reference
Definition MemoryManager.h:249
std::size_t size_type
Definition MemoryManager.h:247
T value_type
Definition MemoryManager.h:246
const_iterator cend() const noexcept
Definition MemoryManager.h:295
pointer data() noexcept
Definition MemoryManager.h:286
iterator begin() noexcept
Definition MemoryManager.h:289
void clear()
Definition MemoryManager.h:301
pointer _data
Definition MemoryManager.h:368
iterator end() noexcept
Definition MemoryManager.h:293
const value_type & const_reference
Definition MemoryManager.h:250
~SimpleArray()
Definition MemoryManager.h:260
reference back() noexcept
Definition MemoryManager.h:283
void * get_head() noexcept
Definition MemoryManager.h:347
value_type * iterator
Definition MemoryManager.h:253
reference front() noexcept
Definition MemoryManager.h:280
void resize(size_type a_count)
Definition MemoryManager.h:310
value_type * pointer
Definition MemoryManager.h:251
bool empty() const noexcept
Definition MemoryManager.h:297
const value_type * const_iterator
Definition MemoryManager.h:254
constexpr SimpleArray() noexcept=default
const_reference front() const noexcept
Definition MemoryManager.h:281
const_reference operator[](size_type a_pos) const noexcept
Definition MemoryManager.h:274
const_pointer data() const noexcept
Definition MemoryManager.h:287
const_iterator cbegin() const noexcept
Definition MemoryManager.h:291
const_reference back() const noexcept
Definition MemoryManager.h:284
std::ptrdiff_t difference_type
Definition MemoryManager.h:248
const void * get_head() const noexcept
Definition MemoryManager.h:357
const value_type * const_pointer
Definition MemoryManager.h:252
reference operator[](size_type a_pos) noexcept
Definition MemoryManager.h:268
Definition Relocation.h:1638
Definition AbsorbEffect.h:6
void * realloc(void *a_ptr, std::size_t a_newSize)
Definition MemoryManager.h:159
T * aligned_alloc()
Definition MemoryManager.h:133
T * malloc()
Definition MemoryManager.h:113
void * calloc(std::size_t a_num, std::size_t a_size)
Definition MemoryManager.h:138
void * aligned_realloc(void *a_ptr, std::size_t a_newSize, std::size_t a_alignment)
Definition MemoryManager.h:173
void free(void *a_ptr)
Definition MemoryManager.h:187
void aligned_free(void *a_ptr)
Definition MemoryManager.h:195
Definition MemoryManager.h:19
ScrapHeap heap
Definition MemoryManager.h:22
ThreadScrapHeap * next
Definition MemoryManager.h:23
std::uint32_t owningThread
Definition MemoryManager.h:24
std::uint32_t pad
Definition MemoryManager.h:25