virt_ptr<void> MEMAllocFromExpHeapEx(MEMHeapHandle handle, uint32_t size, int32_t alignment) { auto heap = virt_cast<MEMExpHeap *>(handle); decaf_check(heap->header.tag == MEMHeapTag::ExpandedHeap); auto expHeapFlags = heap->attribs.value(); if (size == 0) { size = 1; } decaf_check(alignment != 0); internal::HeapLock lock { virt_addrof(heap->header) }; virt_ptr<MEMExpHeapBlock> newBlock = nullptr; size = align_up(size, 4); if (alignment > 0) { auto foundBlock = virt_ptr<MEMExpHeapBlock> { nullptr }; auto bestAlignedSize = 0xFFFFFFFFu; alignment = std::max(4, alignment); decaf_check((alignment & 0x3) == 0); for (auto block = heap->freeList.head; block; block = block->next) { auto alignedSize = getAlignedBlockSize(block, alignment, MEMExpHeapDirection::FromStart); if (alignedSize >= size) { if (expHeapFlags.allocMode() == MEMExpHeapMode::FirstFree) { foundBlock = block; break; } else { if (alignedSize < bestAlignedSize) { foundBlock = block; bestAlignedSize = alignedSize; } } } } if (foundBlock) { newBlock = createUsedBlockFromFreeBlock(heap, foundBlock, size, alignment, MEMExpHeapDirection::FromStart); } } else { alignment = std::max(4, -alignment); decaf_check((alignment & 0x3) == 0); auto foundBlock = virt_ptr<MEMExpHeapBlock> { nullptr }; auto bestAlignedSize = 0xFFFFFFFFu; for (auto block = heap->freeList.head; block; block = block->next) { auto alignedSize = getAlignedBlockSize(block, alignment, MEMExpHeapDirection::FromEnd); if (alignedSize >= size) { if (expHeapFlags.allocMode() == MEMExpHeapMode::FirstFree) { foundBlock = block; break; } else { if (alignedSize < bestAlignedSize) { foundBlock = block; bestAlignedSize = alignedSize; } } } } if (foundBlock) { newBlock = createUsedBlockFromFreeBlock(heap, foundBlock, size, alignment, MEMExpHeapDirection::FromEnd); } } if (!newBlock) { MEMDumpHeap(virt_addrof(heap->header)); return nullptr; } return getBlockDataStart(newBlock); }
void dumpSystemHeap() { MEMDumpHeap(sSystemHeapData->handle); }