6namespace Abstract::Memory {
8Region::Region(
void *start,
void *end) : start(start), end(end) {}
10uintptr_t Region::getRange()
const {
11 return GetAddrNum(end) - GetAddrNum(start);
14MEMiExpBlockHead *MEMiExpBlockList::insert(MEMiExpBlockHead *block, MEMiExpBlockHead *prev) {
15 MEMiExpBlockHead *next;
17 block->m_link.m_prev = prev;
19 next = prev->m_link.m_next;
20 prev->m_link.m_next = block;
26 block->m_link.m_next = next;
28 next->m_link.m_prev = block;
36MEMiExpBlockHead *MEMiExpBlockList::append(MEMiExpBlockHead *block) {
37 return insert(block, m_tail);
40MEMiExpBlockHead *MEMiExpBlockList::remove(MEMiExpBlockHead *block) {
41 MEMiExpBlockHead *prev = block->m_link.m_prev;
42 MEMiExpBlockHead *next = block->m_link.m_next;
45 prev->m_link.m_next = next;
51 next->m_link.m_prev = prev;
59MEMiExpBlockHead::MEMiExpBlockHead(
const Region ®ion,
u16 signature) {
60 m_signature = signature;
63 m_size = region.getRange() -
sizeof(MEMiExpBlockHead);
65 m_link.m_prev =
nullptr;
66 m_link.m_next =
nullptr;
69MEMiExpBlockHead *MEMiExpBlockHead::createFree(
const Region ®ion) {
70 constexpr u16 FREE_BLOCK_SIGNATURE = 0x4652;
71 return new (region.start) MEMiExpBlockHead(region, FREE_BLOCK_SIGNATURE);
74MEMiExpBlockHead *MEMiExpBlockHead::createUsed(
const Region ®ion) {
75 constexpr u16 USED_BLOCK_SIGNATURE = 0x5544;
76 return new (region.start) MEMiExpBlockHead(region, USED_BLOCK_SIGNATURE);
79Region MEMiExpBlockHead::getRegion()
const {
80 return Region(SubOffset(
this, m_attribute.fields.alignment), getMemoryEnd());
83void *MEMiExpBlockHead::getMemoryStart()
const {
84 return AddOffset(
this,
sizeof(MEMiExpBlockHead));
87void *MEMiExpBlockHead::getMemoryEnd()
const {
88 return AddOffset(getMemoryStart(), m_size);
91MEMiExpHeapHead::MEMiExpHeapHead(
void *end,
u16 opt)
92 : MEMiHeapHead(EXP_HEAP_SIGNATURE, AddOffset(this, sizeof(MEMiExpHeapHead)), end, opt) {
97 m_attribute.makeAllZero();
99 Region region = Region(getHeapStart(), getHeapEnd());
100 MEMiExpBlockHead *block = MEMiExpBlockHead::createFree(region);
102 m_freeBlocks.m_head = block;
103 m_freeBlocks.m_tail = block;
104 m_usedBlocks.m_head =
nullptr;
105 m_usedBlocks.m_tail =
nullptr;
109MEMiExpHeapHead::~MEMiExpHeapHead() =
default;
112MEMiExpHeapHead *MEMiExpHeapHead::create(
void *startAddress,
size_t size,
u16 flag) {
113 void *endAddress = AddOffset(startAddress, size);
115 startAddress = RoundUp(startAddress, 4);
116 endAddress = RoundDown(endAddress, 4);
118 uintptr_t startAddrNum = GetAddrNum(startAddress);
119 uintptr_t endAddrNum = GetAddrNum(endAddress);
121 if (startAddrNum > endAddrNum) {
125 if (endAddrNum - startAddrNum <
sizeof(MEMiExpHeapHead) +
sizeof(MEMiExpBlockHead) + 4) {
129 return new (startAddress) MEMiExpHeapHead(endAddress, flag);
132void MEMiExpHeapHead::destroy() {
133 this->~MEMiExpHeapHead();
137void *MEMiExpHeapHead::alloc(
size_t size, s32 align) {
141 size = RoundUp(size, 4);
143 void *block =
nullptr;
145 block = allocFromHead(size, align);
147 block = allocFromTail(size, -align);
154void MEMiExpHeapHead::free(
void *block) {
159 MEMiExpBlockHead *head =
160 reinterpret_cast<MEMiExpBlockHead *
>(SubOffset(block,
sizeof(MEMiExpBlockHead)));
162 Region region = head->getRegion();
163 m_usedBlocks.remove(head);
164 recycleRegion(region);
168u32 MEMiExpHeapHead::getAllocatableSize(s32 align)
const {
170 align = std::abs(align);
173 u32 x = std::numeric_limits<u32>::max();
175 for (MEMiExpBlockHead *block = m_freeBlocks.m_head; block; block = block->m_link.m_next) {
176 void *memptr = block->getMemoryStart();
177 void *start = RoundUp(memptr, align);
178 void *end = block->getMemoryEnd();
180 if (GetAddrNum(start) < GetAddrNum(end)) {
181 u32 size = GetAddrNum(end) - GetAddrNum(start);
182 u32 offset = GetAddrNum(start) - GetAddrNum(memptr);
184 if (maxSize < size || (maxSize == size && x > offset)) {
195void MEMiExpHeapHead::visitAllocated(Visitor visitor, uintptr_t param) {
196 for (MEMiExpBlockHead *block = m_usedBlocks.m_head; block;) {
197 MEMiExpBlockHead *next = block->m_link.m_next;
198 visitor(block->getMemoryStart(),
this, param);
204u16 MEMiExpHeapHead::getGroupID()
const {
209void MEMiExpHeapHead::setGroupID(
u16 groupID) {
214void *MEMiExpHeapHead::allocFromHead(
size_t size, s32 alignment) {
215 MEMiExpBlockHead *found =
nullptr;
217 void *bestAddress =
nullptr;
219 for (MEMiExpBlockHead *block = m_freeBlocks.m_head; block; block = block->m_link.m_next) {
220 void *
const memptr = block->getMemoryStart();
221 void *
const address = RoundUp(memptr, alignment);
222 size_t offset = GetAddrNum(address) - GetAddrNum(memptr);
224 if (block->m_size < size + offset) {
228 if (blockSize <= block->m_size) {
233 blockSize = block->m_size;
234 bestAddress = address;
237 if (m_attribute.offBit(eAttribute::BestFitAlloc) || blockSize == size) {
246 return allocUsedBlockFromFreeBlock(found, bestAddress, size, 0);
250void *MEMiExpHeapHead::allocFromTail(
size_t size, s32 alignment) {
251 MEMiExpBlockHead *found =
nullptr;
253 void *bestAddress =
nullptr;
255 for (MEMiExpBlockHead *block = m_freeBlocks.m_tail; block; block = block->m_link.m_prev) {
256 void *
const start = block->getMemoryStart();
257 void *
const endAddr = AddOffset(start, block->m_size);
258 void *
const end = RoundDown(SubOffset(endAddr, size), alignment);
260 if (
static_cast<intptr_t
>(GetAddrNum(end) - GetAddrNum(start)) < 0) {
264 if (blockSize <= block->m_size) {
269 blockSize = block->m_size;
273 if (m_attribute.offBit(eAttribute::BestFitAlloc) || blockSize == size) {
282 return allocUsedBlockFromFreeBlock(found, bestAddress, size, 1);
286void *MEMiExpHeapHead::allocUsedBlockFromFreeBlock(MEMiExpBlockHead *block,
void *address, u32 size,
291 Region leftRegion = block->getRegion();
292 Region rightRegion = Region(AddOffset(address, size), leftRegion.end);
293 leftRegion.end = SubOffset(address,
sizeof(MEMiExpBlockHead));
295 MEMiExpBlockHead *prev = m_freeBlocks.remove(block);
297 if (leftRegion.getRange() <
sizeof(MEMiExpBlockHead) + 4) {
299 leftRegion.end = leftRegion.start;
301 prev = m_freeBlocks.insert(MEMiExpBlockHead::createFree(leftRegion), prev);
304 if (rightRegion.getRange() <
sizeof(MEMiExpBlockHead) + 4) {
306 rightRegion.end = rightRegion.start;
308 m_freeBlocks.insert(MEMiExpBlockHead::createFree(rightRegion), prev);
311 fillAllocMemory(leftRegion.end, GetAddrNum(rightRegion.start) - GetAddrNum(leftRegion.end));
314 Region region = Region(SubOffset(address,
sizeof(MEMiExpBlockHead)), rightRegion.start);
315 MEMiExpBlockHead *head = MEMiExpBlockHead::createUsed(region);
317 head->m_attribute.fields.direction = direction;
318 head->m_attribute.fields.alignment = GetAddrNum(head) - GetAddrNum(leftRegion.end);
319 head->m_attribute.fields.groupId = m_groupId;
321 head->m_tag = ++m_tag;
324 m_usedBlocks.append(head);
330bool MEMiExpHeapHead::recycleRegion(
const Region &initialRegion) {
331 MEMiExpBlockHead *block =
nullptr;
332 Region region = initialRegion;
334 for (MEMiExpBlockHead *search = m_freeBlocks.m_head; search; search = search->m_link.m_next) {
335 if (search < initialRegion.start) {
340 if (search == initialRegion.end) {
341 region.end = search->getMemoryEnd();
342 m_freeBlocks.remove(search);
343 fillNoUseMemory(search,
sizeof(MEMiExpBlockHead));
349 if (block && block->getMemoryEnd() == initialRegion.start) {
350 region.start = block;
351 block = m_freeBlocks.remove(block);
354 if (region.getRange() <
sizeof(MEMiExpBlockHead)) {
358 fillFreeMemory(initialRegion.start, initialRegion.getRange());
359 m_freeBlocks.insert(MEMiExpBlockHead::createFree(region), block);