Beispiel #1
0
        /// <summary>
        /// Marks all objects referenced
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="type"></param>
        public static void SweepTypedObject(uint *obj, uint type)
        {
            if (obj == null)
            {
                return;
            }
            uint fields  = VTablesImpl.GetGCFieldCount(type);
            var  offsets = VTablesImpl.GetGCFieldOffsets(type);
            var  types   = VTablesImpl.GetGCFieldTypes(type);

            for (int i = 0; i < fields; i++)
            {
                if (!VTablesImpl.IsValueType(types[i]))
                {
                    var location = (uint *)((byte *)obj + offsets[i]) + 1; // +1 since we are only using 32bits from the 64bit
                    if (*location != 0)                                    // Check if its null
                    {
                        location = *(uint **)location;
                        if (RAT.GetPageType(location) == RAT.PageType.HeapSmall)
                        {
                            MarkAndSweepObject(location);
                        }
                    }
                }
                else if (VTablesImpl.IsStruct(types[i]))
                {
                    var obj1 = (uint *)((byte *)obj + offsets[i]);
                    SweepTypedObject(obj1, types[i]);
                }
            }
        }
Beispiel #2
0
        /// <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;
        }
Beispiel #3
0
        /// <summary>
        /// Free block.
        /// </summary>
        /// <param name="aPtr">A pointer to the block.</param>
        /// <exception cref="Exception">Thrown if page type is not found.</exception>
        static public void Free(void *aPtr)
        {
            // TODO - Should check the page type before freeing to make sure it is a Large?
            // or just trust the caller to avoid adding overhead?
            var xPageIdx = RAT.GetFirstRAT(aPtr);

            RAT.Free(xPageIdx);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        // Keep as void* and not byte* or other. Reduces typecasting from callers
        // who may have typed the pointer to their own needs.
        /// <summary>
        /// Free a heap item.
        /// </summary>
        /// <param name="aPtr">A pointer to the heap item to be freed.</param>
        /// <exception cref="Exception">Thrown if:
        /// <list type="bullet">
        /// <item>Page type is not found.</item>
        /// <item>Heap item not found in RAT.</item>
        /// </list>
        /// </exception>
        public static void Free(void *aPtr)
        {
            //TODO find a better way to remove the double look up here for GetPageType and then again in the
            // .Free methods which actually free the entries in the RAT.
            var xType = RAT.GetPageType(aPtr);

            switch (xType)
            {
            case RAT.PageType.HeapLarge:
                HeapLarge.Free(aPtr);
                break;

            default:
                throw new Exception("Heap item not found in RAT.");
            }
        }
Beispiel #6
0
        /// <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
            }
        }
Beispiel #7
0
        /// <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);
        }
Beispiel #8
0
        /// <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);
        }
Beispiel #9
0
        // Keep as void* and not byte* or other. Reduces typecasting from callers
        // who may have typed the pointer to their own needs.
        /// <summary>
        /// Free a heap item.
        /// </summary>
        /// <param name="aPtr">A pointer to the heap item to be freed.</param>
        /// <exception cref="Exception">Thrown if:
        /// <list type="bullet">
        /// <item>Page type is not found.</item>
        /// <item>Heap item not found in RAT.</item>
        /// </list>
        /// </exception>
        public static void Free(void *aPtr)
        {
            //TODO find a better way to remove the double look up here for GetPageType and then again in the
            // .Free methods which actually free the entries in the RAT.
            //Debugger.DoSendNumber(0x77);
            //Debugger.DoSendNumber((uint)aPtr);
            var xType = RAT.GetPageType(aPtr);

            switch (xType)
            {
            case RAT.PageType.HeapSmall:
                HeapSmall.Free(aPtr);
                break;

            case RAT.PageType.HeapMedium:
            case RAT.PageType.HeapLarge:
                HeapLarge.Free(aPtr);
                break;

            default:
                throw new Exception("Heap item not found in RAT.");
            }
        }
Beispiel #10
0
 /// <summary>
 /// Init SMT (Size Map Table).
 /// </summary>
 /// <param name="aMaxItemSize">A max item size.</param>
 static void InitSMT(Native aMaxItemSize)
 {
     mMaxItemSize = aMaxItemSize;
     mSMT         = (void **)RAT.AllocBytes(RAT.PageType.HeapSmall, mMaxItemSize * (Native)sizeof(void *));
 }
