1818# include " Profiler/tracy/Tracy.hpp"
1919#endif // TOSHI_PROFILER_MEMORY
2020
21+ #ifdef __SANITIZE_ADDRESS__
22+ # include < sanitizer/asan_interface.h>
23+ #endif
24+
2125#include " TMemoryDebugOff.h"
2226
2327/* *
@@ -160,39 +164,6 @@ TMemory::~TMemory()
160164 g_pMemory = TNULL;
161165}
162166
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-
196167// $Barnyard: FUNCTION 006b5230
197168/* *
198169 * @brief Allocates memory with specified size and alignment
@@ -212,176 +183,141 @@ TMemory::~TMemory()
212183 */
213184void * TMemory::Alloc ( TSIZE a_uiSize, TSIZE a_uiAlignment, MemBlock* a_pMemBlock, const TCHAR* a_szFileName, TINT a_iLineNum )
214185{
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-
217186 TMUTEX_LOCK_SCOPE ( ms_pGlobalMutex );
218187
219- volatile TSIZE uiSize = a_uiSize;
220- volatile TSIZE uiAlignment = a_uiAlignment;
221- MemBlock* pMemBlock = a_pMemBlock;
222-
188+ TSIZE uiSize = a_uiSize;
223189 if ( uiSize < 4 )
224190 uiSize = 4 ;
225191
192+ TSIZE uiAlignment = a_uiAlignment;
226193 if ( uiAlignment < 16 )
227194 uiAlignment = 16 ;
228195
196+ MemBlock* pBlock = a_pMemBlock;
197+ if ( !pBlock )
198+ pBlock = this ->m_pGlobalBlock ;
199+
229200 if ( uiAlignment < TMEMORY_ROUNDUP )
230201 {
231202 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 );
203+ DebugPrintHALMemInfo ( " Out of Toshi Memory on block [%s]\n " , pBlock ->m_szName );
233204 TASSERT ( TFALSE );
234205 return TNULL;
235206 }
236207
237- if ( !pMemBlock )
238- {
239- pMemBlock = m_pGlobalBlock;
240- }
241-
242- volatile TSIZE uiAlignedSize = TAlignNumUp ( uiSize );
243- volatile TSIZE uiRequiredSize = uiAlignedSize + sizeof ( MemNode );
208+ // Align size up to the nearest 4 bytes boundary
209+ TSIZE alignedSize = TAlignNumUp ( uiSize );
210+ TSIZE listIndex = MapSizeToFreeList ( alignedSize );
244211
245- MemNode* pMemNode = TNULL;
212+ TSIZE index = listIndex;
213+ MemNode* hole = TNULL;
214+ TSIZE availableSize = 0 ;
215+ void * alignedStart = TNULL;
246216
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++ )
217+ // Find a suitable hole in the free lists
218+ if ( index < TMEMORY_NUM_FREELISTS )
256219 {
257- pMemNode = pMemBlock->m_apHoles [ uiNodeId ];
258-
259- while ( pMemNode != TNULL )
220+ while ( index < TMEMORY_NUM_FREELISTS )
260221 {
261- pAllocatedAddress = TAlignPointerUp ( pMemNode->GetDataRegionStart (), uiAlignment );
262- uiDataRegionStart = TREINTERPRETCAST ( TUINTPTR, pAllocatedAddress );
263- uiDataRegionEnd = TREINTERPRETCAST ( TUINTPTR, pMemNode->GetDataRegionEnd () );
264- uiDataRegionSize = uiDataRegionEnd - uiDataRegionStart;
222+ hole = pBlock->m_apHoles [ index ];
223+ while ( hole )
224+ {
225+ // Align start address based on requested alignment
226+ alignedStart = TAlignPointerUp ( hole->GetDataRegionStart (), uiAlignment );
265227
266- if ( uiDataRegionEnd > uiDataRegionStart && uiDataRegionSize >= uiAlignedSize )
267- break ;
228+ if ( (TUINTPTR)hole->GetDataRegionEnd () > (TUINTPTR)alignedStart )
229+ {
230+ availableSize = (TUINTPTR)hole->GetDataRegionEnd () - (TUINTPTR)alignedStart;
231+ if ( availableSize >= alignedSize )
232+ goto HOLE_FOUND;
233+ }
268234
269- // This freelist can't be used, let's check for the next
270- pMemNode = pMemNode->pNextHole ;
235+ hole = hole->pNextHole ;
236+ }
237+ index++;
271238 }
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;
285239 }
286240
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
241+ // Out of memory path
242+ DebugPrintHALMemInfo ( " Out of Toshi Memory on block [%s] \n " , pBlock-> m_szName );
243+ DebugPrintHALMemInfo ( " Requested memory block size: %d \n " , alignedSize );
244+ DumpMemInfo ();
291245
292- MemNode* pAllocNode = MEM_TO_NODE ( pAllocatedAddress );
246+ TASSERT ( TFALSE );
247+ return TNULL;
293248
294- if ( volatile MemNode* pOwner = pMemNode->pOwner )
249+ HOLE_FOUND:
250+ if ( hole->pOwner == TNULL )
295251 {
296- pOwner->uiSize = ( uiDataRegionStart - (TUINTPTR)pOwner - 24 ) | pOwner->uiSize & TMEMORY_FLAGS_MASK;
252+ MemNode* newNode = MEM_TO_NODE ( alignedStart );
253+ if ( newNode != hole )
254+ {
255+ // If this is the root hole and it shifts due to alignment, update the block's tracker
256+ pBlock->m_pFirstHole = newNode;
257+ }
297258 }
298- else if ( pAllocNode != pMemNode )
259+ else
299260 {
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;
261+ // Adjust the owner's size retaining its original flags (bottom 2 bits), extending it to absorb padding
262+ hole->pOwner ->uiSize = ( hole->pOwner ->uiSize & TMEMORY_FLAGS_MASK ) | ( (TUINTPTR)alignedStart - (TUINTPTR)hole->pOwner - 24 );
304263 }
305264
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 ;
265+ // Disconnect old hole from its free list
266+ if ( hole->pPrevHole )
267+ hole->pPrevHole ->pNextHole = hole->pNextHole ;
268+ else
269+ pBlock->m_apHoles [ index ] = hole->pNextHole ;
320270
321- if ( pMemNode != pAllocNode )
322- {
323- TSIZE uiNodeSize = GetNodeSize ( pMemNode );
324- pAllocNode->pOwner = pMemNode->pOwner ;
325- *(MemNode**)( (TUINTPTR)pMemNode->GetDataRegionStart () + uiNodeSize ) = pAllocNode;
326- }
271+ if ( hole->pNextHole )
272+ hole->pNextHole ->pPrevHole = hole->pPrevHole ;
327273
328- // Create a new hole right after the allocated data
329- MemNode* pNewNode = TREINTERPRETCAST ( MemNode*, uiDataRegionStart + uiAlignedSize );
274+ MemNode* newNode = MEM_TO_NODE ( alignedStart );
275+ if ( newNode != hole )
276+ {
277+ MemNode** pBoundaryTag = (MemNode**)hole->GetDataRegionEnd ();
278+ MemNode* pCachedOwner = hole->pOwner ;
330279
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;
280+ newNode->pOwner = pCachedOwner;
281+ *pBoundaryTag = newNode;
282+ }
335283
336- // Place the new hole in the memblock's list
284+ if ( availableSize > alignedSize + sizeof ( MemNode ) )
285+ {
286+ // Split Hole
287+ MemNode* newHole = (MemNode*)( (TUINTPTR)alignedStart + alignedSize );
288+ TSIZE remainingSize = availableSize - ( sizeof ( MemNode ) - sizeof ( void * ) ) - alignedSize;
337289
338- TUINT uiNewHoleId = MapSizeToFreeList ( GetNodeSize ( pNewNode ) );
290+ newHole->uiSize = remainingSize;
291+ newHole->pOwner = newNode;
339292
340- MemNode* pOldNode = pMemBlock-> m_apHoles [ uiNewHoleId ] ;
341- pNewNode-> pNextHole = pOldNode;
293+ newNode-> pMemBlock = pBlock ;
294+ newNode-> uiSize = alignedSize | m_uiGlobalFlags | 1 ; // OR '1' flag sets allocation to true
342295
343- if ( pOldNode )
344- pOldNode->pPrevHole = pNewNode;
296+ // Insert new remainder hole into appropriate free list
297+ TSIZE newIndex = MapSizeToFreeList ( remainingSize - 1 );
298+ newHole->pNextHole = pBlock->m_apHoles [ newIndex ];
345299
346- pNewNode-> pPrevHole = TNULL;
347- pMemBlock-> m_apHoles [ uiNewHoleId ] = pNewNode ;
300+ if ( newHole-> pNextHole )
301+ newHole-> pNextHole -> pPrevHole = newHole ;
348302
349- // Save pointer to the hole right at the end of the data region (probably for some validation)
350- *(MemNode* volatile *)pNewNode-> GetDataRegionEnd () = pNewNode ;
303+ newHole-> pPrevHole = TNULL;
304+ pBlock-> m_apHoles [ newIndex ] = newHole ;
351305
352- # ifdef TOSHI_PROFILER_MEMORY
353- TracyAlloc ( (void *)pAllocatedAddress, uiAlignedSize );
354- # endif
355- return (void *)pAllocatedAddress;
306+ *(MemNode**)newHole->GetDataRegionEnd () = newHole; // Apply boundary tag
356307 }
357308 else
358309 {
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- }
310+ // Consume Entire Hole
311+ newNode->pMemBlock = pBlock;
312+ newNode->uiSize = availableSize | m_uiGlobalFlags | 1 ; // Mark node completely occupied
377313
378- SetProcess ( pMemBlock, pAllocNode, uiDataRegionSize );
314+ }
379315
380316# ifdef TOSHI_PROFILER_MEMORY
381- TracyAlloc ( ( void *)pAllocatedAddress, uiAlignedSize );
317+ TracyAlloc ( alignedStart, alignedSize );
382318# endif
383- return ( void *)pAllocatedAddress;
384- }
319+
320+ return alignedStart;
385321}
386322
387323// $Barnyard: FUNCTION 006b4a20
@@ -398,8 +334,6 @@ void* TMemory::Alloc( TSIZE a_uiSize, TSIZE a_uiAlignment, MemBlock* a_pMemBlock
398334 */
399335TBOOL TMemory::Free ( const void * a_pAllocated )
400336{
401- // return CALL_THIS( 0x006b4a20, TMemory*, TBOOL, this, const void*, a_pAllocated );
402-
403337 TMUTEX_LOCK_SCOPE ( ms_pGlobalMutex );
404338
405339 if ( !a_pAllocated || !TIsPointerAligned ( a_pAllocated ) )
@@ -417,6 +351,10 @@ TBOOL TMemory::Free( const void* a_pAllocated )
417351 TSIZE uiAllocationSize = GetNodeSize ( pAllocationNode );
418352 MemBlock* pMemBlock = GetProcessMemBlock ( pAllocationNode );
419353
354+ # ifdef __SANITIZE_ADDRESS__
355+ __asan_unpoison_memory_region ( a_pAllocated, uiAllocationSize );
356+ # endif
357+
420358 SetHoleSize ( pAllocationNode, uiAllocationSize );
421359
422360 MemNode* pNextLyingNode = (MemNode*)pAllocationNode->GetDataRegionEnd ();
0 commit comments