void MEMDumpHeap(CommonHeap *heap) { switch (heap->tag) { case HeapType::ExpandedHeap: MEMiDumpExpHeap(reinterpret_cast<ExpandedHeap*>(heap)); break; case HeapType::FrameHeap: case HeapType::UnitHeap: case HeapType::UserHeap: case HeapType::BlockHeap: gLog->error("TODO: Unimplemented MEMDumpHeap type"); } }
void MEMDumpHeap(CommonHeap *heap) { switch (heap->tag) { case MEMiHeapTag::ExpandedHeap: MEMiDumpExpHeap(reinterpret_cast<ExpandedHeap*>(heap)); break; case MEMiHeapTag::UnitHeap: MEMiDumpUnitHeap(reinterpret_cast<UnitHeap*>(heap)); break; case MEMiHeapTag::FrameHeap: case MEMiHeapTag::UserHeap: case MEMiHeapTag::BlockHeap: gLog->info("Unimplemented MEMDumpHeap type"); } }
/** * Allocate aligned memory from an expanded heap * * Sets the memory block group ID to the current active group ID. * If alignment is negative the memory is allocated from the top of the heap. * If alignment is positive the memory is allocated from the bottom of the heap. */ void * MEMAllocFromExpHeapEx(ExpandedHeap *heap, uint32_t size, int alignment) { ScopedSpinLock lock(&heap->lock); virtual_ptr<ExpandedHeapBlock> freeBlock, usedBlock; auto direction = MEMExpHeapDirection::FromBottom; uint32_t base; if (alignment < 0) { alignment = -alignment; direction = MEMExpHeapDirection::FromTop; } // Add size for block header and alignment uint32_t originalSize = size; size += sizeof(ExpandedHeapBlock); size += alignment; if (heap->mode == MEMExpHeapMode::FirstFree) { if (direction == MEMExpHeapDirection::FromBottom) { // Find first block large enough from bottom of heap for (auto block = heap->freeBlockList; block; block = block->next) { if (block->size < size) { continue; } freeBlock = block; break; } } else { // direction == MEMExpHeapDirection::FromTop // Find first block large enough from top of heap for (auto block = getTail(heap->freeBlockList); block; block = block->prev) { if (block->size < size) { continue; } freeBlock = block; break; } } } else if (heap->mode == MEMExpHeapMode::NearestSize) { uint32_t nearestSize = -1; if (direction == MEMExpHeapDirection::FromBottom) { // Find block nearest in size from bottom of heap for (auto block = heap->freeBlockList; block; block = block->next) { if (block->size < size) { continue; } if (block->size - size < nearestSize) { nearestSize = block->size - size; freeBlock = block; } } } else { // direction == MEMExpHeapDirection::FromTop // Find block nearest in size from top of heap for (auto block = getTail(heap->freeBlockList); block; block = block->prev) { if (block->size < size) { continue; } if (block->size - size < nearestSize) { nearestSize = block->size - size; freeBlock = block; } } } } if (!freeBlock) { gLog->error("MEMAllocFromExpHeapEx failed, no free block found for size {:08x} ({:08x}+{:x}+{:x})", size, originalSize, sizeof(ExpandedHeapBlock), alignment); MEMiDumpExpHeap(heap); return nullptr; } if (direction == MEMExpHeapDirection::FromBottom) { // Reduce freeblock size base = freeBlock->addr; freeBlock->size -= size; if (freeBlock->size < sMinimumBlockSize) { // Absorb free block as it is too small size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } else { auto freeSize = freeBlock->size; // Replace free block auto old = freeBlock; freeBlock = make_virtual_ptr<ExpandedHeapBlock>(base + size); freeBlock->addr = base + size; freeBlock->size = freeSize; replaceBlock(heap->freeBlockList, old, freeBlock); } } else { // direction == MEMExpHeapDirection::FromTop // Reduce freeblock size freeBlock->size -= size; base = freeBlock->addr + freeBlock->size; if (freeBlock->size < sMinimumBlockSize) { // Absorb free block as it is too small size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } } // Create a new used block auto aligned = align_up(base + static_cast<uint32_t>(sizeof(ExpandedHeapBlock)), alignment); usedBlock = make_virtual_ptr<ExpandedHeapBlock>(aligned - static_cast<uint32_t>(sizeof(ExpandedHeapBlock))); usedBlock->addr = base; usedBlock->size = size; usedBlock->group = heap->group; usedBlock->direction = direction; insertBlock(heap->usedBlockList, usedBlock); return make_virtual_ptr<void>(aligned); }