void BlockAllocator::MergeFreeBlocks() { restart: DEBUG_LOG(HLE, "Merging Blocks"); std::list<Block>::iterator iter1, iter2; iter1 = blocks.begin(); iter2 = blocks.begin(); iter2++; while (iter2 != blocks.end()) { BlockAllocator::Block &b1 = *iter1; BlockAllocator::Block &b2 = *iter2; if (b1.taken == false && b2.taken == false) { DEBUG_LOG(HLE, "Block Alloc found adjacent free blocks - merging"); b1.size += b2.size; blocks.erase(iter2); CheckBlocks(); goto restart; //iterators now invalid - we have to restart our search } iter1++; iter2++; } }
u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) { CheckBlocks(); if (size > rangeSize_) { ERROR_LOG(HLE, "Clearly bogus size: %08x - failing allocation", size); return -1; } // Downalign the position so we're allocating full blocks. u32 alignedPosition = position; u32 alignedSize = size; if (position & (grain_ - 1)) { DEBUG_LOG(HLE, "Position %08x does not align to grain.", position); alignedPosition &= ~(grain_ - 1); // Since the position was decreased, size must increase. alignedSize += alignedPosition - position; } // Upalign size to grain. alignedSize = (alignedSize + grain_ - 1) & ~(grain_ - 1); // Tell the caller the allocated size from their requested starting position. size = alignedSize - (alignedPosition - position); Block *bp = GetBlockFromAddress(alignedPosition); if (bp != NULL) { Block &b = *bp; if (b.taken) { ERROR_LOG(HLE, "Block allocator AllocAt failed, block taken! %08x, %i", position, size); return -1; } else { // Make sure the block is big enough to split. if (b.start + b.size < alignedPosition + alignedSize) { ERROR_LOG(HLE, "Block allocator AllocAt failed, not enough contiguous space %08x, %i", position, size); return -1; } //good to go else if (b.start == alignedPosition) { InsertFreeAfter(&b, b.start + alignedSize, b.size - alignedSize); b.taken = true; b.size = alignedSize; b.SetTag(tag); CheckBlocks(); return position; } else { int size1 = alignedPosition - b.start; InsertFreeBefore(&b, b.start, size1); if (b.start + b.size > alignedPosition + alignedSize) InsertFreeAfter(&b, alignedPosition + alignedSize, b.size - (alignedSize + size1)); b.taken = true; b.start = alignedPosition; b.size = alignedSize; b.SetTag(tag); return position; } } } else { ERROR_LOG(HLE, "Block allocator AllocAt failed :( %08x, %i", position, size); } //Out of memory :( ListBlocks(); ERROR_LOG(HLE, "Block Allocator failed to allocate %i bytes of contiguous memory", alignedSize); return -1; }
u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) { CheckBlocks(); if (size > rangeSize_) { ERROR_LOG(HLE, "Clearly bogus size: %08x - failing allocation", size); return -1; } // upalign size to grain size = (size + grain_ - 1) & ~(grain_ - 1); // check that position is aligned if (position & (grain_ - 1)) { ERROR_LOG(HLE, "Position %08x does not align to grain. Grain will be off.", position); } std::list<Block>::iterator iter = GetBlockIterFromAddress(position); if (iter != blocks.end()) { Block &b = *iter; if (b.taken) { ERROR_LOG(HLE, "Block allocator AllocAt failed, block taken! %08x, %i", position, size); return -1; } else { //good to go if (b.start == position) { blocks.insert(++iter, Block(b.start + size, b.size - size, false)); b.taken = true; b.size = size; b.SetTag(tag); CheckBlocks(); return position; } else { int size1 = position - b.start; blocks.insert(iter, Block(b.start, size1, false)); if (b.start + b.size > position + size) { iter++; blocks.insert(iter, Block(position + size, b.size - (size + size1), false)); } b.taken = true; b.start = position; b.size = size; b.SetTag(tag); return position; } } } else { ERROR_LOG(HLE, "Block allocator AllocAt failed :( %08x, %i", position, size); } //Out of memory :( ListBlocks(); ERROR_LOG(HLE, "Block Allocator failed to allocate %i bytes of contiguous memory", size); return -1; }
u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag) { CheckBlocks(); if (size > rangeSize_) { ERROR_LOG(HLE, "Clearly bogus size: %08x - failing allocation", size); return -1; } // upalign size to grain size = (size + grain_ - 1) & ~(grain_ - 1); // check that position is aligned if (position & (grain_ - 1)) { ERROR_LOG(HLE, "Position %08x does not align to grain. Grain will be off.", position); } Block *bp = GetBlockFromAddress(position); if (bp != NULL) { Block &b = *bp; if (b.taken) { ERROR_LOG(HLE, "Block allocator AllocAt failed, block taken! %08x, %i", position, size); return -1; } else { //good to go if (b.start == position) { InsertFreeAfter(&b, b.start + size, b.size - size); b.taken = true; b.size = size; b.SetTag(tag); CheckBlocks(); return position; } else { int size1 = position - b.start; InsertFreeBefore(&b, b.start, size1); if (b.start + b.size > position + size) InsertFreeAfter(&b, position + size, b.size - (size + size1)); b.taken = true; b.start = position; b.size = size; b.SetTag(tag); return position; } } } else { ERROR_LOG(HLE, "Block allocator AllocAt failed :( %08x, %i", position, size); } //Out of memory :( ListBlocks(); ERROR_LOG(HLE, "Block Allocator failed to allocate %i bytes of contiguous memory", size); return -1; }