#include #include "functions.h" #include "variables.h" #include "SnS.h" /* * Every chunk of allocated memory is prefixed with a HeapHeader. * * Chunks are 0x10 aligned, and cannot have a capacity < 1. * This means the smallest chunksize with the header is 0x20. * * If a chunk is empty, it's contains ptrs to the previous and * next empty chunks. This forms a link list over all the empty * chunks (EmptyHeapBlock) */ extern void func_80253010(void *dest, void *src, s32 size); #define chunkSize(s) ((u32)(s)->next - (u32)(s) - sizeof(HeapHeader)) #define HEAP_SIZE 0x210520 #define LAST_HEAP_BLOCK HEAP_SIZE/sizeof(EmptyHeapBlock) - 1 typedef enum { HEAP_BLOCK_EMPTY = 0, HEAP_BLOCK_USED = 1, HEAP_BLOCK_PERM = 2 } heap_block_type_e; typedef struct heap_header{ struct heap_header * prev; struct heap_header * next; u8 pad8[4]; u32 unusedBytes_C_31:24; //size? u32 unkC_7:2; //state? u32 padC_5:6; }HeapHeader; typedef struct empty_heap_block{ HeapHeader hdr; struct empty_heap_block *prev_free; struct empty_heap_block *next_free; u8 pad18[0x8]; } EmptyHeapBlock; extern EmptyHeapBlock D_8002D500[LAST_HEAP_BLOCK + 1]; extern EmptyHeapBlock D_8023DA00; /* .data */ u32 heap_occupiedBytes = 0; //occupied heap size u8 D_80276594 = 0; u8 D_80276598 = 0; void *D_8027659C = NULL; void *D_802765A0 = NULL; s32 D_802765A4 = 0; void *D_802765A8 = NULL; s32 D_802765AC = 0; struct{ bool unk0; }D_802765B0 = {0}; UNK_TYPE(void *) D_802765B4 = NULL; /* .bss */ s32 D_80283220; void *D_80283224; void *D_80283228; s32 D_8028322C; u32 heap_requested_size; HeapHeader * D_80283234; struct { void *unk0[0x10]; void **unk40; }D_80283238; EmptyHeapBlock *func_802549BC(s32 size); void _heap_sortEmptyBlock(EmptyHeapBlock * arg0); void func_80255ACC(void); /* .code */ s32 __heap_align(s32 size){ s32 misalign = size & 0xf; return(misalign)? (size - misalign + 0x10) : size; } int func_80254490(int arg0){ return FALSE; } void _heap_defragEmptyBlock(EmptyHeapBlock * arg0){ EmptyHeapBlock * defrag_ptr = NULL; if(arg0->hdr.next->unkC_7 == HEAP_BLOCK_EMPTY){ //absorb next block defrag_ptr = arg0; //remove next from empty block link list ((EmptyHeapBlock *)arg0->hdr.next)->next_free->prev_free = ((EmptyHeapBlock *)arg0->hdr.next)->prev_free; ((EmptyHeapBlock *)arg0->hdr.next)->prev_free->next_free = ((EmptyHeapBlock *)arg0->hdr.next)->next_free; //remove next from block link list arg0->hdr.next->next->prev = arg0; arg0->hdr.next = arg0->hdr.next->next; } if(arg0->hdr.prev->unkC_7 == HEAP_BLOCK_EMPTY){ defrag_ptr = arg0->hdr.prev; //remove self from empty block link list arg0->next_free->prev_free = arg0->prev_free; arg0->prev_free->next_free = arg0->next_free; //remove self from block link list arg0->hdr.prev->next = arg0->hdr.next; arg0->hdr.next->prev = arg0->hdr.prev; } if(defrag_ptr != NULL){ _heap_sortEmptyBlock(defrag_ptr); }else{ _heap_sortEmptyBlock(arg0); } } void func_8025456C(EmptyHeapBlock * arg0){ arg0->hdr.unkC_7 = HEAP_BLOCK_EMPTY; arg0->hdr.unusedBytes_C_31 = 0; if((u8*)arg0->hdr.next - (u8*)arg0 < 10000){ arg0->prev_free = &D_8002D500; arg0->next_free = D_8002D500->next_free; D_8002D500->next_free->prev_free = arg0; D_8002D500->next_free = arg0; }else{ arg0->prev_free = D_8002D500[LAST_HEAP_BLOCK].prev_free; arg0->next_free = & D_8002D500[LAST_HEAP_BLOCK]; D_8002D500[LAST_HEAP_BLOCK].prev_free->next_free = arg0; D_8002D500[LAST_HEAP_BLOCK].prev_free = arg0; } _heap_defragEmptyBlock(arg0); } void memcpy(void * dst, void *src, int size){ while(size > 0){ *(u8*)dst = *(u8*)src; size--; ((u8*)dst)++; ((u8*)src)++; } } void wmemcpy(void * dst, void *src, int size){ while(size > 0){ *(u32*)dst = *(u32*)src; size -= 4; ((u32*)dst)++; ((u32*)src)++; } } void memmove(u8* dst, u8* src, s32 n) { if(dst < src){ //copy while(n--){ *(dst++) = *(src++); } }else{ //copy backwards to avoid data lose dst += n -1; src += n -1; while(n--){ *(dst--) = *(src--); } } } s32 heap_get_size(void){ return HEAP_SIZE; } s32 func_802546DC(void){ return 0; } u32 func_802546E4(void * arg0){ HeapHeader *sPtr = (HeapHeader *)arg0 - 1; return chunkSize(sPtr) - sPtr->unusedBytes_C_31; } void func_802546FC(void){ D_80283224 = NULL; D_80283228 = NULL; } void heap_init(void){ bzero(D_8002D500, HEAP_SIZE); func_802546FC(); D_80283238.unk40 = &D_80283238.unk0[0]; heap_occupiedBytes = 0; D_80276594 = 0; D_802765A0 = 0; D_802765A4 = 0; D_802765A8 = 0; D_802765AC = 0; D_802765B0.unk0 = FALSE; D_8002D500[0].hdr.prev = NULL; D_8002D500[0].hdr.next = &D_8002D500[1]; D_8002D500[0].hdr.unkC_7 = 2; D_8002D500[0].hdr.unusedBytes_C_31 = 0; D_8002D500[0].prev_free = NULL; D_8002D500[0].next_free = &D_8002D500[1]; D_8002D500[1].hdr.prev = &D_8002D500[0]; D_8002D500[1].hdr.next = &D_8002D500[LAST_HEAP_BLOCK]; D_8002D500[1].hdr.unkC_7 = 0; D_8002D500[1].hdr.unusedBytes_C_31 = 0; D_8002D500[1].prev_free = &D_8002D500[0]; D_8002D500[1].next_free = &D_8002D500[LAST_HEAP_BLOCK]; D_8002D500[LAST_HEAP_BLOCK].hdr.prev = &D_8002D500[1]; D_8002D500[LAST_HEAP_BLOCK].hdr.next = &D_8002D500[LAST_HEAP_BLOCK + 1]; D_8002D500[LAST_HEAP_BLOCK].hdr.unkC_7 = 2; D_8002D500[LAST_HEAP_BLOCK].hdr.unusedBytes_C_31 = 0; D_8002D500[LAST_HEAP_BLOCK].prev_free = &D_8002D500[1]; D_8002D500[LAST_HEAP_BLOCK].next_free = NULL; sns_init_base_payloads(); } void *func_8025484C(s32 size){ D_802765B4 = malloc(ALIGN((u32)&D_8002D500[1] + 0x100, 0x100) - (u32)&D_8002D500[1] - sizeof(EmptyHeapBlock)); return malloc(0x80); } void *func_80254898(s32 arg0){ void * sp1C = malloc(ALIGN(((u32)&D_8002D500[LAST_HEAP_BLOCK] - (u32)D_8002D500[LAST_HEAP_BLOCK].prev_free) - 0x2FF, 0x100) + - sizeof(EmptyHeapBlock)); void * sp18 = malloc(0x80); free(sp1C); free(D_802765B4); D_802765B4 = NULL; return sp18; } void func_80254908(void){ if(D_802765A0){ free(D_802765A0); D_802765A0 = NULL; } if(D_802765A8){ free(D_802765A8); D_802765A8 = NULL; } } static u32 _heap_get_occupied_size(void){ return heap_occupiedBytes; } u32 heap_get_occupied_size(void){ return _heap_get_occupied_size(); } bool func_8025498C(s32 size){ s32 v0 = func_802549BC(size); return v0 ? TRUE : FALSE; } EmptyHeapBlock *func_802549BC(s32 size){ EmptyHeapBlock *a1; s32 aligned_size; u32 block_size; a1 = D_8002D500->next_free; aligned_size = __heap_align(size > 0 ? size : 1); while( chunkSize(&a1->hdr) < aligned_size && a1->next_free != &D_8002D500[LAST_HEAP_BLOCK] ){ a1 = a1->next_free; } return (chunkSize(&a1->hdr) < aligned_size)? 0 : a1; } EmptyHeapBlock *func_80254A60(bool arg0){ EmptyHeapBlock *v1; EmptyHeapBlock *v0; if(!arg0){ //from start v1 = D_8002D500->next_free; while( chunkSize(&v1->hdr) < heap_requested_size && v1->next_free != &D_8002D500[LAST_HEAP_BLOCK] ){ v1 = v1->next_free; } if(chunkSize(&v1->hdr) < heap_requested_size) return NULL; return v1; }else{ //from back v1 = NULL; v0 = D_8002D500->next_free; while(v0 != &D_8002D500[LAST_HEAP_BLOCK]){ if(chunkSize(&v0->hdr) >= heap_requested_size && v1 < v0) v1 = v0; v0 = v0->next_free; } if(!v1) return NULL; if(chunkSize(&v1->hdr) < heap_requested_size) return NULL; return v1; } } EmptyHeapBlock *func_80254B84(s32 arg0){ if(D_80283234){ return func_80254A60(1); //closest to back }else{ return func_80254A60(0); //closest to from } } int func_80254BC4(int arg0){ return FALSE; } //returns n'th free block and size void *func_80254BD0(s32 *size, u32 arg1) { EmptyHeapBlock *var_v1; var_v1 = &D_8023DA00; while(arg1 != 0){ var_v1 = var_v1->prev_free; if (var_v1 == &D_8002D500[0]) { //less than n blocks return NULL; } arg1--; } *size = ((s32)(var_v1->hdr.next) - (s32)var_v1) - sizeof(HeapHeader); return (s32)var_v1 + 0x10; } void func_80254C98(void){ D_802765B0.unk0 = TRUE; } void *malloc(s32 size){ u32 capacity; EmptyHeapBlock *v1; EmptyHeapBlock *a0; D_80283234 = D_802765B0.unk0; D_802765B0.unk0 = FALSE; if(D_8002D500->next_free == &D_8002D500[LAST_HEAP_BLOCK]) return NULL; heap_requested_size = __heap_align((size > 0 )? size : 1); if(!(v1 = func_80254B84(0))){ //remove stall cache ptrs D_80283234 = NULL; func_803306C8(2); if(!func_80254B84(0)) func_8030A850(2); if(!func_80254B84(0)) animCache_flushStale(); if(!func_80254B84(0)) animBinCache_flushStale(0); //nonpersistent anim if(!func_80254B84(0)) func_8032AD7C(2); if(!(v1 = func_80254B84(0))){ func_8033B61C(); func_802E49E0(); func_803306C8(3); //modelCache if(!func_80254B84(0)) func_8030A850(3); //propModelCache if(!func_80254B84(0)) func_8032AD7C(2); //actorArray if(!(v1 = func_80254B84(0))){ if(!func_80254B84(0)) func_802F1294(); //particleEmitters if(!func_80254B84(0)) animBinCache_flushStale(1); //persistent anim if(v1 = func_80254B84(0)){} else return NULL; } }//L80254E38 }//L80254E38 if( heap_requested_size + sizeof(HeapHeader) < chunkSize(&v1->hdr)){ if(D_80283234){ //reverse split chunk => //split empty chunk: |prev| a0 |next| => |prev| a0 | v1 |next| a0 = v1; v1 = (EmptyHeapBlock *)((u32)v1->hdr.next - (heap_requested_size + sizeof(HeapHeader))); v1->hdr.next = a0->hdr.next; a0->hdr.next->prev = v1; a0->hdr.next = v1; v1->hdr.prev = a0; _heap_sortEmptyBlock(a0); } else{//L80254EA4 //split chunk: |prev| v1 |next| => |prev| v1 | __a0__ |next| a0 = (HeapHeader *)((u32)v1 + (heap_requested_size + sizeof(HeapHeader))); a0->next_free = v1->next_free; a0->prev_free = v1->prev_free; a0->next_free->prev_free = a0; a0->prev_free->next_free = a0; a0->hdr.prev = v1; a0->hdr.next = v1->hdr.next; a0->hdr.next->prev = a0; a0->hdr.unkC_7 = 0; a0->hdr.unusedBytes_C_31 = 0; v1->hdr.next = a0; _heap_sortEmptyBlock(a0); } } else{//L80254F08 //use full chunk/ remove chunk from empty chunk link list v1->next_free->prev_free = v1->prev_free; v1->prev_free->next_free = v1->next_free; }//L80254F20 capacity = (u32)v1->hdr.next - (u32)v1 ; v1->hdr.unusedBytes_C_31 = capacity - size - 0x10; v1->hdr.unkC_7 = 1; heap_occupiedBytes += capacity; return (u8*)v1 + sizeof(HeapHeader); } void func_80254F90(void){ int i; for(i = 0; i < 50; i++){ func_80255ACC(); } } void _heap_sortEmptyBlock(EmptyHeapBlock * arg0){ EmptyHeapBlock *v0 = arg0; EmptyHeapBlock *v1; EmptyHeapBlock *a2 = &D_8002D500[LAST_HEAP_BLOCK]; //move arg0 back while larger than next while( arg0->next_free < &D_8002D500[LAST_HEAP_BLOCK] && (s32)chunkSize(&v0->next_free->hdr) + 0x10 < (s32)chunkSize(&v0->hdr) + 0x10 ){ v1 = arg0->next_free; arg0->next_free = v1->next_free; v1->next_free->prev_free = arg0; v1->next_free = arg0; arg0->prev_free->next_free = v1; v1->prev_free = arg0->prev_free; arg0->prev_free = v1; } //move arg0 foward while smaller prev while( ( (v1 = arg0->prev_free) > &D_8002D500[0]) && (s32)chunkSize(&v0->hdr) + 0x10 < (s32)chunkSize(&v0->prev_free->hdr) + 0x10 ){ a2 = arg0->prev_free; arg0->next_free->prev_free = a2; a2->next_free = arg0->next_free; arg0->next_free = a2; arg0->prev_free = a2->prev_free; a2->prev_free->next_free = arg0; a2->prev_free = arg0; } } void free(void * ptr){ HeapHeader *sPtr; //stack_ptr if(ptr){ sPtr = (HeapHeader *) ptr - 1; heap_occupiedBytes = heap_occupiedBytes - (u32)((u8*)sPtr->next - (u8*)ptr) - sizeof(HeapHeader); func_8025456C(sPtr); if((u32)ptr == (u32)D_802765A0) D_802765A0 = NULL; if((u32)ptr == (u32)D_802765A8) D_802765A8 = NULL; } } void func_80255170(void **arg0){ *D_80283238.unk40 = *arg0; D_80283238.unk40++; *arg0 = NULL; } //heap_free_queue_flush void func_80255198(void){ while(D_80283238.unk40 > &D_80283238.unk0[0]){ D_80283238.unk40--; free(*D_80283238.unk40); } } //resizes and fragments a block; void func_80255200(HeapHeader *block, s32 size){ u32 remaining_bytes; EmptyHeapBlock *a0; u32 tmp, tmp2, tmp3; block->unusedBytes_C_31 = chunkSize(block) - size; tmp = ((u32) (block)->next) - ((u32) (block)); if(size > 0) { // tmp2 = chunkSize(block) - sizeof(HeapHeader); tmp2 = __heap_align(size); remaining_bytes = chunkSize(block) - tmp2; } else{ remaining_bytes = tmp - sizeof(EmptyHeapBlock); } if(remaining_bytes >= sizeof(EmptyHeapBlock)){ tmp = (chunkSize(block) + sizeof(HeapHeader)) - remaining_bytes; if(tmp); a0 = (s32)block + tmp; heap_occupiedBytes -= remaining_bytes; a0->hdr.prev = block; a0->hdr.next = block->next; block->next = &a0->hdr; a0->hdr.next->prev = &a0->hdr; block->unusedBytes_C_31 = chunkSize(block) - size; func_8025456C(a0); } } void func_80255300(HeapHeader *block, s32 size){ func_80255200(block, size); if(block->next->unkC_7 == HEAP_BLOCK_EMPTY){ _heap_sortEmptyBlock(block->next); } } void *func_80255340(void){ return D_80283224; } void *func_8025534C(void){ return D_80283228; } void *realloc(void *ptr, s32 size){ HeapHeader *sPtr; void *newSeg; EmptyHeapBlock *emptySeg; D_80283224 = ptr; D_80283228 = ptr; sPtr = (HeapHeader *)ptr - 1; if(!((u32)((u8*) sPtr->next - (u8*)ptr) < size)){ //current pointer has enough free space to accomidate size change func_80255300(sPtr, size); return ptr; } D_8027659C = ptr; emptySeg = (EmptyHeapBlock*) sPtr->next; if( emptySeg->hdr.unkC_7 == HEAP_BLOCK_EMPTY && !((u32)((u8*)emptySeg->hdr.next - (u8*)sPtr) - 0x10 < size) ){//combine current heap segment with the next one (if next one is free). //remove empty segment from list emptySeg->next_free->prev_free = emptySeg->prev_free; emptySeg->prev_free->next_free = emptySeg->next_free; heap_occupiedBytes += (u8*)emptySeg->hdr.next - (u8*)emptySeg; sPtr->next = emptySeg->hdr.next; emptySeg->hdr.next->prev = sPtr; func_80255300(sPtr, size); D_8027659C = 0; return ptr; }//L80255430 if(!(newSeg = malloc(size))){ return 0; } func_80253010(newSeg, ptr, __heap_align(size)); free(ptr); ptr = newSeg; D_8027659C = 0; D_80283228 = newSeg; if(newSeg); return ptr; } u32 heap_get_free_size(void){ return HEAP_SIZE - heap_get_occupied_size(); } s32 heap_findLargestEmptyBlock(s32 *size_ptr){ EmptyHeapBlock *v0; s32 i; s32 size; v0 = D_8002D500->next_free; *size_ptr = 0; i = 0; while(v0 != &D_8002D500[LAST_HEAP_BLOCK]){ size = (s32)v0->hdr.next - (s32)v0; *size_ptr = (size < *size_ptr) ? *size_ptr : size; v0 = v0->next_free; i++; } return i; } void func_80255524(void){ D_80283220 = (D_80276598)? -6000000 : 0; if(D_802765A0 && D_802765A4 + 1 < D_802765AC){ free(D_802765A0); D_802765A0 = NULL; if(D_802765A8){ free(D_802765A8); D_802765A8 = NULL; } } } void func_802555C4(void){ D_8028322C = FALSE; } bool func_802555D0(void){ return D_8028322C; } void *defrag(void *this){ HeapHeader *new_block; HeapHeader *this_block; EmptyHeapBlock *new_empty; EmptyHeapBlock *prev_empty; EmptyHeapBlock *next_empty; HeapHeader *prev_block; s32 size; if(this == NULL || this == D_8027659C){ return this; } size = (s32)((HeapHeader*)this)[-1].next - (s32)this + 0x10; this_block = &((HeapHeader*)this)[-1]; if(D_80283220 + size >= 1000000){ return this; } new_block = this_block->prev; if(new_block->unkC_7 != HEAP_BLOCK_EMPTY || chunkSize(new_block) < 0x10){ return this; } //previous block is empty, move contents of this block forward D_8028322C = TRUE; D_80283220 = D_80283220 + size; next_empty = ((EmptyHeapBlock *)new_block)->next_free; prev_empty = ((EmptyHeapBlock *)new_block)->prev_free; prev_block = new_block->prev; func_80253010(new_block, this_block, size); //create new empty block at end of new_block; new_empty = (EmptyHeapBlock *)((s32)new_block + size); new_empty->hdr.prev = new_block; new_empty->hdr.next = new_block->next; new_block->next = &new_empty->hdr; new_block->prev = prev_block; new_empty->hdr.next->prev = &new_empty->hdr; prev_empty->next_free = new_empty; next_empty->prev_free = new_empty; new_empty->next_free = next_empty; new_empty->prev_free = prev_empty; new_empty->hdr.unkC_7 = HEAP_BLOCK_EMPTY; new_empty->hdr.unusedBytes_C_31 = 0; if(new_block); _heap_defragEmptyBlock(new_empty); //combine new_empty with any surrounding empty blocks return (void *)((s32)new_block + sizeof(HeapHeader)); } void *defrag_asset(void *arg0){ void *sp1C; if(arg0 == NULL || arg0 == D_8027659C) return arg0; sp1C = defrag(arg0); assetcache_update_ptr(arg0, sp1C); return sp1C; } //recache??? defrag_cache??? void *func_80255774(void *this){ HeapHeader *this_block; HeapHeader *prev_block; s32 size; s32 pad; void *sp24; if( this == NULL || this == D_8027659C || D_802765A0 || func_8033BD8C(this) ){ return this; } size = (s32)((HeapHeader*)this)[-1].next - (s32)this + 0x10; this_block = &((HeapHeader*)this)[-1]; if(D_80283220 + size >= 1000000) return this; prev_block = this_block->prev; if(prev_block->unkC_7 != HEAP_BLOCK_EMPTY){ return this; } sp24 = malloc(size - sizeof(HeapHeader)); func_80253010(sp24, this, size - sizeof(HeapHeader)); osWritebackDCache(sp24, size - sizeof(HeapHeader)); D_80283220 += size - sizeof(HeapHeader); D_802765A0 = this; D_802765A4 = D_802765AC; return sp24; } //recache asset?? defragment cached obj??? void *func_80255888(void *arg0){ void *sp1C; if(arg0 == NULL || arg0 == D_8027659C){ return arg0; } sp1C = func_80255774(arg0); assetcache_update_ptr(arg0, sp1C); return sp1C; } void *func_802558D8(void *arg0, void *arg1){ void *v1; v1 = func_80255888(arg0); if(v1 == arg0){ return arg0; } else{ D_802765A8 = arg1; return v1; } } bool func_80255920(void *arg0) { HeapHeader *block; if ((arg0 == NULL) || (arg0 == D_8027659C) || (D_802765A0 != NULL)) { return FALSE; } block = &((HeapHeader*)arg0)[-1]; return (block->prev->unkC_7 != HEAP_BLOCK_EMPTY ) ? FALSE : TRUE; } HeapHeader * func_80255978(void *ptr){ return ((HeapHeader* )((s32)ptr - sizeof(HeapHeader)))->prev; } void func_80255980(void *arg0, int arg1){ D_802765A0 = arg0; D_802765A4 = D_802765AC; } bool func_802559A0(void) { return (D_80276598 == 0) ? (D_80283220 >= 0xF4240) || ((D_80276594 == 1) ? 0 : 1) : 0; } void func_80255A04(void){ D_80276594 = 1; } void func_80255A14(void){ D_80276594 = 0; } void func_80255A20(void){ D_80276598 = TRUE; } void func_80255A30(void){ D_80276598 = FALSE; } void func_80255A3C(void){ func_80255524(); if(func_802559A0() && D_80276598 != TRUE) return; if(!func_802559A0()) func_802E6820(1); if(!func_802559A0()) printbuffer_defrag(); if(!func_802559A0()){ ml_defrag(); func_80254464(); } } void func_80255ACC(void){ D_802765AC++; } bool func_80255AE4(void){ return (D_802765A0) ? 1 : 0; } int func_80255B08(int arg0){ if(arg0 == 2) return 0x3; return 0x12; }