mirror of
https://github.com/zeldaret/oot.git
synced 2025-05-09 18:43:45 +00:00
472 lines
13 KiB
C
472 lines
13 KiB
C
#include "libc64/os_malloc.h"
|
|
|
|
#include "alignment.h"
|
|
#include "fault.h"
|
|
#include "translation.h"
|
|
|
|
#define NODE_MAGIC 0x7373
|
|
|
|
#define NODE_IS_VALID(node) ((node)->magic == NODE_MAGIC)
|
|
|
|
#define NODE_GET_NEXT(node) ((node)->next)
|
|
#define NODE_GET_PREV(node) ((node)->prev)
|
|
|
|
#define SET_DEBUG_INFO(node, f, l, a) \
|
|
{ \
|
|
(node)->filename = (f); \
|
|
(node)->line = (l); \
|
|
(node)->threadId = osGetThreadId(NULL); \
|
|
(node)->arena = (a); \
|
|
(node)->time = osGetTime(); \
|
|
} \
|
|
(void)0
|
|
|
|
#define FILL_ALLOC_BLOCK(arena, alloc, size) (void)0
|
|
#define FILL_FREE_BLOCK_HEADER(arena, node) (void)0
|
|
#define FILL_FREE_BLOCK_CONTENTS(arena, node) (void)0
|
|
#define CHECK_FREE_BLOCK(arena, node) (void)0
|
|
|
|
// Number of allocation failures across all arenas.
|
|
u32 gTotalAllocFailures = 0; // "Arena_failcnt"
|
|
|
|
#define CHECK_ALLOC_FAILURE(arena, ptr) \
|
|
do { \
|
|
if ((ptr) == NULL) { \
|
|
gTotalAllocFailures++; \
|
|
(arena)->allocFailures++; \
|
|
} \
|
|
} while (0)
|
|
|
|
void __osMallocInit(Arena* arena, void* start, s32 size) {
|
|
ArenaNode* firstNode = (ArenaNode*)ALIGN16((u32)start);
|
|
|
|
size -= (u8*)firstNode - (u8*)start;
|
|
size &= ~0xF;
|
|
|
|
firstNode->next = NULL;
|
|
firstNode->prev = NULL;
|
|
firstNode->size = size - sizeof(ArenaNode);
|
|
firstNode->isFree = true;
|
|
firstNode->magic = NODE_MAGIC;
|
|
|
|
arena->head = firstNode;
|
|
arena->start = start;
|
|
arena->size = size;
|
|
}
|
|
|
|
void __osMallocCleanup(Arena* arena) {
|
|
bzero(arena, sizeof(*arena));
|
|
}
|
|
|
|
s32 __osMallocIsInitialized(Arena* arena) {
|
|
return arena->start != NULL;
|
|
}
|
|
|
|
void* __osMallocDebug(Arena* arena, u32 size, const char* file, int line) {
|
|
ArenaNode* iter;
|
|
u32 blockSize;
|
|
ArenaNode* newNode;
|
|
void* alloc = NULL;
|
|
ArenaNode* next;
|
|
|
|
size = ALIGN16(size);
|
|
blockSize = ALIGN16(size) + sizeof(ArenaNode);
|
|
iter = arena->head;
|
|
|
|
while (iter != NULL) {
|
|
if (iter->isFree && iter->size >= size) {
|
|
CHECK_FREE_BLOCK(arena, iter);
|
|
|
|
if (blockSize < iter->size) {
|
|
newNode = (ArenaNode*)((u32)iter + blockSize);
|
|
newNode->next = NODE_GET_NEXT(iter);
|
|
newNode->prev = iter;
|
|
newNode->size = iter->size - blockSize;
|
|
newNode->isFree = true;
|
|
newNode->magic = NODE_MAGIC;
|
|
|
|
iter->next = newNode;
|
|
iter->size = size;
|
|
next = NODE_GET_NEXT(newNode);
|
|
if (next) {
|
|
next->prev = newNode;
|
|
}
|
|
}
|
|
|
|
iter->isFree = false;
|
|
SET_DEBUG_INFO(iter, file, line, arena);
|
|
alloc = (void*)((u32)iter + sizeof(ArenaNode));
|
|
FILL_ALLOC_BLOCK(arena, alloc, size);
|
|
|
|
break;
|
|
}
|
|
|
|
iter = NODE_GET_NEXT(iter);
|
|
}
|
|
|
|
CHECK_ALLOC_FAILURE(arena, alloc);
|
|
|
|
return alloc;
|
|
}
|
|
|
|
void* __osMallocRDebug(Arena* arena, u32 size, const char* file, int line) {
|
|
ArenaNode* iter;
|
|
ArenaNode* newNode;
|
|
u32 blockSize;
|
|
u32 nodeSize;
|
|
ArenaNode* next;
|
|
void* allocR = NULL;
|
|
ArenaNode* next2;
|
|
|
|
size = ALIGN16(size);
|
|
|
|
iter = arena->head;
|
|
next2 = NODE_GET_NEXT(iter);
|
|
while (next2 != NULL) {
|
|
iter = next2;
|
|
next2 = NODE_GET_NEXT(next2);
|
|
}
|
|
|
|
while (iter != NULL) {
|
|
if (iter->isFree && iter->size >= size) {
|
|
CHECK_FREE_BLOCK(arena, iter);
|
|
|
|
blockSize = ALIGN16(size) + sizeof(ArenaNode);
|
|
nodeSize = iter->size;
|
|
if (blockSize < nodeSize) {
|
|
newNode = (ArenaNode*)((u32)iter + (iter->size - size));
|
|
newNode->next = NODE_GET_NEXT(iter);
|
|
newNode->prev = iter;
|
|
newNode->size = size;
|
|
newNode->magic = NODE_MAGIC;
|
|
|
|
iter->next = newNode;
|
|
iter->size -= blockSize;
|
|
next = NODE_GET_NEXT(newNode);
|
|
if (next) {
|
|
next->prev = newNode;
|
|
}
|
|
iter = newNode;
|
|
}
|
|
|
|
iter->isFree = false;
|
|
SET_DEBUG_INFO(iter, file, line, arena);
|
|
allocR = (void*)((u32)iter + sizeof(ArenaNode));
|
|
FILL_ALLOC_BLOCK(arena, allocR, size);
|
|
|
|
break;
|
|
}
|
|
|
|
iter = NODE_GET_PREV(iter);
|
|
}
|
|
|
|
CHECK_ALLOC_FAILURE(arena, allocR);
|
|
|
|
return allocR;
|
|
}
|
|
|
|
void* __osMalloc(Arena* arena, u32 size) {
|
|
ArenaNode* iter;
|
|
u32 blockSize;
|
|
ArenaNode* newNode;
|
|
void* alloc = NULL;
|
|
ArenaNode* next;
|
|
|
|
size = ALIGN16(size);
|
|
blockSize = ALIGN16(size) + sizeof(ArenaNode);
|
|
iter = arena->head;
|
|
|
|
while (iter != NULL) {
|
|
if (iter->isFree && iter->size >= size) {
|
|
CHECK_FREE_BLOCK(arena, iter);
|
|
|
|
if (blockSize < iter->size) {
|
|
newNode = (ArenaNode*)((u32)iter + blockSize);
|
|
newNode->next = NODE_GET_NEXT(iter);
|
|
newNode->prev = iter;
|
|
newNode->size = iter->size - blockSize;
|
|
newNode->isFree = true;
|
|
newNode->magic = NODE_MAGIC;
|
|
|
|
iter->next = newNode;
|
|
iter->size = size;
|
|
next = NODE_GET_NEXT(newNode);
|
|
if (next) {
|
|
next->prev = newNode;
|
|
}
|
|
}
|
|
|
|
iter->isFree = false;
|
|
SET_DEBUG_INFO(iter, NULL, 0, arena);
|
|
alloc = (void*)((u32)iter + sizeof(ArenaNode));
|
|
FILL_ALLOC_BLOCK(arena, alloc, size);
|
|
|
|
break;
|
|
}
|
|
|
|
iter = NODE_GET_NEXT(iter);
|
|
}
|
|
|
|
CHECK_ALLOC_FAILURE(arena, alloc);
|
|
|
|
return alloc;
|
|
}
|
|
|
|
void* __osMallocR(Arena* arena, u32 size) {
|
|
ArenaNode* iter;
|
|
ArenaNode* newNode;
|
|
u32 blockSize;
|
|
u32 nodeSize;
|
|
ArenaNode* next;
|
|
void* allocR = NULL;
|
|
ArenaNode* next2;
|
|
|
|
size = ALIGN16(size);
|
|
|
|
iter = arena->head;
|
|
next2 = NODE_GET_NEXT(iter);
|
|
while (next2 != NULL) {
|
|
iter = next2;
|
|
next2 = NODE_GET_NEXT(next2);
|
|
}
|
|
|
|
while (iter != NULL) {
|
|
if (iter->isFree && iter->size >= size) {
|
|
CHECK_FREE_BLOCK(arena, iter);
|
|
|
|
blockSize = ALIGN16(size) + sizeof(ArenaNode);
|
|
nodeSize = iter->size;
|
|
if (blockSize < nodeSize) {
|
|
newNode = (ArenaNode*)((u32)iter + (iter->size - size));
|
|
newNode->next = NODE_GET_NEXT(iter);
|
|
newNode->prev = iter;
|
|
newNode->size = size;
|
|
newNode->magic = NODE_MAGIC;
|
|
|
|
iter->next = newNode;
|
|
iter->size -= blockSize;
|
|
next = NODE_GET_NEXT(newNode);
|
|
if (next) {
|
|
next->prev = newNode;
|
|
}
|
|
iter = newNode;
|
|
}
|
|
|
|
iter->isFree = false;
|
|
SET_DEBUG_INFO(iter, NULL, 0, arena);
|
|
allocR = (void*)((u32)iter + sizeof(ArenaNode));
|
|
FILL_ALLOC_BLOCK(arena, allocR, size);
|
|
|
|
break;
|
|
}
|
|
iter = NODE_GET_PREV(iter);
|
|
}
|
|
|
|
CHECK_ALLOC_FAILURE(arena, allocR);
|
|
|
|
return allocR;
|
|
}
|
|
|
|
void __osFree(Arena* arena, void* ptr) {
|
|
ArenaNode* node;
|
|
ArenaNode* next;
|
|
ArenaNode* prev;
|
|
|
|
if (ptr == NULL) {
|
|
return;
|
|
}
|
|
|
|
node = (ArenaNode*)((u32)ptr - sizeof(ArenaNode));
|
|
if (!NODE_IS_VALID(node)) {
|
|
(void)T("__osFree:不正解放(%08x)\n", "__osFree: Unauthorized release (%08x)\n");
|
|
osSetIntMask(OS_IM_ALL);
|
|
return;
|
|
}
|
|
if (node->isFree) {
|
|
(void)T("__osFree:二重解放(%08x)\n", "__osFree: Double release (%08x)\n");
|
|
osSetIntMask(OS_IM_ALL);
|
|
return;
|
|
}
|
|
if (arena != node->arena && arena != NULL) {
|
|
(void)T("__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n",
|
|
"__osFree:arena(%08x) and __osMalloc:arena(%08x) do not match\n");
|
|
}
|
|
|
|
node->isFree = true;
|
|
SET_DEBUG_INFO(node, NULL, 0, arena);
|
|
|
|
if (node->next != NULL) {
|
|
next = node->next;
|
|
if (next->isFree) {
|
|
if (next->next != NULL) {
|
|
next->next->prev = node;
|
|
}
|
|
|
|
node->size += next->size + sizeof(ArenaNode);
|
|
node->next = next->next;
|
|
}
|
|
}
|
|
|
|
if (node->prev != NULL) {
|
|
prev = node->prev;
|
|
if (prev->isFree) {
|
|
prev->size += node->size + sizeof(ArenaNode);
|
|
prev->next = NODE_GET_NEXT(node);
|
|
|
|
if (node->next != NULL) {
|
|
node->next->prev = prev;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) {
|
|
ArenaNode* node;
|
|
ArenaNode* next;
|
|
ArenaNode* prev;
|
|
|
|
if (ptr == NULL) {
|
|
return;
|
|
}
|
|
|
|
node = (ArenaNode*)((u32)ptr - sizeof(ArenaNode));
|
|
if (!NODE_IS_VALID(node)) {
|
|
(void)T("__osFree:不正解放(%08x)\n", "__osFree: Unauthorized release (%08x)\n");
|
|
osSetIntMask(OS_IM_ALL);
|
|
return;
|
|
}
|
|
if (node->isFree) {
|
|
(void)T("__osFree:二重解放(%08x)\n", "__osFree: Double release (%08x)\n");
|
|
osSetIntMask(OS_IM_ALL);
|
|
return;
|
|
}
|
|
if (arena != node->arena && arena != NULL) {
|
|
(void)T("__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n",
|
|
"__osFree:arena(%08x) and __osMalloc:arena(%08x) do not match\n");
|
|
}
|
|
|
|
node->isFree = true;
|
|
SET_DEBUG_INFO(node, file, line, arena);
|
|
|
|
if (node->next != NULL) {
|
|
next = node->next;
|
|
if (next->isFree) {
|
|
if (next->next != NULL) {
|
|
next->next->prev = node;
|
|
}
|
|
|
|
node->size += next->size + sizeof(ArenaNode);
|
|
node->next = next->next;
|
|
}
|
|
}
|
|
|
|
if (node->prev != NULL) {
|
|
prev = node->prev;
|
|
if (prev->isFree) {
|
|
prev->size += node->size + sizeof(ArenaNode);
|
|
prev->next = NODE_GET_NEXT(node);
|
|
|
|
if (node->next != NULL) {
|
|
node->next->prev = prev;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void* __osRealloc(Arena* arena, void* ptr, u32 newSize) {
|
|
ArenaNode* node;
|
|
void* newAlloc;
|
|
ArenaNode* next;
|
|
ArenaNode* newNext;
|
|
u32 sizeDiff;
|
|
|
|
(void)"__osRealloc(%08x, %d)\n";
|
|
osSetIntMask(OS_IM_ALL);
|
|
|
|
if (ptr == NULL) {
|
|
ptr = __osMalloc(arena, newSize);
|
|
} else if (newSize == 0) {
|
|
__osFree(arena, ptr);
|
|
ptr = NULL;
|
|
} else {
|
|
newSize = ALIGN16(newSize);
|
|
node = (ArenaNode*)((u32)ptr - sizeof(ArenaNode));
|
|
if (newSize == node->size) {
|
|
// Do nothing
|
|
} else if (node->size < newSize) {
|
|
next = NODE_GET_NEXT(node);
|
|
sizeDiff = newSize - node->size;
|
|
if (next != NULL && next->isFree && next->size >= sizeDiff) {
|
|
next->size -= sizeDiff;
|
|
newNext = (ArenaNode*)((u32)next + sizeDiff);
|
|
if (NODE_GET_NEXT(next) != NULL) {
|
|
NODE_GET_NEXT(next)->prev = newNext;
|
|
}
|
|
node->next = newNext;
|
|
node->size = newSize;
|
|
memmove(node->next, next, sizeof(ArenaNode));
|
|
} else {
|
|
newAlloc = __osMalloc(arena, newSize);
|
|
if (newAlloc != NULL) {
|
|
memcpy(ptr, newAlloc, node->size);
|
|
__osFree(arena, ptr);
|
|
}
|
|
ptr = newAlloc;
|
|
}
|
|
} else if (newSize < node->size) {
|
|
(void)T("メモリブロックの縮小機能はまだインプリメントしていません\n",
|
|
"Memory block shrinking functionality is not yet implemented\n");
|
|
}
|
|
}
|
|
|
|
CHECK_ALLOC_FAILURE(arena, ptr);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void* __osReallocDebug(Arena* arena, void* ptr, u32 newSize, const char* file, int line) {
|
|
return __osRealloc(arena, ptr, newSize);
|
|
}
|
|
|
|
void ArenaImpl_GetSizes(Arena* arena, u32* outMaxFree, u32* outFree, u32* outAlloc) {
|
|
ArenaNode* iter;
|
|
|
|
*outMaxFree = 0;
|
|
*outFree = 0;
|
|
*outAlloc = 0;
|
|
|
|
iter = arena->head;
|
|
while (iter != NULL) {
|
|
if (iter->isFree) {
|
|
*outFree += iter->size;
|
|
if (*outMaxFree < iter->size) {
|
|
*outMaxFree = iter->size;
|
|
}
|
|
} else {
|
|
*outAlloc += iter->size;
|
|
}
|
|
|
|
iter = NODE_GET_NEXT(iter);
|
|
}
|
|
}
|
|
|
|
s32 __osCheckArena(Arena* arena) {
|
|
ArenaNode* iter;
|
|
|
|
(void)T("アリーナの内容をチェックしています... (%08x)\n", "Checking the arena contents... (%08x)\n");
|
|
iter = arena->head;
|
|
while (iter != NULL) {
|
|
if (!NODE_IS_VALID(iter)) {
|
|
(void)T("おおっと!! (%08x %08x)\n", "Oops!! (%08x %08x)\n");
|
|
return 1;
|
|
}
|
|
iter = NODE_GET_NEXT(iter);
|
|
}
|
|
|
|
(void)T("アリーナはまだ、いけそうです\n", "The arena is still going well\n");
|
|
return 0;
|
|
}
|
|
|
|
u8 ArenaImpl_GetAllocFailures(Arena* arena) {
|
|
return arena->allocFailures;
|
|
}
|