develooper Front page | perl.cvs.parrot | Postings from December 2008

[svn:parrot] r34121 - in branches/pdd09gc_part1: . src/gc

From:
Whiteknight
Date:
December 19, 2008 17:04
Subject:
[svn:parrot] r34121 - in branches/pdd09gc_part1: . src/gc
Message ID:
20081220010355.C3E8ACBA12@x12.develooper.com
Author: Whiteknight
Date: Fri Dec 19 17:03:54 2008
New Revision: 34121

Added:
   branches/pdd09gc_part1/src/gc/incremental_ms.c
Modified:
   branches/pdd09gc_part1/MANIFEST

Log:
[pdd09gc_part1] adding the incremental_mc.c file to the branch, although it's not connected to anything yet

Modified: branches/pdd09gc_part1/MANIFEST
==============================================================================
--- branches/pdd09gc_part1/MANIFEST	(original)
+++ branches/pdd09gc_part1/MANIFEST	Fri Dec 19 17:03:54 2008
@@ -2929,6 +2929,7 @@
 src/exit.c                                                  []
 src/extend.c                                                []
 src/gc/dod.c                                                []
+src/gc/incremental_ms.c                                     []
 src/gc/gc_gms.c                                             []
 src/gc/gc_ims.c                                             []
 src/gc/marksweep.c                                          []

