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  REL::Relocation<func_t> func{ REL::ID(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{ REL::ID(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{ REL::ID(68117) };
47  return func(this, a_mem, a_alignmentRequired);
48  }
49 
50  [[nodiscard]] ScrapHeap* GetThreadScrapHeap()
51  {
52  using func_t = decltype(&MemoryManager::GetThreadScrapHeap);
53  REL::Relocation<func_t> func{ REL::ID(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{ REL::ID(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{ REL::ID(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  return malloc(a_num * a_size);
141  }
142 
143  template <class T>
144  inline T* calloc(std::size_t a_num, std::size_t a_size)
145  {
146  return static_cast<T*>(calloc(a_num, a_size));
147  }
148 
149  template <class T>
150  inline T* calloc(std::size_t a_num)
151  {
152  return calloc<T>(a_num, sizeof(T));
153  }
154 
155  inline void* realloc(void* a_ptr, std::size_t a_newSize)
156  {
157  auto heap = MemoryManager::GetSingleton();
158  return heap ?
159  heap->Reallocate(a_ptr, a_newSize, 0, false) :
160  nullptr;
161  }
162 
163  template <class T>
164  inline T* realloc(void* a_ptr, std::size_t a_newSize)
165  {
166  return static_cast<T*>(realloc(a_ptr, a_newSize));
167  }
168 
169  inline void* aligned_realloc(void* a_ptr, std::size_t a_newSize, std::size_t a_alignment)
170  {
171  auto heap = MemoryManager::GetSingleton();
172  return heap ?
173  heap->Reallocate(a_ptr, a_newSize, static_cast<std::int32_t>(a_alignment), true) :
174  nullptr;
175  }
176 
177  template <class T>
178  inline T* aligned_realloc(void* a_ptr, std::size_t a_newSize, std::size_t a_alignment)
179  {
180  return static_cast<T*>(aligned_realloc(a_ptr, a_newSize, a_alignment));
181  }
182 
183  inline void free(void* a_ptr)
184  {
185  auto heap = MemoryManager::GetSingleton();
186  if (heap) {
187  heap->Deallocate(a_ptr, false);
188  }
189  }
190 
191  inline void aligned_free(void* a_ptr)
192  {
193  auto heap = MemoryManager::GetSingleton();
194  if (heap) {
195  heap->Deallocate(a_ptr, true);
196  }
197  }
198 }
199 
200 #define TES_HEAP_REDEFINE_NEW() \
201  [[nodiscard]] inline void* operator new(std::size_t a_count) \
202  { \
203  const auto mem = RE::malloc(a_count); \
204  if (mem) { \
205  return mem; \
206  } else { \
207  stl::report_and_fail("out of memory"sv); \
208  } \
209  } \
210  \
211  [[nodiscard]] inline void* operator new[](std::size_t a_count) \
212  { \
213  const auto mem = RE::malloc(a_count); \
214  if (mem) { \
215  return mem; \
216  } else { \
217  stl::report_and_fail("out of memory"sv); \
218  } \
219  } \
220  \
221  [[nodiscard]] constexpr void* operator new(std::size_t, void* a_ptr) noexcept { return a_ptr; } \
222  [[nodiscard]] constexpr void* operator new[](std::size_t, void* a_ptr) noexcept { return a_ptr; } \
223  [[nodiscard]] constexpr void* operator new(std::size_t, std::align_val_t, void* a_ptr) noexcept { return a_ptr; } \
224  [[nodiscard]] constexpr void* operator new[](std::size_t, std::align_val_t, void* a_ptr) noexcept { return a_ptr; } \
225  \
226  inline void operator delete(void* a_ptr) { RE::free(a_ptr); } \
227  inline void operator delete[](void* a_ptr) { RE::free(a_ptr); } \
228  inline void operator delete(void* a_ptr, std::align_val_t) { RE::aligned_free(a_ptr); } \
229  inline void operator delete[](void* a_ptr, std::align_val_t) { RE::aligned_free(a_ptr); } \
230  inline void operator delete(void* a_ptr, std::size_t) { RE::free(a_ptr); } \
231  inline void operator delete[](void* a_ptr, std::size_t) { RE::free(a_ptr); } \
232  inline void operator delete(void* a_ptr, std::size_t, std::align_val_t) { RE::aligned_free(a_ptr); } \
233  inline void operator delete[](void* a_ptr, std::size_t, std::align_val_t) { RE::aligned_free(a_ptr); }
234 
235 namespace RE
236 {
237  // this class is an implementation detail of operator new[]/delete[]
238  template <class T>
240  {
241  public:
242  using value_type = T;
243  using size_type = std::size_t;
244  using difference_type = std::ptrdiff_t;
246  using const_reference = const value_type&;
247  using pointer = value_type*;
248  using const_pointer = const value_type*;
250  using const_iterator = const value_type*;
251 
252  constexpr SimpleArray() noexcept = default;
253 
254  explicit SimpleArray(size_type a_count) { resize(a_count); }
255 
257  {
258  static_assert(!std::is_trivially_destructible_v<value_type>, "there's no allocation overhead for trivially destructible types");
259  clear();
260  }
261 
263 
264  [[nodiscard]] reference operator[](size_type a_pos) noexcept
265  {
266  assert(a_pos < size());
267  return _data[a_pos];
268  }
269 
270  [[nodiscard]] const_reference operator[](size_type a_pos) const noexcept
271  {
272  assert(a_pos < size());
273  return _data[a_pos];
274  }
275 
276  [[nodiscard]] reference front() noexcept { return operator[](0); }
277  [[nodiscard]] const_reference front() const noexcept { return operator[](0); }
278 
279  [[nodiscard]] reference back() noexcept { return operator[](size() - 1); }
280  [[nodiscard]] const_reference back() const noexcept { return operator[](size() - 1); }
281 
282  [[nodiscard]] pointer data() noexcept { return _data; }
283  [[nodiscard]] const_pointer data() const noexcept { return _data; }
284 
285  [[nodiscard]] iterator begin() noexcept { return _data; }
286  [[nodiscard]] const_iterator begin() const noexcept { return _data; }
287  [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
288 
289  [[nodiscard]] iterator end() noexcept { return _data ? _data + size() : nullptr; }
290  [[nodiscard]] const_iterator end() const noexcept { return _data ? _data + size() : nullptr; }
291  [[nodiscard]] const_iterator cend() const noexcept { return end(); }
292 
293  [[nodiscard]] bool empty() const noexcept { return size() == 0; }
294 
295  [[nodiscard]] size_type size() const noexcept { return _data ? *static_cast<const std::size_t*>(get_head()) : 0; }
296 
297  void clear()
298  {
299  if (_data) {
300  std::destroy_n(data(), size());
301  free(get_head());
302  _data = nullptr;
303  }
304  }
305 
306  void resize(size_type a_count)
307  {
308  const auto oldSize = size();
309  if (oldSize == a_count) {
310  return;
311  }
312 
313  const auto newData = [=]() {
314  auto bytes = sizeof(value_type) * a_count;
315  if constexpr (alignof(value_type) > alignof(std::size_t)) {
316  bytes += sizeof(value_type);
317  } else {
318  bytes += sizeof(std::size_t);
319  }
320 
321  const auto data = malloc<std::size_t>(bytes);
322  *data = a_count;
323 
324  if constexpr (alignof(value_type) > alignof(std::size_t)) {
325  return reinterpret_cast<pointer>(data) + 1;
326  } else {
327  return reinterpret_cast<pointer>(data + 1);
328  }
329  }();
330 
331  if (a_count < oldSize) { // shrink
332  std::uninitialized_move_n(data(), a_count, newData);
333  } else { // grow
334  std::uninitialized_move_n(data(), oldSize, newData);
335  std::uninitialized_default_construct_n(newData + oldSize, a_count - oldSize);
336  }
337 
338  clear();
339  _data = newData;
340  }
341 
342  protected:
343  [[nodiscard]] void* get_head() noexcept
344  {
345  assert(_data != nullptr);
346  if constexpr (alignof(value_type) > alignof(std::size_t)) {
347  return _data - 1;
348  } else {
349  return reinterpret_cast<std::size_t*>(_data) - 1;
350  }
351  }
352 
353  [[nodiscard]] const void* get_head() const noexcept
354  {
355  assert(_data != nullptr);
356  if constexpr (alignof(value_type) > alignof(std::size_t)) {
357  return _data - 1;
358  } else {
359  return reinterpret_cast<const std::size_t*>(_data) - 1;
360  }
361  }
362 
363  // members
364  pointer _data{ nullptr }; // 0
365  };
366 }
Definition: Relocation.h:841
Definition: Relocation.h:867
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:8
Definition: MemoryManager.h:240
const_iterator begin() const noexcept
Definition: MemoryManager.h:286
const_iterator end() const noexcept
Definition: MemoryManager.h:290
size_type size() const noexcept
Definition: MemoryManager.h:295
value_type & reference
Definition: MemoryManager.h:245
std::size_t size_type
Definition: MemoryManager.h:243
T value_type
Definition: MemoryManager.h:242
void * get_head() noexcept
Definition: MemoryManager.h:343
const_iterator cend() const noexcept
Definition: MemoryManager.h:291
const void * get_head() const noexcept
Definition: MemoryManager.h:353
pointer data() noexcept
Definition: MemoryManager.h:282
iterator begin() noexcept
Definition: MemoryManager.h:285
void clear()
Definition: MemoryManager.h:297
pointer _data
Definition: MemoryManager.h:364
iterator end() noexcept
Definition: MemoryManager.h:289
const value_type & const_reference
Definition: MemoryManager.h:246
~SimpleArray()
Definition: MemoryManager.h:256
reference back() noexcept
Definition: MemoryManager.h:279
value_type * iterator
Definition: MemoryManager.h:249
reference front() noexcept
Definition: MemoryManager.h:276
void resize(size_type a_count)
Definition: MemoryManager.h:306
value_type * pointer
Definition: MemoryManager.h:247
bool empty() const noexcept
Definition: MemoryManager.h:293
const value_type * const_iterator
Definition: MemoryManager.h:250
constexpr SimpleArray() noexcept=default
const_reference front() const noexcept
Definition: MemoryManager.h:277
const_reference operator[](size_type a_pos) const noexcept
Definition: MemoryManager.h:270
const_pointer data() const noexcept
Definition: MemoryManager.h:283
const_iterator cbegin() const noexcept
Definition: MemoryManager.h:287
const_reference back() const noexcept
Definition: MemoryManager.h:280
std::ptrdiff_t difference_type
Definition: MemoryManager.h:244
const value_type * const_pointer
Definition: MemoryManager.h:248
reference operator[](size_type a_pos) noexcept
Definition: MemoryManager.h:264
Definition: AbsorbEffect.h:6
void * realloc(void *a_ptr, std::size_t a_newSize)
Definition: MemoryManager.h:155
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:169
void free(void *a_ptr)
Definition: MemoryManager.h:183
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:191
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