Beispiel #11
0
        /// <summary>
        /// Free a object
        /// </summary>
        /// <param name="aPtr">A pointer to the start object.</param>
        public static void Free(void *aPtr)
        {
            //Debugger.DoSendNumber(0x6666);
            //Debugger.DoSendNumber((uint)aPtr);
            var    heapObject = (ushort *)aPtr;
            ushort size       = heapObject[-2];

            //Debugger.DoSendNumber(size);
            if (size == 0)
            {
                // double free, this object has already been freed
                Debugger.DoBochsBreak();
                Debugger.DoSendNumber((uint)heapObject);
                Debugger.SendKernelPanic(0x99);
            }

            var allocated = (uint *)aPtr;

            allocated[-1] = 0; // zero both size and gc status at once

            // now zero the object so its ready for next allocation
            if (size < 4) // so we dont actually forget to clean up too small items
            {
                size = 4;
            }
            var bytes = size / 4;

            if (size % 4 != 0)
            {
                bytes += 1;
            }
            //Debugger.DoSendNumber(bytes);
            for (int i = 0; i < bytes; i++)
            {
                allocated[i] = 0;
            }

            // need to increase count in SMT again
            var       allocatedOnPage = RAT.GetPagePtr(aPtr);
            var       smtPage         = SMT;
            SMTBlock *blockPtr        = null;

            while (smtPage != null)
            {
                blockPtr = GetFirstBlock(smtPage, size)->First;
                while (blockPtr != null && blockPtr->PagePtr != allocatedOnPage)
                {
                    blockPtr = blockPtr->NextBlock;
                }
                if (blockPtr->PagePtr == allocatedOnPage)
                {
                    break;
                }
                smtPage = smtPage->Next;
            }

            if (blockPtr == null)
            {
                // this shouldnt happen
                Debugger.DoSendNumber((uint)aPtr);
                Debugger.DoSendNumber((uint)SMT);
                Debugger.SendKernelPanic(0x98);
                while (true)
                {
                }
            }
            blockPtr->SpacesLeft++;
            //Debugger.DoSend("Free finished");
        }
