#ifndef MRT_MEM_COMMON_H
#define MRT_MEM_COMMON_H
#include <algorithm>
#include <mutex>
#include <thread>
#include <unordered_map>
#include "PagePool.h"
namespace MapleRuntime {
using pageID = unsigned long long;
constexpr size_t MAX_NPAGES = 129;
constexpr size_t PAGE_SHIFT = 12;
constexpr size_t MAX_BYTES = 256 * 1024;
constexpr size_t NFREELIST = 208;
constexpr int MIN_ALIGN_NUM = 8;
enum AlignNmu { ALIGN_8 = 8, ALIGN_16 = 16, ALIGN_128 = 128, ALIGN_1024 = 1024, ALIGN_8192 = 8 * 1028 };
enum MemberSize {
ALING_8_BYTE = 128,
ALING_16_BYTE = 1024,
ALING_128_BYTE = 8 * 1024,
ALING_1024_BYTE = 64 * 1024,
ALING_8192_BYTE = 256 * 1024,
};
enum AlignShift { ALIGN_8_SIFT = 3, ALIGN_16_SIFT = 4, ALIGN_128_SIFT = 7, ALIGN_1024_SIFT = 10, ALIGN_8192_SIFT = 13 };
inline void* SystemAlloc(size_t kpage)
{
return PagePool::Instance().GetPage(kpage * MapleRuntime::MRT_PAGE_SIZE);
}
inline void*& NextObj(void* obj)
{
CHECK(obj != nullptr);
return *(void**)obj;
}
class FreeList {
public:
void PushFront(void* obj)
{
CHECK(obj != nullptr);
NextObj(obj) = freeList;
freeList = obj;
++size;
}
void* PopFront()
{
CHECK(!Empty());
void* obj = freeList;
freeList = NextObj(obj);
--size;
return obj;
}
void PushAtFront(void* start, void* end, size_t n)
{
CHECK(start != nullptr);
CHECK(end != nullptr);
CHECK(n > 0);
NextObj(end) = freeList;
freeList = start;
size += n;
}
void PopAtFront(void*& start, size_t n)
{
CHECK(n <= size);
start = freeList;
void* end = freeList;
for (size_t i = 0; i < n - 1; ++i) {
end = NextObj(end);
}
freeList = NextObj(end);
NextObj(end) = nullptr;
size -= n;
}
bool Empty() { return size == 0; }
size_t& GetAdjustSize() { return adjustSize; }
size_t GetSize() { return size; }
private:
size_t size = 0;
size_t adjustSize = 1;
void* freeList = nullptr;
};
class SizeManager {
public:
static constexpr int GROUP_ARRAY[4] = { 16, 56, 56, 56 };
static inline size_t RoundUp(size_t bytes)
{
if (bytes <= MemberSize::ALING_8_BYTE) {
return RoundUp(bytes, AlignNmu::ALIGN_8);
} else if (bytes <= MemberSize::ALING_16_BYTE) {
return RoundUp(bytes, AlignNmu::ALIGN_16);
} else if (bytes <= MemberSize::ALING_128_BYTE) {
return RoundUp(bytes, AlignNmu::ALIGN_128);
} else if (bytes <= MemberSize::ALING_1024_BYTE) {
return RoundUp(bytes, AlignNmu::ALIGN_1024);
} else if (bytes <= MemberSize::ALING_8192_BYTE) {
return RoundUp(bytes, AlignNmu::ALIGN_8192);
} else {
return -1;
}
}
static inline size_t Index(size_t bytes)
{
if (bytes <= MemberSize::ALING_8_BYTE) {
return Index(bytes, ALIGN_8_SIFT);
} else if (bytes <= MemberSize::ALING_16_BYTE) {
return Index(bytes - MemberSize::ALING_8_BYTE, ALIGN_16_SIFT) + GROUP_ARRAY[0];
} else if (bytes <= MemberSize::ALING_128_BYTE) {
return Index(bytes - MemberSize::ALING_16_BYTE, ALIGN_128_SIFT) +
GROUP_ARRAY[1] + GROUP_ARRAY[0];
} else if (bytes <= MemberSize::ALING_1024_BYTE) {
return Index(bytes - MemberSize::ALING_128_BYTE, ALIGN_1024_SIFT) +
GROUP_ARRAY[2] + GROUP_ARRAY[1] + GROUP_ARRAY[0];
} else if (bytes <= MemberSize::ALING_8192_BYTE) {
return Index(bytes - MemberSize::ALING_1024_BYTE, ALIGN_8192_SIFT) +
GROUP_ARRAY[3] + GROUP_ARRAY[2] + GROUP_ARRAY[1] + GROUP_ARRAY[0];
} else {
return -1;
}
}
static size_t LimitSize(size_t alignBytes)
{
CHECK(alignBytes != 0);
constexpr int underLimit = 2;
constexpr int upperLimit = 512;
size_t num = MAX_BYTES / alignBytes;
if (num < underLimit) {
num = underLimit;
}
if (num > upperLimit) {
num = upperLimit;
}
return num;
}
static size_t CalculatePageNum(size_t alignBytes)
{
size_t num = LimitSize(alignBytes);
size_t npage = num * alignBytes;
npage >>= PAGE_SHIFT;
if (npage == 0) {
npage = 1;
}
return npage;
}
private:
static inline size_t RoundUp(size_t bytes, size_t alignNum) { return ((bytes + alignNum - 1) & ~(alignNum - 1)); }
static inline size_t Index(size_t bytes, size_t alignShift)
{
return ((bytes + (1 << alignShift) - 1) >> alignShift) - 1;
}
};
struct Span {
size_t pageNum = 0;
pageID pageId = 0;
Span* next = nullptr;
Span* prev = nullptr;
size_t useCount = 0;
void* freeBlocks = nullptr;
bool isUse = false;
};
class SpanList {
public:
SpanList()
{
head->prev = head;
head->next = head;
}
~SpanList()
{
while (!Empty()) {
Span* span = PopFront();
delete span;
}
delete head;
}
void Insert(Span* pos, Span* newSpan)
{
CHECK(pos != nullptr);
CHECK(newSpan != nullptr);
Span* prev = pos->prev;
prev->next = newSpan;
newSpan->prev = prev;
newSpan->next = pos;
pos->prev = newSpan;
}
void Erase(Span* pos)
{
CHECK(pos != nullptr);
CHECK(pos != head);
Span* prev = pos->prev;
Span* next = pos->next;
prev->next = next;
next->prev = prev;
}
Span* Begin() { return head->next; }
Span* End() { return head; }
bool Empty() { return Begin() == head; }
Span* PopFront()
{
CHECK(!Empty());
Span* ret = Begin();
Erase(Begin());
return ret;
}
void PushFront(Span* span)
{
CHECK(span != nullptr);
Insert(Begin(), span);
}
std::mutex& GetSpanListMutex() { return mtx; }
private:
Span* head = new Span;
std::mutex mtx;
};
}
#endif