Files
GTASource/rage/scaleform/Src/GKernel/HeapMH/GMemoryHeapMH.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1079 lines
31 KiB
C++

/**********************************************************************
Filename : MemoryHeapMH.cpp
Content : The main allocator interface. Receive data from heap
management system and allocate/free memory from the
current heap. Manipulates with heaps - creation of
heap chunks, deletes heap chunks, if free.
Created : July 14, 2008
Authors : Michael Antonov, Boris Rayskiy, Maxim Shemanarev
Copyright : (c) 2008 Scaleform Corp. All Rights Reserved.
Licensees may use this file in accordance with the valid Scaleform
Commercial License Agreement provided with the software.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
**********************************************************************/
#include "GHeapRootMH.h"
#include "GHeapAllocEngineMH.h"
#include "GHeapDebugInfoMH.h"
#include "GDebug.h"
#include "GMemoryHeapMH.h"
#include "GMemory.h"
#undef new
#ifdef SN_TARGET_PS3
#include <stdlib.h> // for reallocalign()
#endif
#if defined(GFC_OS_WIN32) && defined(GFC_BUILD_DEBUG)
#define GMEMORY_CHECK_CURRENT_THREAD(h) GASSERT((h->OwnerThreadId == 0) || (h->OwnerThreadId == ::GetCurrentThreadId()))
#else
#define GMEMORY_CHECK_CURRENT_THREAD(h)
#endif
static UPInt GHeapRootMemMH[(sizeof(GHeapRootMH) + sizeof(UPInt) - 1) / sizeof(UPInt)];
//------------------------------------------------------------------------
void GMemoryHeap::InitMH(GSysAlloc* sysAlloc) // static
{
if (GHeapGlobalRootMH)
{
GFC_DEBUG_MESSAGE(1, "GMemoryHeap::Init: Memory system has been already initialized");
GASSERT(0); return;
}
// Function HeapPageTable::Init() does not allocate any memory;
// it just initializes the root page table with zeros. So, the
// sequence of calls must remain as below: First init the page table,
// then create the root.
::new(GHeapRootMemMH) GHeapRootMH(sysAlloc);
}
//------------------------------------------------------------------------
void GMemoryHeap::CleanUpMH() // static
{
if (GHeapGlobalRootMH == 0)
{
GFC_DEBUG_MESSAGE(1, "MemoryHeap::Finalize: Memory system was not initialized");
GASSERT(0); return;
}
GHeapGlobalRootMH->~GHeapRootMH();
GHeapGlobalRootMH = 0;
}
//------------------------------------------------------------------------
GMemoryHeap* GMemoryHeap::CreateRootHeapMH(const HeapDesc& desc) // static
{
if (GHeapGlobalRootMH == 0)
{
GFC_DEBUG_MESSAGE(1, "CreateRootHeap: Memory System is not initialized");
GASSERT(0); return 0;
}
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
if (GMemory::pGlobalHeap)
{
GFC_DEBUG_MESSAGE(1, "CreateRootHeap: Root Memory Heap is already created");
GASSERT(0); return 0;
}
HeapDesc d2 = desc;
d2.HeapId = GHeapId_Global;
GMemory::pGlobalHeap = GHeapGlobalRootMH->CreateHeap("Global", 0, d2);
GASSERT(GMemory::pGlobalHeap);
}
return GMemory::pGlobalHeap;
}
//------------------------------------------------------------------------
GMemoryHeap* GMemoryHeap::CreateRootHeapMH() // static
{
HeapDesc desc;
desc.Flags = Heap_Root;
desc.MinAlign = RootHeap_MinAlign;
desc.Granularity = RootHeap_Granularity;
desc.Reserve = RootHeap_Reserve;
desc.Threshold = RootHeap_Threshold;
desc.Limit = RootHeap_Limit;
desc.HeapId = GHeapId_Global;
return CreateRootHeapMH(desc);
}
//------------------------------------------------------------------------
void GMemoryHeap::ReleaseRootHeapMH() // static
{
// No locks needed because this function can be called
// only after all the threads have shut down.
if (GHeapGlobalRootMH == 0)
{
GFC_DEBUG_MESSAGE(1, "ReleaseRootHeap: Memory System is not initialized");
GASSERT(0); return;
}
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
if (GMemory::pGlobalHeap == 0)
{
GFC_DEBUG_MESSAGE(1, "ReleaseRootHeap:: Root Memory Heap was not created");
GASSERT(0); return;
}
GMemory::pGlobalHeap->dumpMemoryLeaks();
GMemory::pGlobalHeap->destroyItself();
GMemory::pGlobalHeap = 0;
}
//------------------------------------------------------------------------
GMemoryHeapMH::GMemoryHeapMH() : GMemoryHeap(), pEngine(0)
#ifdef GHEAP_DEBUG_INFO
, pDebugStorage(0)
#endif
{
}
// *** Operations with memory arenas
//
//------------------------------------------------------------------------
void GMemoryHeapMH::CreateArena(UPInt, GSysAllocPaged*)
{
}
void GMemoryHeapMH::DestroyArena(UPInt)
{
}
bool GMemoryHeapMH::ArenaIsEmpty(UPInt)
{
return true;
}
//------------------------------------------------------------------------
GMemoryHeap* GMemoryHeapMH::CreateHeap(const char* name,
const HeapDesc& desc)
{
GMemoryHeap* heap = 0;
{
GLockSafe::Locker lock(GHeapGlobalRootMH->GetLock());
heap = GHeapGlobalRootMH->CreateHeap(name, this, desc);
if (heap)
{
RefCount++;
// printf("Created heap %p: %s\n", heap, name); // DBG
}
}
if (heap)
{
GLock::Locker lock(&HeapLock);
ChildHeaps.PushBack(heap);
}
return heap;
}
//------------------------------------------------------------------------
UPInt GMemoryHeapMH::GetFootprint() const
{
GLock::Locker lock(&HeapLock);
return pEngine->GetFootprint();
}
//------------------------------------------------------------------------
UPInt GMemoryHeapMH::GetTotalFootprint() const
{
GLock::Locker lock(&HeapLock);
UPInt footprint = 0;
if (!(Info.Desc.Flags & GMemoryHeap::Heap_UserDebug))
{
footprint = pEngine->GetFootprint();
}
const GMemoryHeap* heap = ChildHeaps.GetFirst();
while(!ChildHeaps.IsNull(heap))
{
footprint += heap->GetTotalFootprint();
heap = heap->pNext;
}
return footprint;
}
//------------------------------------------------------------------------
UPInt GMemoryHeapMH::GetUsedSpace() const
{
GLock::Locker lock(&HeapLock);
return pEngine->GetUsedSpace();
}
//------------------------------------------------------------------------
UPInt GMemoryHeapMH::GetTotalUsedSpace() const
{
GLock::Locker lock(&HeapLock);
UPInt space = 0;
if (!(Info.Desc.Flags & GMemoryHeap::Heap_UserDebug))
{
space = pEngine->GetUsedSpace();
}
const GMemoryHeap* heap = ChildHeaps.GetFirst();
while(!ChildHeaps.IsNull(heap))
{
space += heap->GetTotalUsedSpace();
heap = heap->pNext;
}
return space;
}
//------------------------------------------------------------------------
void GMemoryHeapMH::SetLimitHandler(LimitHandler* handler)
{
GLock::Locker locker(&HeapLock);
pEngine->SetLimitHandler(handler);
}
//------------------------------------------------------------------------
void GMemoryHeapMH::SetLimit(UPInt newLimit)
{
GLock::Locker locker(&HeapLock);
if (newLimit < Info.Desc.Limit)
{
if (newLimit < pEngine->GetFootprint())
newLimit = pEngine->GetFootprint();
}
Info.Desc.Limit = pEngine->SetLimit(newLimit);
}
//------------------------------------------------------------------------
void GMemoryHeapMH::AddRef()
{
// We use lock instead of atomic ops here to avoid accidental
// heap release during VisitChildHeaps iteration.
GLockSafe::Locker lock(GHeapGlobalRootMH->GetLock());
RefCount++;
}
//------------------------------------------------------------------------
void GMemoryHeapMH::Release()
{
GMemoryHeap* parent = Info.pParent;
if (parent)
{
// Lock scope.
GLock::Locker localLock(&parent->HeapLock);
GLockSafe::Locker globalLock(GHeapGlobalRootMH->GetLock());
if (--RefCount == 0)
{
// printf("Releasing heap %p: %s\n", this, GetName()); // DBG
GASSERT((Info.Desc.Flags & Heap_Root) == 0); // Cannot free root.
dumpMemoryLeaks();
GASSERT(ChildHeaps.IsEmpty());
parent->ChildHeaps.Remove(this);
GHeapGlobalRootMH->DestroyHeap(this);
}
else
{
parent = 0;
}
}
else
{
GLockSafe::Locker lock(GHeapGlobalRootMH->GetLock());
RefCount--;
// The global heap can be destroyed only from ReleaseRootHeap().
GASSERT(RefCount);
}
// This Release() must be performed out of the lock scopes.
if (parent)
parent->Release();
}
//------------------------------------------------------------------------
bool GMemoryHeapMH::dumpMemoryLeaks()
{
bool ret = false;
#ifdef GHEAP_DEBUG_INFO
ret = pDebugStorage->DumpMemoryLeaks(Info.pName);
#endif
// TO DO: May use something else instead of SF_DEBUG_MESSAGE
// to report unreleased heaps. Or turn on SF_DEBUG_MESSAGE in
// Release mode.
#ifdef GFC_BUILD_DEBUG
GMemoryHeap* heap = ChildHeaps.GetFirst();
while(!ChildHeaps.IsNull(heap))
{
GFC_DEBUG_MESSAGE2(1, "Heap '%s' has unreleased child '%s'",
Info.pName,
heap->Info.pName);
heap->dumpMemoryLeaks();
heap = heap->pNext;
ret = true;
}
#endif
return ret;
}
//------------------------------------------------------------------------
void GMemoryHeapMH::destroyItself()
{
GMemoryHeap* heap = ChildHeaps.GetFirst();
while(!ChildHeaps.IsNull(heap))
{
GMemoryHeap* next = heap->pNext;
heap->destroyItself();
heap = next;
}
GHeapGlobalRootMH->DestroyHeap(this);
}
//------------------------------------------------------------------------
void GMemoryHeapMH::freeLocked(void* ptr)
{
GLock::Locker heapLocker(&HeapLock);
GLockSafe::Locker rootLocker(GHeapGlobalRootMH->GetLock());
pEngine->Free(ptr);
}
//------------------------------------------------------------------------
inline void* GMemoryHeapMH::allocMem(UPInt size, const GAllocDebugInfo* info)
{
GHeapPageInfoMH pageInfo;
void* ptr = pEngine->Alloc(size, &pageInfo);
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->OnAlloc(this, size, 0, 0, ptr);
#endif
#ifdef GHEAP_DEBUG_INFO
#ifdef GHEAP_MEMSET_ALL
if (ptr)
memset(ptr, 0xCC, pageInfo.UsableSize);
#endif
if (ptr && TrackDebugInfo)
{
if (!pDebugStorage->AddAlloc(UPInt(ptr), size, &pageInfo, info))
{
freeLocked(ptr);
ptr = 0;
}
}
#else
GUNUSED(info);
#endif
return ptr;
}
//------------------------------------------------------------------------
inline void* GMemoryHeapMH::allocMem(UPInt size, UPInt align, const GAllocDebugInfo* info)
{
GHeapPageInfoMH pageInfo;
void* ptr = pEngine->Alloc(size, align, &pageInfo);
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->OnAlloc(this, size, align, 0, ptr);
#endif
#ifdef GHEAP_DEBUG_INFO
#ifdef GHEAP_MEMSET_ALL
if (ptr)
memset(ptr, 0xCC, pageInfo.UsableSize);
#endif
if (ptr && TrackDebugInfo)
{
if (!pDebugStorage->AddAlloc(UPInt(ptr), size, &pageInfo, info))
{
freeLocked(ptr);
ptr = 0;
}
}
#else
GUNUSED(info);
#endif
return ptr;
}
//------------------------------------------------------------------------
inline void* GMemoryHeapMH::allocMem(GHeapPageInfoMH* parentInfo, const void *thisPtr,
UPInt size, const GAllocDebugInfo* info)
{
GHeapPageInfoMH pageInfo;
void* ptr = pEngine->Alloc(size, &pageInfo);
#ifdef GHEAP_TRACE_ALL
unsigned sid = 0;
#ifdef GHEAP_ENABLE_DEBUG_INFO
if (ptr && TrackDebugInfo)
{
sid = pDebugStorage->GetStatId(&pageInfo, UPInt(thisPtr), info);
}
#endif
GHeapGlobalRootMH->OnAlloc(this, size, 0, sid, ptr);
#endif
#ifdef GHEAP_DEBUG_INFO
#ifdef GHEAP_MEMSET_ALL
if (ptr)
memset(ptr, 0xCC, pageInfo.UsableSize);
#endif
if (ptr && TrackDebugInfo)
{
if (!pDebugStorage->AddAlloc(parentInfo, UPInt(thisPtr),
UPInt(ptr), size,
&pageInfo, info))
{
freeLocked(ptr);
ptr = 0;
}
}
#else
GUNUSED3(parentInfo, thisPtr, info);
#endif
return ptr;
}
//------------------------------------------------------------------------
inline void* GMemoryHeapMH::allocMem(GHeapPageInfoMH* parentInfo,
const void *thisPtr, UPInt size, UPInt align,
const GAllocDebugInfo* info)
{
GHeapPageInfoMH pageInfo;
void* ptr = pEngine->Alloc(size, align, &pageInfo);
#ifdef GHEAP_TRACE_ALL
unsigned sid = 0;
#ifdef GHEAP_DEBUG_INFO
if (ptr && TrackDebugInfo)
{
sid = pDebugStorage->GetStatId(&pageInfo, UPInt(thisPtr), info);
}
#endif
GHeapGlobalRootMH->OnAlloc(this, size, align, sid, ptr);
#endif
#ifdef GHEAP_DEBUG_INFO
#ifdef GHEAP_MEMSET_ALL
if (ptr)
memset(ptr, 0xCC, pageInfo.UsableSize);
#endif
if (ptr && TrackDebugInfo)
{
if (!pDebugStorage->AddAlloc(parentInfo, UPInt(thisPtr),
UPInt(ptr), size,
&pageInfo, info))
{
freeLocked(ptr);
ptr = 0;
}
}
#else
GUNUSED3(parentInfo, thisPtr, info);
#endif
return ptr;
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::Alloc(UPInt size, const GAllocDebugInfo* info)
{
if (UseLocks)
{
GLock::Locker locker(&HeapLock);
return allocMem(size, info);
}
GMEMORY_CHECK_CURRENT_THREAD(this);
return allocMem(size, info);
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::Alloc(UPInt size, UPInt align, const GAllocDebugInfo* info)
{
if (UseLocks)
{
GLock::Locker locker(&HeapLock);
return allocMem(size, align, info);
}
GMEMORY_CHECK_CURRENT_THREAD(this);
return allocMem(size, align, info);
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::AllocAutoHeap(const void *thisPtr, UPInt size,
const GAllocDebugInfo* info)
{
GMemoryHeapMH* heap;
GHeapPageMH* page = GHeapGlobalRootMH->ResolveAddress(UPInt(thisPtr));
#ifdef GHEAP_DEBUG_INFO
GHeapPageInfoMH parentInfo;
#endif
void* ptr = 0;
if (page)
{
heap = page->pHeap;
if (heap->UseLocks)
{
GLock::Locker locker(&heap->HeapLock);
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(page, &parentInfo);
return heap->allocMem(&parentInfo, thisPtr, size, info);
#else
return heap->allocMem(0, thisPtr, size, info);
#endif
}
else
{
GMEMORY_CHECK_CURRENT_THREAD(this);
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(page, &parentInfo);
return heap->allocMem(&parentInfo, thisPtr, size, info);
#else
return heap->allocMem(0, thisPtr, size, info);
#endif
}
}
else
{
GHeapNodeMH* node = 0;
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
node = GHeapGlobalRootMH->FindNodeInGlobalTree((UByte*)thisPtr);
GASSERT(node);
heap = node->GetHeap();
}
if (heap->UseLocks)
{
GLock::Locker locker1(&heap->HeapLock);
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(node, &parentInfo);
ptr = heap->allocMem(&parentInfo, thisPtr, size, info);
#else
ptr = heap->allocMem(0, thisPtr, size, info);
#endif
}
else
{
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(node, &parentInfo);
ptr = heap->allocMem(&parentInfo, thisPtr, size, info);
#else
ptr = heap->allocMem(0, thisPtr, size, info);
#endif
}
}
return ptr;
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::AllocAutoHeap(const void *thisPtr, UPInt size, UPInt align,
const GAllocDebugInfo* info)
{
GMemoryHeapMH* heap;
GHeapPageMH* page = GHeapGlobalRootMH->ResolveAddress(UPInt(thisPtr));
#ifdef GHEAP_DEBUG_INFO
GHeapPageInfoMH parentInfo;
#endif
void* ptr = 0;
if (page)
{
heap = page->pHeap;
if (heap->UseLocks)
{
GLock::Locker locker(&heap->HeapLock);
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(page, &parentInfo);
return heap->allocMem(&parentInfo, thisPtr, size, align, info);
#else
return heap->allocMem(0, thisPtr, size, align, info);
#endif
}
else
{
GMEMORY_CHECK_CURRENT_THREAD(this);
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(page, &parentInfo);
return heap->allocMem(&parentInfo, thisPtr, size, align, info);
#else
return heap->allocMem(0, thisPtr, size, align, info);
#endif
}
}
else
{
GHeapNodeMH* node = 0;
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
node = GHeapGlobalRootMH->FindNodeInGlobalTree((UByte*)thisPtr);
GASSERT(node);
heap = node->GetHeap();
}
if (heap->UseLocks)
{
GLock::Locker locker1(&heap->HeapLock);
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(page, &parentInfo);
ptr = heap->allocMem(&parentInfo, thisPtr, size, align, info);
#else
ptr = heap->allocMem(0, thisPtr, size, align, info);
#endif
}
else
{
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
#ifdef GHEAP_DEBUG_INFO
heap->pEngine->GetPageInfo(page, &parentInfo);
ptr = heap->allocMem(&parentInfo, thisPtr, size, align, info);
#else
ptr = heap->allocMem(0, thisPtr, size, align, info);
#endif
}
}
return ptr;
}
//------------------------------------------------------------------------
void GMemoryHeapMH::freeMem(GHeapPageMH* page, void* ptr)
{
#ifdef GHEAP_DEBUG_INFO
GHeapPageInfoMH pageInfo;
pEngine->GetPageInfoWithSize(page, ptr, &pageInfo);
pDebugStorage->RemoveAlloc(UPInt(ptr), &pageInfo);
#ifdef GHEAP_MEMSET_ALL
memset(ptr, 0xFE, pageInfo.UsableSize);
#endif //GHEAP_MEMSET_ALL
#endif //GHEAP_DEBUG_INFO
pEngine->Free(page, ptr);
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->OnFree(this, ptr);
#endif
}
//------------------------------------------------------------------------
void GMemoryHeapMH::freeMem(GHeapNodeMH* node, void* ptr)
{
#ifdef GHEAP_DEBUG_INFO
GHeapPageInfoMH pageInfo;
pEngine->GetPageInfoWithSize(node, ptr, &pageInfo);
pDebugStorage->RemoveAlloc(UPInt(ptr), &pageInfo);
#ifdef GHEAP_MEMSET_ALL
memset(ptr, 0xFE, pageInfo.UsableSize);
#endif //GHEAP_MEMSET_ALL
#endif //GHEAP_DEBUG_INFO
pEngine->Free(node, ptr);
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->OnFree(this, ptr);
#endif
}
//------------------------------------------------------------------------
void GMemoryHeapMH::Free(void* ptr)
{
//UltimateCheck(); // DBG
//static int c; if(++c % 500 == 0) return; // DBG Simulate memory leaks
if (ptr)
{
GMemoryHeapMH* heap = 0;
GHeapPageMH* page = GHeapGlobalRootMH->ResolveAddress(UPInt(ptr));
if (page)
{
heap = page->pHeap;
if (heap->UseLocks)
{
GLock::Locker locker(&heap->HeapLock);
heap->freeMem(page, ptr);
}
else
{
GMEMORY_CHECK_CURRENT_THREAD(this);
heap->freeMem(page, ptr);
}
}
else
{
GHeapNodeMH* node = 0;
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
node = GHeapGlobalRootMH->FindNodeInGlobalTree((UByte*)ptr);
GASSERT(node);
heap = node->GetHeap();
}
if (heap->UseLocks)
{
GLock::Locker locker1(&heap->HeapLock);
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
heap->freeMem(node, ptr);
}
else
{
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
heap->freeMem(node, ptr);
}
}
GASSERT(heap);
if (ptr == heap->pAutoRelease)
heap->Release();
}
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::reallocMem(GHeapPageMH* page, void* oldPtr, UPInt newSize)
{
#ifdef GHEAP_DEBUG_INFO
GHeapPageInfoMH oldPageInfo;
pEngine->GetPageInfoWithSize(page, oldPtr, &oldPageInfo);
GHeapDebugStorageMH::DebugDataPtr debugData;
if (TrackDebugInfo)
{
pDebugStorage->UnlinkAlloc(UPInt(oldPtr), &oldPageInfo, &debugData);
pDebugStorage->CheckDataTail(&debugData, oldPageInfo.UsableSize);
}
#ifdef GHEAP_MEMSET_ALL
if (newSize < oldPageInfo.UsableSize)
{
memset((UByte*)oldPtr + newSize, 0xFE, oldPageInfo.UsableSize - newSize);
}
#endif //GHEAP_MEMSET_ALL
#endif //GHEAP_DEBUG_INFO
GHeapPageInfoMH newPageInfo;
void* newPtr = pEngine->ReallocInPage(page, oldPtr, newSize, &newPageInfo);
if (newPtr == 0)
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
newPtr = pEngine->ReallocGeneral(page, oldPtr, newSize, &newPageInfo);
}
#ifdef GHEAP_DEBUG_INFO
if (newPtr)
{
#ifdef GHEAP_MEMSET_ALL
if (newPtr && newSize > newPageInfo.UsableSize)
{
memset((UByte*)newPtr + newPageInfo.UsableSize, 0xCC, newSize - newPageInfo.UsableSize);
}
#endif //GHEAP_MEMSET_ALL
if (TrackDebugInfo && newPtr)
{
pDebugStorage->RelinkAlloc(&debugData, UPInt(oldPtr),
UPInt(newPtr), newSize,
&newPageInfo);
}
}
#endif //GHEAP_DEBUG_INFO
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->OnRealloc(this, oldPtr, newSize, newPtr);
#endif
return newPtr;
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::reallocMem(GHeapNodeMH* node, void* oldPtr, UPInt newSize)
{
#ifdef GHEAP_DEBUG_INFO
GHeapPageInfoMH oldPageInfo;
pEngine->GetPageInfoWithSize(node, oldPtr, &oldPageInfo);
GHeapDebugStorageMH::DebugDataPtr debugData;
if (TrackDebugInfo)
{
pDebugStorage->UnlinkAlloc(UPInt(oldPtr), &oldPageInfo, &debugData);
pDebugStorage->CheckDataTail(&debugData, oldPageInfo.UsableSize);
}
#ifdef GHEAP_MEMSET_ALL
if (newSize < oldPageInfo.UsableSize)
{
memset((UByte*)oldPtr + newSize, 0xFE, oldPageInfo.UsableSize - newSize);
}
#endif //GHEAP_MEMSET_ALL
#endif //GHEAP_DEBUG_INFO
GHeapPageInfoMH newPageInfo;
void* newPtr = pEngine->ReallocInNode(node, oldPtr, newSize, &newPageInfo);
#ifdef GHEAP_DEBUG_INFO
if (newPtr)
{
#ifdef GHEAP_MEMSET_ALL
if (newPtr && newSize > newPageInfo.UsableSize)
{
memset((UByte*)newPtr + newPageInfo.UsableSize, 0xCC, newSize - newPageInfo.UsableSize);
}
#endif //GHEAP_MEMSET_ALL
if (TrackDebugInfo && newPtr)
{
pDebugStorage->RelinkAlloc(&debugData, UPInt(oldPtr),
UPInt(newPtr), newSize,
&newPageInfo);
}
}
#endif //GHEAP_DEBUG_INFO
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->OnRealloc(this, oldPtr, newSize, newPtr);
#endif
return newPtr;
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::Realloc(void* oldPtr, UPInt newSize)
{
// Realloc cannot work as Alloc in case oldPtr is 0. It's done in
// order not to pass a lot of parameters, such as DebugInfo, alignment,
// parent allocation, etc.
//------------------------
GASSERT(oldPtr != 0);
GMemoryHeapMH* heap;
GHeapPageMH* page = GHeapGlobalRootMH->ResolveAddress(UPInt(oldPtr));
void* newPtr = 0;
if (page)
{
heap = page->pHeap;
if (heap->UseLocks)
{
GLock::Locker locker(&heap->HeapLock);
newPtr = heap->reallocMem(page, oldPtr, newSize);
}
else
{
GMEMORY_CHECK_CURRENT_THREAD(this);
newPtr = heap->reallocMem(page, oldPtr, newSize);
}
}
else
{
GHeapNodeMH* node = 0;
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
node = GHeapGlobalRootMH->FindNodeInGlobalTree((UByte*)oldPtr);
GASSERT(node);
heap = node->GetHeap();
}
if (heap->UseLocks)
{
GLock::Locker locker1(&heap->HeapLock);
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
newPtr = heap->reallocMem(node, oldPtr, newSize);
}
else
{
GLockSafe::Locker locker2(GHeapGlobalRootMH->GetLock());
newPtr = heap->reallocMem(node, oldPtr, newSize);
}
}
return newPtr;
}
//------------------------------------------------------------------------
GMemoryHeap* GMemoryHeapMH::GetAllocHeap(const void *thisPtr)
{
GHeapPageMH* page = GHeapGlobalRootMH->ResolveAddress(UPInt(thisPtr));
if (page) return page->pHeap;
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
GHeapNodeMH* node = GHeapGlobalRootMH->FindNodeInGlobalTree((UByte*)thisPtr);
GASSERT(node);
return node->GetHeap();
}
//------------------------------------------------------------------------
UPInt GMemoryHeapMH::GetUsableSize(const void* ptr)
{
GHeapPageMH* page = GHeapGlobalRootMH->ResolveAddress(UPInt(ptr));
GHeapPageInfoMH pageInfo;
if (page)
{
page->pHeap->pEngine->GetPageInfoWithSize(page, ptr, &pageInfo);
return pageInfo.UsableSize;
}
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
GHeapNodeMH* node = GHeapGlobalRootMH->FindNodeInGlobalTree((UByte*)ptr);
GASSERT(node);
node->GetHeap()->pEngine->GetPageInfoWithSize(node, ptr, &pageInfo);
return pageInfo.UsableSize;
}
//------------------------------------------------------------------------
void* GMemoryHeapMH::AllocSysDirect(UPInt size)
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
return GHeapGlobalRootMH->GetSysAlloc()->Alloc(size, sizeof(void*));
}
void GMemoryHeapMH::FreeSysDirect(void* ptr, UPInt size)
{
GLockSafe::Locker locker(GHeapGlobalRootMH->GetLock());
return GHeapGlobalRootMH->GetSysAlloc()->Free(ptr, size, sizeof(void*));
}
//------------------------------------------------------------------------
bool GMemoryHeapMH::GetStats(GStatBag* bag)
{
GLock::Locker locker(&HeapLock);
UPInt footprint = pEngine->GetFootprint();
bag->AddStat(GStatHeap_LocalFootprint, GCounterStat(footprint));
bag->AddStat(GStatHeap_LocalUsedSpace, GCounterStat(pEngine->GetUsedSpace()));
bag->AddStat(GStatHeap_Granularity, GCounterStat(0));
bag->AddStat(GStatHeap_Reserve, GCounterStat(0));
bag->AddStat(GStatHeap_Bookkeeping, GCounterStat(0));
#ifdef GHEAP_DEBUG_INFO
bag->AddStat(GStatHeap_DebugInfo, GCounterStat(pDebugStorage->GetUsedSpace()));
#endif
bag->AddStat(GStatHeap_Segments, GCounterStat(0));
bag->AddStat(GStatHeap_DynamicGranularity, GCounterStat(0));
bag->AddStat(GStatHeap_SysDirectSpace, GCounterStat(0));
// Collect child footprint.
UPInt childHeapCount = 0;
UPInt childFootprint = 0;
GMemoryHeap* heap = ChildHeaps.GetFirst();
while(!ChildHeaps.IsNull(heap))
{
// TBD: Should we have more detailed logic here?
if (!(heap->Info.Desc.Flags & GMemoryHeap::Heap_UserDebug))
{
childHeapCount++;
// Thread TBD: Need to make sure that child heap locks are not obtained before parent.
childFootprint += heap->GetTotalFootprint();
}
heap = heap->pNext;
}
if (childHeapCount)
{
bag->AddStat(GStatHeap_ChildHeaps, GCounterStat(childHeapCount));
bag->AddStat(GStatHeap_ChildFootprint,GCounterStat(childFootprint));
}
bag->AddStat(GStatHeap_TotalFootprint, GCounterStat(childFootprint + footprint));
// Collect detailed memory summary information in debug builds.
#ifdef GHEAP_DEBUG_INFO
pDebugStorage->GetStats(pEngine, bag);
#endif
return true;
}
//------------------------------------------------------------------------
void GMemoryHeapMH::VisitMem(GHeapMemVisitor*, unsigned)
{
}
//------------------------------------------------------------------------
void GMemoryHeapMH::VisitHeapSegments(GHeapSegVisitor*) const
{
}
//------------------------------------------------------------------------
void GMemoryHeapMH::VisitRootSegments(GHeapSegVisitor*)
{
}
//------------------------------------------------------------------------
void GMemoryHeapMH::getUserDebugStats(RootStats* stats) const
{
GLock::Locker lock(&HeapLock);
if (Info.Desc.Flags & GMemoryHeap::Heap_UserDebug)
{
stats->UserDebugFootprint += pEngine->GetFootprint();
stats->UserDebugUsedSpace += pEngine->GetUsedSpace();
}
const GMemoryHeap* heap = ChildHeaps.GetFirst();
while(!ChildHeaps.IsNull(heap))
{
heap->getUserDebugStats(stats);
heap = heap->pNext;
}
}
//------------------------------------------------------------------------
void GMemoryHeapMH::GetRootStats(RootStats* stats)
{
stats->UserDebugFootprint = 0;
stats->UserDebugUsedSpace = 0;
GMemory::pGlobalHeap->getUserDebugStats(stats);
stats->SysMemFootprint = GMemory::pGlobalHeap->GetTotalFootprint() + stats->UserDebugFootprint;
stats->SysMemUsedSpace = GMemory::pGlobalHeap->GetTotalUsedSpace() + stats->UserDebugFootprint;
stats->PageMapFootprint = 0;
stats->PageMapUsedSpace = 0;
stats->BookkeepingFootprint = 0;
stats->BookkeepingUsedSpace = 0;
stats->DebugInfoFootprint = 0;
stats->DebugInfoUsedSpace = 0;
}
//------------------------------------------------------------------------
void GMemoryHeapMH::SetTracer(HeapTracer* tracer)
{
#ifdef GHEAP_TRACE_ALL
GHeapGlobalRootMH->pTracer = tracer;
#else
GUNUSED(tracer);
#endif
}
//------------------------------------------------------------------------
void GMemoryHeapMH::ultimateCheck()
{
}
//------------------------------------------------------------------------
void GMemoryHeapMH::checkIntegrity() const
{
}
//------------------------------------------------------------------------
void GMemoryHeapMH::releaseCachedMem()
{
}
//------------------------------------------------------------------------
// Implementation of GSysAllocBase based on MemoryHeapMH.
// Initializes heap system, creating and initializing GlobalHeap.
bool GSysAlloc::initHeapEngine(const void* heapDesc)
{
GMemoryHeap::InitMH(this);
const GMemoryHeap::HeapDesc& rootHeapDesc = *(const GMemoryHeap::HeapDesc*)heapDesc;
GMemoryHeap* p = GMemoryHeap::CreateRootHeapMH(rootHeapDesc);
return p != 0;
}
void GSysAlloc::shutdownHeapEngine()
{
GMemoryHeap::ReleaseRootHeapMH();
GMemoryHeap::CleanUpMH();
}