/// <summary> /// Create a page with the size of an item and add it to the SMT at a certain page /// </summary> /// <param name="aItemSize">Object size in bytes</param> /// <exception cref="Exception">Thrown if: /// <list type="bullet"> /// <item>aItemSize is 0.</item> /// <item>aItemSize is not word aligned.</item> /// <item>SMT is not initialized.</item> /// <item>The item size is bigger then a small heap size.</item> /// </list> /// </exception> static void CreatePage(SMTPage *aPage, uint aItemSize) { var xPtr = (byte *)RAT.AllocPages(RAT.PageType.HeapSmall, 1); if (xPtr == null) { return; // we failed to create the page, Alloc should still handle this case } uint xSlotSize = aItemSize + PrefixItemBytes; uint xItemCount = RAT.PageSize / xSlotSize; for (uint i = 0; i < xItemCount; i++) { byte * xSlotPtr = xPtr + i * xSlotSize; ushort *xMetaDataPtr = (ushort *)xSlotPtr; xMetaDataPtr[0] = 0; // Actual data size. 0 is empty. xMetaDataPtr[1] = 0; // Ref count } //now add it to the smt var parent = GetLastBlock(aPage, aItemSize); var smtBlock = NextFreeBlock(aPage); //get the next free block in the smt if (smtBlock == null) // we could not allocate a new block since the SMT table is all full { // we need to expand the SMT table by a page var last = SMT; while (last->Next != null) { last = last->Next; } last->Next = InitSMTPage(); parent = GetLastBlock(last->Next, aItemSize); smtBlock = NextFreeBlock(); if (smtBlock == null) { Debugger.SendKernelPanic(0x93); while (true) { } ; } } if (parent != null) { // there is already a block for the same size on the same page parent->NextBlock = smtBlock; } else { // in this case this is the first block of the size, so we can link it to root var root = GetFirstBlock(aPage, aItemSize); root->First = smtBlock; } smtBlock->SpacesLeft = xItemCount; smtBlock->PagePtr = xPtr; }
/// <summary> /// Alloc memory block, of a given size. /// </summary> /// <param name="aSize">A size of block to alloc, in bytes.</param> /// <returns>Byte pointer to the start of the block.</returns> static public byte *Alloc(Native aSize) { Native xPages = (Native)((aSize + PrefixBytes) / RAT.PageSize) + 1; var xPtr = (Native *)RAT.AllocPages(RAT.PageType.HeapLarge, xPages); xPtr[0] = xPages * RAT.PageSize - PrefixBytes; // Allocated data size xPtr[1] = aSize; // Actual data size xPtr[2] = 0; // Ref count xPtr[3] = 0; // Ptr to first return((byte *)xPtr + PrefixBytes); }
/// <summary> /// Create a page with the size of an item. /// </summary> /// <param name="aItemSize">Item size.</param> /// <exception cref="Exception">Thrown if: /// <list type="bullet"> /// <item>aItemSize is 0.</item> /// <item>aItemSize is not word aligned.</item> /// <item>SMT is not initialized.</item> /// <item>The item size is bigger then a small heap size.</item> /// </list> /// </exception> 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 } }
/// <summary> /// Alloc memory block, of a given size. /// </summary> /// <param name="aSize">A size of block to alloc, in bytes.</param> /// <returns>Byte pointer to the start of the block.</returns> public static byte *Alloc(uint aSize, byte aType = RAT.PageType.HeapLarge) { uint xPages = ((aSize + PrefixBytes) / RAT.PageSize) + 1; var xPtr = (uint *)RAT.AllocPages(aType, xPages); if (xPtr == null) { Debugger.SendKernelPanic(0x67); // out of pages while (true) { } } xPtr[0] = xPages * RAT.PageSize - PrefixBytes; // Allocated data size xPtr[1] = aSize; // Actual data size xPtr[3] = 0; // padding for now?, xPtr[2] = 0; // padding + GC object status return((byte *)xPtr + PrefixBytes); }
/// <summary> /// Allocates and initialise a page for the SMT table /// </summary> /// <returns></returns> private static SMTPage *InitSMTPage() { var page = (SMTPage *)RAT.AllocPages(RAT.PageType.SMT, 1); page->First = (RootSMTBlock *)(page + 1); // 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. // The current algorithm only works if we create the inital pages in increasing order AddRootSMTBlock(page, 16); AddRootSMTBlock(page, 24); AddRootSMTBlock(page, 48); AddRootSMTBlock(page, 64); AddRootSMTBlock(page, 128); AddRootSMTBlock(page, 256); AddRootSMTBlock(page, 512); AddRootSMTBlock(page, mMaxItemSize); return(page); }