#include "Malloc.h" #define LTIMING(x) // RTIMING(x) struct MLink; struct MHeader { byte free; byte d1, d2, d3; word size; word prev; MLink *Block() { return (MLink *)(this + 1); } MHeader *Next() { return (MHeader *)((byte *)this + size) + 1; } MHeader *Prev() { return (MHeader *)((byte *)this - prev) - 1; } }; struct MLink { MLink *next; MLink *prev; void LinkSelf() { Dbl_Self(this); } void Unlink() { Dbl_Unlink(this); } void Link(MLink *lnk) { Dbl_LinkAfter(this, lnk); } MHeader *Header() { return (MHeader *)this - 1; } }; #define LBINS 113 #define MAXBLOCK 65504 static word sBinSz[LBINS]; static byte s_SzBin[MAXBLOCK / 8 + 1]; static byte s_BlBin[MAXBLOCK / 8 + 1]; static MLink s_freebin[LBINS]; static MLink s_mall; static MLink s_ball; inline static void sLInit() { int p = 24; int bi = 0; while(p < MAXBLOCK) { sBinSz[bi++] = p; int add = minmax(6 * p / 100 / 32 * 32, 32, 2048); p += add; } ASSERT(bi == LBINS - 1); sBinSz[LBINS - 1] = MAXBLOCK; int k = 0; for(int i = 0; i < MAXBLOCK / 8; i++) { while(i * 8 + 7 > sBinSz[k]) k++; s_SzBin[i] = k; } k = LBINS - 1; for(int i = MAXBLOCK / 8; i >= 0; i--) { while(i * 8 < sBinSz[k]) k--; s_BlBin[i] = k; } s_BlBin[0] = 0; for(int i = 0; i < LBINS; i++) s_freebin[i].LinkSelf(); s_mall.LinkSelf(); s_ball.LinkSelf(); } inline static int sSzBin(int n) { return s_SzBin[(n - 1) >> 3]; } inline static int sBlBin(int n) { return s_BlBin[n >> 3]; } static void sLinkFree(MLink *b, int size) { int q = sBlBin(size); b->Link(&s_freebin[q]); } static MLink *sAddChunk() { ASSERT(sizeof(MHeader) == 8); ASSERT(sizeof(MLink) <= 16); MLink *ml = (MLink *)AllocRaw64KB(); if(!ml) return NULL; ml->Link(&s_mall); MHeader *bh = (MHeader *)((byte *)ml + 16); bh->size = MAXBLOCK; bh->prev = 0; bh->free = true; MLink *b = bh->Block(); sLinkFree(b, MAXBLOCK); bh = bh->Next(); bh->prev = MAXBLOCK; bh->size = 0; bh->free = false; return b; } static void *sDivideBlock(MLink *b, int size, int ii) { b->Unlink(); MHeader *bh = b->Header(); ASSERT(bh->size >= size); bh->free = false; int sz2 = bh->size - size - sizeof(MHeader); if(sz2 >= 32) { MHeader *bh2 = (MHeader *)((byte *)b + size); bh2->prev = size; bh2->free = true; sLinkFree(bh2->Block(), sz2); bh->Next()->prev = bh2->size = sz2; bh->size = size; } return b; } static StaticCriticalSection llock; void *LAlloc(size_t& size) { PROFILEMT(llock); llock.Enter(); static bool inited; if(!inited) { sLInit(); inited = true; } if(size > MAXBLOCK) { LTIMING("Big alloc"); sHeapStat(17); MLink *b = (MLink *)SysAllocRaw(size + 40); if(!b) Panic("Out of memory!"); b->Link(&s_ball); size = ((size + 40 + 4095) & ~4095) - 40; *(size_t *)((byte *)b + 16) = size; MHeader *h = (MHeader *)((byte *)b + 32); h->size = 0; h->free = false; llock.Leave(); return (byte *)b + 40; } LTIMING("Large alloc"); sHeapStat(16); if(size < 256) size = 256; int ii = sSzBin((int)size); size = sBinSz[ii]; while(ii < LBINS) { MLink *b = &s_freebin[ii]; MLink *n = b->next; if(b != n) { void *ptr = sDivideBlock(n, (int)size, ii); llock.Leave(); sDoPeakProfile(); return ptr; } ii++; } MLink *n = sAddChunk(); if(!n) Panic("Out of memory!"); void *ptr = sDivideBlock(n, (int)size, LBINS - 1); llock.Leave(); sDoPeakProfile(); return ptr; } void LFree(void *ptr) { CriticalSection::Lock __(llock); MLink *b = (MLink *)ptr; MHeader *bh = b->Header(); if(bh->size == 0) { LTIMING("Big free"); ASSERT(((dword)(uintptr_t)bh & 4095) == 32); b = (MLink *)((byte *)bh - 32); b->Unlink(); SysFreeRaw(b, *(size_t *)((byte *)b + 16)); return; } LTIMING("Large free"); if(bh->prev) { MHeader *p = bh->Prev(); if(p->free) { b = p->Block(); b->Unlink(); p->size += bh->size + sizeof(MHeader); p->Next()->prev = p->size; bh = p; } } MHeader *n = bh->Next(); if(n->free) { n->Block()->Unlink(); bh->size += n->size + sizeof(MHeader); n->Next()->prev = bh->size; } bh->free = true; sLinkFree(b, bh->size); } void LMemoryShrink() { #ifdef flagMEMSHRINK LTIMING("LMemoryShrink"); CriticalSection::Lock __(llock); MLink *m = s_freebin[BINS - 1].next; while(m != &s_freebin[BINS - 1]) { MLink *cm = (MLink *)((byte *)m - 24); MLink *mm = m; m = m->next; mm->Unlink(); cm->Unlink(); SysFreeRaw(cm, 65536); } #endif } void LMake(MemoryProfile& p) { CriticalSection::Lock __(llock); int ii = 0; int fi = 0; MLink *m = s_ball.next; while(m != &s_ball) { int sz = (int)*(size_t *)((byte *)m + 16); p.large_count++; p.large_total += sz; if(ii < 4096) p.large_size[ii++] = sz; m = m->next; } m = s_mall.next; while(m != &s_mall) { MHeader *h = (MHeader *)((byte *)m + 16); int sz = h->size; if(h->free) { p.large_free_count++; p.large_free_total += sz; if(fi < 4096) p.large_free_size[fi++] = sz; } else { p.large_count++; p.large_total += sz; if(ii < 4096) p.large_size[ii++] = sz; } m = m->next; } }