Example #1
0
        /// <summary>
        /// Find the next free block in the smt
        /// </summary>
        /// <returns>Pointer to the start of block in the SMT. null if all SMT pages are full</returns>
        private static SMTBlock *NextFreeBlock()
        {
            var       page = SMT;
            SMTBlock *pos  = null;

            while (page != null && pos == null)
            {
                pos  = NextFreeBlock(page);
                page = page->Next;
            }
            return(pos);
        }
Example #2
0
        private static SMTBlock *GetFirstWithSpace(uint aSize)
        {
            var       page  = SMT;
            SMTBlock *block = null;

            do
            {
                block = GetFirstWithSpace(page, aSize);
                page  = page->Next;
            } while (block == null && page != null);
            return(block);
        }
Example #3
0
        /// <summary>
        /// Gets the last block on a certain page for objects of this size
        /// </summary>
        /// <param name="page">Page to search</param>
        /// <param name="aSize"></param>
        /// <returns></returns>
        private static SMTBlock *GetLastBlock(SMTPage *page, uint aSize)
        {
            SMTBlock *ptr = GetFirstBlock(page, aSize)->First;

            if (ptr == null)
            {
                return(null);
            }

            while (ptr->NextBlock != null)
            {
                ptr = ptr->NextBlock;
            }
            return(ptr);
        }
Example #4
0
        /// <summary>
        /// Get the first block for this size, which has space left to allocate to
        /// </summary>
        /// <param name="aSize"></param>
        /// <param name="root">The root node to start the search at</param>
        /// <returns></returns>
        private static SMTBlock *GetFirstWithSpace(uint aSize, RootSMTBlock *root)
        {
            SMTBlock *ptr = root->First;

            if (ptr == null)
            {
                return(null);
            }
            var lptr = ptr;

            while (ptr->SpacesLeft == 0 && ptr->NextBlock != null)
            {
                lptr = ptr;
                ptr  = ptr->NextBlock;
            }
            if (ptr->SpacesLeft == 0 && ptr->NextBlock == null)
            {
                return(null);
            }
            return(ptr);
        }
Example #5
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");
        }
Example #6
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);
        }