#include "Malloc.h" #define LTIMING(x) // RTIMING(x) struct Link; word Heap::BinSz[LBINS]; byte Heap::SzBin[MAXBLOCK / 8 + 1]; byte Heap::BlBin[MAXBLOCK / 8 + 1]; Heap::DLink Heap::allmedium; Heap::DLink Heap::allbig; void Heap::GlobalLInit() { ONCELOCK { int p = 24; int bi = 0; while(p < MAXBLOCK) { BinSz[bi++] = p; int add = minmax(6 * p / 100 / 32 * 32, 32, 2048); p += add; } ASSERT(bi == LBINS - 1); BinSz[LBINS - 1] = MAXBLOCK; int k = 0; for(int i = 0; i < MAXBLOCK / 8; i++) { while(i * 8 + 7 > BinSz[k]) k++; SzBin[i] = k; } k = LBINS - 1; for(int i = MAXBLOCK / 8; i >= 0; i--) { while(i * 8 < BinSz[k]) k--; BlBin[i] = k; } BlBin[0] = 0; allmedium.LinkSelf(); allbig.LinkSelf(); } } void Heap::LInit() { ASSERT(sizeof(Header) == 8); ASSERT(sizeof(DLink) <= 16); GlobalLInit(); for(int i = 0; i < LBINS; i++) freebin[i]->LinkSelf(); } Heap::DLink *Heap::AddChunk() { Mutex::Lock __(global_lock); DLink *ml = (DLink *)AllocRaw64KB(); if(!ml) return NULL; ml->Link(&allmedium); Header *bh = (Header *)((byte *)ml + 16); bh->size = MAXBLOCK; bh->prev = 0; bh->free = true; // bh->heap = this; //!!!!! DLink *b = bh->GetBlock(); LinkFree(b, MAXBLOCK); bh = bh->Next(); bh->prev = MAXBLOCK; bh->size = 0; bh->free = false; return b; } void *Heap::DivideBlock(DLink *b, int size, int ii) { b->Unlink(); Header *bh = b->GetHeader(); ASSERT(bh->size >= size); bh->free = false; int sz2 = bh->size - size - sizeof(Header); if(sz2 >= 32) { Header *bh2 = (Header *)((byte *)b + size); bh2->prev = size; bh2->free = true; // bh2->heap = this; // Heap here!!! LinkFree(bh2->GetBlock(), sz2); bh->Next()->prev = bh2->size = sz2; bh->size = size; } return b; } void *Heap::LAlloc(size_t& size) { ASSERT(size > 256); static bool inited; if(!inited) { LInit(); inited = true; } if(size > MAXBLOCK) { Mutex::Lock __(global_lock); LTIMING("Big alloc"); sHeapStat(17); DLink *b = (DLink *)SysAllocRaw(size + 40); if(!b) Panic("Out of memory!"); b->Link(&allbig); size = ((size + 40 + 4095) & ~4095) - 40; *(size_t *)((byte *)b + 16) = size; Header *h = (Header *)((byte *)b + 32); h->size = 0; h->free = false; return (byte *)b + 40; } sHeapStat(16); int ii = SizeToBin((int)size); size = BinSz[ii]; while(ii < LBINS) { DLink *b = freebin[ii]; DLink *n = b->next; if(b != n) { void *ptr = DivideBlock(n, (int)size, ii); sDoPeakProfile(); return ptr; } ii++; } DLink *n = AddChunk(); if(!n) Panic("Out of memory!"); void *ptr = DivideBlock(n, (int)size, LBINS - 1); sDoPeakProfile(); return ptr; } void Heap::LFree(void *ptr) { DLink *b = (DLink *)ptr; Header *bh = b->GetHeader(); if(bh->size == 0) { Mutex::Lock __(global_lock); LTIMING("Big free"); ASSERT(((dword)(uintptr_t)bh & 4095) == 32); b = (DLink *)((byte *)bh - 32); b->Unlink(); SysFreeRaw(b, *(size_t *)((byte *)b + 16)); return; } LTIMING("Large free"); if(bh->prev) { Header *p = bh->Prev(); if(p->free) { b = p->GetBlock(); b->Unlink(); p->size += bh->size + sizeof(Header); p->Next()->prev = p->size; bh = p; } } Header *n = bh->Next(); if(n->free) { n->GetBlock()->Unlink(); bh->size += n->size + sizeof(Header); n->Next()->prev = bh->size; } bh->free = true; LinkFree(b, bh->size); } /* void LMake(MemoryProfile& p) { CriticalSection::Lock __(llock); int ii = 0; int fi = 0; Link *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) { Header *h = (Header *)((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; } } */