CommonLibSSE (powerof3)
MemoryManager.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "RE/S/ScrapHeap.h"
4 
5 namespace 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
22  ScrapHeap heap; // 00
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  static 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  static 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  static REL::Relocation<func_t> func{ RELOCATION_ID(66861, 68117) };
47  return func(this, a_mem, a_alignmentRequired);
48  }
49 
50  [[nodiscard]] ScrapHeap* GetThreadScrapHeap()
51  {
52  using func_t = decltype(&MemoryManager::GetThreadScrapHeap);
53  static 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  static 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  static 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
84  IMemoryHeap* externalHavokAllocator{ nullptr }; // 440
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 
239 namespace 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;
250  using const_reference = const value_type&;
251  using pointer = value_type*;
252  using const_pointer = const value_type*;
254  using const_iterator = 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(SE, AE)
Definition: PCH.h:505
Definition: Relocation.h:210
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
ScrapHeap * GetThreadScrapHeap()
Definition: MemoryManager.h:50
void Deallocate(void *a_mem, bool a_alignmentRequired)
Definition: MemoryManager.h:43
std::size_t failedAllocationSize
Definition: MemoryManager.h:91
ThreadScrapHeap * threadScrapHeap
Definition: MemoryManager.h:78
bool allowPoolUse
Definition: MemoryManager.h:86
static MemoryManager * GetSingleton()
Definition: MemoryManager.h:29
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
void * Reallocate(void *a_oldMem, std::size_t a_newSize, std::int32_t a_alignment, bool a_aligned)
Definition: MemoryManager.h:57
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
void * Allocate(std::size_t a_size, std::int32_t a_alignment, bool a_alignmentRequired)
Definition: MemoryManager.h:36
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
Definition: ScrapHeap.h:10
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
void * get_head() noexcept
Definition: MemoryManager.h:347
const_iterator cend() const noexcept
Definition: MemoryManager.h:295
const void * get_head() const noexcept
Definition: MemoryManager.h:357
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
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 value_type * const_pointer
Definition: MemoryManager.h:252
reference operator[](size_type a_pos) noexcept
Definition: MemoryManager.h:268
Definition: AbsorbEffect.h:6
void * realloc(void *a_ptr, std::size_t a_newSize)
Definition: MemoryManager.h:159
void * calloc(std::size_t a_num, std::size_t a_size)
Definition: MemoryManager.h:138
void * malloc(std::size_t a_size)
Definition: MemoryManager.h:98
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_alloc(std::size_t a_alignment, std::size_t a_size)
Definition: MemoryManager.h:118
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