Exemple #1
0
        private void allocate_root_block()
        {
            /* Default each root block to store 1024 root definitions
             * Each definition is a start and end pointer, thus size of block
             * is sizeof(root_header) + 2 * 1024 * sizeof(byte *)
             */

            chunk_header *chk = allocate_chunk(sizeof(root_header) + 2048 * sizeof(byte *));

            if (chk == null)
            {
                Formatter.WriteLine("gengc: add_root_block: allocate_chunk() returned null",
                                    Program.arch.DebugOutput);
                libsupcs.OtherOperations.Halt();
            }
            chk->flags &= ~(1 << 4);        // not large block
            chk->flags |= 1 << 5;           // is root block

            root_header *r = (root_header *)((byte *)chk + sizeof(chunk_header));

            r->next     = hdr->roots;
            r->capacity = 1024;
            r->size     = 0;

            hdr->roots = r;
        }
Exemple #2
0
        public void AddRoots(byte *start, byte *end)
        {
            if (hdr->roots == null || hdr->roots->size == hdr->roots->capacity)
            {
                allocate_root_block();
            }

            root_header *r    = hdr->roots;
            byte **      rptr = (byte **)((byte *)r + sizeof(root_header) +
                                          r->size * sizeof(byte *) * 2);

            *rptr++ = start;
            *rptr++ = end;

            r->size++;

            Formatter.Write("gengc: adding root: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)start, "X", Program.arch.DebugOutput);
            Formatter.Write(" - ", Program.arch.DebugOutput);
            Formatter.Write((ulong)end, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);
        }
Exemple #3
0
        public void DoCollection()
        {
            /* We only want one collection to run at once.  If we just used a lock{} section,
             * then all threads that request a collection whilst one is already running would
             * have to wait for the current collection to finish, then run one themselves
             * immediately afterwards.  This is wasteful as they can just rely on the already
             * running collection to be good enough.
             *
             * Thus, we protect the entry to the function so only one thread can check if a
             * collection is running and immediately start one if it isn't.  This is a short
             * code block so other threads won't have to wait long, they will then see the
             * collection_in_progress flag is true and exit.
             *
             * The flag is reset at function exit atomically so no need for to reacquire the
             * mutex.
             */

            bool can_continue = false;

            while (can_continue == false)
            {
                libsupcs.Monitor.Enter(collection_mutex);
                {
                    if (collection_in_progress)
                    {
                        Formatter.WriteLine("gengc: attempt to run collection whilst already in progress",
                                            Program.arch.DebugOutput);
                        libsupcs.Monitor.Exit(collection_mutex);
                        libsupcs.OtherOperations.AsmBreakpoint();
                        return;
                    }

                    if (alloc_in_progress == false)
                    {
                        collection_in_progress = true;
                        can_continue           = true;
                    }
                }
                libsupcs.Monitor.Exit(collection_mutex);
            }

            /* Run a collection.  Process is:
             *
             * 1)       Whiten all objects (all chunks/small objects that are not root blocks)
             *              (this is done implicitly on assignment and on freeing)
             * 2)       Grey those listed in a root block
             * 3a)      Set blackened_count to 0
             * 3b)      Iterate though all blocks.  If a grey is encountered:
             * 3b.1)        Iterate through the object on native int boundaries
             * 3b.2)        Grey all white objects it points to
             * 3b.3)        Blacken the object
             * 3b.4)        blackened_count++
             * 3c)      If blackened_count > 0 loop to 3a
             * 4)       Iterate through again, reclaiming white blocks to be free, and
             *              whitening black blocks (there should be no grey blocks now)
             */

#if GENGC_BASICDEBUG
            Formatter.WriteLine("gengc: Starting collection", Program.arch.DebugOutput);
#endif

/* grey root blocks */
#if GENGC_BASICDEBUG
            Formatter.WriteLine("gengc: greying roots... ", Program.arch.DebugOutput);
#endif
            root_header *cur_root_hdr = hdr->roots;
            while (cur_root_hdr != null)
            {
                for (int i = 0; i < cur_root_hdr->size; i++)
                {
                    byte *root_start = *(byte **)((byte *)cur_root_hdr + sizeof(root_header) +
                                                  i * 2 * sizeof(byte *));
                    byte *root_end = *(byte **)((byte *)cur_root_hdr + sizeof(root_header) +
                                                (i * 2 + 1) * sizeof(byte *));

                    grey_object(root_start, root_end);

#if GENGC_DEBUG
                    Formatter.Write((ulong)root_start, "X", Program.arch.DebugOutput);
                    Formatter.Write(" - ", Program.arch.DebugOutput);
                    Formatter.Write((ulong)root_end, "X", Program.arch.DebugOutput);
                    Formatter.WriteLine(Program.arch.DebugOutput);
#endif
                }
                cur_root_hdr = cur_root_hdr->next;
            }
#if GENGC_BASICDEBUG
            Formatter.WriteLine("done", Program.arch.DebugOutput);
#endif

            /* blacken reachable blocks */
#if GENGC_BASICDEBUG
            Formatter.Write("gengc: blackening reachable blocks... ", Program.arch.DebugOutput);
#endif
            int           blackened_count;
            int           total_blackened = 0;
            int           small_blackened = 0;
            int           large_blackened = 0;
            int           loops           = 0;
            int           block_count     = 0; // debugging count to ensure we traverse the whole tree
            chunk_header *chk;

            do
            {
                blackened_count = 0;
                block_count     = 0;
                /* Iterate all blocks */

                // Get the first block
                chk = hdr->root_used_chunk;
                while (chk->left != hdr->nil)
                {
                    chk = chk->left;
                }

                while (chk != hdr->nil)
                {
                    block_count++;

                    if ((chk->flags & 0x30) == 0x10)
                    {
                        /* large object - is it grey? */
                        if ((chk->flags & 0x3) == 0x3)
                        {
                            byte *obj_start = (byte *)chk + sizeof(chunk_header);
                            byte *obj_end   = obj_start + (int)chk->length;

                            /* grey all it points to */
                            grey_object(obj_start, obj_end);

                            /* blacken the object */
                            chk->flags &= ~0x1;
                            blackened_count++;
                            large_blackened++;

#if GENGC_DEBUG
                            Formatter.Write("gengc: INFO: greying large object: ", Program.arch.DebugOutput);
                            Formatter.Write((ulong)obj_start, "X", Program.arch.DebugOutput);
                            Formatter.Write(" - ", Program.arch.DebugOutput);
                            Formatter.Write((ulong)obj_end, "X", Program.arch.DebugOutput);
                            Formatter.WriteLine(Program.arch.DebugOutput);
#endif
                        }
                    }
                    else if ((chk->flags & 0x30) == 0x0)
                    {
                        /* small object array, iterate through each */
                        sma_header *smhdr = (sma_header *)((byte *)chk + sizeof(chunk_header));

                        for (int i = 0; i < smhdr->total_count; i += 8)
                        {
                            uint *uint_ptr = (uint *)((byte *)smhdr + sizeof(sma_header) +
                                                      i / 2);

                            for (int bit_idx = 0; bit_idx < 8; bit_idx++)
                            {
                                uint flag_pattern  = 0x3U << (bit_idx * 4);
                                uint grey_pattern  = 0x3U << (bit_idx * 4);
                                uint black_pattern = 0x2U << (bit_idx * 4);

                                if ((*uint_ptr & flag_pattern) == grey_pattern)
                                {
                                    byte *data_start = (byte *)smhdr + sizeof(sma_header) +
                                                       smhdr->total_count * 4;
                                    byte *obj_start = data_start + (i + bit_idx) *
                                                      smhdr->obj_length;
                                    byte *obj_end = obj_start + smhdr->obj_length;

                                    /* grey all it points to */
                                    grey_object(obj_start, obj_end);

                                    /* blacken the object */
                                    *uint_ptr &= ~flag_pattern;
                                    *uint_ptr |= black_pattern;
                                    blackened_count++;
                                    small_blackened++;
                                }
                            }
                        }
                    }

                    // Loop to the next chunk
                    chk = TreeSuccessor(hdr, 1, chk);
                }

                total_blackened += blackened_count;
                loops++;

#if GENGC_DEBUG
                Formatter.Write("gengc: loop visited ", Program.arch.DebugOutput);
                Formatter.Write((ulong)block_count, Program.arch.DebugOutput);
                Formatter.WriteLine(" blocks", Program.arch.DebugOutput);
#endif
            } while (blackened_count > 0);
#if GENGC_BASICDEBUG
            Formatter.WriteLine("done", Program.arch.DebugOutput);
#endif

            /* Iterate through again, setting white to free and black to white */
#if GENGC_BASICDEBUG
            Formatter.Write("gengc: freeing white blocks... ", Program.arch.DebugOutput);
#endif
            // Get the first block
            chk = hdr->root_used_chunk;
            while (chk->left != hdr->nil)
            {
                chk = chk->left;
            }

            int white_large_objects = 0;
            int white_small_objects = 0;
            int black_large_objects = 0;
            int black_small_objects = 0;
            block_count = 0;

            while (chk != hdr->nil)
            {
                block_count++;
                if ((chk->flags & 0x30) == 0x10)
                {
                    /* large object - is it white? */
                    if ((chk->flags & 0x3) == 0x3)
                    {
                        // TODO: delete large object
                        // Can we do a tree node delete whilst traversal is in progress?
                        white_large_objects++;
                    }
                    else if ((chk->flags & 0x3) == 0x2)
                    {
                        // its black - set back to white
                        chk->flags &= ~0x3;
                        chk->flags |= 0x1;
                        black_large_objects++;
                    }
                }

                else if ((chk->flags & 0x30) == 0x0)
                {
                    /* small object array, iterate through each */
                    sma_header *smhdr = (sma_header *)((byte *)chk + sizeof(chunk_header));

                    for (int i = 0; i < smhdr->total_count; i += 8)
                    {
                        uint *uint_ptr = (uint *)((byte *)smhdr + sizeof(sma_header) +
                                                  i / 2);

                        for (int bit_idx = 0; bit_idx < 8; bit_idx++)
                        {
                            uint flag_pattern  = 0x3U << (bit_idx * 4);
                            uint white_pattern = 0x1U << (bit_idx * 4);
                            uint black_pattern = 0x2U << (bit_idx * 4);

                            /* debugging - check we are not freeing a process/thread etc */
                            byte *data_start = (byte *)smhdr + sizeof(sma_header) +
                                               smhdr->total_count * 4;
                            byte *obj_start = data_start + (i + bit_idx) *
                                              smhdr->obj_length;

                            if ((*uint_ptr & flag_pattern) == white_pattern)
                            {
                                /* free the object */
                                *uint_ptr &= ~flag_pattern;
                                smhdr->free_count++;
                                (*smhdr->global_free_count)++;
                                white_small_objects++;
                            }
                            else if ((*uint_ptr & flag_pattern) == black_pattern)
                            {
                                /* whiten the object */
                                *uint_ptr &= ~flag_pattern;
                                *uint_ptr |= white_pattern;
                                black_small_objects++;
                            }
                            else if ((*uint_ptr & flag_pattern) == flag_pattern)
                            {
                                Formatter.Write("gengc: WARNING: object at ", Program.arch.DebugOutput);
                                Formatter.Write((ulong)obj_start, "X", Program.arch.DebugOutput);
                                Formatter.Write(" is grey on final loop: ", Program.arch.DebugOutput);
                                Formatter.Write(*uint_ptr & flag_pattern, "X", Program.arch.DebugOutput);
                                Formatter.WriteLine(Program.arch.DebugOutput);
                            }
                        }
                    }
                }

                // Loop to the next chunk
                chk = TreeSuccessor(hdr, 1, chk);
            }
#if GENGC_BASICDEBUG
            Formatter.WriteLine("done", Program.arch.DebugOutput);
#endif

#if GENGC_DEBUG
            Formatter.Write("gengc: final loop visited ", Program.arch.DebugOutput);
            Formatter.Write((ulong)block_count, Program.arch.DebugOutput);
            Formatter.WriteLine(" blocks", Program.arch.DebugOutput);

            /* Sanity check to ensure we visited all nodes */
            Formatter.Write("gengc: total number of blocks: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)hdr->used_chunks, Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);
#endif

#if GENGC_BASICDEBUG
            Formatter.Write("gengc: Collection completed: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)white_large_objects, Program.arch.DebugOutput);
            Formatter.Write(" large objects and ", Program.arch.DebugOutput);
            Formatter.Write((ulong)white_small_objects, Program.arch.DebugOutput);
            Formatter.WriteLine(" small objects freed", Program.arch.DebugOutput);
#endif

#if GENGC_DEBUG
            Formatter.Write("gengc: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)black_large_objects, Program.arch.DebugOutput);
            Formatter.Write(" large objects and ", Program.arch.DebugOutput);
            Formatter.Write((ulong)black_small_objects, Program.arch.DebugOutput);
            Formatter.WriteLine(" small objects not freed", Program.arch.DebugOutput);

            Formatter.Write("gengc: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)large_blackened, Program.arch.DebugOutput);
            Formatter.Write(" large objects and ", Program.arch.DebugOutput);
            Formatter.Write((ulong)small_blackened, Program.arch.DebugOutput);
            Formatter.WriteLine(" small objects were blackened", Program.arch.DebugOutput);
#endif

#if GENGC_BASICDEBUG
            Formatter.Write("gengc: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)total_blackened, Program.arch.DebugOutput);
            Formatter.WriteLine(" objects remain in use", Program.arch.DebugOutput);
            Formatter.Write("gengc: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)loops, Program.arch.DebugOutput);
            Formatter.WriteLine(" loops required to blacken all in-use objects", Program.arch.DebugOutput);
#endif

            allocs = 0;
            collection_in_progress = false;
        }