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);
}
Example #2
0
void
dumpSystemHeap()
{
   MEMDumpHeap(sSystemHeapData->handle);
}