Added: branches/pdd09gc_part1/src/gc/incremental_ms.c
==============================================================================
--- (empty file)
+++ branches/pdd09gc_part1/src/gc/incremental_ms.c	Fri Dec 19 17:03:54 2008
@@ -0,0 +1,1400 @@
+/*
+Copyright (C) 2001-2008, The Perl Foundation.
+$Id: gc_it.c 34092 2008-12-19 01:35:50Z Whiteknight $
+
+=head1 NAME
+
+src/gc/gc_it.c - Incremental Tricolor Garbage Collector
+
+=head1 DESCRIPTION
+
+This file implements the majority of the incremental tri-color garbage
+collector for Parrot. The interface for this and all collectors is
+specified in F<docs/pdds/pdd09_gc.pod>.
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+#include "parrot/dod.h"
+
+#if PARROT_GC_IT
+
+#  if GC_IT_SERIAL_MODE
+#    define gc_it_trace(i) gc_it_trace_normal(i);
+#  elif GC_IT_PARALLEL_MODE
+#    define gc_it_trace(i) gc_it_trace_threaded(i);
+#  endif
+
+/* HEADERIZER HFILE: include/parrot/dod.h */
+
+/* HEADERIZER BEGIN: static */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+static void gc_it_add_arena_to_free_list(PARROT_INTERP,
+    ARGMOD(Small_Object_Pool *pool),
+    ARGMOD(Small_Object_Arena *new_arena))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*pool)
+        FUNC_MODIFIES(*new_arena);
+
+PARROT_INLINE
+static void gc_it_enqueue_all_roots(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_it_enqueue_next_root(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_it_finalize_all_pmc(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_it_finalize_arena(PARROT_INTERP,
+    ARGMOD(Small_Object_Pool * pool),
+    ARGMOD(Small_Object_Arena *arena))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(* pool)
+        FUNC_MODIFIES(*arena);
+
+static void gc_it_finalize_PMC_arenas(PARROT_INTERP,
+    ARGMOD(Gc_it_data *gc_priv_data),
+    ARGMOD(Small_Object_Pool *pool))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*gc_priv_data)
+        FUNC_MODIFIES(*pool);
+
+PARROT_INLINE
+static void gc_it_mark_PObj_children_grey(PARROT_INTERP,
+    ARGMOD(Gc_it_hdr *hdr))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*hdr);
+
+static void gc_it_post_sweep_cleanup(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_it_sweep_header_arenas(PARROT_INTERP,
+    ARGMOD(Gc_it_data *gc_priv_data),
+    ARGMOD(Small_Object_Pool *pool))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*gc_priv_data)
+        FUNC_MODIFIES(*pool);
+
+static void gc_it_sweep_PMC_arenas(PARROT_INTERP,
+    ARGMOD(Gc_it_data *gc_priv_data),
+    ARGMOD(Small_Object_Pool *pool))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*gc_priv_data)
+        FUNC_MODIFIES(*pool);
+
+static void gc_it_sweep_pmc_pools(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_it_sweep_sized_pools(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: static */
+
+/*
+
+=head1 Functions
+
+=over 4
+
+=item C<void Parrot_gc_it_init>
+
+Initializes the GC, sets the necessary pointers in the interpreter.
+We initialize the Gc_it_data structure for the GC, and set the initial
+state of the collector.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+Parrot_gc_it_init(PARROT_INTERP)
+{
+    Gc_it_data        *gc_priv_data;
+    Arenas     * const arena_base  = interp->arena_base;
+
+    /* Create our private data. We might need to initialize some things
+    here, depending on the data we include in this structure */
+    arena_base->gc_private         = mem_allocate_zeroed_typed(Gc_it_data);
+    gc_priv_data                   = (Gc_it_data *)arena_base->gc_private;
+    gc_priv_data->state            = GC_IT_READY;
+
+    /* set function hooks according to pdd09 */
+    arena_base->do_gc_mark         = Parrot_gc_it_run;
+    arena_base->finalize_gc_system = Parrot_gc_it_deinit;
+    arena_base->init_pool          = Parrot_gc_it_pool_init;
+    {
+        /* Let's just test the hell out of this to make sure that things are
+           doing what I think they are doing. */
+        Gc_it_hdr * hdr = 0;
+        UINTVAL h = (UINTVAL)hdr;
+        UINTVAL p;
+        PObj * pobj = (PObj*)(hdr + 1);
+        p = h + sizeof(Gc_it_hdr);
+        PARROT_ASSERT(hdr == PObj_to_IT_HDR(IT_HDR_to_PObj(hdr)));
+        PARROT_ASSERT(&(hdr[1]) == (hdr + 1));
+        PARROT_ASSERT((hdr + 1) == (Gc_it_hdr*)((char*)hdr + sizeof(Gc_it_hdr)));
+        PARROT_ASSERT((void*)pobj > (void*)hdr);
+        PARROT_ASSERT(p > h);
+        PARROT_ASSERT(p == (UINTVAL)pobj);
+        PARROT_ASSERT(hdr == PObj_to_IT_HDR(pobj));
+        PARROT_ASSERT(pobj == IT_HDR_to_PObj(hdr));
+    }
+#  if GC_IT_DEBUG
+    fprintf(stderr, "GC IT Initialized: %p\n", gc_priv_data);
+    fprintf(stderr, "SIZES. Hdr: %d, Data: %d\n", sizeof (Gc_it_hdr),
+        sizeof (Gc_it_data));
+#  endif
+}
+
+
+/*
+
+=item C<void Parrot_gc_it_run>
+
+Run the GC. Not sure what it means to "run" yet, might only run one
+increment, or one step from many.
+
+Basic Algorithm:
+1) Determine which pool/generation to scan
+2) Mark root items as being grey
+3) For all grey items, mark all children as grey, then mark item as black
+4) repeat (3) until there are no grey items in current pool/generation
+5) mark all objects grey that appear in IGP lists. Repeat (1) - (4) for these
+6) Add all items that are still white to the free list
+7) Scan through simple buffers, add white objects to free list
+8) reset all flags to white
+Only reclaim objects where there are no greys in the current area,
+and when a run has completed. Do not reclaim, for instance, any white
+objects after a run has completed and all black objects have been turned
+back to white (which would free all objects, alive or dead).
+
+Flags and other issues:
+GC_trace_normal = run a trace, or a partial trace, but not a sweep.
+    set the macro CHECK_IF_WE_BREAK_BEFORE_SWEEP, however we do that,
+    to break off the function after the trace phase.
+GC_trace_stack_FLAG = we need to trace the C stack and the processor
+    registers too. I wouldn't even know how to start doing this.
+GC_lazy_FLAG = Appears we run a sweep phase if we have already marked,
+    or complete the current mark and then sweep. Or, we find some other
+    way to free items that are obviously dead.
+GC_finish_FLAG = set all objects to dead, call all finalizers on PMC
+    objects. We don't need to mark free items, since everything is going
+    to die anyway.
+
+If GC_trace_normal && (GC_IT_FLAG_NEW_MARK || GC_IT_FLAG_RESUME_MARK)
+    run a trace or resume the current trace.
+
+if GC_trace_normal && (GC_IT_FLAG_NEW_SWEEP || GC_IT_FLAG_RESUME_SWEEP)
+    do nothing
+
+if GC_lazy_FLAG && (GC_IT_FLAG_NEW_SWEEP || GC_IT_FLAG_RESUME_SWEEP)
+    run a sweep, possibly to conclusion.
+
+if GC_finish_FLAG
+    run a complete sweep of the PMC area calling finalizers only but not
+    marking objects or adding objects to the free list
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+Parrot_gc_it_run(PARROT_INTERP, int flags)
+{
+    const Arenas * const arena_base   = interp->arena_base;
+    Gc_it_data   * const gc_priv_data = (Gc_it_data *)(arena_base->gc_private);
+    const UINTVAL gc_trace    = flags & (GC_trace_normal | GC_trace_stack_FLAG);
+    const UINTVAL gc_lazy     = flags & GC_lazy_FLAG;
+    const UINTVAL gc_stack    = (gc_lazy) ? (0) : (flags & GC_trace_stack_FLAG);
+    const UINTVAL gc_finish   = flags & GC_finish_FLAG;
+    const UINTVAL gc_force    = gc_lazy && interp->arena_base->num_early_DOD_PMCs;
+
+    /* on a lazy run, we only sweep if there are PMCs needing early destruction.
+       However, we must also sweep from the very beginning, to ensure the timely
+       objects get destroyed. */
+    if (gc_lazy && !gc_force)
+        return;
+    if (gc_finish) {
+
+#  if GC_IT_DEBUG
+        fprintf(stderr, "Finalizing GC system\n");
+#  endif
+
+        /* If we've gotten the finish flag, the interpreter is closing down.
+           go through all items, call finalization on all PMCs, and do
+           whatever else we need to do. */
+        gc_priv_data->state = GC_IT_RESUME_MARK;
+
+        /* Go through the PMC arena and finalize all PMCs that are still
+           alive at this point. */
+        gc_it_finalize_all_pmc(interp);
+        gc_priv_data->state = GC_IT_FINAL_CLEANUP;
+        return;
+    }
+#  if GC_IT_DEBUG
+    //fprintf(stderr, "GC Run. items total: %d, flags: %x, state: %d\n",
+    //        (int)gc_priv_data->total_count, flags, gc_priv_data->state);
+#  endif
+
+    /* items scanned this run */
+    gc_priv_data->item_count = 0;
+
+    switch (gc_priv_data->state) {
+        case GC_IT_READY:
+            gc_priv_data->state = GC_IT_START_MARK;
+            GC_IT_BREAK_AFTER_0;
+
+        case GC_IT_START_MARK:
+            gc_priv_data->total_count = 0;
+            gc_priv_data->state       = GC_IT_MARK_ROOTS;
+            GC_IT_BREAK_AFTER_1;
+
+        case GC_IT_MARK_ROOTS:
+            if (Parrot_is_blocked_GC_mark(interp))
+                break;
+            if (gc_trace && gc_stack)
+                Parrot_dod_trace_root(interp, 1);
+            else if (gc_stack)
+                Parrot_dod_trace_root(interp, 2);
+            else if (gc_trace)
+                Parrot_dod_trace_root(interp, 0);
+            gc_priv_data->state = GC_IT_RESUME_MARK;
+            GC_IT_BREAK_AFTER_2;
+
+        case GC_IT_RESUME_MARK:
+            if (Parrot_is_blocked_GC_mark(interp))
+                break;
+#  if GC_IT_INCREMENT_MODE
+            /* scan a single tree. Check to ensure we've hit a minimum number
+               of items. If not, scan another tree. */
+            /*do {
+                gc_it_enqueue_next_root(interp);
+                gc_it_trace(interp);
+            } while (gc_priv_data->item_count < GC_IT_ITEMS_MARKED_MIN
+            &&      gc_priv_data->root_queue);*/
+            /* We've either scanned the necessary number of items, or we've
+               run out of new root items to scan. Check to see if the mark
+               is complete, and if so move to the next state. Otherwise,
+               stay at the same state so we can come back. */
+            if (!gc_priv_data->queue
+            &&  !gc_priv_data->root_queue)
+                gc_priv_data->state = GC_IT_END_MARK;
+            else
+                break;
+#  elif GC_IT_BATCH_MODE
+            /* in batch mode, enqueue all roots, and scan the entire pile */
+            gc_it_enqueue_all_roots(interp);
+            gc_it_trace(interp);
+#  endif
+            GC_IT_BREAK_AFTER_3;
+
+        case GC_IT_END_MARK:
+            /* Don't know if there is anything to be done here */
+            gc_priv_data->state = GC_IT_SWEEP_PMCS;
+            GC_IT_BREAK_AFTER_4;
+
+        case GC_IT_SWEEP_PMCS:
+            if (Parrot_is_blocked_GC_sweep(interp))
+                break;
+            //gc_it_sweep_pmc_pools(interp);
+            gc_priv_data->state = GC_IT_SWEEP_BUFFERS;
+            GC_IT_BREAK_AFTER_5;
+
+        case GC_IT_SWEEP_BUFFERS:
+            if (Parrot_is_blocked_GC_sweep(interp))
+                break;
+            gc_it_sweep_sized_pools(interp);
+            gc_priv_data->state = GC_IT_FINAL_CLEANUP;
+            GC_IT_BREAK_AFTER_6;
+
+        case GC_IT_FINAL_CLEANUP:
+            gc_it_post_sweep_cleanup(interp); /* if any. */
+        default:
+            gc_priv_data->state = GC_IT_READY;
+    }
+    return;
+}
+
+/*
+
+=item C<void gc_it_trace_normal>
+
+Perform a "normal" (i.e. not "threaded") trace. We run through the entire
+queue, and continue to scan until the queue is empty. The secret to the
+incremental behavior of the collector is careful limiting of what objects
+are added to the queue in the first place. We store root objects on the
+separate C<root_queue>, and add them one-at-a-time to the queue before
+we call this function. This algorithm is probably best called "tree at a
+time", because we scan a single tree from the root all the way through to
+it's children.
+
+=cut
+
+*/
+
+#  if GC_IT_SERIAL_MODE
+void
+gc_it_trace_normal(PARROT_INTERP)
+{
+    /* trace through the entire queue until it is empty. */
+    Gc_it_hdr         *hdr;
+    Gc_it_data * const gc_priv_data =
+        (Gc_it_data *)interp->arena_base->gc_private;
+
+    if (!gc_priv_data->queue)
+        /* The queue is empty, don't try to trace because it won't work. */
+        return;
+
+#    if GC_IT_DEBUG
+    fprintf(stderr, "Tracing queue, starting with %p\n", gc_priv_data->queue);
+#    endif
+
+    for (hdr = gc_priv_data->queue; hdr; hdr = gc_priv_data->queue) {
+        /* for each item, add all chidren to the queue, and then mark the item
+           black. Once black, the item can be removed from the queue and
+           discarded */
+        PARROT_ASSERT(hdr);
+        gc_it_mark_PObj_children_grey(interp, hdr);
+        gc_it_set_card_mark(hdr, GC_IT_CARD_BLACK);
+        gc_priv_data->queue = hdr->next;
+
+        /* Items that have been marked are not left to just float like they
+           were. They are instead put into a "marked" list to keep them from
+           being marked twice in the same mark phase. */
+        hdr->next = gc_priv_data->marked;
+        gc_priv_data->marked = hdr->next;
+
+        /* total items since beginning of scan */
+        gc_priv_data->total_count++;
+
+        /* number of items this increment */
+        gc_priv_data->item_count++;
+    }
+#    if GC_IT_DEBUG
+    fprintf(stderr, "Trace complete: %d\n", (gc_priv_data->queue == NULL));
+#    endif
+    PARROT_ASSERT(gc_priv_data->queue == NULL);
+}
+
+
+/*
+
+=item C<static void gc_it_sweep_pmc_pools>
+
+Sweeps through pools that are not part of the sized header pools, such as the
+string header pool and the PMC pool. Does not sweep through related pools,
+such as the constant string header pool or the constant PMC pool because those
+should not be swept. Frees dead objects and returns them to the pool free lists.
+
+=cut
+
+*/
+
+static void
+gc_it_sweep_pmc_pools(PARROT_INTERP)
+{
+    const Arenas * const arena_base   = interp->arena_base;
+    Gc_it_data   * const gc_priv_data = (Gc_it_data *)arena_base->gc_private;
+
+    if (gc_priv_data->queue)
+        gc_it_trace(interp);
+    gc_it_sweep_PMC_arenas(interp, gc_priv_data, arena_base->pmc_pool);
+}
+
+
+/*
+
+=item C<static void gc_it_finalize_all_pmc>
+
+Performs the final GC run, sweeping through the pmc pool and calling any custom
+destroy VTABLE entries.
+
+=cut
+
+*/
+
+static void
+gc_it_finalize_all_pmc(PARROT_INTERP)
+{
+    const Arenas * const arena_base   = interp->arena_base;
+    Gc_it_data   * const gc_priv_data = (Gc_it_data *)arena_base->gc_private;
+    register UINTVAL i;
+    /* PMCs need to be handled differently from other types of pools.  Set
+       up lists of our pools here, and handle different types differently. */
+
+    gc_it_finalize_PMC_arenas(interp, gc_priv_data, arena_base->pmc_pool);
+}
+
+
+/*
+
+=item C<static void gc_it_finalize_PMC_arenas>
+
+In a particular PMC pool, runs through all arenas and call custom finalization
+methods of all live PMCs, if any.
+
+I need to rework this whole function, but it's a good placeholder for now
+
+=cut
+
+*/
+
+static void
+gc_it_finalize_PMC_arenas(PARROT_INTERP, ARGMOD(Gc_it_data *gc_priv_data),
+    ARGMOD(Small_Object_Pool *pool))
+{
+    Small_Object_Arena *arena;
+
+    /* walking backwards helps avoid incorrect order-of-destruction bugs */
+    for (arena = pool->last_Arena; arena; arena = arena->prev) {
+        gc_it_finalize_arena(interp, pool, arena);
+    }
+}
+
+/*
+
+=item C<static void gc_it_finalize_arena>
+
+Finalizes one arena, assume the objects in it are PMCs.
+Loops through the arena and adds all objects in it to a linked list in
+reverse order. Then, traverse through this linked list and finalize any
+items that are still alive.
+
+=cut
+
+*/
+
+static void
+gc_it_finalize_arena(PARROT_INTERP, ARGMOD(Small_Object_Pool * pool),
+    ARGMOD(Small_Object_Arena *arena))
+{
+    UINTVAL i;
+    const UINTVAL num_objs = arena->total_objects;
+    Gc_it_hdr * hdr = (Gc_it_hdr *)arena->start_objects;
+    Gc_it_hdr * list = NULL;
+
+    for (i = 0; i < num_objs; i++) {
+        PObj * const obj = IT_HDR_to_PObj(hdr);
+        hdr->next = list;
+        list = hdr;
+        hdr = ((Gc_it_hdr *)((char *)hdr + pool->object_size));
+    }
+    while ((hdr = list) != NULL) {
+        list = hdr->next;
+        /* We call Parrot_dod_free_pmc here, when it might be easier
+           to just call the finalization methods and not free them. */
+        if (gc_it_get_card_mark(hdr) != GC_IT_CARD_FREE)
+            Parrot_dod_free_pmc(interp, pool, IT_HDR_to_PObj(hdr));
+    }
+}
+
+/*
+
+=item C<static void gc_it_sweep_sized_pools>
+
+Sweeps through the sized pools, freeing dead objects.
+
+=cut
+
+*/
+
+static void
+gc_it_sweep_sized_pools(PARROT_INTERP)
+{
+    const Arenas * const arena_base   = interp->arena_base;
+    Gc_it_data   * const gc_priv_data = (Gc_it_data *)arena_base->gc_private;
+    register INTVAL i;
+
+    if (gc_priv_data->queue)
+        gc_it_trace(interp);
+    for (i = arena_base->num_sized - 1; i >= 0; i--) {
+        Small_Object_Pool * const pool = arena_base->sized_header_pools[i];
+        if (pool)
+            gc_it_sweep_header_arenas(interp, gc_priv_data, pool);
+    }
+
+}
+
+
+/*
+
+=item C<static void gc_it_sweep_PMC_arenas>
+
+If the pool contains PMCs, we sweep through it. When a dead object is found, we
+call C<Parrot_dod_free_pmc> on it. This should, in theory, kill the PMC and
+clean up all its dependencies. After the PMC is dead, we add it to the pool's
+free list.
+
+=cut
+
+*/
+
+static void
+gc_it_sweep_PMC_arenas(PARROT_INTERP, ARGMOD(Gc_it_data *gc_priv_data),
+    ARGMOD(Small_Object_Pool *pool))
+{
+    /* Go through each arena in the pool, free objects marked white,
+       set black cards to white, and call finalization routines, if needed. */
+    Small_Object_Arena *arena;
+    Gc_it_hdr * hdr;
+
+#    if GC_IT_DEBUG
+    fprintf(stderr, "Sweeping PMC pool %s (%p)\n", pool->name, pool);
+#    endif
+
+    for (arena = pool->last_Arena; arena; arena = arena->prev) {
+        INTVAL i         = arena->total_objects;
+        Gc_it_hdr *hdr   = (Gc_it_hdr *)arena->start_objects;
+        UINTVAL    mark;
+
+        while (i > 0) {
+            /* this is a heavily stripped-down version of what it should be.
+               Eventually, this is all going to get more efficient:
+               1) going to re-unroll the loop like I have in the sized header
+                  sweep loop.
+               2) Going to handle the cards directly, instead of making all
+                  these function calls.
+            */
+            mark = gc_it_get_card_mark(hdr);
+            if (mark == GC_IT_CARD_WHITE) {
+                PObj * pobj = IT_HDR_to_PObj(hdr);
+                if (PObj_needs_early_DOD_TEST(pobj))
+                    --interp->arena_base->num_early_DOD_PMCs;
+                if (!PObj_constant_TEST(pobj)) {
+                    gc_it_add_free_header(interp, pool, hdr);
+                    Parrot_dod_free_pmc(interp, pool, IT_HDR_to_PObj(hdr));
+                    ++pool->num_free_objects;
+                }
+            }
+            else if (mark == GC_IT_CARD_BLACK) {
+                gc_it_set_card_mark(hdr, GC_IT_CARD_WHITE);
+                /* Make sure it's not on the marked list anymore */
+                hdr->next = NULL;
+            }
+
+            hdr = (Gc_it_hdr*)((char*)hdr + (pool->object_size));
+            i--;
+        }
+    }
+}
+
+
+/*
+
+=item C<static void gc_it_sweep_header_arenas>
+
+Sweeps through the header pool, and frees dead objects. Unlike PMCs, we don't
+need to kill the dead object first (that i'm aware of), we just add the header
+to the pool's free list.
+
+=cut
+
+*/
+
+static void
+gc_it_sweep_header_arenas(PARROT_INTERP, ARGMOD(Gc_it_data *gc_priv_data),
+    ARGMOD(Small_Object_Pool *pool))
+{
+    Small_Object_Arena *arena;
+
+#    if GC_IT_DEBUG
+    fprintf(stderr, "Sweeping buffer pool %s (%p)\n", pool->name, pool);
+#    endif
+
+    for (arena = pool->last_Arena; arena; arena = arena->prev) {
+        INTVAL i                      = arena->total_objects;
+        Gc_it_hdr *hdr                = (Gc_it_hdr *)arena->start_objects;
+        UINTVAL mark;
+
+        /* Partially unroll the loop with Duff's device: four items at a time.
+           I can make some parts of this more efficient, but for now let's
+           stick with the basics. */
+        while (i > 0) {
+            mark = gc_it_get_card_mark(hdr);
+            if (mark == GC_IT_CARD_WHITE) {
+                gc_it_add_free_header(interp, pool, hdr);
+                ++pool->num_free_objects;
+            }
+            else if (mark == GC_IT_CARD_BLACK) {
+                gc_it_set_card_mark(hdr, GC_IT_CARD_WHITE);
+                hdr->next = NULL;
+            }
+            hdr = (Gc_it_hdr*)((char*)hdr + (pool->object_size));
+            i--;
+        }
+    }
+}
+#  endif
+
+
+/*
+
+=item C<void gc_it_trace_threaded>
+
+If the GC is running in multithreaded mode, we do whatever we need to do
+in that situation. This is not implemented. Here are some ideas of what we
+could do:
+
+1) We have a GC thread which is persistent. In that case, this function will
+do nothing, and that thread will run continuously in the background doing it's
+thing.
+2) We launch child threads every time this function is called. For each child
+thread, we enqueue a single root (probably as a thread function parameter)
+and run the thread to completion. The GC thread will trace through it's queue
+entirely, and will terminate when it's queue has become empty. When all child
+threads have terminated, and when all root queue items have been scanned, we
+move on to the sweep phase.
+3) Same as #2, but instead of blindly launching a child thread every time this
+function is called, we only launch up to a finite number of threads. If we
+have too many threads running already, we do not launch another one here.
+
+=cut
+
+*/
+
+#  if GC_IT_PARALLEL_MODE
+void
+gc_it_trace_threaded(SHIM_INTERP) {}
+
+
+/*
+
+=item C<void gc_it_mark_threaded>
+
+Run one thread's worth of the trace algorithm, as discussed in the function
+documentation of C<gc_it_trace_threaded>
+
+=cut
+
+*/
+
+void
+gc_it_mark_threaded(SHIM_INTERP) {}
+
+#  endif
+
+
+/*
+
+=item C<static void gc_it_enqueue_all_roots>
+
+"batch mode" is a mode where the GC performs a complete stop-the-world
+mark phase, instead of the incremental behaviour which is the default.
+
+Moves all items from the root queue into the ordinary queue. If the queue
+is not empty, we run a trace first to mark all items on the queue already.
+
+=cut
+
+*/
+
+#  if GC_IT_BATCH_MODE
+PARROT_INLINE
+static void
+gc_it_enqueue_all_roots(PARROT_INTERP)
+{
+    Gc_it_data * const gc_priv_data =
+        (Gc_it_data *)interp->arena_base->gc_private;
+
+    /* If the queue is not currently empty, trace through it real quick so
+       we don't lose anything. This is probably not the right way to go, but
+       it should work. */
+    if (gc_priv_data->queue) {
+#  if GC_IT_DEBUG
+        fprintf(stderr, "Objects on queue before root queue. Tracing.\n");
+#  endif
+        gc_it_trace_normal(interp);
+    }
+
+    PARROT_ASSERT(!gc_priv_data->queue);
+    /* Move the entire root queue to the queue */
+    gc_priv_data->queue       = gc_priv_data->root_queue;
+    gc_priv_data->root_queue  = NULL;
+#  if GC_IT_DEBUG
+    fprintf(stderr, "Root queue added to queue\n");
+#  endif
+}
+#  endif
+
+#  if GC_IT_INCREMENT_MODE
+/*
+
+=item C<static void gc_it_enqueue_next_root>
+
+In normal incremental mode, we add a single item from the root queue onto
+the ordinary queue. However, we only add aggregate items: non-aggregate
+root items are marked immediately and discarded. We don't want to waste
+an entire GC increment marking a single item.
+
+=cut
+
+*/
+
+static void
+gc_it_enqueue_next_root(PARROT_INTERP)
+{
+    Gc_it_data * const gc_priv_data =
+        (Gc_it_data *)interp->arena_base->gc_private;
+    Gc_it_hdr         *hdr          = gc_priv_data->root_queue;
+
+    /* The root queue is empty, nothing for us to do here. We return
+       immediately so the GC can move to the next state. */
+    if (!hdr)
+        return;
+
+    /* Move the hdr off the root queue, and add it to the queue. */
+    gc_priv_data->root_queue = hdr->next;
+    hdr->next = gc_priv_data->queue;
+    gc_priv_data->queue = hdr;
+}
+#  endif
+
+
+/*
+
+=item C<static void gc_it_mark_PObj_children_grey>
+
+Marks the children of the current PObj node grey. "Children" can be data, or
+metadata, and may be in several places. We need to search around to see
+what children there are, and add all of them to the queue.
+
+Places to search (for PMCs):
+1) C<PMC_metadata(obj)>
+2) C<obj->real_self>
+3) C<PMC_next_for_GC(obj)>
+4) C<obj->pmc_ext>
+5) C<VTABLE_mark(obj)>, if C<PObj_custom_mark_TEST(obj) == 1>
+Notice that "special" children of the PMC are marked already using
+C<mark_special> in the call to C<pobject_lives>.
+
+For all PObjs:
+1) PObj data, if C<PObj_data_is_PMC_array_FLAG>
+
+For strings:
+1) Memory pool buffer that contains the actual string data
+
+To mark a child as grey, we do one of two things:
+1) If the child is a PMC, we call C<pobject_lives> to ensure that special
+   PMCs go through C<mark_special>
+2) If the child is a non-PMC PObj, we add it's header to the queue directly,
+   and do not need to call C<pobject_lives>.
+3) If the child is a non-PObj simple buffer, we mark it black directly and
+   do not enqueue it.
+
+=cut
+
+*/
+
+PARROT_INLINE
+static void
+gc_it_mark_PObj_children_grey(PARROT_INTERP, ARGMOD(Gc_it_hdr *hdr))
+{
+    /* Add all children of the current node to the queue for processing. */
+    PObj * const obj = IT_HDR_to_PObj(hdr);
+    PMC  * const pmc = (PMC *)obj;
+
+    PARROT_ASSERT(hdr);
+    PARROT_ASSERT(obj);
+
+    if (PObj_is_PMC_TEST(obj)) {
+        if (pmc->pmc_ext) {
+            const PMC * next_for_gc = PMC_next_for_GC(pmc);
+            object_lives(interp, (PObj *)(pmc->pmc_ext));
+            if (PMC_metadata(pmc))
+                pobject_lives(interp, (PObj *)PMC_metadata(pmc));
+            if (next_for_gc != pmc && next_for_gc != NULL)
+                pobject_lives(interp, (PObj *)PMC_next_for_GC(pmc));
+        }
+
+        if (pmc->real_self != pmc && pmc->real_self != NULL)
+            pobject_lives(interp, (PObj *)(pmc->real_self));
+    }
+    else if (PObj_is_string_TEST(obj)) {
+        /* It's a string or a const-string, or whatever. Deal with that here. */
+    }
+
+    /* if the PMC is an array of other PMCs, we cycle through those. I'm
+       surprised if this isn't covered by VTABLE_mark, but I won't question it
+       now. */
+    if (obj->flags & PObj_data_is_PMC_array_FLAG)
+        Parrot_dod_trace_pmc_data(interp, pmc);
+
+    /* if it's a PMC with a custom mark routine, call that here. The
+       custom mark routine will call pobject_lives on the children,
+       which will add them to the queue properly. */
+    if (PObj_custom_mark_TEST(obj))
+        VTABLE_mark(interp, pmc);
+
+    /* If the item is shared, we need to do some magic trickery with it. I
+       don't know if I'm going to do said trickery here, or offload it to a
+       function like src/gc/dod.c:mark_special (which is where some of the
+       other logic in this function originated) */
+}
+
+
+/*
+
+=item C<void Parrot_gc_it_deinit>
+
+Kill the GC and reset everything.
+
+1) Free all generation structures
+2) Free all GC headers in all pools and arenas, if possible
+3) Free any additional memory that i will create in the future
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+Parrot_gc_it_deinit(PARROT_INTERP)
+{
+    Arenas * const arena_base = interp->arena_base;
+
+    mem_internal_free(arena_base->gc_private);
+    arena_base->gc_private        = NULL;
+
+    /* Null-out the function pointers, except the init pointer
+       who knows? the interp might want to load us up again. */
+    arena_base->do_gc_mark         = NULL;
+    arena_base->finalize_gc_system = NULL;
+    arena_base->init_pool          = NULL;
+}
+
+
+/*
+
+=item C<void Parrot_gc_it_pool_init>
+
+Initializes a new memory pool by setting the pointers to the necessary
+functions, and setting the size of the objects to include the GC header.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+Parrot_gc_it_pool_init(PARROT_INTERP, ARGMOD(Small_Object_Pool *pool))
+{
+    /* Set up function pointers for pool. */
+    pool->add_free_object = gc_it_add_free_object;
+    pool->get_free_object = gc_it_get_free_object;
+    pool->alloc_objects   = gc_it_alloc_objects;
+    pool->more_objects    = gc_it_more_objects;
+    pool->free_list       = NULL;
+    pool->last_Arena      = NULL;
+
+    /* Initially, arena allocations are relatively small. Let's not try to
+       force a GC run until a few arena's are allocated. This should also
+       prevent wasting time in the GC for small one-liner programs. */
+    pool->skip            = 2;
+
+    /* Increase allocated space to account for GC header */
+    pool->object_size += sizeof (Gc_it_hdr);
+
+#  if GC_IT_DEBUG
+    fprintf(stderr, "Initialized pool (%p). Item size: %d\n", pool,
+        pool->object_size);
+#  endif
+}
+
+
+/*
+
+=item C<void gc_it_add_free_object>
+
+Adds a dead item to the free list. I suppose this is for cases where other
+systems are trying to manage their own memory manually.
+
+This forces an unused item to be moved to the free list of it's parent pool.
+We only free an object if it's not already on the free list or on the queue.
+Ideally, all items should be freed automatically, so this function should
+become obsolete. If it's no longer used, I will get rid of it.
+
+=item C<void gc_it_add_free_header>
+
+Takes a Gc_it_hdr object and adds it's corresponding object to the pool's
+free list.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+gc_it_add_free_object(PARROT_INTERP, ARGMOD(struct Small_Object_Pool *pool),
+    ARGMOD(void *to_add))
+{
+    PObj * p = (PObj*)to_add;
+    Gc_it_hdr * const hdr = PObj_to_IT_HDR(p);
+    PARROT_ASSERT(IT_HDR_to_PObj(hdr) == p);
+    PARROT_ASSERT(contained_in_pool(pool, p));
+    gc_it_add_free_header(interp, pool, hdr);
+}
+
+PARROT_INLINE
+void
+gc_it_add_free_header(SHIM_INTERP, ARGMOD(struct Small_Object_Pool * pool),
+    ARGMOD(Gc_it_hdr * hdr))
+{
+    /* If the item is already on the free list, short-circuit and return. If
+       it's in the queue, we can't free it or we lose all the free objects
+       in the queue after this one. So, in either case, we short circuit
+       here and don't free the object manually. */
+    if (hdr->next)
+       return;
+
+#  if GC_IT_DEBUG
+    /* This check is costly but helpful. */
+    {
+        const PObj * const p = IT_HDR_to_PObj(hdr);
+        PARROT_ASSERT(contained_in_pool(pool, p));
+    }
+#  endif
+
+    ++pool->num_free_objects;
+
+    hdr->next       = (Gc_it_hdr *)pool->free_list;
+    pool->free_list = hdr;
+
+    gc_it_set_card_mark(hdr, GC_IT_CARD_FREE);
+}
+
+
+/*
+
+=item C<void * gc_it_get_free_object>
+
+Gets an object from the pool's free list and return a pointer to it. If
+no objects are on the free list, allocate a new arena of objects. The item
+allocated is immediately marked black so any concurrent GC action doesn't
+snatch it up.
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+PARROT_EXPORT
+void *
+gc_it_get_free_object(PARROT_INTERP, ARGMOD(struct Small_Object_Pool *pool))
+{
+    Gc_it_hdr * hdr;
+    const Gc_it_data * const gc_priv_data = (Gc_it_data *)interp->arena_base->gc_private;
+    const Gc_it_state state = gc_priv_data->state;
+
+    /* If there are no objects, allocate a new arena */
+    if (!pool->free_list)
+        (pool->more_objects)(interp, pool);
+    PARROT_ASSERT(pool->free_list);
+
+    /* pull the first header off the free list */
+    hdr = (Gc_it_hdr *)pool->free_list;
+    pool->free_list = (void *)hdr->next;
+    hdr->next = NULL;
+    --pool->num_free_objects;
+
+    PARROT_ASSERT(hdr);
+
+    /* Depending where we are in the GC run, we can set the mark accordingly */
+    switch (state) {
+        case GC_IT_READY:
+        case GC_IT_START_MARK:
+        case GC_IT_MARK_ROOTS:
+        case GC_IT_FINAL_CLEANUP:
+            gc_it_set_card_mark(hdr, GC_IT_CARD_WHITE);
+            break;
+        case GC_IT_RESUME_MARK:
+            gc_it_set_card_mark(hdr, GC_IT_CARD_BLACK);
+            break;
+        case GC_IT_END_MARK:
+        case GC_IT_SWEEP_PMCS:
+        case GC_IT_SWEEP_BUFFERS:
+            gc_it_set_card_mark(hdr, GC_IT_CARD_BLACK);
+            break;
+        default:
+            /* we shouldn't ever be here, but the compiler spits out a
+               warning if we don't have a default, so I jam it in. */
+            break;
+    }
+
+    /* clear the aggregate flag, in case it hasn't been done yet */
+    hdr->data.agg = 0;
+
+/*
+#  if GC_IT_DEBUG
+    fprintf(stderr, "Get free object from pool %s (%p): %p (%d left) \n",
+            pool->name, pool, hdr, pool->num_free_objects);
+#  endif
+*/
+    /* return pointer to the object from the header */
+    return (void *)IT_HDR_to_PObj(hdr);
+}
+
+
+/*
+
+=item C<void gc_it_alloc_objects>
+
+Allocates a new Small_Object_Arena from the OS and sets it up as necessary. The
+arena contains enough space to house several objects of the given size, and we
+allocate locally from these arenas as needed.
+
+The memory block for the arena is allocated large enough to hold not only the
+arena's object, but also the C<Small_Object_Arena> structure itself and the
+C<Gc_it_card> array for cardmarking. Here's a layout of how things look in
+memory:
+
+[ Small_Object_Arena | Cards | ... Objects ... ]
+
+And each object looks like this:
+
+[ Gc_it_hdr | Data ]
+
+This kind of layout requires a few extra pointer operations, which is
+obnoxious, but it saves on fewer allocations and making better use of memory
+locality. Once everything gets set up, macros and cached pointers hide all
+the initialization nastyness.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+gc_it_alloc_objects(PARROT_INTERP, ARGMOD(struct Small_Object_Pool *pool))
+{
+    const size_t object_size       = pool->object_size;
+    const size_t objects_per_alloc = pool->objects_per_alloc;
+
+    /* The size of the allocated arena. This is the size of the
+       Small_Object_Arena structure, which goes at the front, the card, and
+       the objects. */
+    const size_t arena_size = (object_size * objects_per_alloc)
+                            + sizeof (Small_Object_Arena);
+    Small_Object_Arena * const new_arena =
+        (Small_Object_Arena *)mem_internal_allocate_zeroed(arena_size);
+
+    new_arena->total_objects = objects_per_alloc;
+    new_arena->start_objects = (void *)(((char *)new_arena) + sizeof (Small_Object_Arena));
+
+    /* insert new_arena in pool's arena linked list */
+    new_arena->next = NULL;
+    new_arena->prev = NULL;
+    Parrot_append_arena_in_pool(interp, pool, new_arena,
+        object_size * objects_per_alloc);
+
+    /* Add all these new objects we've created into the pool's free list.
+       this is where the rest of the messy pointer arithmetic happens. */
+    gc_it_add_arena_to_free_list(interp, pool, new_arena);
+
+    /* allocate more next time */
+    pool->objects_per_alloc =
+        (UINTVAL)objects_per_alloc * UNITS_PER_ALLOC_GROWTH_FACTOR;
+    pool->replenish_level   =
+        (size_t)(pool->total_objects * REPLENISH_LEVEL_FACTOR);
+
+    if (arena_size > POOL_MAX_BYTES)
+        pool->objects_per_alloc = POOL_MAX_BYTES / object_size;
+    if (pool->objects_per_alloc > GC_IT_MAX_IN_ARENA)
+        pool->objects_per_alloc = GC_IT_MAX_IN_ARENA;
+}
+
+
+/*
+
+=item C<static void gc_it_add_arena_to_free_list>
+
+Adds all of the new objects from a newly allocated arena structure to the
+pool's free list. We start at the beginning of the arena's memory block and do
+the following steps:
+
+1) add the current object to the free list
+2) calculate the address of the next GC header in the arena. This is the part
+   that requires pointer dark magic, and is likely the source of bugs.
+3) set the C<next> field of the current object to the address of the
+   next object, which we've just calculated in #3 above. Update the current
+   object pointer to point to the next item.
+4) repeat for all items in the arena
+
+=cut
+
+*/
+
+static void
+gc_it_add_arena_to_free_list(PARROT_INTERP,
+    ARGMOD(Small_Object_Pool *pool), ARGMOD(Small_Object_Arena *new_arena))
+{
+    Gc_it_hdr       *p        = (Gc_it_hdr *)new_arena->start_objects;
+    const size_t     num_objs = new_arena->total_objects;
+    register size_t  i;
+
+    PARROT_ASSERT(new_arena == pool->last_Arena);
+    PARROT_ASSERT((ptrdiff_t)p - (ptrdiff_t)new_arena->start_objects == 0);
+    //PARROT_ASSERT(contained_in_pool(pool, IT_HDR_to_PObj(p)));
+
+    /* Here, we loop over the entire arena, finding the various object
+       headers and attaching them to the pool's free list. Each object
+       is also marked with a card and flag number to determine where the
+       corresponding flag is located. This is done backwards, so the first
+       object in the pool has the highest card number and therefore
+       corresponds to the last flag on the last card. The very last object
+       in contrast corresponds to the very first flag on the first card. */
+    for (i = 0; i < num_objs; i++) {
+        PObj * pobj = IT_HDR_to_PObj(p);
+        Gc_it_hdr *next = (Gc_it_hdr *)((char*)p + pool->object_size);
+
+        /* Add the current item to the free list */
+        //PARROT_ASSERT(contained_in_pool(pool, pobj));
+        gc_it_add_free_object(interp, pool, pobj);
+        p->data.agg = 0;
+        p = next;
+    }
+
+    pool->num_free_objects += num_objs;
+}
+
+
+/*
+
+=item C<void gc_it_set_card_mark>
+
+Marks the card associated with the given item to the value given by C<flag>.
+This is just a simple field access, and could probably be turned into a
+macro instead of a function call.
+
+=cut
+
+*/
+
+PARROT_INLINE
+void
+gc_it_set_card_mark(ARGMOD(Gc_it_hdr *hdr), UINTVAL flag)
+{
+    /* I'm going to try to mirror the GC flags in the PMC flags field, for
+       objects which are marked as being aggregates (and are therefore
+       isomorphic with Buffer *.
+    */
+#  ifdef GC_IT_USE_POBJ_FLAGS
+    if(hdr->agg) {
+        PObj * const p = IT_HDR_to_PObj(hdr);
+        switch (flag) {
+            /* This is relatively inefficient. I should be able to create
+               constant bitmaps for each condition and perform a logical
+               AND or OR to set them in a single operation. That's an
+               optimization to pursue later. */
+            case GC_IT_FLAG_BLACK:
+                PObj_live_SET(p);
+                PObj_is_fully_live_SET(p);
+                PObj_on_free_list_CLEAR(p);
+                break;
+            case GC_IT_FLAG_WHITE:
+                PObj_live_CLEAR(p);
+                PObj_is_fully_live_CLEAR(p);
+                PObj_on_free_list_CLEAR(p);
+                break;
+            case GC_IT_FLAG_GREY:
+                PObj_live_SET(p);
+                PObj_is_fully_live_CLEAR(p);
+                PObj_on_free_list_CLEAR(p);
+                break;
+            case CG_IT_FLAG_FREE:
+                PObj_live_CLEAR(p);
+                PObj_is_fully_live_CLEAR(p);
+                PObj_on_free_list_SET(p);
+        }
+    }
+#  else
+    hdr->data.flag = flag;
+#  endif
+
+}
+
+/*
+
+=item C<UINTVAL gc_it_get_card_mark>
+
+Returns the current flag value associated with the given object header.
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_INLINE
+UINTVAL
+gc_it_get_card_mark(ARGMOD(Gc_it_hdr *hdr))
+{
+#  ifdef GC_IT_USE_POBJ_FLAGS
+    /* Add the stuff here to check the PObj flags in the object, if it's an
+       aggregate. Get the data from the hdr->data.flag, and compare values
+       to make sure we have a sensical result (PARROR_ASSERT it). Return
+       the value if it's good. */
+#  endif
+    return hdr->data.flag;
+}
+
+/*
+
+=item C<void gc_it_more_objects>
+
+Tries to allocate new objects. If the mark phase is finished, run a quick
+sweep.  If the sweep frees up some objects, return one of those. Otherwise, we
+allocate a new arena and return an object from that.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+gc_it_more_objects(PARROT_INTERP, ARGMOD(Small_Object_Pool *pool))
+{
+    const Gc_it_data * const gc_priv_data = (Gc_it_data *)interp->arena_base->gc_private;
+
+    /* If the last GC run didn't turn up a lot of new objects, it's probably
+       not worthwhile to try it again. We'll skip DOD once and just go
+       straight to the new object allocation. */
+    if (pool->skip) {
+        --pool->skip;
+    }
+    else if (gc_priv_data->state >= GC_IT_END_MARK) {
+        /* If we're after the trace phase in our GC, we'll try to complete the
+           run and look for new objects. If the GC run doesn't turn up new
+           objects, allocate more. */
+        while (gc_priv_data->state >= GC_IT_END_MARK)
+            Parrot_gc_it_run(interp, 0);
+
+        /* If we don't turn up enough new objects, this pool is pretty densly
+           packed and we should skip the dod attempt next round. */
+        if (pool->num_free_objects <= pool->replenish_level)
+            ++pool->skip;
+        if (pool->free_list)
+            return;
+    }
+
+    gc_it_alloc_objects(interp, pool);
+}
+
+
+/*
+
+=item C<static void gc_it_post_sweep_cleanup>
+
+Cleans up the GC system after completing an entire mark and sweep.
+
+=cut
+
+*/
+
+static void
+gc_it_post_sweep_cleanup(PARROT_INTERP)
+{
+    Gc_it_hdr * ptr;
+    Gc_it_data * const gc_priv_data = (Gc_it_data *)interp->arena_base->gc_private;
+
+    while ((ptr = gc_priv_data->marked) != NULL) {
+        gc_priv_data->marked = ptr->next;
+        ptr->next = NULL;
+    }
+    PARROT_ASSERT(gc_priv_data->root_queue == NULL);
+    PARROT_ASSERT(gc_priv_data->queue == NULL);
+    PARROT_ASSERT(gc_priv_data->marked == NULL);
+
+#  if GC_IT_DEBUG
+    fprintf(stderr, "Post-sweep cleanup. Sweep ended\n");
+#  endif
+}
+
+/*
+
+=item C<void gc_it_ptr_set_aggregate>
+
+Sets whether the given object is a PObj or not
+
+=item C<UINTVAL gc_it_ptr_get_aggregate>
+
+Returns a boolean value for whether the given object is flagged as an
+aggregate object or not.
+
+=cut
+
+*/
+
+void
+gc_it_ptr_set_aggregate(ARGMOD(void *ptr), unsigned char flag)
+{
+    Gc_it_hdr * const hdr = PObj_to_IT_HDR(ptr);
+    hdr->data.agg = flag;
+}
+
+UINTVAL
+gc_it_ptr_get_aggregate(ARGIN(void * const ptr))
+{
+    const Gc_it_hdr * const hdr = PObj_to_IT_HDR(ptr);
+    return (UINTVAL)hdr->data.agg;
+}
+
+/*
+
+=item C<gc_it_pmc_dead>
+
+Determines whether a given PMC has been prematurely swept.
+
+=cut
+
+*/
+
+# if GC_IT_DEBUG
+
+UINTVAL
+gc_it_pmc_dead(ARGIN(PMC * p))
+{
+    return(p->pmc_ext    == (PMC_EXT *)0xdeadbeef ||
+        p->vtable        == (void *)0xdeadbeef ||
+        PMC_pmc_val(p)   == (PMC *)0xdeadbeef);
+}
+
+#  endif
+
+#endif  /* PARROT_GC_IT */
+
+/*
+
+=back
+
+=head1 HISTORY
+
+Initial version by Whiteknight (2008.05.26)
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About