Beispiel #12
0
        /// <summary>
        /// Marks a GC managed object as referenced and recursivly marks child objects as well
        /// </summary>
        /// <param name="aPtr"></param>
        public static void MarkAndSweepObject(void *aPtr)
        {
            var gcPointer = (ObjectGCStatus *)aPtr;

            if ((gcPointer[-1] & ObjectGCStatus.Hit) == ObjectGCStatus.Hit)
            {
                return; // we already hit this object
            }

            // Mark
            gcPointer[-1] |= ObjectGCStatus.Hit;

            // Sweep

            uint *obj = (uint *)aPtr;

            // Check what we are dealing with
            if (*(obj + 1) == (uint)ObjectUtils.InstanceTypeEnum.NormalObject)
            {
                if (_StringType == 0)
                {
                    _StringType = GetStringTypeID();
                }
                var type = *obj;
                // Deal with strings first
                if (type == _StringType)
                {
                    return; // we are done since they dont hold any reference to fields
                }

                SweepTypedObject(obj, type);
            }
            else if (*(obj + 1) == (uint)ObjectUtils.InstanceTypeEnum.Array)
            {
                var elementType = *obj;
                var length      = *(obj + 2);
                var size        = *(obj + 3);
                if (VTablesImpl.IsValueType(elementType))
                {
                    if (VTablesImpl.IsStruct(elementType))
                    {
                        for (int i = 0; i < length; i++)
                        {
                            var location = (uint *)((byte *)obj + size * i) + 4;
                            SweepTypedObject(location, elementType);
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < length; i++)
                    {
                        var location = (uint *)((byte *)obj + size * i) + 4 + 1;
                        if (*location != 0)
                        {
                            location = *(uint **)location;
                            if (RAT.GetPageType(location) == RAT.PageType.HeapSmall) // so we dont try free string literals
                            {
                                MarkAndSweepObject(location);
                            }
                        }
                    }
                }
            }
            else if (*(obj + 1) == (uint)ObjectUtils.InstanceTypeEnum.BoxedValueType)
            {
                // do nothing
            }
        }
Beispiel #13
0
        /// <summary>
        /// Collects all unreferenced objects after identifying them first
        /// </summary>
        /// <returns>Number of objects freed</returns>
        public static int Collect()
        {
            // Mark and sweep objects from roots
            // 1. Check if a page is in use if medium/large mark and sweep object
            // 2. Go throught the SMT table for small objects and go through pages by size
            //    mark and sweep all allocated objects as well

            // Medium and large objects
            for (int ratIndex = 0; ratIndex < RAT.TotalPageCount; ratIndex++)
            {
                var pageType = *(RAT.mRAT + ratIndex);
                if (pageType == RAT.PageType.HeapMedium || pageType == RAT.PageType.HeapLarge)
                {
                    var pagePtr = RAT.RamStart + ratIndex * RAT.PageSize;
                    if (*(ushort *)(pagePtr + 3) != 0)
                    {
                        MarkAndSweepObject(pagePtr + HeapLarge.PrefixBytes);
                    }
                }
            }

            // Small objects
            // we go one size at a time
            var rootSMTPtr = HeapSmall.SMT->First;

            while (rootSMTPtr != null)
            {
                uint size           = rootSMTPtr->Size;
                var  objectSize     = size + HeapSmall.PrefixItemBytes;
                uint objectsPerPage = RAT.PageSize / objectSize;

                var smtBlock = rootSMTPtr->First;

                while (smtBlock != null)
                {
                    var pagePtr = smtBlock->PagePtr;
                    for (int i = 0; i < objectsPerPage; i++)
                    {
                        if (*(ushort *)(pagePtr + i * objectSize + 1) > 1) // 0 means not found and 1 means marked
                        {
                            MarkAndSweepObject(pagePtr + i * objectSize + HeapSmall.PrefixItemBytes);
                        }
                    }

                    smtBlock = smtBlock->NextBlock;
                }

                rootSMTPtr = rootSMTPtr->LargerSize;
            }

            // Mark and sweep objects from stack
            uint *currentStackPointer = (uint *)CPU.GetEBPValue();

            while (StackStart != currentStackPointer)
            {
                if (RAT.RamStart < (byte *)*currentStackPointer && (byte *)*currentStackPointer < RAT.HeapEnd)
                {
                    if ((RAT.GetPageType((uint *)*currentStackPointer) & RAT.PageType.GCManaged) == RAT.PageType.GCManaged)
                    {
                        MarkAndSweepObject((uint *)*currentStackPointer);
                    }
                }
                currentStackPointer += 1;
            }

            // Free all unreferenced and reset hit flag
            // This means we do the same transversal as we did before of the heap
            // but we done have to touch the stack again
            int freed = 0;

            // Medium and large objects
            for (int ratIndex = 0; ratIndex < RAT.TotalPageCount; ratIndex++)
            {
                var pageType = *(RAT.mRAT + ratIndex);
                if (pageType == RAT.PageType.HeapMedium || pageType == RAT.PageType.HeapLarge)
                {
                    var pagePointer = RAT.RamStart + ratIndex * RAT.PageSize;
                    if (*((ushort *)(pagePointer + HeapLarge.PrefixBytes) - 1) == 0)
                    {
                        Free(pagePointer + HeapLarge.PrefixBytes);
                        freed += 1;
                    }
                    else
                    {
                        *((ushort *)(pagePointer + HeapLarge.PrefixBytes) - 1) &= (ushort)~ObjectGCStatus.Hit;
                    }
                }
            }

            // Small objects
            // we go one size at a time
            rootSMTPtr = HeapSmall.SMT->First;
            while (rootSMTPtr != null)
            {
                uint size           = rootSMTPtr->Size;
                uint objectSize     = size + HeapSmall.PrefixItemBytes;
                uint objectsPerPage = RAT.PageSize / objectSize;

                SMTBlock *smtBlock = rootSMTPtr->First;

                while (smtBlock != null)
                {
                    byte *pagePtr = smtBlock->PagePtr;
                    for (int i = 0; i < objectsPerPage; i++)
                    {
                        if (*(ushort *)(pagePtr + i * objectSize) != 0)
                        {
                            if (*((ushort *)(pagePtr + i * objectSize) + 1) == 0)
                            {
                                Free(pagePtr + i * objectSize + HeapSmall.PrefixItemBytes);
                                freed += 1;
                            }
                            else
                            {
                                *((ushort *)(pagePtr + i * objectSize) + 1) &= (ushort)~ObjectGCStatus.Hit;
                            }
                        }
                    }
                    smtBlock = smtBlock->NextBlock;
                }

                rootSMTPtr = rootSMTPtr->LargerSize;
            }

            return(freed);
        }
Beispiel #14
0
        /// <summary>
        /// Free block.
        /// </summary>
        /// <param name="aPtr">A pointer to the block.</param>
        /// <exception cref="Exception">Thrown if page type is not found.</exception>
        public static void Free(void *aPtr)
        {
            var xPageIdx = RAT.GetFirstRATIndex(aPtr);

            RAT.Free(xPageIdx);
        }