Files
ac-decomp/src/JSystem/JKernel/JKRHeap.cpp
T
2023-03-13 07:15:03 +00:00

427 lines
11 KiB
C++

#include "JSystem/JUtility/JUTAssertion.h"
#include "JSystem/JKernel/JKRHeap.h"
#include "dolphin/os.h"
#include "dolphin/os/OSArena.h"
#include "dolphin/os/OSAlloc.h"
#include "dolphin/os/OSMemory.h"
#include "dolphin/os/OSUtil.h"
#include "dolphin/os/OSAddress.h"
JKRHeap *JKRHeap::sSystemHeap;
JKRHeap *JKRHeap::sCurrentHeap;
JKRHeap *JKRHeap::sRootHeap;
JKRHeapErrorHandler *JKRHeap::mErrorHandler;
void *JKRHeap::mCodeStart;
void *JKRHeap::mCodeEnd;
void *JKRHeap::mUserRamStart;
void *JKRHeap::mUserRamEnd;
u32 JKRHeap::mMemorySize;
bool JKRHeap::sDefaultFillFlag = true;
JKRHeap::JKRHeap(void *data, u32 size, JKRHeap *heap, bool errorFlag) : JKRDisposer(),
mChildTree(this),
mDisposerList()
{
OSInitMutex(&mMutex);
mSize = size;
mStart = (u8 *)data;
mEnd = ((u8 *)data + size);
if (heap == nullptr)
{
becomeSystemHeap();
becomeCurrentHeap();
}
else
{
heap->mChildTree.appendChild(&mChildTree);
if (sSystemHeap == sRootHeap)
becomeSystemHeap();
if (sCurrentHeap == sRootHeap)
becomeCurrentHeap();
}
mErrorFlag = errorFlag;
if (mErrorFlag == true && mErrorHandler == nullptr)
mErrorHandler = JKRDefaultMemoryErrorRoutine;
mDebugFill = sDefaultFillFlag;
mInitFlag = false;
}
JKRHeap::~JKRHeap()
{
mChildTree.getParent()->removeChild(&mChildTree);
JSUTree<JKRHeap> *nextRootHeap = sRootHeap->mChildTree.getFirstChild();
if (sCurrentHeap == this)
sCurrentHeap = !nextRootHeap ? sRootHeap : nextRootHeap->getObject();
if (sSystemHeap == this)
sSystemHeap = !nextRootHeap ? sRootHeap : nextRootHeap->getObject();
}
bool JKRHeap::initArena(char **outUserRamStart, u32 *outUserRamSize, int numHeaps)
{
void *arenaLo = OSGetArenaLo();
void *arenaHi = OSGetArenaHi();
if (arenaLo == arenaHi)
{
return false;
}
void *arenaStart = OSInitAlloc(arenaLo, arenaHi, numHeaps);
arenaHi = (u8 *)OSRoundDown32B(arenaHi);
arenaLo = (u8 *)OSRoundUp32B(arenaStart);
u8 *start = (u8 *)OSPhysicalToCached(0);
mCodeStart = (u8 *)start;
mCodeEnd = (u8 *)arenaLo;
mUserRamStart = (u8 *)arenaLo;
mUserRamEnd = (u8 *)arenaHi;
mMemorySize = *(u32 *)((start + 0x28));
OSSetArenaLo(arenaHi);
OSSetArenaHi(arenaHi);
*outUserRamStart = (char *)arenaLo;
*outUserRamSize = (u32)arenaHi - (u32)arenaLo;
return true;
}
JKRHeap *JKRHeap::becomeSystemHeap()
{
JKRHeap *old = sSystemHeap;
sSystemHeap = this;
return old;
}
JKRHeap *JKRHeap::becomeCurrentHeap()
{
JKRHeap *old = sCurrentHeap;
sCurrentHeap = this;
return old;
}
void JKRHeap::destroy(JKRHeap *heap)
{
JUT_ASSERT(200, heap != 0);
heap->destroy();
}
void *JKRHeap::alloc(u32 byteCount, int padding, JKRHeap *heap)
{
void *memory = nullptr;
if (heap)
{
memory = heap->do_alloc(byteCount, padding);
}
else if (sCurrentHeap)
{
memory = sCurrentHeap->do_alloc(byteCount, padding);
}
return memory;
}
void *JKRHeap::alloc(u32 byteCount, int padding)
{
JUT_WARNING_F(317, !mInitFlag, "alloc %x byte in heap %x", byteCount, this);
return do_alloc(byteCount, padding);
}
void JKRHeap::free(void *memory, JKRHeap *heap)
{
if ((heap) || (heap = findFromRoot(memory), heap))
{
heap->free(memory);
}
}
void JKRHeap::free(void *memory)
{
JUT_WARNING_F(365, !mInitFlag, "free %x in heap %x", memory, this);
do_free(memory);
}
void JKRHeap::callAllDisposer()
{
JSUListIterator<JKRDisposer> iterator;
while (iterator = mDisposerList.getFirst(), iterator != mDisposerList.getEnd())
{
iterator->~JKRDisposer();
}
}
void JKRHeap::freeAll()
{
JUT_WARNING_F(417, !mInitFlag, "freeAll in heap %x", this);
do_freeAll();
}
void JKRHeap::freeTail()
{
JUT_WARNING_F(431, !mInitFlag, "freeTail in heap %x", this);
do_freeTail();
}
void JKRHeap::resize(void *memoryBlock, u32 newSize)
{
JUT_WARNING_F(491, !mInitFlag, "resize block %x into %x in heap %x", memoryBlock, newSize, this);
do_resize(memoryBlock, newSize);
}
s32 JKRHeap::getSize(void *memoryBlock, JKRHeap *heap)
{
if (heap == nullptr && (heap = findFromRoot(memoryBlock), heap == nullptr))
{
return -1;
}
else
return heap->getSize(memoryBlock);
}
s32 JKRHeap::getSize(void *memoryBlock) { return do_getSize(memoryBlock); }
s32 JKRHeap::getFreeSize() { return do_getFreeSize(); }
s32 JKRHeap::getTotalFreeSize() { return do_getTotalFreeSize(); }
s32 JKRHeap::changeGroupID(u8 newGroupID)
{
JUT_WARNING_F(570, !mInitFlag, "change heap ID into %x in heap %x", newGroupID, this);
return do_changeGroupID(newGroupID);
}
u8 JKRHeap::getCurrentGroupId() { return do_getCurrentGroupId(); }
JKRHeap *JKRHeap::findFromRoot(void *ptr)
{
if (sRootHeap != nullptr)
return sRootHeap->find(ptr);
return nullptr;
}
JKRHeap *JKRHeap::find(void *memory) const
{
if ((mStart <= memory) && (memory <= mEnd))
{
if (mChildTree.getNumChildren() != 0)
{
for (JSUTreeIterator<JKRHeap> iterator(mChildTree.getFirstChild()); iterator != mChildTree.getEndChild(); ++iterator)
{
JKRHeap *result = iterator->find(memory);
if (result)
{
return result;
}
}
}
return const_cast<JKRHeap *>(this);
}
return nullptr;
}
JKRHeap *JKRHeap::findAllHeap(void *memory) const
{
if (mChildTree.getNumChildren() != 0)
{
for (JSUTreeIterator<JKRHeap> iterator(mChildTree.getFirstChild()); iterator != mChildTree.getEndChild(); ++iterator)
{
JKRHeap *result = iterator->findAllHeap(memory);
if (result)
{
return result;
}
}
}
if (mStart <= memory && memory < mEnd)
{
return const_cast<JKRHeap *>(this);
}
return nullptr;
}
// generates __as__25JSUTreeIterator<7JKRHeap>FP17JSUTree<7JKRHeap> and __ct__25JSUTreeIterator<7JKRHeap>Fv, remove this
void JKRHeap::dispose_subroutine(u32 begin, u32 end)
{
JSUListIterator<JKRDisposer> last_iterator;
JSUListIterator<JKRDisposer> next_iterator;
JSUListIterator<JKRDisposer> iterator;
for (iterator = mDisposerList.getFirst(); iterator != mDisposerList.getEnd();
iterator = next_iterator)
{
JKRDisposer *disposer = iterator.getObject();
if ((void *)begin <= disposer && disposer < (void *)end)
{
disposer->~JKRDisposer();
if (last_iterator == nullptr)
{
next_iterator = mDisposerList.getFirst();
}
else
{
next_iterator = last_iterator;
next_iterator++;
}
}
else
{
last_iterator = iterator;
next_iterator = iterator;
next_iterator++;
}
}
}
bool JKRHeap::dispose(void *memory, u32 size)
{
u32 begin = (u32)memory;
u32 end = (u32)memory + size;
dispose_subroutine(begin, end);
return false;
}
void JKRHeap::dispose(void *begin, void *end)
{
dispose_subroutine((u32)begin, (u32)end);
}
void JKRHeap::dispose()
{
JSUListIterator<JKRDisposer> iterator;
while (iterator = mDisposerList.getFirst(), iterator != mDisposerList.getEnd())
{
iterator->~JKRDisposer();
}
}
void JKRHeap::copyMemory(void *dst, void *src, u32 size)
{
u32 count = (size + 3) / 4;
u32 *dst_32 = (u32 *)dst;
u32 *src_32 = (u32 *)src;
while (count > 0)
{
*dst_32 = *src_32;
dst_32++;
src_32++;
count--;
}
}
void JKRDefaultMemoryErrorRoutine(void *heap, u32 size, int alignment)
{
// OSReport("Error: Cannot allocate memory %d(0x%x)byte in %d byte alignment from %08x\n", size, size, alignment, heap);
OSErrorLine(710, "abort\n");
}
JKRHeapErrorHandler *JKRHeap::setErrorHandler(JKRHeapErrorHandler *newHandler)
{
JKRHeapErrorHandler *oldHandler = mErrorHandler;
if (!newHandler)
{
newHandler = JKRDefaultMemoryErrorRoutine;
}
mErrorHandler = newHandler;
return oldHandler;
}
bool JKRHeap::isSubHeap(JKRHeap *heap) const
{
if (!heap)
return false;
if (mChildTree.getNumChildren() != 0)
{
JSUTreeIterator<JKRHeap> iterator;
for (iterator = mChildTree.getFirstChild(); iterator != mChildTree.getEndChild(); ++iterator)
{
if (iterator.getObject() == heap)
{
return true;
}
if (iterator.getObject()->isSubHeap(heap))
{
return true;
}
}
}
return false;
}
void *operator new(u32 byteCount)
{
return JKRHeap::alloc(byteCount, 4, nullptr);
}
void *operator new(u32 byteCount, int alignment)
{
return JKRHeap::alloc(byteCount, alignment, nullptr);
}
void *operator new(u32 byteCount, JKRHeap *heap, int alignment)
{
return JKRHeap::alloc(byteCount, alignment, heap);
}
void *operator new[](u32 byteCount)
{
return JKRHeap::alloc(byteCount, 4, nullptr);
}
void *operator new[](u32 byteCount, int alignment)
{
return JKRHeap::alloc(byteCount, alignment, nullptr);
}
void *operator new[](u32 byteCount, JKRHeap *heap, int alignment)
{
return JKRHeap::alloc(byteCount, alignment, heap);
}
// this is not needed without the other pragma and asm bs
void operator delete(void *memory) { JKRHeap::free(memory, nullptr); }
void operator delete[](void *memory) { JKRHeap::free(memory, nullptr); }
/*JKRHeap::TState::TState(const JKRHeap::TState::TArgument &arg, const JKRHeap::TState::TLocation &location)
{
// UNUSED FUNCTION
}
JKRHeap::TState::TState(const JKRHeap::TState &other, bool p2)
{
// UNUSED FUNCTION
}
JKRHeap::TState::TState(const JKRHeap::TState &other, const JKRHeap::TState::TLocation &location, bool p3)
{
// UNUSED FUNCTION
}*/
JKRHeap::TState::~TState()
{
// Unused, however might need it
}
void JKRHeap::state_register(JKRHeap::TState *p, u32) const
{
JUT_ASSERT(1132, p != 0);
JUT_ASSERT(1133, p->getHeap() == this);
}
bool JKRHeap::state_compare(const JKRHeap::TState &r1, const JKRHeap::TState &r2) const
{
JUT_ASSERT(1141, r1.getHeap() == r2.getHeap());
return (r1.getCheckCode() == r2.getCheckCode());
}
// fabricated, but probably matches(except for line numbers)
void JKRHeap::state_dumpDifference(const JKRHeap::TState &r1, const JKRHeap::TState &r2)
{
JUT_LOG_F(1157, "heap : %p / %p", r1.getHeap(), r2.getHeap());
JUT_LOG_F(1158, "check-code : 0x%08x / 0x%08x", r1.getCheckCode(), r2.getCheckCode());
JUT_LOG_F(1159, "id : 0x%08x / 0x%08x", r1.getId(), r2.getId());
JUT_LOG_F(1160, "used size : %10u / %10u", r1.getUsedSize(), r2.getUsedSize());
}
void JKRHeap::state_dump(const TState &state) const
{
JUT_LOG_F(1165, "check-code : 0x%08x", state.getCheckCode());
JUT_LOG_F(1166, "id : 0x%08x", state.getId());
JUT_LOG_F(1167, "used size : %u", state.getUsedSize());
}