using System; using System.Linq; using System.Threading.Tasks; using Native = System.UInt32; namespace Cosmos.Core.Memory { //TODO Remove empty pages as necessary /// /// HeapSmall class. Used to alloc and free small memory blocks on the heap. /// unsafe static public class HeapSmall { // Keep word aligned for faster access to slots with small data. /// /// Number of prefix bytes for the heap. /// private const Native PrefixBytes = 3 * sizeof(Native); /// /// Number of prefix bytes for each item. /// private const Native PrefixItemBytes = 3 * sizeof(Native); /// /// Max item size in the heap. /// public static Native mMaxItemSize; /// /// Size map table /// /// Smaller sizes point to next bigger slot, each Page then is linked forward to next for each slot size. private static void** mSMT; /// /// Init small heap. /// /// Thrown on fatal error, contact support. static public void Init() { //TODO Adjust for new page and header sizes // 4 slots, ~1k ea Native xMaxItemSize = (RAT.PageSize - PrefixBytes) / 4 - PrefixItemBytes; // Word align it xMaxItemSize = xMaxItemSize / sizeof(Native) * sizeof(Native); InitSMT(xMaxItemSize); // TODO Change these sizes after further study and also when page size changes. // SMT can be grown as needed. Also can adjust and create new ones dynamicaly as it runs. CreatePage(16); CreatePage(24); CreatePage(48); CreatePage(64); CreatePage(128); CreatePage(256); CreatePage(512); CreatePage(mMaxItemSize); } /// /// Init SMT (Size Map Table). /// /// A max item size. static void InitSMT(Native aMaxItemSize) { mMaxItemSize = aMaxItemSize; mSMT = (void**)RAT.AllocBytes(RAT.PageType.HeapSmall, mMaxItemSize * (Native)sizeof(void*)); } /// /// Create a page with the size of an item. /// /// Item size. /// Thrown if: /// /// aItemSize is 0. /// aItemSize is not word aligned. /// SMT is not initialized. /// The item size is bigger then a small heap size. /// /// static void CreatePage(Native aItemSize) { if (aItemSize == 0) { throw new Exception("aItemSize cannot be 0."); } else if (aItemSize % sizeof(Native) != 0) { throw new Exception("aItemSize must be word aligned."); } else if (mMaxItemSize == 0) { throw new Exception("SMT is not initialized."); } else if (aItemSize > mMaxItemSize) { throw new Exception("Cannot allocate more than MaxItemSize in SmallHeap."); } // Limit to one page so they are allocated low and easy to move around. // In future may put some up top and be larger as well. Native xPages = 1; var xPtr = (Native*)RAT.AllocPages(RAT.PageType.HeapSmall, xPages); // Ptr to next page of same size xPtr[0] = 0; // // # of slots. Necessary for future use when more than one page, but used currently as well. Native xSlotSize = aItemSize + PrefixItemBytes; Native xItemCount = RAT.PageSize * xPages / xSlotSize; xPtr[1] = xItemCount; // // # of free slots xPtr[2] = xItemCount; // xPtr = xPtr + 3; for (Native i = 0; i < xItemCount; i++) { byte* xSlotPtr = (byte*)xPtr + i * xSlotSize; Native* xMetaDataPtr = (Native*)xSlotPtr; xMetaDataPtr[0] = 0; // Actual data size. 0 is empty. xMetaDataPtr[1] = 0; // Ref count xMetaDataPtr[2] = 0; // Ptr to first } } /// /// Alloc memory block, of a given size. /// /// A size of block to alloc, in bytes. /// Byte pointer to the start of the block. static public byte* Alloc(Native aSize) { return HeapLarge.Alloc(aSize); } /// /// Free block. /// /// A pointer to the block. /// Thrown if page type is not found. static public void Free(void* aPtr) { HeapLarge.Free(aPtr); } } }