OpenBarnyard
 
Loading...
Searching...
No Matches
TMemory.cpp
Go to the documentation of this file.
1
11
12#include "ToshiPCH.h"
13#include "TMemory.h"
14#include "Thread/TMutex.h"
15#include "Thread/TMutexLock.h"
16
17#ifdef TOSHI_PROFILER_MEMORY
18# include "Profiler/tracy/Tracy.hpp"
19#endif // TOSHI_PROFILER_MEMORY
20
21#include "TMemoryDebugOff.h"
22
28void* __CRTDECL operator new( TSIZE size )
29{
30#ifdef TOSHI_PROFILER_MEMORY
31 return TMalloc( size, TNULL, TMemory__FILE__, TMemory__LINE__ );
32#else
33 return TMalloc( size, TNULL, TNULL, -1 );
34#endif // TOSHI_PROFILER_MEMORY
35}
36
42void* __CRTDECL operator new( TSIZE size, ::std::nothrow_t const& ) noexcept
43{
44#ifdef TOSHI_PROFILER_MEMORY
45 return TMalloc( size, TNULL, TMemory__FILE__, TMemory__LINE__ );
46#else
47 return TMalloc( size, TNULL, TNULL, -1 );
48#endif // TOSHI_PROFILER_MEMORY
49}
50
56void* __CRTDECL operator new[]( TSIZE size )
57{
58#ifdef TOSHI_PROFILER_MEMORY
59 return TMalloc( size, TNULL, TMemory__FILE__, TMemory__LINE__ );
60#else
61 return TMalloc( size, TNULL, TNULL, -1 );
62#endif // TOSHI_PROFILER_MEMORY
63}
64
70void* __CRTDECL operator new[]( TSIZE size, ::std::nothrow_t const& ) noexcept
71{
72#ifdef TOSHI_PROFILER_MEMORY
73 return TMalloc( size, TNULL, TMemory__FILE__, TMemory__LINE__ );
74#else
75 return TMalloc( size, TNULL, TNULL, -1 );
76#endif // TOSHI_PROFILER_MEMORY
77}
78
83void __CRTDECL operator delete( void* ptr ) noexcept
84{
85 TFree( ptr );
86}
87
92void __CRTDECL operator delete( void* ptr, ::std::nothrow_t const& ) noexcept
93{
94 TFree( ptr );
95}
96
101void __CRTDECL operator delete[]( void* ptr ) noexcept
102{
103 TFree( ptr );
104}
105
110void __CRTDECL operator delete[]( void* ptr, ::std::nothrow_t const& ) noexcept
111{
112 TFree( ptr );
113}
114
120void __CRTDECL operator delete[]( void* ptr, TSIZE _Size ) noexcept
121{
122 TFree( ptr );
123}
124
125#ifndef TMEMORY_USE_DLMALLOC
126
127# define MEM_TO_NODE( PTR ) ( ( (MemNode*)( ( (TUINTPTR)PTR ) + sizeof( void* ) ) ) - 1 )
128
130
132
133// $Barnyard: FUNCTION 006b56b0
139{
140 TASSERT( g_pMemory == TNULL );
141 g_pMemory = this;
142
143 m_TotalAllocatedSize = 0;
144
145 for ( TINT i = 0; i < TMEMORY_NUM_BLOCK_SLOTS; i++ )
146 {
147 m_FreeBlocks.InsertTail( &m_aBlockSlots[ i ] );
148 }
149
150 m_bFlag1 = TFALSE;
151 m_bFlag2 = TTRUE;
152}
153
162
163// General utility macro
164# define PP_CAT( A, B ) A##B
165# define PP_EXPAND( ... ) __VA_ARGS__
166
167// Macro overloading feature support
168# define PP_VA_ARG_SIZE( ... ) PP_EXPAND( PP_APPLY_ARG_N( ( PP_ZERO_ARGS_DETECT( __VA_ARGS__ ), PP_RSEQ_N ) ) )
169
170# define PP_ZERO_ARGS_DETECT( ... ) PP_EXPAND( PP_ZERO_ARGS_DETECT_PREFIX_##__VA_ARGS__##_ZERO_ARGS_DETECT_SUFFIX )
171# define PP_ZERO_ARGS_DETECT_PREFIX__ZERO_ARGS_DETECT_SUFFIX , , , , , , , , , , , 0
172
173# define PP_APPLY_ARG_N( ARGS ) PP_EXPAND( PP_ARG_N ARGS )
174# define PP_ARG_N( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, N, ... ) N
175# define PP_RSEQ_N 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
176
177# define PP_OVERLOAD_SELECT( NAME, NUM ) PP_CAT( NAME##_, NUM )
178# define PP_MACRO_OVERLOAD( NAME, ... ) PP_OVERLOAD_SELECT( NAME, PP_VA_ARG_SIZE( __VA_ARGS__ ) )( __VA_ARGS__ )
179
180# define CALL_THIS_4( ADDR, TYPE, RET_TYPE, THIS ) ( ( RET_TYPE( __thiscall* )( TYPE pThis ) )( ADDR ) )( THIS )
181# define CALL_THIS_6( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1 ) )( ADDR ) )( THIS, VALUE1 )
182# define CALL_THIS_8( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2 ) )( ADDR ) )( THIS, VALUE1, VALUE2 )
183# define CALL_THIS_10( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2, TYPE3 ) )( ADDR ) )( THIS, VALUE1, VALUE2, VALUE3 )
184# define CALL_THIS_12( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2, TYPE3, TYPE4 ) )( ADDR ) )( THIS, VALUE1, VALUE2, VALUE3, VALUE4 )
185# define CALL_THIS_14( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4, TYPE5, VALUE5 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2, TYPE3, TYPE4, TYPE5 ) )( ADDR ) )( THIS, VALUE1, VALUE2, VALUE3, VALUE4, VALUE5 )
186# define CALL_THIS( ... ) PP_MACRO_OVERLOAD( CALL_THIS, __VA_ARGS__ )
187
188# define CALL_2( ADDR, RET_TYPE ) ( ( RET_TYPE( __stdcall* )() )( ADDR ) )()
189# define CALL_4( ADDR, RET_TYPE, TYPE1, VALUE1 ) ( ( RET_TYPE( __stdcall* )( TYPE1 ) )( ADDR ) )( VALUE1 )
190# define CALL_6( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2 ) )( ADDR ) )( VALUE1, VALUE2 )
191# define CALL_8( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2, TYPE3 ) )( ADDR ) )( VALUE1, VALUE2, VALUE3 )
192# define CALL_10( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2, TYPE3, TYPE4 ) )( ADDR ) )( VALUE1, VALUE2, VALUE3, VALUE4 )
193# define CALL_12( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4, TYPE5, VALUE5 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2, TYPE3, TYPE4, TYPE5 ) )( ADDR ) )( VALUE1, VALUE2, VALUE3, VALUE4, VALUE5 )
194# define CALL( ... ) PP_MACRO_OVERLOAD( CALL, __VA_ARGS__ )
195
196// $Barnyard: FUNCTION 006b5230
213void* TMemory::Alloc( TSIZE a_uiSize, TSIZE a_uiAlignment, MemBlock* a_pMemBlock, const TCHAR* a_szFileName, TINT a_iLineNum )
214{
215 //return CALL_THIS( 0x006b5230, TMemory*, void*, this, TUINT, a_uiSize, TINT, a_uiAlignment, MemBlock*, a_pMemBlock, const TCHAR*, a_szFileName, TINT, a_iLineNum );
216
217 TMUTEX_LOCK_SCOPE( ms_pGlobalMutex );
218
219 volatile TSIZE uiSize = a_uiSize;
220 volatile TSIZE uiAlignment = a_uiAlignment;
221 MemBlock* pMemBlock = a_pMemBlock;
222
223 if ( uiSize < 4 )
224 uiSize = 4;
225
226 if ( uiAlignment < 16 )
227 uiAlignment = 16;
228
229 if ( uiAlignment < TMEMORY_ROUNDUP )
230 {
231 TDebug_FinalPrintf( "MEMORY ERROR: CANT ALLOC Alignment(%d)<TMEMORY_ROUNDUP\n", uiAlignment );
232 DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
233 TASSERT( TFALSE );
234 return TNULL;
235 }
236
237 if ( !pMemBlock )
238 {
239 pMemBlock = m_pGlobalBlock;
240 }
241
242 volatile TSIZE uiAlignedSize = TAlignNumUp( uiSize );
243 volatile TSIZE uiRequiredSize = uiAlignedSize + sizeof( MemNode );
244
245 MemNode* pMemNode = TNULL;
246
247 volatile void* pAllocatedAddress;
248 volatile TUINTPTR uiDataRegionStart;
249 volatile TUINTPTR uiDataRegionEnd;
250 volatile TUINTPTR uiDataRegionSize;
251
252 volatile TUINT uiNodeId = MapSizeToFreeList( uiAlignedSize );
253
254 // Find a hole that can allocate the required number of bytes
255 for ( ; uiNodeId < TMEMORY_NUM_FREELISTS; uiNodeId++ )
256 {
257 pMemNode = pMemBlock->m_apHoles[ uiNodeId ];
258
259 while ( pMemNode != TNULL )
260 {
261 pAllocatedAddress = TAlignPointerUp( pMemNode->GetDataRegionStart(), uiAlignment );
262 uiDataRegionStart = TREINTERPRETCAST( TUINTPTR, pAllocatedAddress );
263 uiDataRegionEnd = TREINTERPRETCAST( TUINTPTR, pMemNode->GetDataRegionEnd() );
264 uiDataRegionSize = uiDataRegionEnd - uiDataRegionStart;
265
266 if ( uiDataRegionEnd > uiDataRegionStart && uiDataRegionSize >= uiAlignedSize )
267 break;
268
269 // This freelist can't be used, let's check for the next
270 pMemNode = pMemNode->pNextHole;
271 }
272
273 if ( pMemNode )
274 break;
275 }
276
277 if ( !pMemNode )
278 {
279 DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
280 DebugPrintHALMemInfo( "Requested memory block size: %d\n", uiAlignedSize );
281 DumpMemInfo();
282
283 TASSERT( TFALSE );
284 return TNULL;
285 }
286
287# ifdef TOSHI_PROFILER_MEMORY
288 // Create named zone to make it possible to know where the allocation occured
289 tracy::ScopedZone zone( TMemory__LINE__, TMemory__FILE__, T2String8::Length( TMemory__FILE__ ), "", 0, TMemory__FUNC__ ? TMemory__FUNC__ : "", TMemory__FUNC__ ? T2String8::Length( TMemory__FUNC__ ) : 0 );
290# endif
291
292 MemNode* pAllocNode = MEM_TO_NODE( pAllocatedAddress );
293
294 if ( volatile MemNode* pOwner = pMemNode->pOwner )
295 {
296 pOwner->uiSize = ( uiDataRegionStart - (TUINTPTR)pOwner - 24 ) | pOwner->uiSize & TMEMORY_FLAGS_MASK;
297 }
298 else if ( pAllocNode != pMemNode )
299 {
300 // Seems that due to alignment we have a gap between start of the
301 // data region and the actual address we gonna return so let's
302 // make sure we don't lost this pointer
303 pMemBlock->m_pFirstHole = pAllocNode;
304 }
305
306 // Check if we can split the hole in two
307 if ( uiDataRegionSize > uiRequiredSize )
308 {
309 // We can split it!
310
311 // Unlink the hole from the linked list
312 if ( volatile MemNode* pPrev = pMemNode->pPrevHole )
313 pPrev->pNextHole = pMemNode->pNextHole;
314 else
315 pMemBlock->m_apHoles[ uiNodeId ] = pMemNode->pNextHole;
316
317 // Remove reference to this hole from the next one
318 if ( volatile MemNode* pNext = pMemNode->pNextHole )
319 pNext->pPrevHole = pMemNode->pPrevHole;
320
321 if ( pMemNode != pAllocNode )
322 {
323 TSIZE uiNodeSize = GetNodeSize( pMemNode );
324 pAllocNode->pOwner = pMemNode->pOwner;
325 *(MemNode**)( (TUINTPTR)pMemNode->GetDataRegionStart() + uiNodeSize ) = pAllocNode;
326 }
327
328 // Create a new hole right after the allocated data
329 MemNode* pNewNode = TREINTERPRETCAST( MemNode*, uiDataRegionStart + uiAlignedSize );
330
331 SetProcess( pMemBlock, pAllocNode, uiDataRegionSize );
332 SetHoleSize( pNewNode, (TUINTPTR)pAllocNode + GetNodeSize( pAllocNode ) - uiDataRegionStart - uiAlignedSize );
333 SetProcess( pMemBlock, pAllocNode, uiAlignedSize + uiDataRegionStart - (TUINTPTR)pAllocNode - TMEMORY_ALLOC_RESERVED_SIZE );
334 pNewNode->pOwner = pAllocNode;
335
336 // Place the new hole in the memblock's list
337
338 TUINT uiNewHoleId = MapSizeToFreeList( GetNodeSize( pNewNode ) );
339
340 MemNode* pOldNode = pMemBlock->m_apHoles[ uiNewHoleId ];
341 pNewNode->pNextHole = pOldNode;
342
343 if ( pOldNode )
344 pOldNode->pPrevHole = pNewNode;
345
346 pNewNode->pPrevHole = TNULL;
347 pMemBlock->m_apHoles[ uiNewHoleId ] = pNewNode;
348
349 // Save pointer to the hole right at the end of the data region (probably for some validation)
350 *(MemNode* volatile*)pNewNode->GetDataRegionEnd() = pNewNode;
351
352# ifdef TOSHI_PROFILER_MEMORY
353 TracyAlloc( (void*)pAllocatedAddress, uiAlignedSize );
354# endif
355 return (void*)pAllocatedAddress;
356 }
357 else
358 {
359 // Damn, we can't split this one but it surely can fit the allocation
360
361 // Unlink the hole from the linked list
362 if ( volatile MemNode* pPrev = pMemNode->pPrevHole )
363 pPrev->pNextHole = pMemNode->pNextHole;
364 else
365 pMemBlock->m_apHoles[ uiNodeId ] = pMemNode->pNextHole;
366
367 // Remove reference to this hole from the next one
368 if ( volatile MemNode* pNext = pMemNode->pNextHole )
369 pNext->pPrevHole = pMemNode->pPrevHole;
370
371 if ( pMemNode != pAllocNode )
372 {
373 TSIZE uiNodeSize = GetNodeSize( pMemNode );
374 pAllocNode->pOwner = pMemNode->pOwner;
375 *(MemNode* volatile*)( (TUINTPTR)pMemNode->GetDataRegionStart() + uiNodeSize ) = pAllocNode;
376 }
377
378 SetProcess( pMemBlock, pAllocNode, uiDataRegionSize );
379
380# ifdef TOSHI_PROFILER_MEMORY
381 TracyAlloc( (void*)pAllocatedAddress, uiAlignedSize );
382# endif
383 return (void*)pAllocatedAddress;
384 }
385}
386
387// $Barnyard: FUNCTION 006b4a20
399TBOOL TMemory::Free( const void* a_pAllocated )
400{
401 //return CALL_THIS( 0x006b4a20, TMemory*, TBOOL, this, const void*, a_pAllocated );
402
403 TMUTEX_LOCK_SCOPE( ms_pGlobalMutex );
404
405 if ( !a_pAllocated || !TIsPointerAligned( a_pAllocated ) )
406 {
407 // Can't free TNULL or unaligned pointer
408 return TFALSE;
409 }
410
411# ifdef TOSHI_PROFILER_MEMORY
412 TracyFree( a_pAllocated );
413# endif
414
415 MemNode* pAllocationNode = MEM_TO_NODE( a_pAllocated );
416
417 TSIZE uiAllocationSize = GetNodeSize( pAllocationNode );
418 MemBlock* pMemBlock = GetProcessMemBlock( pAllocationNode );
419
420 SetHoleSize( pAllocationNode, uiAllocationSize );
421
422 MemNode* pNextLyingNode = (MemNode*)pAllocationNode->GetDataRegionEnd();
423 MemNode* pOwner = pAllocationNode->pOwner;
424
425 MemNode** ppNextNode = &pAllocationNode->pNextHole;
426
427 if ( pOwner && !IsProcess( pOwner ) )
428 {
429 pAllocationNode = pOwner;
430 TSIZE uiOwnerSize = GetNodeSize( pOwner );
431
432 ExtendNodeSize( pOwner, uiAllocationSize + uiOwnerSize + TMEMORY_ALLOC_RESERVED_SIZE );
433 pNextLyingNode->pOwner = pOwner;
434 ppNextNode = &pOwner->pNextHole;
435
436 if ( MemNode* pPrev = pOwner->pPrevHole )
437 pPrev->pNextHole = pOwner->pNextHole;
438 else
439 pMemBlock->m_apHoles[ MapSizeToFreeList( uiOwnerSize ) ] = pOwner->pNextHole;
440
441 if ( MemNode* pNext = pOwner->pNextHole )
442 pNext->pPrevHole = pOwner->pPrevHole;
443 }
444
445 if ( !IsProcess( pNextLyingNode ) )
446 {
447 TSIZE uiNextNodeSize = GetNodeSize( pNextLyingNode );
448
449 if ( MemNode* pPrev = pNextLyingNode->pPrevHole )
450 pPrev->pNextHole = pNextLyingNode->pNextHole;
451 else
452 pMemBlock->m_apHoles[ MapSizeToFreeList( uiNextNodeSize ) ] = pNextLyingNode->pNextHole;
453
454 if ( MemNode* pNext = pNextLyingNode->pNextHole )
455 pNext->pPrevHole = pNextLyingNode->pPrevHole;
456
457 ExtendNodeSize( pAllocationNode, GetNodeSize( pAllocationNode ) + GetNodeSize( pNextLyingNode ) + TMEMORY_ALLOC_RESERVED_SIZE );
458 *(MemNode**)pNextLyingNode->GetDataRegionEnd() = pAllocationNode;
459 }
460
461 TUINT uiId = MapSizeToFreeList( GetNodeSize( pAllocationNode ) );
462 pAllocationNode->pPrevHole = TNULL;
463 *ppNextNode = pMemBlock->m_apHoles[ uiId ];
464
465 if ( *ppNextNode )
466 ( *ppNextNode )->pPrevHole = pAllocationNode;
467
468 pMemBlock->m_apHoles[ uiId ] = pAllocationNode;
469
470 return TTRUE;
471}
472
473// $Barnyard: FUNCTION 006b5510
488TMemory::MemBlock* TMemory::CreateMemBlock( TSIZE a_uiSize, const TCHAR* a_szName, MemBlock* a_pOwnerBlock, TINT a_iUnused )
489{
490 void* pMem = Alloc( a_uiSize, 16, a_pOwnerBlock, TNULL, -1 );
491 return CreateMemBlockInPlace( pMem, a_uiSize, a_szName );
492}
493
494// $Barnyard: FUNCTION 006b4e60
508TMemory::MemBlock* TMemory::CreateMemBlockInPlace( void* a_pMem, TSIZE a_uiSize, const TCHAR* a_szName )
509{
510 TMUTEX_LOCK_SCOPE( ms_pGlobalMutex );
511
512 if ( a_pMem && a_uiSize != 0 && !m_FreeBlocks.IsEmpty() )
513 {
514 auto pBlock = TREINTERPRETCAST( MemBlock*, TAlignNumDown( TREINTERPRETCAST( TUINTPTR, a_pMem ) ) );
515 auto uiBlockTotalSize = ( TREINTERPRETCAST( TUINTPTR, a_pMem ) + TAlignNumDown( a_uiSize ) ) - TREINTERPRETCAST( TUINTPTR, pBlock );
516
517 if ( pBlock )
518 {
519 auto pSlot = m_FreeBlocks.RemoveHead();
520 m_UsedBlocks.InsertHead( pSlot );
521
522 pBlock->m_pSlot = pSlot;
523 pBlock->m_pSlot->m_pPtr = pBlock;
524 }
525
526 if ( uiBlockTotalSize != 0 )
527 {
528 constexpr TSIZE CHUNK_RESERVED_SIZE = ( sizeof( MemBlock ) + ( sizeof( MemNode ) - sizeof( void* ) ) );
529
530 pBlock->m_uiTotalSize1 = uiBlockTotalSize;
531 TUtil::MemClear( pBlock->m_apHoles, sizeof( pBlock->m_apHoles ) );
532 pBlock->m_pFirstHole = &pBlock->m_RootHole;
533
534 auto pHole = &pBlock->m_RootHole;
535 pHole->uiSize = uiBlockTotalSize - CHUNK_RESERVED_SIZE;
536 pHole->pNextHole = TNULL;
537 pHole->pPrevHole = TNULL;
538 pHole->pOwner = TNULL;
539
540 auto uiFreeListId = MapSizeToFreeList( uiBlockTotalSize - CHUNK_RESERVED_SIZE );
541 pBlock->m_apHoles[ uiFreeListId ] = pHole;
542
543 auto pBlockFooter = TREINTERPRETCAST( MemBlockFooter*, TREINTERPRETCAST( TUINTPTR, pBlock ) + uiBlockTotalSize ) - 1;
544 pBlockFooter->m_pBlockOwner = TNULL;
545 pBlockFooter->m_Unk4 = 0;
546 pBlockFooter->m_Unk1 = 0;
547 pBlockFooter->m_Unk2 = g_pMemory->m_uiGlobalFlags | TMEMORY_FLAGS_HOLE_PROCESS;
548 pBlockFooter->m_pBlockOwner = pBlock;
549
550 pBlock->m_pNextBlock = pBlock;
551 pBlock->m_uiTotalSize2 = uiBlockTotalSize;
552 TStringManager::String8Copy( pBlock->m_szSignature, "#MB_uID" );
553 TStringManager::String8Copy( pBlock->m_szName, a_szName );
554
555 return pBlock;
556 }
557 }
558
559 return TNULL;
560}
561
562// $Barnyard: FUNCTION 006b5090
573{
574 FreeMemBlock( a_pMemBlock );
575 Free( a_pMemBlock );
576}
577
582Toshi::TMemory::MemBlock* TMemory::GetGlobalBlock() const
583{
584 return m_pGlobalBlock;
585}
586
587// $Barnyard: FUNCTION 006b4fb0
598TBOOL TMemory::FreeMemBlock( MemBlock* a_pMemBlock )
599{
600 TMUTEX_LOCK_SCOPE( ms_pGlobalMutex );
601
602 SetMemBlockUnused( a_pMemBlock );
603 a_pMemBlock->m_pSlot->Remove();
604 m_FreeBlocks.InsertHead( a_pMemBlock->m_pSlot );
605
606 return TTRUE;
607}
608
618void TMemory::SetMemBlockUnused( MemBlock* a_pMemBlock )
619{
620 a_pMemBlock->m_pSlot->Remove();
621 m_FreeBlocks.InsertHead( a_pMemBlock->m_pSlot );
622
623 CreateMemBlockInPlace( a_pMemBlock, a_pMemBlock->m_uiTotalSize1, "_unused" );
624 TStringManager::String8Copy( a_pMemBlock->m_szSignature, "xxxxxxx" );
625}
626
637Toshi::TMemory::MemNode* TMemory::GetMemNodeFromAddress( void* a_pMem )
638{
639 if ( !a_pMem || HASANYFLAG( TREINTERPRETCAST( TUINTPTR, a_pMem ), TMEMORY_FLAGS_MASK ) )
640 return TNULL;
641
642 MemNode* pMemNode = MEM_TO_NODE( a_pMem );
643 TVALIDPTR( pMemNode );
644
645 return pMemNode;
646}
647
658int TMemory::TestMemIntegrity( MemBlock* a_pMemBlock )
659{
660 // TODO: this method is cut in the release build
661 return 0;
662}
663
674int TMemory::DebugTestMemoryBlock( MemBlock* a_pMemBlock )
675{
676 TIMPLEMENT();
677 DebugPrintHALMemInfo( "TMemory: DebugTestMemoryBlock:" );
678
679 MemBlock* pMemBlock = a_pMemBlock;
680
681 if ( !pMemBlock )
682 {
683 pMemBlock = g_pMemory->m_pGlobalBlock;
684 }
685
686 MemInfo memInfo;
687 GetMemInfo( memInfo, pMemBlock );
688
689 // ...
690
691 return 0;
692}
693
694// $Barnyard: FUNCTION 006b5740
708TBOOL TMemory::Initialise( TSIZE a_uiHeapSize, TSIZE a_uiReservedSize, TUINT a_uiUnused )
709{
710 auto tmemory = TSTATICCAST( TMemory, calloc( sizeof( TMemory ), 1 ) );
711 new ( tmemory ) TMemory();
712
713 tmemory->m_pMemory = TNULL;
714 tmemory->m_pGlobalBlock = TNULL;
715 tmemory->m_uiGlobalFlags = 0;
716 tmemory->m_Unknown2 = 0;
717
718 ms_pGlobalMutex = TSTATICCAST( TMutex, malloc( sizeof( TMutex ) ) );
719 new ( ms_pGlobalMutex ) TMutex();
720
721 tmemory->m_ReservedSize = a_uiReservedSize;
722 tmemory->m_TotalAllocatedSize = ( a_uiHeapSize == 0 ) ? 128 * 1024 * 1024 : a_uiHeapSize;
723 tmemory->m_MainBlockSize = tmemory->m_TotalAllocatedSize - a_uiReservedSize;
724 tmemory->m_pMemory = malloc( tmemory->m_TotalAllocatedSize );
725 tmemory->m_pGlobalBlock = tmemory->CreateMemBlockInPlace(
726 tmemory->m_pMemory,
727 tmemory->m_TotalAllocatedSize,
728 "Toshi"
729 );
730
731 return TTRUE;
732}
733
734// $Barnyard: FUNCTION 006b57e0
744{
745 TASSERT( g_pMemory != TNULL );
746 auto pMainBlockMemory = g_pMemory->m_pMemory;
747
748 g_pMemory->m_UsedBlocks.RemoveAll();
749 g_pMemory->m_FreeBlocks.RemoveAll();
750 g_pMemory->~TMemory();
751
752 free( g_pMemory );
753 free( pMainBlockMemory );
754}
755
756// $Barnyard: FUNCTION 006b49e0
757/*
758 * @brief Maps a size to a free list index
759 * @param a_uiSize Size to map
760 * @return Free list index
761 *
762 * This function:
763 * 1. Calculates the appropriate free list index based on size
764 * 2. Ensures the index is within valid range
765 * 3. Returns the index
766 */
768{
769 TFLOAT fSize = TFLOAT( TAlignNumUp( a_uiSize ) - 1 );
770 TUINT uiExponentSign = ( *(TINT*)&fSize ) >> 23;
771 TUINT uiResult = uiExponentSign - 127;
772
773 if ( uiResult & 1 )
774 uiResult = uiExponentSign - 126;
775
776 uiResult = uiResult >> 1;
777
778 if ( uiResult != 0 )
779 uiResult = uiResult - 1;
780
781 if ( uiResult >= TMEMORY_NUM_FREELISTS )
782 uiResult = TMEMORY_NUM_FREELISTS - 1;
783
784 return uiResult;
785}
786
787// $Barnyard: FUNCTION 006b4b80
788/*
789 * @brief Sets the global memory block
790 * @param a_pMemBlock New global memory block
791 * @return Previous global memory block
792 */
794{
795 MemBlock* pOldMemBlock = m_pGlobalBlock;
796 m_pGlobalBlock = a_pMemBlock;
797 return pOldMemBlock;
798}
799
800// $Barnyard: FUNCTION 006b50b0
801/*
802 * @brief Dumps memory usage information to debug output
803 *
804 * This function:
805 * 1. Iterates through all used blocks
806 * 2. Gets memory info for each block
807 * 3. Prints detailed usage statistics
808 */
810{
811 MemInfo memInfo;
812
813 for ( auto it = m_UsedBlocks.Tail(); it != m_UsedBlocks.End(); --it )
814 {
815 GetMemInfo( memInfo, it->m_pPtr );
816
817 DebugPrintHALMemInfo( "Pool: \'%s\'\n", it->m_pPtr->m_szName );
818 DebugPrintHALMemInfo( "\tLargest Hole : %d\n", memInfo.m_uiLargestHole );
819 DebugPrintHALMemInfo( "\tSmallest Hole : %d\n", memInfo.m_uiSmallestHole );
820 DebugPrintHALMemInfo( "\tLargest Process : %d\n", memInfo.m_uiLargestProcess );
821 DebugPrintHALMemInfo( "\tSmallest Process: %d\n", memInfo.m_uiSmallestProcess );
822 DebugPrintHALMemInfo( "\tTotal Free : %d\n", memInfo.m_uiTotalFree );
823 DebugPrintHALMemInfo( "\tTotal Used : %d\n", memInfo.m_uiTotalUsed );
824 DebugPrintHALMemInfo( "\tTotal Size : %d\n", memInfo.m_uiTotalSize );
825 DebugPrintHALMemInfo( "\tLogic Total Free: %d\n", memInfo.m_uiLogicTotalFree );
826 DebugPrintHALMemInfo( "\tLogic Total Used: %d\n", memInfo.m_uiLogicTotalUsed );
827 DebugPrintHALMemInfo( "\tLogic Total Size: %d\n", memInfo.m_uiLogicTotalSize );
828
829 TFLOAT fLogicTotalUsed = TMath::Abs( TFLOAT( memInfo.m_uiLogicTotalUsed ) );
830 TFLOAT fLogicTotalSize = TMath::Abs( TFLOAT( memInfo.m_uiLogicTotalSize ) );
831 DebugPrintHALMemInfo( "\t%%Logical Used : %f\n", ( fLogicTotalUsed / fLogicTotalSize ) * 100.0 );
832
833 TFLOAT fTotalUsed = TMath::Abs( TFLOAT( memInfo.m_uiTotalUsed ) );
834 TFLOAT fTotalSize = TMath::Abs( TFLOAT( memInfo.m_uiTotalSize ) );
835 DebugPrintHALMemInfo( "\t%%Used\t : %f\n", ( fTotalUsed / fTotalSize ) * 100.0 );
836 DebugPrintHALMemInfo( "------\n\n" );
837 }
838}
839
845void TMemory::DebugPrintHALMemInfo( const TCHAR* a_szFormat, ... )
846{
847 va_list args;
848 va_start( args, a_szFormat );
849 TDebug_FinalVPrintf( a_szFormat, args );
850 va_end( args );
851}
852
853// $Barnyard: FUNCTION 006b4ba0
854/*
855 * @brief Gets memory usage information
856 * @param a_rMemInfo Structure to fill with memory info
857 * @param a_pMemBlock Memory block to get info for
858 *
859 * This function:
860 * 1. Initializes the info structure
861 * 2. Iterates through all holes in the block
862 * 3. Calculates various memory statistics
863 */
864void TMemory::GetMemInfo( MemInfo& a_rMemInfo, MemBlock* a_pMemBlock )
865{
866 TMUTEX_LOCK_SCOPE( ms_pGlobalMutex );
867
868 if ( !a_pMemBlock )
869 {
870 a_pMemBlock = g_pMemory->m_pGlobalBlock;
871 }
872
873 a_rMemInfo.m_uiUnk3 = 28;
874 a_rMemInfo.m_uiUnk4 = 28;
875 a_rMemInfo.m_uiTotalSize = 0;
876 a_rMemInfo.m_uiLogicTotalSize = 0;
877 a_rMemInfo.m_uiLargestHole = 0;
878 a_rMemInfo.m_uiLargestProcess = 0;
879 a_rMemInfo.m_uiSmallestHole = 0;
880 a_rMemInfo.m_uiSmallestProcess = 0;
881 a_rMemInfo.m_uiTotalFree = 0;
882 a_rMemInfo.m_uiLogicTotalFree = 0;
883 a_rMemInfo.m_uiTotalUsed = 0;
884 a_rMemInfo.m_uiLogicTotalUsed = 0;
885 a_rMemInfo.m_iNumHoles = 0;
886 a_rMemInfo.m_iNumProcesses = 0;
887 a_rMemInfo.m_uiTotalSize = a_pMemBlock->m_uiTotalSize1;
888 a_rMemInfo.m_uiLogicTotalSize = a_pMemBlock->m_uiTotalSize1;
889 a_rMemInfo.m_uiSmallestProcess = -1;
890 a_rMemInfo.m_uiSmallestHole = -1;
891 a_rMemInfo.m_uiLargestProcess = 0;
892 a_rMemInfo.m_uiLargestHole = 0;
893
894 auto uiUnk = (TUINTPTR)a_pMemBlock->m_pFirstHole + ( -88 - (TUINTPTR)a_pMemBlock );
895 a_rMemInfo.m_uiUnk3 = uiUnk;
896 a_rMemInfo.m_uiUnk4 = uiUnk;
897
898 auto pHole = a_pMemBlock->m_pFirstHole;
899 TSIZE uiHoleSize = pHole->uiSize;
900
901 while ( TAlignNumDown( uiHoleSize ) != 0 )
902 {
903 a_rMemInfo.m_uiUnk3 += sizeof( MemNode ) - sizeof( void* );
904 uiHoleSize = TAlignNumDown( pHole->uiSize );
905
906 if ( ( pHole->uiSize & 1 ) == 0 )
907 {
908 a_rMemInfo.m_iNumHoles += 1;
909 a_rMemInfo.m_uiTotalFree += uiHoleSize;
910
911 if ( a_rMemInfo.m_uiLargestHole <= uiHoleSize && uiHoleSize != a_rMemInfo.m_uiLargestHole )
912 {
913 a_rMemInfo.m_uiLargestHole = uiHoleSize;
914 }
915
916 if ( uiHoleSize < a_rMemInfo.m_uiSmallestHole )
917 {
918 a_rMemInfo.m_uiSmallestHole = uiHoleSize;
919 }
920 }
921 else
922 {
923 a_rMemInfo.m_iNumProcesses += 1;
924 a_rMemInfo.m_uiTotalUsed += uiHoleSize;
925
926 if ( a_rMemInfo.m_uiLargestProcess <= uiHoleSize && uiHoleSize != a_rMemInfo.m_uiLargestProcess )
927 {
928 a_rMemInfo.m_uiLargestProcess = uiHoleSize;
929 }
930
931 if ( uiHoleSize < a_rMemInfo.m_uiSmallestProcess )
932 {
933 a_rMemInfo.m_uiSmallestProcess = uiHoleSize;
934 }
935 }
936
937 auto pOldHole = pHole;
938 pHole = (MemNode*)( (TUINTPTR)&pHole->pPrevHole + uiHoleSize );
939 uiHoleSize = pHole->uiSize;
940 }
941
942 a_rMemInfo.m_uiLogicTotalFree = a_rMemInfo.m_uiTotalFree;
943 a_rMemInfo.m_uiLogicTotalUsed = a_rMemInfo.m_uiTotalUsed + uiUnk;
944
945 if ( a_rMemInfo.m_uiSmallestHole == -1 )
946 {
947 a_rMemInfo.m_uiSmallestHole = 0;
948 }
949}
950
951// $Barnyard: FUNCTION 006b4b60
952/*
953 * @brief Gets hardware abstraction layer memory info
954 * @param a_rHALMemInfo Structure to fill with HAL memory info
955 */
956void TMemory::GetHALMemInfo( HALMemInfo& a_rHALMemInfo )
957{
958 TUtil::MemClear( &a_rHALMemInfo, sizeof( a_rHALMemInfo ) );
959}
960
966{
967 TUtil::MemClear( this, sizeof( *this ) );
968}
969
971
972// $Barnyard: FUNCTION 006b5540
973void* TMalloc( TSIZE a_uiSize, Toshi::TMemory::MemBlock* a_pMemBlock, const TCHAR* a_szFileName, TINT a_iLineNum )
974{
975 if ( !a_pMemBlock )
976 {
977 a_pMemBlock = Toshi::g_pMemory->GetGlobalBlock();
978 }
979
980 auto pMem = Toshi::g_pMemory->Alloc( a_uiSize, 16, a_pMemBlock, a_szFileName, a_iLineNum );
981
982 if ( !pMem )
983 {
984 Toshi::TMemory::DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", a_pMemBlock->m_szName );
985 }
986
987 return pMem;
988}
989
990void* TMalloc( TSIZE a_uiSize, const TCHAR* a_szFileName, TINT a_iLineNum )
991{
992 auto pMemBlock = Toshi::g_pMemory->GetGlobalBlock();
993
994 auto pMem = Toshi::g_pMemory->Alloc( a_uiSize, 16, pMemBlock, a_szFileName, a_iLineNum );
995
996 if ( !pMem )
997 {
998 Toshi::TMemory::DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
999 }
1000
1001 return pMem;
1002}
1003
1004// $Barnyard: FUNCTION 006b5630
1005void* TMalloc( TSIZE a_uiSize )
1006{
1007 auto pMemBlock = Toshi::g_pMemory->GetGlobalBlock();
1008
1009 auto pMem = Toshi::g_pMemory->Alloc( a_uiSize, 16, pMemBlock, TNULL, -1 );
1010
1011 if ( !pMem )
1012 {
1013 Toshi::TMemory::DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
1014 }
1015
1016 return pMem;
1017}
1018
1019// $Barnyard: FUNCTION 006b5590
1020void* TMemalign( TSIZE a_uiAlignment, TSIZE a_uiSize, Toshi::TMemory::MemBlock* a_pMemBlock )
1021{
1022 if ( !a_pMemBlock )
1023 {
1024 a_pMemBlock = Toshi::g_pMemory->GetGlobalBlock();
1025 }
1026
1027 auto pMem = Toshi::g_pMemory->Alloc( a_uiSize, a_uiAlignment, a_pMemBlock, TNULL, -1 );
1028
1029 if ( !pMem )
1030 {
1031 Toshi::TMemory::DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", a_pMemBlock->m_szName );
1032 }
1033
1034 return pMem;
1035}
1036
1037// $Barnyard: FUNCTION 006b5670
1038void* TMemalign( TSIZE a_uiSize, TSIZE a_uiAlignment )
1039{
1040 auto pMemBlock = Toshi::g_pMemory->GetGlobalBlock();
1041
1042 auto pMem = Toshi::g_pMemory->Alloc( a_uiSize, a_uiAlignment, pMemBlock, TNULL, -1 );
1043
1044 if ( !pMem )
1045 {
1046 Toshi::TMemory::DebugPrintHALMemInfo( "Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
1047 }
1048
1049 return pMem;
1050}
1051
1052// $Barnyard: FUNCTION 00401020
1053// $Barnyard: FUNCTION 006b4df0
1054void TFree( void* a_pMem )
1055{
1056 Toshi::g_pMemory->Free( a_pMem );
1057}
1058
1059#else // !TMEMORY_USE_DLMALLOC
1060
1062
1064
1066{
1067 m_pMemModule = TNULL;
1068}
1069
1070TBOOL TMemory::Initialise( TUINT a_uiHeapSize, TUINT a_uiReservedSize, TMemoryDL::Flags a_eFlags /*= TMemoryDL::Flags_Standard*/ )
1071{
1072 TASSERT( g_pMemory == TNULL );
1073
1074 // Allocate TMemory
1075 TMemory* pMemory = (TMemory*)GlobalAlloc( GMEM_ZEROINIT, sizeof( TMemory ) );
1076
1077 new ( pMemory ) TMemory();
1078 g_pMemory = pMemory;
1079
1080 // Allocate TMemory_dlmalloc
1081 TMemoryDL* pMemModule = (TMemoryDL*)GlobalAlloc( GMEM_ZEROINIT, sizeof( TMemoryDL ) );
1082
1083 // Set minimum heap size
1084 if ( a_uiHeapSize == 0 )
1085 a_uiHeapSize = 128 * 1024 * 1024;
1086
1087 new ( pMemModule ) TMemoryDL( a_eFlags, a_uiHeapSize + a_uiReservedSize );
1088 g_pMemory->m_pMemModule = pMemModule;
1089 g_pMemoryDL = pMemModule;
1090
1091 // Initialise the memory block
1092 TBOOL bInitialised = pMemModule->Init() == TMemoryDL::Error_Ok;
1093
1094 g_pMemory->m_pGlobalBlock = g_pMemoryDL->GetHeap();
1095
1096 return bInitialised;
1097}
1098
1100{
1101 TASSERT( g_pMemory != TNULL );
1102
1103 g_pMemory->m_pMemModule->Shutdown();
1104
1105 GlobalFree( g_pMemory->m_pMemModule );
1106 GlobalFree( g_pMemory );
1107
1108 g_pMemory = TNULL;
1109}
1110
1111TMemory::MemBlock* TMemory::CreateMemBlock( TUINT a_uiSize, const TCHAR* a_szName, MemBlock* a_pOwnerBlock, TINT a_iUnused )
1112{
1113 if ( !a_pOwnerBlock )
1114 a_pOwnerBlock = m_pMemModule->GetHeap();
1115
1116 return g_pMemoryDL->dlheapcreatesubheap( a_pOwnerBlock, a_uiSize, TMemoryHeapFlags_UseMutex, a_szName );
1117}
1118
1119TMemory::MemBlock* TMemory::CreateMemBlockInPlace( void* a_pMem, TUINT a_uiSize, const TCHAR* a_szName )
1120{
1121 TVALIDPTR( a_pMem );
1122
1123 return g_pMemoryDL->dlheapcreateinplace( a_pMem, a_uiSize, TMemoryHeapFlags_UseMutex, a_szName );
1124}
1125
1126void TMemory::DestroyMemBlock( MemBlock* a_pMemBlock )
1127{
1128 g_pMemoryDL->dlheapdestroy( a_pMemBlock );
1129}
1130
1131TMemory::MemBlock* TMemory::GetGlobalBlock() const
1132{
1133 return g_pMemoryDL->GetHeap();
1134}
1135
1136TMemory::MemBlock* TMemory::SetGlobalBlock( MemBlock* a_pMemBlock )
1137{
1138 MemBlock* pOldHeap = g_pMemoryDL->GetHeap();
1139 m_pGlobalBlock = a_pMemBlock;
1140 g_pMemoryDL->SetHeap( a_pMemBlock );
1141 return pOldHeap;
1142}
1143
1144void TMemory::GetMemInfo( MemInfo& a_rMemInfo, MemBlock* a_pMemBlock )
1145{
1146 TUtil::MemClear( &a_rMemInfo, sizeof( a_rMemInfo ) );
1147}
1148
1149void TMemory::GetHALMemInfo( HALMemInfo& a_rHALMemInfo )
1150{
1151 TUtil::MemClear( &a_rHALMemInfo, sizeof( a_rHALMemInfo ) );
1152}
1153
1155
1156void* TMalloc( TUINT a_uiSize, Toshi::TMemory::MemBlock* a_pMemBlock, const TCHAR* a_szFileName, TINT a_iLineNum )
1157{
1158 if ( !a_pMemBlock )
1159 {
1160 a_pMemBlock = Toshi::g_pMemoryDL->GetHeap();
1161 }
1162
1163 if ( a_pMemBlock )
1164 return a_pMemBlock->Malloc( a_uiSize );
1165 else
1166 return Toshi::g_pMemoryDL->GetContext().Malloc( a_uiSize );
1167}
1168
1169void* TMalloc( TUINT a_uiSize, const TCHAR* a_szFileName, TINT a_iLineNum )
1170{
1171 return Toshi::g_pMemoryDL->GetContext().Malloc( a_uiSize );
1172}
1173
1174void* TMalloc( TUINT a_uiSize )
1175{
1176 return Toshi::g_pMemoryDL->GetContext().Malloc( a_uiSize );
1177}
1178
1179void* TMemalign( TUINT a_uiAlignment, TUINT a_uiSize, Toshi::TMemory::MemBlock* a_pMemBlock )
1180{
1181 if ( !a_pMemBlock )
1182 a_pMemBlock = Toshi::g_pMemoryDL->GetHeap();
1183
1184 if ( a_pMemBlock )
1185 return a_pMemBlock->Memalign( a_uiAlignment, a_uiSize );
1186 else
1187 return Toshi::g_pMemoryDL->GetContext().Memalign( a_uiAlignment, a_uiSize );
1188}
1189
1190void* TMemalign( TUINT a_uiSize, TUINT a_uiAlignment )
1191{
1192 return Toshi::g_pMemoryDL->GetContext().Memalign( a_uiAlignment, a_uiSize );
1193}
1194
1195void TFree( void* a_pMem )
1196{
1197 Toshi::g_pMemoryDL->GetContext().Free( a_pMem );
1198}
1199
1200#endif // TMEMORY_USE_DLMALLOC
#define MEM_TO_NODE(PTR)
Definition TMemory.cpp:127
void * TMalloc(TSIZE a_uiSize, Toshi::TMemory::MemBlock *a_pMemBlock, const TCHAR *a_szFileName, TINT a_iLineNum)
Allocates memory from a specific memory block.
Definition TMemory.cpp:973
void TFree(void *a_pMem)
Frees previously allocated memory.
Definition TMemory.cpp:1054
Core memory management system for the Toshi engine.
#define TMEMORY_NUM_FREELISTS
Number of free list buckets for different sizes.
Definition TMemory.h:28
#define TMEMORY_ROUNDUP
Minimum alignment for memory blocks.
Definition TMemory.h:25
void * TMemalign(TSIZE a_uiSize, TSIZE a_uiAlignment)
Allocates aligned memory.
Definition TMemory.cpp:1038
TOSHI_NAMESPACE_START class TMemory * g_pMemory
#define TMEMORY_NUM_BLOCK_SLOTS
Maximum number of memory block slots.
Definition TMemory.h:29
TOSHI_NAMESPACE_END void * TMalloc(TSIZE a_uiSize)
Allocates memory with default alignment.
Definition TMemory.cpp:1005
#define TMEMORY_FLAGS_HOLE_PROCESS
Flag indicating a memory block is in use.
Definition TMemory.h:26
#define TMEMORY_ALLOC_RESERVED_SIZE
Reserved space in allocations.
Definition TMemory.h:31
void TFree(void *a_pMem)
Frees previously allocated memory.
Definition TMemory.cpp:1054
#define TMEMORY_FLAGS_MASK
Mask for memory block flags.
Definition TMemory.h:27
void TDebug_FinalPrintf(const TCHAR *a_szFormat,...)
void TDebug_FinalVPrintf(const TCHAR *a_szFormat, va_list a_Args)
#define TMUTEX_LOCK_SCOPE(mutex)
Definition TMutexLock.h:4
#define TIMPLEMENT()
Definition Defines.h:136
#define TASSERT(X,...)
Definition Defines.h:138
#define TSTATICCAST(POINTERTYPE, VALUE)
Definition Defines.h:69
#define HASANYFLAG(STATE, FLAG)
Definition Defines.h:5
#define TREINTERPRETCAST(TYPE, VALUE)
Definition Defines.h:68
#define TOSHI_NAMESPACE_START
Definition Defines.h:47
#define TOSHI_NAMESPACE_END
Definition Defines.h:50
#define TVALIDPTR(PTR)
Definition Defines.h:139
TFORCEINLINE constexpr T * TAlignPointerUp(T *a_pMem, TSIZE a_uiAlignment=sizeof(T *))
Definition Helpers.h:41
TFORCEINLINE constexpr T TAlignNumUp(T a_iValue, TSIZE a_uiAlignment=4)
Definition Helpers.h:66
TFORCEINLINE constexpr T TAlignNumDown(T a_iValue, TSIZE a_uiAlignment=4)
Definition Helpers.h:59
TFORCEINLINE TBOOL TIsPointerAligned(const void *a_pPointer, TSIZE a_uiAlignment=sizeof(void *))
Definition Helpers.h:35
unsigned int TUINT
Definition Typedefs.h:8
uintptr_t TUINTPTR
Definition Typedefs.h:18
size_t TSIZE
Definition Typedefs.h:9
char TCHAR
Definition Typedefs.h:20
float TFLOAT
Definition Typedefs.h:4
#define TNULL
Definition Typedefs.h:23
int TINT
Definition Typedefs.h:7
#define TFALSE
Definition Typedefs.h:24
#define TTRUE
Definition Typedefs.h:25
bool TBOOL
Definition Typedefs.h:6
TMemory * g_pMemory
Definition TMemory.cpp:131
TFORCEINLINE TFLOAT Abs(TFLOAT fVal)
Definition TMathInline.h:63
Core memory management class that handles all memory allocations and deallocations.
Definition TMemory.h:48
static TBOOL Initialise(TSIZE a_uiHeapSize, TSIZE a_uiReservedSize, TUINT a_uiUnused=0)
Initializes the memory system.
Definition TMemory.cpp:708
TBOOL Free(const void *a_pMem)
Frees previously allocated memory.
Definition TMemory.cpp:399
static TUINT MapSizeToFreeList(TSIZE a_uiSize)
Definition TMemory.cpp:767
static void GetMemInfo(MemInfo &a_rMemInfo, MemBlock *a_pMemBlock)
Definition TMemory.cpp:864
static void Deinitialise()
Deinitializes the memory system.
Definition TMemory.cpp:743
MemBlock * GetGlobalBlock() const
Gets the global memory block.
Definition TMemory.cpp:582
void DumpMemInfo()
Definition TMemory.cpp:809
MemBlock * CreateMemBlockInPlace(void *a_pMem, TSIZE a_uiSize, const TCHAR *a_szName)
Creates a memory block at a specific location.
Definition TMemory.cpp:508
static void GetHALMemInfo(HALMemInfo &a_rHALMemInfo)
Definition TMemory.cpp:956
void DestroyMemBlock(MemBlock *a_pMemBlock)
Destroys a memory block.
Definition TMemory.cpp:572
static void DebugPrintHALMemInfo(const TCHAR *a_szFormat,...)
Debug print of HAL memory info.
Definition TMemory.cpp:845
void * Alloc(TSIZE a_uiSize, TSIZE a_uiAlignment, MemBlock *a_pMemBlock, const TCHAR *a_szFileName, TINT a_iLineNum)
Allocates memory with specified size and alignment.
Definition TMemory.cpp:213
TMemory::MemBlock * SetGlobalBlock(MemBlock *a_pMemBlock)
Sets the global memory block.
Definition TMemory.cpp:793
MemBlock * CreateMemBlock(TSIZE a_uiSize, const TCHAR *a_szName, MemBlock *a_pOwnerBlock, TINT a_iUnused)
Creates a new memory block.
Definition TMemory.cpp:488
TMemory()
Constructor for TMemory class Initializes the memory management system.
Definition TMemory.cpp:138
~TMemory()
Destructor for TMemory class Cleans up the memory management system.
Definition TMemory.cpp:158
Represents a node in the memory allocation system.
Definition TMemory.h:70
MemNode * pOwner
Owner node if this is a sub-allocation.
Definition TMemory.h:85
MemNode * pNextHole
Next free hole in the list.
Definition TMemory.h:89
MemNode * pPrevHole
Previous free hole in the list.
Definition TMemory.h:93
void * GetDataRegionEnd() const
Gets the end address of the data region for this node.
Definition TMemory.h:82
Represents a contiguous block of memory that can be allocated from.
Definition TMemory.h:101
MemNode * m_apHoles[9]
Array of free lists by size.
Definition TMemory.h:106
MemNode * m_pFirstHole
First free hole in the block.
Definition TMemory.h:107
TCHAR m_szName[52]
Name of the memory block.
Definition TMemory.h:109
TSIZE m_uiTotalSize1
Total size of the block.
Definition TMemory.h:103
Footer structure at the end of each memory block for validation.
Definition TMemory.h:118
Structure containing memory usage statistics.
Definition TMemory.h:139
TSIZE m_uiTotalFree
Total free memory.
Definition TMemory.h:142
TSIZE m_uiSmallestProcess
Size of smallest allocation.
Definition TMemory.h:151
TINT m_iNumProcesses
Number of allocated regions.
Definition TMemory.h:147
TSIZE m_uiUnk4
Unknown field 4.
Definition TMemory.h:153
TSIZE m_uiLogicTotalSize
Logical total size.
Definition TMemory.h:141
TSIZE m_uiUnk3
Unknown field 3.
Definition TMemory.h:152
TSIZE m_uiLogicTotalUsed
Logical total used memory.
Definition TMemory.h:145
TSIZE m_uiSmallestHole
Size of smallest free hole.
Definition TMemory.h:150
TSIZE m_uiLargestProcess
Size of largest allocation.
Definition TMemory.h:149
TSIZE m_uiLargestHole
Size of largest free hole.
Definition TMemory.h:148
TSIZE m_uiLogicTotalFree
Logical total free memory.
Definition TMemory.h:143
TSIZE m_uiTotalSize
Total size of memory block.
Definition TMemory.h:140
TINT m_iNumHoles
Number of free holes.
Definition TMemory.h:146
TSIZE m_uiTotalUsed
Total used memory.
Definition TMemory.h:144
Hardware abstraction layer memory information.
Definition TMemory.h:161
HALMemInfo()
Constructor for HALMemInfo Initializes all fields to zero.
Definition TMemory.cpp:965
static TSIZE Length(const TCHAR *str)
static TCHAR * String8Copy(TCHAR *dst, const TCHAR *src, TSIZE size=-1)
static void MemClear(void *ptr, TSIZE size)
Definition TUtil.h:91