[svn:parrot] r49269 - in trunk: . config/gen/makefiles docs/pdds examples/benchmarks include/parrot src src/call src/gc src/interp t/op t/pmc

bacek at svn.parrot.org bacek at svn.parrot.org
Thu Sep 23 08:34:40 UTC 2010


Author: bacek
Date: Thu Sep 23 08:34:38 2010
New Revision: 49269
URL: https://trac.parrot.org/parrot/changeset/49269

Log:
Merge branch gc_massacre back to trunk. Default GC set MS2 now

Added:
   trunk/examples/benchmarks/stress_integers.pir
   trunk/include/parrot/list.h
   trunk/src/gc/fixed_allocator.c
   trunk/src/gc/fixed_allocator.h
   trunk/src/gc/gc_ms2.c
   trunk/src/gc/variable_size_pool.c
   trunk/src/gc/variable_size_pool.h
   trunk/src/list.c
Modified:
   trunk/MANIFEST
   trunk/MANIFEST.SKIP
   trunk/config/gen/makefiles/root.in
   trunk/docs/pdds/pdd09_gc.pod
   trunk/include/parrot/gc_api.h
   trunk/include/parrot/pobj.h
   trunk/include/parrot/settings.h
   trunk/src/call/context.c
   trunk/src/call/context_accessors.c
   trunk/src/gc/api.c
   trunk/src/gc/gc_ms.c
   trunk/src/gc/gc_private.h
   trunk/src/gc/mark_sweep.c
   trunk/src/gc/string_gc.c
   trunk/src/gc/system.c
   trunk/src/interp/inter_create.c
   trunk/src/main.c
   trunk/t/op/gc-leaky-box.t
   trunk/t/op/gc-leaky-call.t
   trunk/t/op/string_mem.t
   trunk/t/pmc/filehandle.t
   trunk/t/pmc/io.t

Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/MANIFEST	Thu Sep 23 08:34:38 2010	(r49269)
@@ -583,6 +583,7 @@
 examples/benchmarks/stress2.pl                              [examples]
 examples/benchmarks/stress2.rb                              [examples]
 examples/benchmarks/stress3.pasm                            [examples]
+examples/benchmarks/stress_integers.pir                     [examples]
 examples/benchmarks/stress_strings.pir                      [examples]
 examples/benchmarks/vpm.pir                                 [examples]
 examples/benchmarks/vpm.pl                                  [examples]
@@ -970,6 +971,7 @@
 include/parrot/io_win32.h                                   [main]include
 include/parrot/key.h                                        [main]include
 include/parrot/library.h                                    [main]include
+include/parrot/list.h                                       [main]include
 include/parrot/longopt.h                                    [main]include
 include/parrot/memory.h                                     [main]include
 include/parrot/misc.h                                       [main]include
@@ -1282,14 +1284,19 @@
 src/gc/alloc_memory.c                                       []
 src/gc/alloc_resources.c                                    []
 src/gc/api.c                                                []
+src/gc/fixed_allocator.c                                    []
+src/gc/fixed_allocator.h                                    []
 src/gc/gc_inf.c                                             []
 src/gc/gc_ms.c                                              []
+src/gc/gc_ms2.c                                             []
 src/gc/gc_private.h                                         []
 src/gc/malloc.c                                             []
 src/gc/malloc_trace.c                                       []
 src/gc/mark_sweep.c                                         []
 src/gc/string_gc.c                                          []
 src/gc/system.c                                             []
+src/gc/variable_size_pool.c                                 []
+src/gc/variable_size_pool.h                                 []
 src/global_setup.c                                          []
 src/hash.c                                                  []
 src/hll.c                                                   []
@@ -1311,6 +1318,7 @@
 src/key.c                                                   []
 src/libnci_test.def                                         []
 src/library.c                                               []
+src/list.c                                                  []
 src/longopt.c                                               []
 src/main.c                                                  []
 src/misc.c                                                  []

Modified: trunk/MANIFEST.SKIP
==============================================================================
--- trunk/MANIFEST.SKIP	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/MANIFEST.SKIP	Thu Sep 23 08:34:38 2010	(r49269)
@@ -1,6 +1,6 @@
 # ex: set ro:
 # $Id$
-# generated by tools/dev/mk_manifest_and_skip.pl Tue Sep 14 05:49:01 2010 UT
+# generated by tools/dev/mk_manifest_and_skip.pl Sun Sep 19 08:35:39 2010 UT
 #
 # This file should contain a transcript of the svn:ignore properties
 # of the directories in the Parrot subversion repository. (Needed for
@@ -69,8 +69,6 @@
 ^config_lib\.pir/
 ^cover_db$
 ^cover_db/
-^generated_hello\.pbc$
-^generated_hello\.pbc/
 ^install_config\.fpmc$
 ^install_config\.fpmc/
 ^installable.*$
@@ -626,9 +624,6 @@
 # generated from svn:ignore of 'runtime/parrot/library/Test/Builder/'
 ^runtime/parrot/library/Test/Builder/.*\.pbc$
 ^runtime/parrot/library/Test/Builder/.*\.pbc/
-# generated from svn:ignore of 'runtime/parrot/library/URI/'
-^runtime/parrot/library/URI/.*\.pbc$
-^runtime/parrot/library/URI/.*\.pbc/
 # generated from svn:ignore of 'runtime/parrot/library/YAML/'
 ^runtime/parrot/library/YAML/.*\.pbc$
 ^runtime/parrot/library/YAML/.*\.pbc/
@@ -845,8 +840,6 @@
 ^src/packfile/.*\.o/
 ^src/packfile/.*\.obj$
 ^src/packfile/.*\.obj/
-^src/packfile/.*\.str$
-^src/packfile/.*\.str/
 # generated from svn:ignore of 'src/pmc/'
 ^src/pmc/.*\.c$
 ^src/pmc/.*\.c/
@@ -1032,9 +1025,6 @@
 ^t/op/.*\.pir/
 ^t/op/.*_pbcexe.*$
 ^t/op/.*_pbcexe.*/
-# generated from svn:ignore of 't/op/testlib/'
-^t/op/testlib/.*\.pbc$
-^t/op/testlib/.*\.pbc/
 # generated from svn:ignore of 't/perl/'
 ^t/perl/Parrot_Test_1\.pasm$
 ^t/perl/Parrot_Test_1\.pasm/
@@ -1051,9 +1041,6 @@
 ^t/pmc/.*\.pir/
 ^t/pmc/.*_pbcexe.*$
 ^t/pmc/.*_pbcexe.*/
-# generated from svn:ignore of 't/pmc/testlib/'
-^t/pmc/testlib/.*\.pbc$
-^t/pmc/testlib/.*\.pbc/
 # generated from svn:ignore of 't/src/'
 ^t/src/.*_.*$
 ^t/src/.*_.*/
@@ -1085,9 +1072,6 @@
 ^t/tools/pmc2c\..*\.h/
 ^t/tools/pmc2c\..*\.pmc$
 ^t/tools/pmc2c\..*\.pmc/
-# generated from svn:ignore of 'tools/dev/'
-^tools/dev/mk_language_shell\.pl$
-^tools/dev/mk_language_shell\.pl/
 # Local variables:
 #   mode: text
 #   buffer-read-only: t

Modified: trunk/config/gen/makefiles/root.in
==============================================================================
--- trunk/config/gen/makefiles/root.in	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/config/gen/makefiles/root.in	Thu Sep 23 08:34:38 2010	(r49269)
@@ -410,6 +410,7 @@
 	$(INC_DIR)/core_pmcs.h \
 	$(INC_DIR)/compiler.h \
 	$(INC_DIR)/cclass.h \
+	$(INC_DIR)/list.h \
 	include/pmc/pmc_callcontext.h
 
 # generated list of header files
@@ -462,8 +463,11 @@
     src/gc/api$(O) \
     src/gc/gc_ms$(O) \
     src/gc/gc_inf$(O) \
+    src/gc/gc_ms2$(O) \
     src/gc/mark_sweep$(O) \
     src/gc/system$(O) \
+    src/gc/fixed_allocator$(O) \
+    src/gc/variable_size_pool$(O) \
     src/gc/string_gc$(O) \
     src/global_setup$(O) \
     src/hash$(O) \
@@ -478,6 +482,7 @@
     src/call/context_accessors$(O) \
     src/key$(O) \
     src/library$(O) \
+    src/list$(O) \
     src/longopt$(O) \
     src/misc$(O) \
     src/multidispatch$(O) \
@@ -919,6 +924,8 @@
 
 src/null_config$(O) : $(PARROT_H_HEADERS) src/null_config.c
 
+src/list$(O): $(PARROT_H_HEADERS) include/pmc/pmc_callcontext.h src/list.c
+
 src/oo$(O) : $(PARROT_H_HEADERS) include/pmc/pmc_class.h src/oo.c \
     include/pmc/pmc_object.h src/oo.str $(INC_DIR)/oo_private.h
 
@@ -1296,11 +1303,19 @@
 
 src/gc/gc_inf$(O) : $(PARROT_H_HEADERS) src/gc/gc_private.h src/gc/gc_inf.c
 
+src/gc/gc_ms2$(O) : $(PARROT_H_HEADERS) src/gc/gc_private.h src/gc/fixed_allocator.h src/gc/gc_ms2.c
+
 src/gc/api$(O) : $(PARROT_H_HEADERS) src/gc/gc_private.h src/gc/api.c
 
 src/gc/alloc_resources$(O) : $(PARROT_H_HEADERS) \
 	src/gc/gc_private.h src/gc/alloc_resources.c
 
+src/gc/fixed_allocator$(O) : $(PARROT_H_HEADERS) \
+	src/gc/fixed_allocator.h src/gc/fixed_allocator.c
+
+src/gc/variable_size_pool$(O) : $(PARROT_H_HEADERS) \
+	src/gc/variable_size_pool.h src/gc/variable_size_pool.c
+
 src/gc/string_gc$(O) : $(PARROT_H_HEADERS) \
 	src/gc/gc_private.h src/gc/string_gc.c
 

Modified: trunk/docs/pdds/pdd09_gc.pod
==============================================================================
--- trunk/docs/pdds/pdd09_gc.pod	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/docs/pdds/pdd09_gc.pod	Thu Sep 23 08:34:38 2010	(r49269)
@@ -5,7 +5,8 @@
 
 =head2 Abstract
 
-This PDD specifies Parrot's garbage collection subsystems.
+This PDD specifies Parrot's garbage collection and memory management
+subsystems.
 
 =head2 Version
 
@@ -19,14 +20,15 @@
 the interpreter, by determining which objects will not be referenced again and
 can be reclaimed.
 
-=head3 Simple mark
+=head3 Mark and sweep (MS)
 
-All reachable objects are marked as alive, first marking a root set, and then
-recursively marking objects reachable from other reachable objects. Objects
-not reached are considered dead. After collection, all objects are reset to
-unmarked, and the process starts again.
+Starting from a known root set, the GC traces all reachable memory objects by
+following pointers. Objects reached in this way, and therefore visible for
+use by the program, are alive. Objects which are not reached in the trace are
+marked dead. In the second stage, sweep, all dead objects are destroyed and
+reclaimed.
 
-=head3 Tri-color mark
+=head3 Tri-color mark and sweep
 
 Instead of a simple separation of marked (as live) and unmarked (dead), the
 object set is divided into three parts: white, gray, and black. The white
@@ -44,30 +46,27 @@
 The advantage of a tri-color mark over a simple mark is that it can be broken
 into smaller stages.
 
-=head3 Mark-and-sweep
-
-In this GC scheme, after all reachable objects are marked as live, a sweep
-through the object arenas collects all unmarked objects.
-
 =head3 Copying collection
 
-In this scheme, live objects are copied into a new memory region. The entire
-old memory region can then be reclaimed.
+A copying GC copies objects from one memory region to another during the mark
+phase. At the end of the mark, all memory in the old region is dead and the
+whole region can be reclaimed at once.
 
 =head3 Compacting collection
 
-In this scheme, live objects are moved closer together, eliminating fragments
-of free space between live objects. This compaction makes later allocation of
-new objects faster, since the allocator doesn't have to scan for fragments of
-free space.
-
-=head3 Reference counting
-
-In this scheme, all objects have a count of how often they are referred to by
-other objects. If that count reaches zero, the object's memory can be
-reclaimed. This scheme doesn't cope well with reference loops--loops of dead
-objects, all referencing one another but not reachable from elsewhere, never
-get collected.
+The compacting GC moves live objects close together in a single region in
+memory. This helps to elimianate fragmented free space and allows the
+allocation of large live objects. Compacting and copying collectors are often
+similar or even identical in implementation.
+
+=head3 Uncooperative
+
+An uncooperative GC is implemented as a separate module, often without
+affecting the remainder of the program. The programmer can write software
+without needing to be aware of the operations or implementation of the GC.
+The alternative is a cooperative GC, which is often implemented as a reference
+counting scheme and requires GC-related logic to be dispersed throughout the
+entire program.
 
 =head3 Stop-the-world
 
@@ -79,9 +78,10 @@
 
 =head3 Incremental
 
-Rather than suspending the system for marking and collection, GC is done in
-small increments intermittent with normal program operation. Some
-implementations perform the marking as part of ordinary object access.
+In order to alleviate the arbitrarily long pauses in a stop-the-world GC, the
+incremental GC breaks the mark and sweep process up into smaller, shorter
+phases. Each GC phase may still require the entire program to pause, but the
+pauses are shorter and more frequent.
 
 =head3 Real-time
 
@@ -91,13 +91,8 @@
 
 The object space is divided between a young generation (short-lived
 temporaries) and one or more old generations. Only young generations are reset
-to white (presumed dead). Avoiding scanning the old generations repeatedly can
-considerably speed up GC.
-
-Generational collection does not guarantee that all unreachable objects will
-be reclaimed, so in large systems it is sometimes combined with a
-mark-and-sweep or copying collection scheme, one for light collection runs
-performed frequently, and the other for more complete runs performed rarely.
+to white (presumed dead). The older generations are scanned less often because
+it is assumed that long-lived objects tend to live longer.
 
 =head3 Concurrent
 
@@ -105,47 +100,47 @@
 threads participating in GC. On a multi-processor machine, concurrent GC may
 be truly parallel.
 
+=head3 Conservative
+
+A conservative GC traces through memory looking for pointers to living
+objects. The GC does not necessarily have information about the layout of
+memory, so it cannot differentiate between an actual pointer and an integral
+value which has the characteristics of a pointer. The Conservative GC follows
+a policy of "no false negatives" and traces any value which appears to be a
+pointer.
+
+=head3 Precise
+
+A precise GC has intimate knowledge of the memory layout of the system and
+knows where to find pointers. In this way the precise collector never has
+any false positives.
+
 =head2 Synopsis
 
 Not applicable.
 
 =head2 Description
 
-=over 4
-
-=item - Parrot provides swappable garbage collection schemes. The GC scheme
-can be selected at configure/compile time.  The GC scheme cannot be changed
-on-the-fly at runtime, but in the future may be selected with a command-line
-option at execution time.
-
-=item - All live PMCs must be reachable from the root set of objects in the
-interpreter.
-
-=item - Garbage collection must be safe for objects shared across multiple
-interpreters/threads.
-
-=item - The phrase "dead object detection" and abbreviation "DOD" are
-deprecated.
-
-=back
+No GC algorithm is ideal for all workloads. To support multiple workloads,
+Parrot provides support for pluggable uncooperative GC cores. Parrot will
+attempt to provide a default core which has reasonable performance for most
+programs. Parrot provides no built-in support for cooperative GCs.
+
+Parrot uses two separate memory allocation mechanisms: a fixed-size system for
+small objects of fixed size (PMC and STRING headers, etc), and a buffer
+allocator for arbitrary-sized objects, such as string contents. The default
+fixed-size memory allocator uses a SLAB-like algorithm to allocate objects
+from large pre-allocated pools. The default buffer allocator uses a compacting
+algorithm.
 
 =head2 Implementation
 
-Parrot supports pluggable garbage collection cores, so ultimately any garbage
-collection model devised can run on it. However, different GC models are more
-or less appropriate for different application areas. The current default
-stop-the-world mark-and-sweep model is not well suited for concurrent/parallel
-execution. We will keep the simple mark-and-sweep implementation, but it will
-no longer be primary.
+Parrot supports pluggable garbage collection cores, so ultimately any
+uncooperative garbage collection model devised can run on it.
 
 Parrot really has two independent GC models, one used for objects (PMCs) and
 the other used for buffers (including strings). The core difference is that
 buffers cannot contain other buffers, so incremental marking is unnecessary.
-Currently, PMCs are not allowed to move after creation, so the GC model used
-there is not copying nor compacting.
-
-The primary GC model for PMCs, at least for the 1.0 release, will use a
-tri-color incremental marking scheme, combined with a concurrent sweep scheme.
 
 =head3 Terminology
 
@@ -153,134 +148,228 @@
 dead (the "trace" or "mark" phase) and freeing dead objects for later reuse
 (the "sweep" phase). The sweep phase is also known as the collection phase.
 The trace phase is less frequently known as the "dead object detection" phase.
-The use of the term "dead object detection" and its acronym DOD has been
-deprecated.
 
-=head3 Initial Marking
+=head3 Marking
+
+Each PMC and STRING has a C<flags> member which is a bitfield of various
+flags. Three flags in particular are important for GC operation.
+C<PObj_live_FLAG> is set if the object is currently alive and active.
+C<PObj_on_free_list_FLAG> is set if the object is currently on the free list
+and is available for reallocation. A third flag, C<PObj_grey_FLAG> can be used
+to support tricolor mark. Despite the given names of these flags, they can be
+used by the active GC core for almost any purpose, or they can be ignored
+entirely if the GC provides another mechanism for marking the various life
+stages of the object. These flags are typically not used outside the GC
+subsystem.
+
+=head4 Special PMCs
+
+=head4 Root Set
+
+The root set for the GC mark is the interpreter object and, if necessary,
+the C system stack. If the C system stack is traced, the GC is conservative.
+
+=head4 Initiating a mark and sweep
+
+Depending on the core in use, the mark and sweep phases may be initiated in
+different ways. A concurrent core would always be running in the background.
+The most common mechanism for a non-concurrent core is to initiate a run of
+the GC system when an attempt is made to allocate
+
+=head4 Object marking
+
+To mark a PMC, the C<Parrot_gc_mark_pmc_alive> function is called. To mark a
+STRING, the C<Parrot_gc_mark_string_alive> function is called. These functions
+mark the object alive, typically by setting the C<PObj_live_FLAG> flag.
+
+If the PMC contains references to other PMCs and STRINGS, it must have the
+C<PObj_custom_mark_FLAG> flag set. If this flag is set, the C<mark> VTABLE
+for that PMC is called to mark the pointers in that PMC. The custom_mark flag
+is ignored in STRINGs.
+
+=head4 Buffer Marking
+
+Buffers are always attached to a fixed-size header, or several headers. During
+the mark phase of the fixed-size objects, owned buffers are flagged as alive.
+At somet time after the fixed-size objects are marked, the buffer pool is
+compacted by moving all alive buffers to a new pool and then freeing the old
+pool back to the operating system.
+
+=head3 Collection
+
+When all objects have been marked, the collection phase begins.
+
+=head4 Collecting objects
+
+During the sweep phase, objects which had previously been alive but were not
+traced in the most recent mark phase are dead and are collected. If the
+C<PObj_custom_destroy_FLAG> is set on a PMC, the GC will call the C<destroy>
+VTABLE on that PMC to do custom cleanup. This flag is ignored in STRINGs.
+
+The GC does not collect dead PMCs in any particular order and does not
+guarantee any ordering of collection between dependant PMCs. Some GC cores may
+enforce some ordering or dependency recognition, but this is not guaranteed.
 
-Each PMC has a C<flags> member which, among other things, facilitates garbage
-collection. At the beginning of the mark phase, the C<PObj_is_live_FLAG> and
-C<PObj_is_fully_marked_FLAG> are both unset, which flags the PMC as presumed
-dead (white). The initial mark phase of the collection cycle goes through each
-PMC in the root set and sets the C<PObj_is_live_FLAG> bit in the C<flags>
-member (the PMC is gray).  It does not set the C<PObj_is_fully_marked_FLAG>
-bit (changing the PMC to black), because in the initial mark, the PMCs or
-buffers contained by a PMC are not marked. It also appends the PMC to the end
-of a list used for further marking. However, if the PMC has already been
-marked as black, the current end of list is returned (instead of appending the
-already processed PMC) to prevent endless looping.
-
-The fourth combination of the two flags, where C<PObj_is_live_FLAG> is unset
-and C<PObj_is_fully_marked_FLAG> is set, is reserved for PMCs of an older
-generation not actively participating in the GC run.
+=head3 Finalization
 
-The root set for the initial marking phase includes the following core storage
-locations:
+When the interpreter object is destroyed, the GC system is finalized. During
+finalization, all living PMCs in the system are destroyed unconditionally and
+all memory owned by the interpreter is freed back to the operating system.
+
+=head3 Internal Structures
+
+A GC core is defined in memory by a structure of function pointers to various
+routines that perform the primitive operations of the GC. A GC core must
+define most of the pointers in the C<< interp->gc_sys >> structure, which is
+a C<GC_Subsystem> structure.
+
+C<GC_Subsystem> has the following fields:
 
 =over 4
 
-=item Global stash
+=item C<void (*finalize_gc_system) (PARROT_INTERP)>
 
-=item System stack and processor registers
+Function to finalize the GC system, by freeing all PMCs and returning all
+allocated memory to the operating system.
 
-=item Current PMC register set
+=item C<void (*destroy_child_interp)(Interp *dest_interp,
+Interp *child_interp)>
 
-=item Stashes
+=item C<void (*do_gc_mark)(PARROT_INTERP, UINTVAL flags)>
 
-=item PMC register stack
+Perform a GC mark and sweep run, or at least run a single increment of it.
 
-=back
+=item C<void (*compact_string_pool)(PARROT_INTERP)>
 
-=head3 Incremental Marking
+Compact the string pool and destroy all unused buffers.
 
-After the root set of PMCs have been marked, a series of incremental mark runs
-are performed. These may be performed frequently, between other operations.
-The incremental mark runs work to move gray PMCs to black. They take a PMC
-from the list for further marking, mark any PMCs or buffers it contains as
-gray (the C<PObj_is_live_FLAG> is set and the C<PObj_is_fully_marked_FLAG> is
-left unset), and add the contained PMCs or buffers to the list for further
-marking.  If the PMC has a custom mark function in its vtable, it is called at
-this point.
-
-After all contained PMCs or buffers have been marked, the PMC itself is marked
-as black (the C<PObj_is_live_FLAG> and C<PObj_is_fully_marked_FLAG> are both
-set). A limit may be placed on the number of PMCs handled in each incremental
-mark run.
-
-=head3 Buffer Marking
-
-The initial marking phase also marks the root set of buffers. Because buffers
-cannot contain other buffers, they are immediately marked as black and not
-added to the list for further marking. Because PMCs may contain buffers, the
-buffer collection phase can't run until the incremental marking of PMCs is
-completed.
+=item C<void (*mark_special)(PARROT_INTERP, PMC *)>
 
-The root set for buffers includes the following locations:
+Mark a special PMC. A PMC is special if it has the C<PObj_is_special_FLAG>
+flag set.
 
-=over 4
+=item C<void (*pmc_needs_early_collection)(PARROT_INTERP, PMC *)>
 
-=item Current String register set
+Flag a PMC as needing early collection.
 
-=item String register set stack
+=item C<void (*init_pool)(PARROT_INTERP, struct Fixed_Size_Pool *)>
 
-=item Control stack
+Initialize a new memory pool.
 
-=back
+=item C<PMC* (*allocate_pmc_header)(PARROT_INTERP, UINTVAL flags)>
 
-Once a buffer is found to be live, the C<flags> member of the buffer structure
-has the C<PObj_live_FLAG> and C<PObj_is_fully_marked_FLAG> bits set.
+Allocate a new PMC object from the system.
 
-=head3 Collection
+=item C<void (*free_pmc_header)(PARROT_INTERP, PMC *)>
 
-When the list for further marking is empty (all gray PMCs have changed to
-black), the collection stage is started. First, PMCs are collected, followed
-by buffers. In both cases (PMC and buffer), the "live" and "fully_marked"
-flags are reset after examination for reclamation.
-
-=head4 Collecting PMCs
-
-To collect PMCs, each PMC arena is examined from the most recently created
-backwards.  Each PMC is examined to see if it is live, already on the free
-list, or constant.  If it is not, then it is added to the free list and marked
-as being on the free list with the C<PObj_on_free_list_FLAG>.
-
-=for question
-Are the PMCs in the arena examined back-to-front as well?  How about Buffers?
-Order of destruction can be important.
-
-=head4 Collecting buffers
-
-To collect buffers, each Buffer arena is examined from the most recently
-created backwards.  If the buffer is not live, not already on the free list
-and it is not a constant or copy on write, then it is added to the free pool
-for reuse and marked with the C<PObj_on_free_list_FLAG>.
-
-=head4 Concurrent collection
-
-For the most part, the variable sets between concurrent tasks don't interact.
-They have independent root sets and don't require information on memory usage
-from other tasks before performing a collection phase. In Parrot, tasks tend
-to be short-lived, and their variables can be considered young generations
-from a generational GC perspective. Because of this, a full heavyweight task
-will maintain its own small memory pools, quickly born and quickly dying.
-
-Shared variables, on the other hand, do require information from multiple
-concurrent tasks before they can be collected. Because of this, they live in
-the parent interpreter's global pools, and can only be collected after all
-concurrent tasks have completed a full mark phase without marking the shared
-variable as live. Because GC in the concurrent tasks happens incrementally
-between operations, a full collection of the shared variables can happen
-lazily, and does not require a stop-the-world sweep through all concurrent
-tasks simultaneously.
+Free a PMC object back to the system.
 
-=head3 Internal Structures
+=item C<STRING* (*allocate_string_header)(PARROT_INTERP, UINTVAL flags)>
+
+Allocate a new STRING header from the system.
+
+=item C<void (*free_string_header)(PARROT_INTERP, STRING*)>
+
+Free a STRING object back to the system.
+
+=item C<Buffer* (*allocate_bufferlike_header)(PARROT_INTERP, size_t size)>
+
+=item C<void (*free_bufferlike_header)(PARROT_INTERP, Buffer*, size_t size)>
+
+=item C<int  (*is_pmc_ptr)(PARROT_INTERP, void*)>
+
+Determine if the given pointer is or resembles a valid PMC pointer.
+
+=item C<int  (*is_string_ptr)(PARROT_INTERP, void*)>
+
+Determine if the given pointer is or resembles a valid STRING pointer.
+
+=item C<void (*mark_pobj_header)(PARROT_INTERP, PObj*)>
 
-The different GC cores are independent, but they share some code and
-resources.  The arena structures and arena creation routines are common across
-most GC cores, and some GC cores also share mark routines.
+=item C<void (*mark_pmc_header)(PARROT_INTERP, PMC *)>
 
-The main interpreter structure has an mem_pools member, which is a pointer to
-an Memory_Pools struct.
+Mark a PMC alive.
+
+=item C<void* (*allocate_pmc_attributes)(PARROT_INTERP, PMC *)>
+
+Allocate attribute storage for a PMC. The size of the attributes structure is
+determined from the PMCs VTABLE.
+
+=item C<void (*free_pmc_attributes)(PARROT_INTERP, PMC *)>
+
+Free an attribute structure back to the system.
+
+=item C<void (*allocate_string_storage)
+(PARROT_INTERP, STRING *str, size_t size)>
+
+Allocate buffer storage for a string.
+
+=item C<void (*reallocate_string_storage)
+(PARROT_INTERP, STRING *str, size_t size)>
+
+Resize existing string storage to fit data of the new size.
+
+=item C<void (*allocate_buffer_storage)
+(PARROT_INTERP, ARGMOD(Buffer *buffer), size_t nsize)>
+
+Allocate buffer storage for any purpose.
+
+=item C<void (*reallocate_buffer_storage)
+(PARROT_INTERP, ARGMOD(Buffer *buffer), size_t newsize)>
+
+Reallocate or resize existing buffer storage.
+
+=item C<void* (*allocate_fixed_size_storage)(PARROT_INTERP, size_t size)>
+
+Allocate storage for a fixed-size header which is not a PMC or a STRING. The
+contents of this structure are not marked automatically by GC.
+
+=item C<void (*free_fixed_size_storage)(PARROT_INTERP, size_t size, void *)>
+
+Free a fixed-size structure back to the system.
+
+=item C<void* (*allocate_memory_chunk)(PARROT_INTERP, size_t size)>
+
+=item C<void* (*reallocate_memory_chunk)(PARROT_INTERP, void *data,
+size_t newsize)>
+
+=item C<void* (*allocate_memory_chunk_with_interior_pointers)(PARROT_INTERP,
+size_t size)>
+
+=item C<void* (*reallocate_memory_chunk_with_interior_pointers)(PARROT_INTERP,
+void *data, size_t oldsize, size_t newsize)>
+
+=item C<void (*free_memory_chunk)(PARROT_INTERP, void *data)>
+
+=item C<void (*block_mark)(PARROT_INTERP)>
+
+Block the GC mark from occuring.
+
+=item C<void (*unblock_mark)(PARROT_INTERP)>
+
+Unblock the GC mark.
+
+=item C<unsigned int (*is_blocked_mark)(PARROT_INTERP)>
+
+Query the blocked state of the GC mark.
+
+=item C<void (*block_sweep)(PARROT_INTERP)>
+
+Block the GC sweep phase.
+
+=item C<void (*unblock_sweep)(PARROT_INTERP)>
+
+Unblock the GC sweep phase.
+
+=item C<unsigned int (*is_blocked_sweep)(PARROT_INTERP)>
+
+Query the blocked state of the GC sweep.
+
+=item C<size_t (*get_gc_info)(PARROT_INTERP, Interpinfo_enum)>
+
+Query information about the GC core.
+
+=back
 
 =head4 The Memory_Pools structure
 
@@ -320,14 +409,6 @@
 
 =head3 Internal API
 
-Currently only one GC system is active at a time, selected at configure or
-compile time. Future versions will support switching GC systems at
-execution-time to accommodate different work loads.
-
-=for question
-Does "execution-time" mean "before starting a runcore" or "at some point after
-starting a runcore"?
-
 Each GC core provides a standard interface for interaction with the core.
 
 =head4 Initialization

Added: trunk/examples/benchmarks/stress_integers.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/examples/benchmarks/stress_integers.pir	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,45 @@
+# Copyright (C) 2010, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+examples/benchmarks/stress_strings.pir - GC strings stress-testing
+
+=head1 SYNOPSIS
+
+    % time ./parrot examples/benchmarks/stress_strings.pir
+
+=head1 DESCRIPTION
+
+Create a lots of strings. Some of them are long-lived, most of them are short lived.
+
+Main purpose - test compact_pool performance.
+
+=cut
+
+.sub 'main' :main
+    .local pmc rsa # array of long lived strings.
+
+    .local int i
+
+    rsa = new ['ResizablePMCArray']
+    i = 0
+  loop:
+    $I0 = i % 10    # every 10th string is longlived
+    if $I0 goto inc_i
+    push rsa, i
+    $I0 = i % 1000
+    if $I0 goto inc_i
+    sweep 1
+  inc_i:
+    inc i
+    if i < 100000 goto loop
+
+.end
+
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Modified: trunk/include/parrot/gc_api.h
==============================================================================
--- trunk/include/parrot/gc_api.h	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/include/parrot/gc_api.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -99,6 +99,7 @@
 #define GC_trace_normal_FLAG   (UINTVAL)(1 << 1)   /* the same */
 #define GC_lazy_FLAG           (UINTVAL)(1 << 2)   /* timely destruction run */
 #define GC_finish_FLAG         (UINTVAL)(1 << 3)   /* on Parrot exit: mark (almost) all PMCs dead and */
+#define GC_strings_cb_FLAG     (UINTVAL)(1 << 4)   /* Invoked from String GC during mem_alloc to sweep dead strings */
                                                    /* garbage collect. */
 
 /* HEADERIZER BEGIN: src/gc/api.c */
@@ -140,8 +141,9 @@
         FUNC_MODIFIES(*obj);
 
 PARROT_EXPORT
-void Parrot_gc_mark_STRING_alive_fun(SHIM_INTERP,
+void Parrot_gc_mark_STRING_alive_fun(PARROT_INTERP,
     ARGMOD_NULLOK(STRING *obj))
+        __attribute__nonnull__(1)
         FUNC_MODIFIES(*obj);
 
 PARROT_EXPORT
@@ -343,7 +345,8 @@
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(obj))
 #define ASSERT_ARGS_Parrot_gc_mark_STRING_alive_fun \
-     __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_Parrot_gc_reallocate_memory_chunk \
      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))

Added: trunk/include/parrot/list.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/include/parrot/list.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,169 @@
+/*
+Copyright (C) 2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/gc/list.h - Linked lists of allocated objects.
+
+=head1 DESCRIPTION
+
+Implementation of double linked lists used by various GC implementations.
+
+*/
+
+#ifndef PARROT_GC_LIST_H_GUARD
+#define PARROT_GC_LIST_H_GUARD
+
+/* Allocatable objects has headers to use in linked lists */
+typedef struct List_Item_Header {
+    struct List_Item_Header *prev;
+    struct List_Item_Header *next;
+
+#ifndef NDEBUG
+    struct Linked_List *owner;
+#endif
+} List_Item_Header;
+
+/* Double-linked list. */
+/* N.B. List doesn't _own_ items */
+typedef struct Linked_List {
+    struct List_Item_Header *first;
+    struct List_Item_Header *last;
+
+    /* Cache object count in list. We use it very often */
+    size_t count;
+} Linked_List;
+
+/* Such headers allocated in front of real objects. */
+/* There is helper macros to convert to/from real objects */
+#define Obj2LLH(p) ((List_Item_Header *)((char*)(p) - sizeof (List_Item_Header)))
+#define LLH2Obj_typed(p, type) ((type*)((char*)(p) + sizeof (List_Item_Header)))
+#define LLH2Obj(p) LLH2Obj_typed(p, void)
+
+#ifdef NDEBUG
+#  define SET_LIST_OWNER(l, i)
+#else
+#  define SET_LIST_OWNER(l, i) (i)->owner = (l);
+#endif
+
+#define LIST_APPEND(l, i)                   \
+do {                                        \
+    List_Item_Header *_item = (i);          \
+    Linked_List      *_list = (l);          \
+                                            \
+    if (_list->last) {                      \
+        _item->prev       = _list->last;    \
+        _list->last->next = _item;          \
+    }                                       \
+    else if (!_list->first) {               \
+        _item->prev  = NULL;                \
+        _list->first = _item;               \
+    }                                       \
+                                            \
+    _list->last = _item;                    \
+    _item->next = NULL;                     \
+                                            \
+    SET_LIST_OWNER(_list, _item)            \
+    _list->count++;                         \
+} while (0);
+
+#define LIST_REMOVE(l, i)                   \
+do {                                        \
+    List_Item_Header *_item = (i);          \
+    Linked_List      *_list = (l);          \
+    List_Item_Header *next = _item->next;   \
+    List_Item_Header *prev = _item->prev;   \
+                                            \
+    PARROT_ASSERT(_list == _item->owner);   \
+                                            \
+    /* First _item */                       \
+    if (_list->first == _item)              \
+        _list->first = next;                \
+                                            \
+    if (_list->last == _item)               \
+        _list->last = prev;                 \
+                                            \
+    if (prev)                               \
+        prev->next = next;                  \
+    if (next)                               \
+        next->prev = prev;                  \
+                                            \
+    _list->count--;                         \
+} while (0)
+
+
+/* HEADERIZER BEGIN: src/list.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+PARROT_EXPORT
+void Parrot_list_append(SHIM_INTERP,
+    ARGMOD(Linked_List *list),
+    ARGMOD(List_Item_Header *item))
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*list)
+        FUNC_MODIFIES(*item);
+
+PARROT_EXPORT
+INTVAL Parrot_list_check(SHIM_INTERP, ARGIN(Linked_List *list))
+        __attribute__nonnull__(2);
+
+PARROT_EXPORT
+INTVAL Parrot_list_contains(SHIM_INTERP,
+    ARGIN(Linked_List *list),
+    ARGIN(List_Item_Header *item))
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3);
+
+PARROT_EXPORT
+void Parrot_list_destroy(SHIM_INTERP, ARGMOD(Linked_List* list))
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(* list);
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+struct Linked_List* Parrot_list_new(SHIM_INTERP);
+
+PARROT_EXPORT
+List_Item_Header* Parrot_list_pop(PARROT_INTERP, ARGIN(Linked_List *list))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+PARROT_EXPORT
+List_Item_Header* Parrot_list_remove(SHIM_INTERP,
+    ARGMOD(Linked_List *list),
+    ARGMOD(List_Item_Header *item))
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*list)
+        FUNC_MODIFIES(*item);
+
+#define ASSERT_ARGS_Parrot_list_append __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(list) \
+    , PARROT_ASSERT_ARG(item))
+#define ASSERT_ARGS_Parrot_list_check __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(list))
+#define ASSERT_ARGS_Parrot_list_contains __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(list) \
+    , PARROT_ASSERT_ARG(item))
+#define ASSERT_ARGS_Parrot_list_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(list))
+#define ASSERT_ARGS_Parrot_list_new __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_Parrot_list_pop __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(list))
+#define ASSERT_ARGS_Parrot_list_remove __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(list) \
+    , PARROT_ASSERT_ARG(item))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/list.c */
+
+#endif /* PARROT_GC_LIST_H_GUARD */
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Modified: trunk/include/parrot/pobj.h
==============================================================================
--- trunk/include/parrot/pobj.h	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/include/parrot/pobj.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -153,6 +153,9 @@
     PObj_sysmem_FLAG            = POBJ_FLAG(15),
 
 /* PObj usage FLAGs, COW & GC */
+    /* Used during tri-color mark&sweep */
+    PObj_grey_FLAG              = POBJ_FLAG(16),
+
     /* The Buffer allows COW copies, and may have some. */
     PObj_is_COWable_FLAG        = POBJ_FLAG(17),
     /* Private flag for the GC system. Set if the PObj's in use as
@@ -235,6 +238,9 @@
 #define PObj_report_SET(o) PObj_flag_SET(report, o)
 #define PObj_report_CLEAR(o) PObj_flag_CLEAR(report, o)
 
+#define PObj_grey_TEST(o) gc_flag_TEST(grey, o)
+#define PObj_grey_SET(o) gc_flag_SET(grey, o)
+#define PObj_grey_CLEAR(o) gc_flag_CLEAR(grey, o)
 
 #define PObj_on_free_list_TEST(o) gc_flag_TEST(on_free_list, o)
 #define PObj_on_free_list_SET(o) gc_flag_SET(on_free_list, o)

Modified: trunk/include/parrot/settings.h
==============================================================================
--- trunk/include/parrot/settings.h	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/include/parrot/settings.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -37,8 +37,10 @@
  * GC_DEFAULT_TYPE selection
  * MS  -- stop-the-world mark & sweep
  * INF -- infinite memory "collector"
+ * TMS -- TriColor Mark & Sweep
+ * MS2 -- new style mark & sweep
  */
-#define PARROT_GC_DEFAULT_TYPE MS
+#define PARROT_GC_DEFAULT_TYPE MS2
 
 /*
  * JIT/i386 can use the CGP run core for external functions instead

Modified: trunk/src/call/context.c
==============================================================================
--- trunk/src/call/context.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/call/context.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -260,6 +260,8 @@
 
     PARROT_ASSERT_MSG(!PMC_IS_NULL(pmcctx), "Can't initialise Null CallContext");
 
+    PARROT_ASSERT(PMC_IS_NULL(pmcold) || pmcold->vtable->base_type == enum_class_CallContext);
+
     /*
      * FIXME Invoking corotine shouldn't initialise context. So just
      * check ctx->current_sub. If it's not null return from here

Modified: trunk/src/call/context_accessors.c
==============================================================================
--- trunk/src/call/context_accessors.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/call/context_accessors.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -91,6 +91,7 @@
 Parrot_pcc_get_pmc_constants_func(SHIM_INTERP, ARGIN(PMC *ctx))
 {
     ASSERT_ARGS(Parrot_pcc_get_pmc_constants_func)
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return CONTEXT_STRUCT(ctx)->pmc_constants;
 }
 
@@ -102,6 +103,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_constants_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->num_constants = ct->num.constants;
     c->str_constants = ct->str.constants;
     c->pmc_constants = ct->pmc.constants;
@@ -124,6 +126,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_recursion_depth_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->recursion_depth;
 }
 
@@ -143,6 +146,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_inc_recursion_depth_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->recursion_depth++;
 }
 
@@ -162,6 +166,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_dec_recursion_depth_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return --c->recursion_depth;
 }
 
@@ -186,6 +191,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_caller_ctx_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->caller_ctx;
 }
 
@@ -195,6 +201,8 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_caller_ctx_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
+    PARROT_ASSERT(caller_ctx->vtable->base_type == enum_class_CallContext);
     c->caller_ctx = caller_ctx;
 }
 
@@ -219,6 +227,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_outer_ctx_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->outer_ctx;
 }
 
@@ -228,6 +237,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_outer_ctx_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->outer_ctx = outer_ctx;
 }
 
@@ -251,6 +261,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_lex_pad_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->lex_pad;
 }
 
@@ -260,6 +271,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_lex_pad_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->lex_pad = lex_pad;
 }
 
@@ -284,6 +296,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_namespace_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->current_namespace;
 }
 
@@ -293,6 +306,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_namespace_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->current_namespace = _namespace;
 }
 
@@ -315,6 +329,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_HLL_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->current_HLL;
 }
 
@@ -324,6 +339,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_HLL_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->current_HLL = hll;
 }
 
@@ -348,6 +364,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_handlers_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->handlers;
 }
 
@@ -358,6 +375,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_handlers_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->handlers = handlers;
 }
 
@@ -382,6 +400,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_continuation_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->current_cont;
 }
 
@@ -391,6 +410,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_continuation_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->current_cont = _continuation;
 }
 
@@ -415,6 +435,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_signature_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->current_sig;
 }
 
@@ -424,6 +445,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_signature_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->current_sig = sig_object;
 }
 
@@ -447,6 +469,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_object_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->current_object;
 }
 
@@ -456,6 +479,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_object_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->current_object = object;
 }
 
@@ -479,6 +503,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_pc_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->current_pc;
 }
 
@@ -488,6 +513,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_set_pc_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->current_pc = pc;
 }
 
@@ -508,6 +534,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_warnings_on_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->warns |= flags;
     return c->warns;
 }
@@ -530,6 +557,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_warnings_off_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->warns &= ~flags;
 }
 
@@ -552,6 +580,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_warnings_test_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->warns & flags;
 }
 
@@ -571,6 +600,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_errors_on_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->errors |= flags;
 }
 
@@ -591,6 +621,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_errors_off_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->errors &= ~flags;
 }
 
@@ -612,6 +643,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_errors_test_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->errors & flags;
 }
 
@@ -632,6 +664,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_trace_flags_on_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->trace_flags |= flags;
 }
 
@@ -653,6 +686,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_trace_flags_off_func)
     Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     c->trace_flags &= ~flags;
 }
 
@@ -674,6 +708,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_trace_flags_test_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->trace_flags & flags;
 }
 
@@ -703,6 +738,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_num_constant_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->num_constants[idx];
 }
 
@@ -714,6 +750,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_string_constant_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->str_constants[idx];
 }
 
@@ -725,6 +762,7 @@
 {
     ASSERT_ARGS(Parrot_pcc_get_pmc_constant_func)
     const Parrot_Context * const c = CONTEXT_STRUCT(ctx);
+    PARROT_ASSERT(ctx->vtable->base_type == enum_class_CallContext);
     return c->pmc_constants[idx];
 }
 

Modified: trunk/src/gc/api.c
==============================================================================
--- trunk/src/gc/api.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/gc/api.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -126,27 +126,16 @@
 Parrot_gc_mark_PObj_alive(PARROT_INTERP, ARGMOD(PObj *obj))
 {
     ASSERT_ARGS(Parrot_gc_mark_PObj_alive)
-    /* TODO: Have each core register a ->pobject_lives function pointer in the
-       Memory_Pools struct, and call that pointer directly instead of having a messy
-       set of #if preparser conditions. */
 
     /* if object is live or on free list return */
     if (PObj_is_live_or_free_TESTALL(obj))
         return;
 
-    /* mark it live */
-    PObj_live_SET(obj);
-
-    /* if object is a PMC and contains buffers or PMCs, then attach the PMC
-     * to the chained mark list. */
     if (PObj_is_PMC_TEST(obj)) {
-        PMC * const p = (PMC *)obj;
-
-        if (PObj_is_special_PMC_TEST(obj))
-            interp->gc_sys->mark_special(interp, p);
-
-        else if (PMC_metadata(p))
-            Parrot_gc_mark_PMC_alive(interp, PMC_metadata(p));
+        interp->gc_sys->mark_pmc_header(interp, (PMC*) obj);
+    }
+    else {
+        interp->gc_sys->mark_pobj_header(interp, obj);
     }
 }
 
@@ -165,25 +154,7 @@
 Parrot_gc_mark_PMC_alive_fun(PARROT_INTERP, ARGMOD_NULLOK(PMC *obj))
 {
     ASSERT_ARGS(Parrot_gc_mark_PMC_alive_fun)
-    if (!PMC_IS_NULL(obj)) {
-        PARROT_ASSERT(PObj_is_PMC_TEST(obj));
-
-        if (PObj_is_live_or_free_TESTALL(obj))
-            return;
-
-        /* mark it live */
-        PObj_live_SET(obj);
-
-        /* if object is a PMC and contains buffers or PMCs, then attach the PMC
-         * to the chained mark list. */
-        if (PObj_is_special_PMC_TEST(obj)) {
-            if (PObj_custom_mark_TEST(obj))
-                VTABLE_mark(interp, obj);
-        }
-
-        if (PMC_metadata(obj))
-            Parrot_gc_mark_PMC_alive(interp, PMC_metadata(obj));
-    }
+    interp->gc_sys->mark_pmc_header(interp, obj);
 }
 
 /*
@@ -198,15 +169,10 @@
 
 PARROT_EXPORT
 void
-Parrot_gc_mark_STRING_alive_fun(SHIM_INTERP, ARGMOD_NULLOK(STRING *obj))
+Parrot_gc_mark_STRING_alive_fun(PARROT_INTERP, ARGMOD_NULLOK(STRING *obj))
 {
     ASSERT_ARGS(Parrot_gc_mark_STRING_alive_fun)
-    if (!STRING_IS_NULL(obj)) {
-        PARROT_ASSERT(PObj_is_string_TEST(obj));
-
-        /* mark it live */
-        PObj_live_SET(obj);
-    }
+    interp->gc_sys->mark_pobj_header(interp, (PObj*)obj);
 }
 
 /*
@@ -239,6 +205,9 @@
       case INF:
         Parrot_gc_inf_init(interp);
         break;
+      case MS2:
+        Parrot_gc_ms2_init(interp);
+        break;
       default:
         /*die horribly because of invalid GC core specified*/
         break;
@@ -974,7 +943,7 @@
 {
     ASSERT_ARGS(Parrot_is_blocked_GC_sweep)
     if (interp->gc_sys->is_blocked_sweep)
-        return interp->gc_sys->is_blocked_mark(interp);
+        return interp->gc_sys->is_blocked_sweep(interp);
     else
         return 0;
 }
@@ -1030,6 +999,9 @@
         case INF:
             name = Parrot_str_new(interp, "inf", 3);
             break;
+        case MS2:
+            name = Parrot_str_new(interp, "ms2", 3);
+            break;
         default:
             name = Parrot_str_new(interp, "unknown", 7);
             break;

Added: trunk/src/gc/fixed_allocator.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/gc/fixed_allocator.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,476 @@
+/*
+Copyright (C) 2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/gc/fixed_allocator.c - Implementation of allocator for small objects.
+
+=head1 DESCRIPTION
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+#include "fixed_allocator.h"
+
+/* HEADERIZER HFILE: src/gc/fixed_allocator.h */
+
+/* HEADERIZER BEGIN: static */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+static void allocate_new_pool_arena(ARGMOD(Pool_Allocator *pool))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*pool);
+
+static size_t arena_size(ARGIN(const Pool_Allocator *self))
+        __attribute__nonnull__(1);
+
+PARROT_CANNOT_RETURN_NULL
+static void * get_free_list_item(ARGMOD(Pool_Allocator *pool))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*pool);
+
+PARROT_CANNOT_RETURN_NULL
+static void * get_newfree_list_item(ARGMOD(Pool_Allocator *pool))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*pool);
+
+PARROT_CANNOT_RETURN_NULL
+static void * pool_allocate(ARGMOD(Pool_Allocator *pool))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*pool);
+
+static void pool_free(ARGMOD(Pool_Allocator *pool), ARGFREE(void *data))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*pool);
+
+static int pool_is_owned(ARGMOD(Pool_Allocator *pool), ARGIN(void *ptr))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pool);
+
+#define ASSERT_ARGS_allocate_new_pool_arena __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_arena_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(self))
+#define ASSERT_ARGS_get_free_list_item __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_get_newfree_list_item __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_pool_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_pool_free __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_pool_is_owned __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool) \
+    , PARROT_ASSERT_ARG(ptr))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: static */
+
+/*
+
+=head1 FixedAllocator METHODS
+
+=over 4
+
+=item C<struct Fixed_Allocator* Parrot_gc_fixed_allocator_new(PARROT_INTERP)>
+
+Create new Fixed_Allocator.
+
+=item C<void Parrot_gc_fixed_allocator_destroy(PARROT_INTERP, Fixed_Allocator
+*allocator)>
+
+Destroy Fixed_Allocator.
+
+=item C<void* Parrot_gc_fixed_allocator_allocate(PARROT_INTERP, Fixed_Allocator
+*allocator, size_t size)>
+
+Allocate fixed size memory from Fixed_Allocator.
+
+=item C<void Parrot_gc_fixed_allocator_free(PARROT_INTERP, Fixed_Allocator
+*allocator, void *data, size_t size)>
+
+Free fixed size memory from Fixed_Allocator.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_CAN_RETURN_NULL
+struct Fixed_Allocator*
+Parrot_gc_fixed_allocator_new(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_gc_fixed_allocator_new)
+
+    return mem_internal_allocate_zeroed_typed(Fixed_Allocator);
+}
+
+PARROT_EXPORT
+void
+Parrot_gc_fixed_allocator_destroy(PARROT_INTERP, ARGFREE_NOTNULL(Fixed_Allocator *allocator))
+{
+    ASSERT_ARGS(Parrot_gc_fixed_allocator_destroy)
+    size_t i;
+    for (i = 0; i < allocator->num_pools; ++i) {
+        if (allocator->pools[i]) {
+            Parrot_gc_pool_destroy(interp, allocator->pools[i]);
+        }
+    }
+}
+
+PARROT_EXPORT
+PARROT_CAN_RETURN_NULL
+void*
+Parrot_gc_fixed_allocator_allocate(PARROT_INTERP,
+        ARGIN(Fixed_Allocator *allocator),
+        size_t size)
+{
+    ASSERT_ARGS(Parrot_gc_fixed_allocator_allocate)
+
+    /* We always align size to 4/8 bytes. */
+    const size_t index = (size - 1) / sizeof (void *);
+    void   *ret;
+    PARROT_ASSERT(size);
+
+    if (index >= allocator->num_pools) {
+        size_t new_size = index + 1;
+        /* (re)allocate pools */
+        if (allocator->num_pools)
+            allocator->pools = mem_internal_realloc_n_zeroed_typed(
+                                    allocator->pools, new_size,
+                                    allocator->num_pools, Pool_Allocator *);
+        else
+            allocator->pools = mem_internal_allocate_n_zeroed_typed(new_size,
+                                    Pool_Allocator *);
+
+        allocator->num_pools = new_size;
+    }
+
+    if (! allocator->pools[index]) {
+        const size_t alloc_size = (index + 1) * sizeof (void *);
+        allocator->pools[index] = Parrot_gc_pool_new(interp, alloc_size);
+    }
+
+    ret = pool_allocate(allocator->pools[index]);
+
+    /* memset ret to 0 here? */
+    return ret;
+}
+
+
+PARROT_EXPORT
+void
+Parrot_gc_fixed_allocator_free(PARROT_INTERP,
+        ARGIN(Fixed_Allocator *allocator),
+        ARGFREE_NOTNULL(void *data), size_t size)
+{
+    ASSERT_ARGS(Parrot_gc_fixed_allocator_free)
+
+    /* We always align size to 4/8 bytes. */
+    size_t index = (size - 1) / sizeof (void*);
+
+    PARROT_ASSERT(allocator->pools[index]);
+
+    pool_free(allocator->pools[index], data);
+}
+
+/*
+
+=back
+
+=head1 PoolAllocator METHODS
+
+=over 4
+
+=item C<Pool_Allocator * Parrot_gc_pool_new(PARROT_INTERP, size_t object_size)>
+
+Create Pool Allocator
+
+=item C<void Parrot_gc_pool_destroy(PARROT_INTERP, Pool_Allocator *pool)>
+
+Destroy allocated Pool - free memory for all areanas in the alocated pool
+
+=item C<void * Parrot_gc_pool_allocate(PARROT_INTERP, Pool_Allocator * pool)>
+
+Allocate from Pool
+
+=item C<void Parrot_gc_pool_free(PARROT_INTERP, Pool_Allocator *pool, void
+*data)>
+
+Frees a fixed-size data item back to the Pool for later reallocation
+
+=item C<int Parrot_gc_pool_is_owned(PARROT_INTERP, Pool_Allocator *pool, void
+*ptr)>
+
+check for pool validity
+
+=cut
+
+*/
+
+PARROT_CANNOT_RETURN_NULL
+PARROT_MALLOC
+Pool_Allocator *
+Parrot_gc_pool_new(SHIM_INTERP, size_t object_size)
+{
+    ASSERT_ARGS(Parrot_gc_pool_new)
+    const size_t attrib_size = object_size < sizeof (void *) ? sizeof (void*) : object_size;
+    const size_t num_objs_raw =
+        (GC_FIXED_SIZE_POOL_SIZE - sizeof (Pool_Allocator_Arena)) / attrib_size;
+    const size_t num_objs = (num_objs_raw == 0)?(1):(num_objs_raw);
+    Pool_Allocator * const newpool = mem_internal_allocate_typed(Pool_Allocator);
+
+    newpool->object_size       = attrib_size;
+    newpool->total_objects     = 0;
+    newpool->objects_per_alloc = num_objs;
+    newpool->num_free_objects  = 0;
+    newpool->free_list         = NULL;
+    newpool->top_arena         = NULL;
+    newpool->lo_arena_ptr      = (void *)((size_t)-1);
+    newpool->hi_arena_ptr      = 0;
+    newpool->newfree           = 0;
+    newpool->newlast           = 0;
+
+    return newpool;
+}
+
+PARROT_EXPORT
+void
+Parrot_gc_pool_destroy(SHIM_INTERP, ARGMOD(Pool_Allocator *pool))
+{
+    ASSERT_ARGS(Parrot_gc_pool_destroy)
+
+    Pool_Allocator_Arena *arena = pool->top_arena;
+
+    while (arena) {
+        Pool_Allocator_Arena *next = arena->next;
+        mem_internal_free(arena);
+        arena = next;
+    }
+
+    mem_internal_free(pool);
+}
+
+PARROT_CANNOT_RETURN_NULL
+PARROT_EXPORT
+void *
+Parrot_gc_pool_allocate(PARROT_INTERP, ARGMOD(Pool_Allocator * pool))
+{
+    ASSERT_ARGS(Parrot_gc_pool_allocate)
+    return pool_allocate(pool);
+}
+
+PARROT_EXPORT
+void
+Parrot_gc_pool_free(SHIM_INTERP, ARGMOD(Pool_Allocator *pool), ARGFREE(void *data))
+{
+    ASSERT_ARGS(Parrot_gc_pool_free)
+    pool_free(pool, data);
+}
+
+PARROT_EXPORT
+int
+Parrot_gc_pool_is_owned(SHIM_INTERP, ARGMOD(Pool_Allocator *pool), ARGMOD(void *ptr))
+{
+    ASSERT_ARGS(Parrot_gc_pool_is_owned)
+    return pool_is_owned(pool, ptr);
+}
+
+
+/*
+
+=item C<static void * pool_allocate(Pool_Allocator *pool)>
+
+=item C<static void * get_free_list_item(Pool_Allocator *pool)>
+
+=item C<static void * get_newfree_list_item(Pool_Allocator *pool)>
+
+=item C<static void pool_free(Pool_Allocator *pool, void *data)>
+
+=item C<static int pool_is_owned(Pool_Allocator *pool, void *ptr)>
+
+Static implementation of public methods.
+
+=cut
+
+*/
+
+PARROT_CANNOT_RETURN_NULL
+static void *
+get_free_list_item(ARGMOD(Pool_Allocator *pool))
+{
+    ASSERT_ARGS(get_free_list_item)
+
+    Pool_Allocator_Free_List * const item = pool->free_list;
+    pool->free_list = item->next;
+    return item;
+}
+
+PARROT_CANNOT_RETURN_NULL
+static void *
+get_newfree_list_item(ARGMOD(Pool_Allocator *pool))
+{
+    ASSERT_ARGS(get_newfree_list_item)
+
+    Pool_Allocator_Free_List * const item = pool->newfree;
+    pool->newfree = (Pool_Allocator_Free_List *)
+                    ((char *)(pool->newfree) + pool->object_size);
+
+    if (pool->newfree >= pool->newlast)
+        pool->newfree = NULL;
+
+    return item;
+}
+
+PARROT_CANNOT_RETURN_NULL
+static void *
+pool_allocate(ARGMOD(Pool_Allocator *pool))
+{
+    ASSERT_ARGS(pool_allocate)
+    Pool_Allocator_Free_List *item;
+
+    if (pool->free_list)
+        item = (Pool_Allocator_Free_List*)get_free_list_item(pool);
+
+    else if (pool->newfree)
+        item = (Pool_Allocator_Free_List*)get_newfree_list_item(pool);
+
+    else {
+        allocate_new_pool_arena(pool);
+        item = (Pool_Allocator_Free_List*)get_newfree_list_item(pool);
+    }
+
+    --pool->num_free_objects;
+    return (void *)item;
+}
+
+static void
+pool_free(ARGMOD(Pool_Allocator *pool), ARGFREE(void *data))
+{
+    ASSERT_ARGS(pool_free)
+    Pool_Allocator_Free_List * const item = (Pool_Allocator_Free_List *)data;
+
+    /* It's too expensive.
+    PARROT_ASSERT(Parrot_gc_pool_is_owned(pool, data));
+    */
+
+    item->next      = pool->free_list;
+    pool->free_list = item;
+
+    ++pool->num_free_objects;
+}
+
+
+static int
+pool_is_owned(ARGMOD(Pool_Allocator *pool), ARGIN(void *ptr))
+{
+    ASSERT_ARGS(pool_is_owned)
+    Pool_Allocator_Arena *arena = pool->top_arena;
+    size_t                a_size;
+
+    if (ptr < pool->lo_arena_ptr || ptr > pool->hi_arena_ptr)
+        return 0;
+
+    /* We can cache this value. All arenas are same size */
+    a_size = arena_size(pool);
+    while (arena) {
+        const ptrdiff_t ptr_diff =
+            (ptrdiff_t)ptr - (ptrdiff_t)(arena + 1);
+
+        if (0 <= ptr_diff
+              && ptr_diff < a_size
+              && ptr_diff % pool->object_size == 0)
+            return 1;
+
+        arena = arena->next;
+    }
+
+    return 0;
+}
+
+/*
+
+=item C<static void allocate_new_pool_arena(Pool_Allocator *pool)>
+
+Allocate a new pool arena
+
+=cut
+
+*/
+
+static void
+allocate_new_pool_arena(ARGMOD(Pool_Allocator *pool))
+{
+    ASSERT_ARGS(allocate_new_pool_arena)
+    Pool_Allocator_Free_List *next;
+
+    const size_t num_items  = pool->objects_per_alloc;
+    const size_t item_size  = pool->object_size;
+    const size_t item_space = item_size * num_items;
+
+    /* Round up to 4kb */
+    Pool_Allocator_Arena * const new_arena = (Pool_Allocator_Arena *)mem_internal_allocate(
+                                                arena_size(pool));
+
+    new_arena->prev = NULL;
+    new_arena->next = pool->top_arena;
+    pool->top_arena = new_arena;
+    next            = (Pool_Allocator_Free_List *)(new_arena + 1);
+
+    pool->newfree   = next;
+    pool->newlast   = (Pool_Allocator_Free_List *)((char *)next + item_space);
+
+    pool->num_free_objects += num_items;
+    pool->total_objects    += num_items;
+
+    if (pool->lo_arena_ptr > new_arena)
+        pool->lo_arena_ptr = new_arena;
+
+    if (pool->hi_arena_ptr < (char*)new_arena + GC_FIXED_SIZE_POOL_SIZE)
+        pool->hi_arena_ptr = new_arena + GC_FIXED_SIZE_POOL_SIZE;
+}
+
+/*
+
+=item C<static size_t arena_size(const Pool_Allocator *self)>
+
+Calculate size of Arena.
+
+=cut
+
+*/
+
+static size_t
+arena_size(ARGIN(const Pool_Allocator *self))
+{
+    ASSERT_ARGS(arena_size)
+
+    const size_t num_items  = self->objects_per_alloc;
+    const size_t item_size  = self->object_size;
+    const size_t item_space = item_size * num_items;
+    const size_t total_size = sizeof (Pool_Allocator_Arena) + item_space;
+
+    /* Round up to 4kb */
+    return total_size < GC_FIXED_SIZE_POOL_SIZE
+                      ? GC_FIXED_SIZE_POOL_SIZE
+                      : total_size;
+}
+
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Added: trunk/src/gc/fixed_allocator.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/gc/fixed_allocator.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,158 @@
+/*
+Copyright (C) 2001-2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/gc/fixed_allocator.h - implementation of allocator for small-size objects.
+
+=head1 DESCRIPTION
+
+*/
+
+#ifndef PARROT_GC_FIXED_ALLOCATOR_H_GUARD
+#define PARROT_GC_FIXED_ALLOCATOR_H_GUARD
+
+#include "parrot/settings.h"
+
+/* these values are used for the attribute allocator */
+#define GC_ATTRIB_POOLS_HEADROOM 8
+#define GC_FIXED_SIZE_POOL_SIZE 4096
+
+/* Use the lazy allocator. Since it amortizes arena allocation costs, turn
+   this on at the same time that you increase the size of allocated arenas.
+   increase *_HEADERS_PER_ALLOC and GC_FIXED_SIZE_POOL_SIZE to be large
+   enough to satisfy most startup costs. */
+
+typedef struct Pool_Allocator_Free_List {
+    struct Pool_Allocator_Free_List * next;
+} Pool_Allocator_Free_List;
+
+typedef struct Pool_Allocator_Arena {
+    struct Pool_Allocator_Arena * next;
+    struct Pool_Allocator_Arena * prev;
+} Pool_Allocator_Arena;
+
+typedef struct Pool_Allocator {
+    size_t object_size;
+    size_t total_objects;
+    size_t objects_per_alloc;
+    size_t num_free_objects;
+    Pool_Allocator_Free_List * free_list;
+    Pool_Allocator_Arena     * top_arena;
+    Pool_Allocator_Free_List * newfree;
+    Pool_Allocator_Free_List * newlast;
+
+    /* Pointers of arena bounds. Used in .is_owned check */
+    void *lo_arena_ptr;
+    void *hi_arena_ptr;
+} Pool_Allocator;
+
+typedef struct Fixed_Allocator
+{
+    Pool_Allocator **pools;
+    size_t           num_pools;
+} Fixed_Allocator;
+
+
+/* HEADERIZER BEGIN: src/gc/fixed_allocator.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+PARROT_EXPORT
+PARROT_CAN_RETURN_NULL
+void* Parrot_gc_fixed_allocator_allocate(PARROT_INTERP,
+    ARGIN(Fixed_Allocator *allocator),
+    size_t size)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+PARROT_EXPORT
+void Parrot_gc_fixed_allocator_destroy(PARROT_INTERP,
+    ARGFREE_NOTNULL(Fixed_Allocator *allocator))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+PARROT_EXPORT
+void Parrot_gc_fixed_allocator_free(PARROT_INTERP,
+    ARGIN(Fixed_Allocator *allocator),
+    ARGFREE_NOTNULL(void *data),
+    size_t size)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3);
+
+PARROT_EXPORT
+PARROT_CAN_RETURN_NULL
+struct Fixed_Allocator* Parrot_gc_fixed_allocator_new(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+PARROT_CANNOT_RETURN_NULL
+PARROT_EXPORT
+void * Parrot_gc_pool_allocate(PARROT_INTERP, ARGMOD(Pool_Allocator * pool))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(* pool);
+
+PARROT_EXPORT
+void Parrot_gc_pool_destroy(SHIM_INTERP, ARGMOD(Pool_Allocator *pool))
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pool);
+
+PARROT_EXPORT
+void Parrot_gc_pool_free(SHIM_INTERP,
+    ARGMOD(Pool_Allocator *pool),
+    ARGFREE(void *data))
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pool);
+
+PARROT_EXPORT
+int Parrot_gc_pool_is_owned(SHIM_INTERP,
+    ARGMOD(Pool_Allocator *pool),
+    ARGMOD(void *ptr))
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*pool)
+        FUNC_MODIFIES(*ptr);
+
+PARROT_CANNOT_RETURN_NULL
+PARROT_MALLOC
+Pool_Allocator * Parrot_gc_pool_new(SHIM_INTERP, size_t object_size);
+
+#define ASSERT_ARGS_Parrot_gc_fixed_allocator_allocate \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(allocator))
+#define ASSERT_ARGS_Parrot_gc_fixed_allocator_destroy \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(allocator))
+#define ASSERT_ARGS_Parrot_gc_fixed_allocator_free \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(allocator) \
+    , PARROT_ASSERT_ARG(data))
+#define ASSERT_ARGS_Parrot_gc_fixed_allocator_new __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_gc_pool_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_Parrot_gc_pool_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_Parrot_gc_pool_free __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_Parrot_gc_pool_is_owned __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(pool) \
+    , PARROT_ASSERT_ARG(ptr))
+#define ASSERT_ARGS_Parrot_gc_pool_new __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/gc/fixed_allocator.c */
+
+
+#endif /* PARROT_GC_FIXED_ALLOCATOR_H_GUARD */
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Modified: trunk/src/gc/gc_ms.c
==============================================================================
--- trunk/src/gc/gc_ms.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/gc/gc_ms.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -16,6 +16,7 @@
 
 #include "parrot/parrot.h"
 #include "gc_private.h"
+#include "parrot/list.h"
 
 #define DEBUG_FREE_LIST 0
 
@@ -43,10 +44,11 @@
 static int gc_ms_active_sized_buffers(ARGIN(const Memory_Pools *mem_pools))
         __attribute__nonnull__(1);
 
-static void gc_ms_add_free_object(SHIM_INTERP,
+static void gc_ms_add_free_object(PARROT_INTERP,
     ARGMOD(Memory_Pools *mem_pools),
     ARGMOD(Fixed_Size_Pool *pool),
     ARGIN(void *to_add))
+        __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(3)
         __attribute__nonnull__(4)
@@ -155,6 +157,12 @@
 static unsigned int gc_ms_is_blocked_GC_sweep(PARROT_INTERP)
         __attribute__nonnull__(1);
 
+static int gc_ms_is_pmc_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+        __attribute__nonnull__(1);
+
+static int gc_ms_is_string_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+        __attribute__nonnull__(1);
+
 static void gc_ms_iterate_live_strings(PARROT_INTERP,
     string_iterator_callback callback,
     ARGIN_NULLOK(void *data))
@@ -163,6 +171,10 @@
 static void gc_ms_mark_and_sweep(PARROT_INTERP, UINTVAL flags)
         __attribute__nonnull__(1);
 
+static void gc_ms_mark_pobj_header(PARROT_INTERP, ARGMOD_NULLOK(PObj *obj))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*obj);
+
 static void gc_ms_mark_special(PARROT_INTERP, ARGIN(PMC *pmc))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
@@ -252,7 +264,8 @@
 #define ASSERT_ARGS_gc_ms_active_sized_buffers __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(mem_pools))
 #define ASSERT_ARGS_gc_ms_add_free_object __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools) \
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(mem_pools) \
     , PARROT_ASSERT_ARG(pool) \
     , PARROT_ASSERT_ARG(to_add))
 #define ASSERT_ARGS_gc_ms_alloc_objects __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -308,10 +321,16 @@
        PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_gc_ms_is_blocked_GC_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms_is_pmc_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms_is_string_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_gc_ms_iterate_live_strings __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_gc_ms_mark_and_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms_mark_pobj_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_gc_ms_mark_special __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(pmc))
@@ -400,6 +419,11 @@
     interp->gc_sys->allocate_bufferlike_header  = gc_ms_allocate_bufferlike_header;
     interp->gc_sys->free_bufferlike_header      = gc_ms_free_bufferlike_header;
 
+    interp->gc_sys->is_pmc_ptr              = gc_ms_is_pmc_ptr;
+    interp->gc_sys->is_string_ptr           = gc_ms_is_string_ptr;
+    interp->gc_sys->mark_pmc_header         = gc_ms_mark_pmc_header;
+    interp->gc_sys->mark_pobj_header        = gc_ms_mark_pobj_header;
+
     interp->gc_sys->allocate_pmc_attributes = gc_ms_allocate_pmc_attributes;
     interp->gc_sys->free_pmc_attributes     = gc_ms_free_pmc_attributes;
 
@@ -433,6 +457,10 @@
 
     interp->gc_sys->iterate_live_strings = gc_ms_iterate_live_strings;
 
+    /* gc_private is @objects */
+    interp->gc_sys->gc_private       = Parrot_list_new(interp);
+
+
     Parrot_gc_str_initialize(interp, &interp->mem_pools->string_gc);
     initialize_fixed_size_pools(interp, interp->mem_pools);
     Parrot_gc_initialize_fixed_size_pools(interp, interp->mem_pools,
@@ -513,8 +541,8 @@
     size_t dynamic_threshold;
 
     /* new_mem is the additional amount of memory used since the last GC */
-    size_t new_mem = mem_pools->memory_used
-                   - mem_pools->mem_used_last_collect;
+    size_t new_mem = interp->gc_sys->stats.memory_used
+                   - interp->gc_sys->stats.mem_used_last_collect;
 
     /* Never run a GC if new_mem is below static GC_SIZE_THRESHOLD */
     if (new_mem <= GC_SIZE_THRESHOLD)
@@ -522,7 +550,7 @@
 
     /* The dynamic threshold is a configurable percentage of the amount of
        memory used after the last GC */
-    dynamic_threshold = (size_t)(mem_pools->mem_used_last_collect *
+    dynamic_threshold = (size_t)(interp->gc_sys->stats.mem_used_last_collect *
                                  (0.01 * interp->gc_threshold));
 
     return new_mem > dynamic_threshold;
@@ -581,7 +609,7 @@
 
     }
     else {
-        ++mem_pools->gc_lazy_mark_runs;
+        ++interp->gc_sys->stats.gc_lazy_mark_runs;
 
         Parrot_gc_clear_live_bits(interp, mem_pools->pmc_pool);
     }
@@ -592,10 +620,12 @@
     pt_gc_stop_mark(interp);
 
     /* Note it */
-    ++mem_pools->gc_mark_runs;
+    ++interp->gc_sys->stats.gc_mark_runs;
+    interp->gc_sys->stats.header_allocs_since_last_collect = 0;
+
     --mem_pools->gc_mark_block_level;
-    mem_pools->header_allocs_since_last_collect = 0;
-    mem_pools->mem_used_last_collect = mem_pools->memory_used;
+    interp->gc_sys->stats.header_allocs_since_last_collect = 0;
+    interp->gc_sys->stats.mem_used_last_collect = interp->gc_sys->stats.memory_used;
 
     return;
 }
@@ -777,6 +807,83 @@
 
 /*
 
+=item C<void gc_ms_mark_pmc_header(PARROT_INTERP, PMC *obj)>
+
+Mark the PMC *obj as live and attach PMCs and/or buffers
+
+=cut
+
+*/
+
+void
+gc_ms_mark_pmc_header(PARROT_INTERP, ARGMOD_NULLOK(PMC *obj))
+{
+    ASSERT_ARGS(gc_ms_mark_pmc_header)
+    if (!PMC_IS_NULL(obj)) {
+        PARROT_ASSERT(PObj_is_PMC_TEST(obj));
+
+        if (PObj_is_live_or_free_TESTALL(obj))
+            return;
+
+        /* mark it live */
+        PObj_live_SET(obj);
+
+        /* if object is a PMC and contains buffers or PMCs, then attach the PMC
+         * to the chained mark list. */
+        if (PObj_is_special_PMC_TEST(obj)) {
+            if (PObj_custom_mark_TEST(obj))
+                VTABLE_mark(interp, obj);
+        }
+
+        if (PMC_metadata(obj))
+            Parrot_gc_mark_PMC_alive(interp, PMC_metadata(obj));
+    }
+}
+
+/*
+
+=item C<static int gc_ms_is_pmc_ptr(PARROT_INTERP, void *ptr)>
+
+return True if *ptr is contained in the pool
+
+=cut
+
+*/
+
+static int
+gc_ms_is_pmc_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+{
+    ASSERT_ARGS(gc_ms_is_pmc_ptr)
+    return contained_in_pool(interp->mem_pools->pmc_pool, ptr);
+}
+
+/*
+
+=item C<static int gc_ms_is_string_ptr(PARROT_INTERP, void *ptr)>
+
+establish if string *ptr is owned
+
+=cut
+
+*/
+
+static int
+gc_ms_is_string_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+{
+    ASSERT_ARGS(gc_ms_is_string_ptr)
+    UINTVAL        i;
+
+    for (i = 0; i < interp->mem_pools->num_sized; ++i) {
+        if (interp->mem_pools->sized_header_pools[i]
+            &&  contained_in_pool(interp->mem_pools->sized_header_pools[i], ptr))
+            return 1;
+    }
+
+    return 0;
+}
+
+/*
+
 =item C<static STRING* gc_ms_allocate_string_header(PARROT_INTERP, UINTVAL
 flags)>
 
@@ -824,6 +931,26 @@
 
 /*
 
+=item C<static void gc_ms_mark_pobj_header(PARROT_INTERP, PObj *obj)>
+
+mark *obj as live
+
+=cut
+
+*/
+
+static void
+gc_ms_mark_pobj_header(PARROT_INTERP, ARGMOD_NULLOK(PObj *obj))
+{
+    ASSERT_ARGS(gc_ms_mark_pobj_header)
+    if (obj) {
+        /* mark it live */
+        PObj_live_SET(obj);
+    }
+}
+
+/*
+
 =item C<static Buffer * gc_ms_allocate_bufferlike_header(PARROT_INTERP, size_t
 size)>
 
@@ -1415,7 +1542,7 @@
 */
 
 static void
-gc_ms_add_free_object(SHIM_INTERP,
+gc_ms_add_free_object(PARROT_INTERP,
         ARGMOD(Memory_Pools *mem_pools),
         ARGMOD(Fixed_Size_Pool *pool),
         ARGIN(void *to_add))
@@ -1431,7 +1558,7 @@
 
     object->next_ptr = pool->free_list;
     pool->free_list  = object;
-    mem_pools->memory_used -= pool->object_size;
+    interp->gc_sys->stats.memory_used -= pool->object_size;
 }
 
 /*
@@ -1482,7 +1609,7 @@
     }
 
     --pool->num_free_objects;
-    mem_pools->memory_used += pool->object_size;
+    interp->gc_sys->stats.memory_used += pool->object_size;
 
     return ptr;
 }
@@ -1632,12 +1759,6 @@
 
     Memory_Pools * const mem_pools = interp->mem_pools;
     switch (which) {
-        case TOTAL_MEM_ALLOC:
-            return mem_pools->memory_allocated;
-        case GC_MARK_RUNS:
-            return mem_pools->gc_mark_runs;
-        case GC_COLLECT_RUNS:
-            return mem_pools->gc_collect_runs;
         case ACTIVE_PMCS:
             return mem_pools->pmc_pool->total_objects -
                    mem_pools->pmc_pool->num_free_objects;
@@ -1647,17 +1768,50 @@
             return mem_pools->pmc_pool->total_objects;
         case TOTAL_BUFFERS:
             return gc_ms_total_sized_buffers(mem_pools);
+        case IMPATIENT_PMCS:
+            return mem_pools->num_early_gc_PMCs;
+        default:
+            return Parrot_gc_get_info(interp, which, &interp->gc_sys->stats);
+            break;
+    }
+    return 0;
+}
+
+/*
+TODO Move it somewhere.
+*/
+
+/*
+
+=item C<size_t Parrot_gc_get_info(PARROT_INTERP, Interpinfo_enum which,
+GC_Statistics *stats)>
+
+returns stats as required by enum which
+
+=cut
+
+*/
+
+size_t
+Parrot_gc_get_info(PARROT_INTERP, Interpinfo_enum which, ARGIN(GC_Statistics *stats))
+{
+    ASSERT_ARGS(Parrot_gc_get_info)
+
+    switch (which) {
+        case TOTAL_MEM_ALLOC:
+            return stats->memory_allocated;
+        case GC_MARK_RUNS:
+            return stats->gc_mark_runs;
+        case GC_COLLECT_RUNS:
+            return stats->gc_collect_runs;
         case HEADER_ALLOCS_SINCE_COLLECT:
-            return mem_pools->header_allocs_since_last_collect;
+            return stats->header_allocs_since_last_collect;
         case MEM_ALLOCS_SINCE_COLLECT:
-            return mem_pools->mem_allocs_since_last_collect;
+            return stats->mem_allocs_since_last_collect;
         case TOTAL_COPIED:
-            return mem_pools->memory_collected;
-        case IMPATIENT_PMCS:
-            return mem_pools->num_early_gc_PMCs;
+            return stats->memory_collected;
         case GC_LAZY_MARK_RUNS:
-            return mem_pools->gc_lazy_mark_runs;
-        case EXTENDED_PMCS:
+            return stats->gc_lazy_mark_runs;
         default:
             break;
     }

Added: trunk/src/gc/gc_ms2.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/gc/gc_ms2.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,1459 @@
+/*
+Copyright (C) 2001-2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/gc/gc_ms2.c - Non-recursive M&S
+
+=head1 DESCRIPTION
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+#include "parrot/gc_api.h"
+#include "parrot/list.h"
+#include "gc_private.h"
+#include "fixed_allocator.h"
+
+#define PANIC_OUT_OF_MEM(size) failed_allocation(__LINE__, (size))
+
+/* Private information */
+typedef struct MarkSweep_GC {
+    /* Allocator for PMC headers */
+    struct Pool_Allocator *pmc_allocator;
+    /* Currently allocate objects */
+    struct Linked_List    *objects;
+    /* During M&S gather new live objects in this list */
+    struct Linked_List    *new_objects;
+
+    /* Allocator for strings */
+    struct Pool_Allocator *string_allocator;
+    struct Linked_List    *strings;
+
+    /* Fixed-size allocator */
+    struct Fixed_Allocator *fixed_size_allocator;
+
+    /* String GC */
+    struct String_GC        string_gc;
+
+    /* Number of allocated objects before trigger gc */
+    size_t gc_threshold;
+
+    /* GC blocking */
+    UINTVAL gc_mark_block_level;  /* How many outstanding GC block
+                                     requests are there? */
+    UINTVAL gc_sweep_block_level; /* How many outstanding GC block
+                                     requests are there? */
+
+    UINTVAL num_early_gc_PMCs;    /* how many PMCs want immediate destruction */
+
+} MarkSweep_GC;
+
+/* Callback to destroy PMC or free string storage */
+typedef void (*sweep_cb)(PARROT_INTERP, PObj *obj);
+
+/* HEADERIZER HFILE: src/gc/gc_private.h */
+
+/* HEADERIZER BEGIN: static */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+PARROT_DOES_NOT_RETURN
+static void failed_allocation(unsigned int line, unsigned long size);
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static Buffer* gc_ms2_allocate_buffer_header(PARROT_INTERP,
+    SHIM(size_t size))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_allocate_buffer_storage(PARROT_INTERP,
+    ARGIN(Buffer *str),
+    size_t size)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+PARROT_CAN_RETURN_NULL
+static void* gc_ms2_allocate_fixed_size_storage(PARROT_INTERP, size_t size)
+        __attribute__nonnull__(1);
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void * gc_ms2_allocate_memory_chunk(SHIM_INTERP, size_t size);
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void * gc_ms2_allocate_memory_chunk_zeroed(SHIM_INTERP, size_t size);
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static void* gc_ms2_allocate_pmc_attributes(PARROT_INTERP, ARGMOD(PMC *pmc))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pmc);
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static PMC* gc_ms2_allocate_pmc_header(PARROT_INTERP, UINTVAL flags)
+        __attribute__nonnull__(1);
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static STRING* gc_ms2_allocate_string_header(PARROT_INTERP,
+    SHIM(UINTVAL flags))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_allocate_string_storage(PARROT_INTERP,
+    ARGIN(STRING *str),
+    size_t size)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static void gc_ms2_block_GC_mark(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_ms2_block_GC_sweep(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_ms2_compact_memory_pool(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static size_t gc_ms2_count_used_pmc_memory(PARROT_INTERP,
+    ARGIN(Linked_List *list))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static size_t gc_ms2_count_used_string_memory(PARROT_INTERP,
+    ARGIN(Linked_List *list))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static void gc_ms2_finalize(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_ms2_free_buffer_header(PARROT_INTERP,
+    ARGFREE(Buffer *s),
+    SHIM(size_t size))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_free_fixed_size_storage(PARROT_INTERP,
+    size_t size,
+    ARGMOD(void *data))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*data);
+
+static void gc_ms2_free_memory_chunk(SHIM_INTERP, ARGFREE(void *data));
+static void gc_ms2_free_pmc_attributes(PARROT_INTERP, ARGMOD(PMC *pmc))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pmc);
+
+static void gc_ms2_free_pmc_header(PARROT_INTERP, ARGFREE(PMC *pmc))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_free_string_header(PARROT_INTERP, ARGFREE(STRING *s))
+        __attribute__nonnull__(1);
+
+static size_t gc_ms2_get_gc_info(PARROT_INTERP, Interpinfo_enum which)
+        __attribute__nonnull__(1);
+
+static unsigned int gc_ms2_is_blocked_GC_mark(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static unsigned int gc_ms2_is_blocked_GC_sweep(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static int gc_ms2_is_pmc_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+        __attribute__nonnull__(1);
+
+static int gc_ms2_is_ptr_owned(PARROT_INTERP,
+    ARGIN_NULLOK(void *ptr),
+    ARGIN(Pool_Allocator *pool),
+    ARGIN(Linked_List *list))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(3)
+        __attribute__nonnull__(4);
+
+static int gc_ms2_is_string_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_iterate_live_strings(PARROT_INTERP,
+    string_iterator_callback callback,
+    ARGIN_NULLOK(void *data))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_mark_and_sweep(PARROT_INTERP, UINTVAL flags)
+        __attribute__nonnull__(1);
+
+static void gc_ms2_mark_pmc_header(PARROT_INTERP, ARGIN(PMC *pmc))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static void gc_ms2_mark_pobj_header(PARROT_INTERP, ARGIN_NULLOK(PObj * obj))
+        __attribute__nonnull__(1);
+
+static void gc_ms2_maybe_mark_and_sweep(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_ms2_pmc_needs_early_collection(PARROT_INTERP,
+    ARGMOD(PMC *pmc))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*pmc);
+
+static void gc_ms2_reallocate_buffer_storage(PARROT_INTERP,
+    ARGIN(Buffer *str),
+    size_t size)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void * gc_ms2_reallocate_memory_chunk(SHIM_INTERP,
+    ARGFREE(void *from),
+    size_t size);
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void * gc_ms2_reallocate_memory_chunk_zeroed(SHIM_INTERP,
+    ARGFREE(void *data),
+    size_t newsize,
+    size_t oldsize);
+
+static void gc_ms2_reallocate_string_storage(PARROT_INTERP,
+    ARGIN(STRING *str),
+    size_t size)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static void gc_ms2_sweep_pmc_cb(PARROT_INTERP, ARGIN(PObj *obj))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static void gc_ms2_sweep_pool(PARROT_INTERP,
+    ARGIN(Pool_Allocator *pool),
+    ARGIN(Linked_List *list),
+    ARGIN(sweep_cb callback))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        __attribute__nonnull__(4);
+
+static void gc_ms2_sweep_string_cb(PARROT_INTERP, ARGIN(PObj *obj))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
+static void gc_ms2_unblock_GC_mark(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+static void gc_ms2_unblock_GC_sweep(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+#define ASSERT_ARGS_failed_allocation __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_gc_ms2_allocate_buffer_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_allocate_buffer_storage \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_gc_ms2_allocate_fixed_size_storage \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_allocate_memory_chunk __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_gc_ms2_allocate_memory_chunk_zeroed \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_gc_ms2_allocate_pmc_attributes \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pmc))
+#define ASSERT_ARGS_gc_ms2_allocate_pmc_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_allocate_string_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_allocate_string_storage \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_gc_ms2_block_GC_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_block_GC_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_compact_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_count_used_pmc_memory __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(list))
+#define ASSERT_ARGS_gc_ms2_count_used_string_memory \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(list))
+#define ASSERT_ARGS_gc_ms2_finalize __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_free_buffer_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_free_fixed_size_storage \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(data))
+#define ASSERT_ARGS_gc_ms2_free_memory_chunk __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_gc_ms2_free_pmc_attributes __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pmc))
+#define ASSERT_ARGS_gc_ms2_free_pmc_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_free_string_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_get_gc_info __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_is_blocked_GC_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_is_blocked_GC_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_is_pmc_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_is_ptr_owned __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pool) \
+    , PARROT_ASSERT_ARG(list))
+#define ASSERT_ARGS_gc_ms2_is_string_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_iterate_live_strings __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_mark_and_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_mark_pmc_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pmc))
+#define ASSERT_ARGS_gc_ms2_mark_pobj_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_maybe_mark_and_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_pmc_needs_early_collection \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pmc))
+#define ASSERT_ARGS_gc_ms2_reallocate_buffer_storage \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_gc_ms2_reallocate_memory_chunk \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_gc_ms2_reallocate_memory_chunk_zeroed \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_gc_ms2_reallocate_string_storage \
+     __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_gc_ms2_sweep_pmc_cb __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(obj))
+#define ASSERT_ARGS_gc_ms2_sweep_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(pool) \
+    , PARROT_ASSERT_ARG(list) \
+    , PARROT_ASSERT_ARG(callback))
+#define ASSERT_ARGS_gc_ms2_sweep_string_cb __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(obj))
+#define ASSERT_ARGS_gc_ms2_unblock_GC_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_gc_ms2_unblock_GC_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: static */
+
+/*
+
+=head1 Functions
+
+=over 4
+
+=item C<static void gc_ms2_mark_and_sweep(PARROT_INTERP, UINTVAL flags)>
+
+This function would perform a GC run, if we needed to. Luckily we have
+infinite memory!
+
+This function is called from the GC API function C<Parrot_gc_mark_and_sweep>.
+
+Flags can be a combination of these values:
+
+  GC_finish_FLAG
+  GC_lazy_FLAG
+  GC_trace_stack_FLAG
+
+=cut
+
+*/
+
+/*
+
+=item C<static void gc_ms2_compact_memory_pool(PARROT_INTERP)>
+
+Stub for compacting memory pools.
+
+=cut
+
+*/
+static void
+gc_ms2_compact_memory_pool(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_compact_memory_pool)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    Parrot_gc_str_compact_pool(interp, &self->string_gc);
+}
+
+/*
+
+=item C<static PMC* gc_ms2_allocate_pmc_header(PARROT_INTERP, UINTVAL flags)>
+
+=item C<static void gc_ms2_free_pmc_header(PARROT_INTERP, PMC *pmc)>
+
+=item C<static STRING* gc_ms2_allocate_string_header(PARROT_INTERP, UINTVAL
+flags)>
+
+=item C<static void gc_ms2_free_string_header(PARROT_INTERP, STRING *s)>
+
+=item C<static void* gc_ms2_allocate_pmc_attributes(PARROT_INTERP, PMC *pmc)>
+
+=item C<static void gc_ms2_free_pmc_attributes(PARROT_INTERP, PMC *pmc)>
+
+=item C<static void gc_ms2_allocate_string_storage(PARROT_INTERP, STRING *str,
+size_t size)>
+
+=item C<static void gc_ms2_reallocate_string_storage(PARROT_INTERP, STRING *str,
+size_t size)>
+
+=item C<static void gc_ms2_allocate_buffer_storage(PARROT_INTERP, Buffer *str,
+size_t size)>
+
+=item C<static void gc_ms2_reallocate_buffer_storage(PARROT_INTERP, Buffer *str,
+size_t size)>
+
+=item C<static void* gc_ms2_allocate_fixed_size_storage(PARROT_INTERP, size_t
+size)>
+
+=item C<static void gc_ms2_free_fixed_size_storage(PARROT_INTERP, size_t size,
+void *data)>
+
+Functions for allocating/deallocating various objects.
+
+*/
+
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static void*
+gc_ms2_allocate_pmc_attributes(PARROT_INTERP, ARGMOD(PMC *pmc))
+{
+    ASSERT_ARGS(gc_ms2_allocate_pmc_attributes)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    const size_t  attr_size = pmc->vtable->attr_size;
+    PMC_data(pmc) = Parrot_gc_fixed_allocator_allocate(interp,
+                        self->fixed_size_allocator, attr_size);
+    memset(PMC_data(pmc), 0, attr_size);
+
+    interp->gc_sys->stats.mem_used_last_collect += attr_size;
+
+    return PMC_data(pmc);
+}
+
+static void
+gc_ms2_free_pmc_attributes(PARROT_INTERP, ARGMOD(PMC *pmc))
+{
+    ASSERT_ARGS(gc_ms2_free_pmc_attributes)
+    if (PMC_data(pmc)) {
+        MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+        Parrot_gc_fixed_allocator_free(interp, self->fixed_size_allocator,
+                PMC_data(pmc), pmc->vtable->attr_size);
+
+        interp->gc_sys->stats.mem_used_last_collect -= pmc->vtable->attr_size;
+    }
+}
+
+PARROT_CAN_RETURN_NULL
+static void*
+gc_ms2_allocate_fixed_size_storage(PARROT_INTERP, size_t size)
+{
+    ASSERT_ARGS(gc_ms2_allocate_fixed_size_storage)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+
+    interp->gc_sys->stats.memory_allocated      += size;
+    interp->gc_sys->stats.mem_used_last_collect += size;
+
+    return Parrot_gc_fixed_allocator_allocate(interp, self->fixed_size_allocator, size);
+}
+
+static void
+gc_ms2_free_fixed_size_storage(PARROT_INTERP, size_t size, ARGMOD(void *data))
+{
+    ASSERT_ARGS(gc_ms2_free_fixed_size_storage)
+    if (data) {
+        MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+
+        interp->gc_sys->stats.memory_allocated      -= size;
+        interp->gc_sys->stats.mem_used_last_collect -= size;
+
+        Parrot_gc_fixed_allocator_free(interp, self->fixed_size_allocator, data, size);
+    }
+}
+
+/*
+
+=item C<static size_t gc_ms2_get_gc_info(PARROT_INTERP, Interpinfo_enum which)>
+
+GC introspection function.
+gets stats based on enum which
+
+=cut
+
+*/
+static size_t
+gc_ms2_get_gc_info(PARROT_INTERP, Interpinfo_enum which)
+{
+    ASSERT_ARGS(gc_ms2_get_gc_info)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+
+    if (which == IMPATIENT_PMCS)
+        return self->num_early_gc_PMCs;
+
+    return Parrot_gc_get_info(interp, which, &interp->gc_sys->stats);
+}
+
+
+
+
+/*
+
+=item C<void Parrot_gc_ms2_init(PARROT_INTERP)>
+
+Initializes the infinite memory collector. Installs the necessary function
+pointers into the Memory_Pools structure. The two most important are the
+C<mark_and_sweep> and C<pool_init> functions. C<finalize_gc_system> function
+will be called at Parrot exit and will shut down the GC system if things
+need to be flushed/closed/deactivated/freed/etc. It can be set to NULL if no
+finalization is necessary.
+
+=cut
+
+*/
+
+void
+Parrot_gc_ms2_init(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_gc_ms2_init)
+    struct MarkSweep_GC *self;
+
+    interp->gc_sys->finalize_gc_system = gc_ms2_finalize;
+
+    interp->gc_sys->do_gc_mark              = gc_ms2_mark_and_sweep;
+    interp->gc_sys->compact_string_pool     = gc_ms2_compact_memory_pool;
+
+    /*
+    interp->gc_sys->mark_special                = gc_ms2_mark_special;
+    */
+    interp->gc_sys->pmc_needs_early_collection  = gc_ms2_pmc_needs_early_collection;
+
+    interp->gc_sys->allocate_pmc_header     = gc_ms2_allocate_pmc_header;
+    interp->gc_sys->free_pmc_header         = gc_ms2_free_pmc_header;
+
+    interp->gc_sys->allocate_string_header  = gc_ms2_allocate_string_header;
+    interp->gc_sys->free_string_header      = gc_ms2_free_string_header;
+
+    interp->gc_sys->allocate_bufferlike_header  = gc_ms2_allocate_buffer_header;
+    interp->gc_sys->free_bufferlike_header      = gc_ms2_free_buffer_header;
+
+    interp->gc_sys->allocate_pmc_attributes = gc_ms2_allocate_pmc_attributes;
+    interp->gc_sys->free_pmc_attributes     = gc_ms2_free_pmc_attributes;
+
+    interp->gc_sys->is_pmc_ptr              = gc_ms2_is_pmc_ptr;
+    interp->gc_sys->is_string_ptr           = gc_ms2_is_string_ptr;
+    interp->gc_sys->mark_pmc_header         = gc_ms2_mark_pmc_header;
+    interp->gc_sys->mark_pobj_header        = gc_ms2_mark_pobj_header;
+
+    interp->gc_sys->block_mark      = gc_ms2_block_GC_mark;
+    interp->gc_sys->unblock_mark    = gc_ms2_unblock_GC_mark;
+    interp->gc_sys->is_blocked_mark = gc_ms2_is_blocked_GC_mark;
+
+    interp->gc_sys->block_sweep      = gc_ms2_block_GC_sweep;
+    interp->gc_sys->unblock_sweep    = gc_ms2_unblock_GC_sweep;
+    interp->gc_sys->is_blocked_sweep = gc_ms2_is_blocked_GC_sweep;
+
+    interp->gc_sys->allocate_string_storage     = gc_ms2_allocate_string_storage;
+    interp->gc_sys->reallocate_string_storage   = gc_ms2_reallocate_string_storage;
+
+    interp->gc_sys->allocate_buffer_storage     = gc_ms2_allocate_buffer_storage;
+    interp->gc_sys->reallocate_buffer_storage   = gc_ms2_reallocate_buffer_storage;
+
+    interp->gc_sys->allocate_fixed_size_storage = gc_ms2_allocate_fixed_size_storage;
+    interp->gc_sys->free_fixed_size_storage     = gc_ms2_free_fixed_size_storage;
+
+    /* We don't distinguish between chunk and chunk_with_pointers */
+    interp->gc_sys->allocate_memory_chunk   = gc_ms2_allocate_memory_chunk;
+    interp->gc_sys->reallocate_memory_chunk = gc_ms2_reallocate_memory_chunk;
+    interp->gc_sys->allocate_memory_chunk_with_interior_pointers
+                = gc_ms2_allocate_memory_chunk_zeroed;
+    interp->gc_sys->reallocate_memory_chunk_with_interior_pointers
+                = gc_ms2_reallocate_memory_chunk_zeroed;
+    interp->gc_sys->free_memory_chunk       = gc_ms2_free_memory_chunk;
+
+    interp->gc_sys->iterate_live_strings = gc_ms2_iterate_live_strings;
+
+    interp->gc_sys->get_gc_info      = gc_ms2_get_gc_info;
+
+    if (interp->parent_interpreter && interp->parent_interpreter->gc_sys) {
+        /* This is a "child" interpreter. Just reuse parent one */
+        self = (MarkSweep_GC*)interp->parent_interpreter->gc_sys->gc_private;
+    }
+    else {
+        self = mem_allocate_zeroed_typed(MarkSweep_GC);
+
+        self->pmc_allocator = Parrot_gc_pool_new(interp,
+            sizeof (List_Item_Header) + sizeof (PMC));
+        self->objects = Parrot_list_new(interp);
+
+        self->string_allocator = Parrot_gc_pool_new(interp,
+            sizeof (List_Item_Header) + sizeof (STRING));
+        self->strings = Parrot_list_new(interp);
+
+        self->fixed_size_allocator = Parrot_gc_fixed_allocator_new(interp);
+
+        /* Collect every 256M allocated. */
+        /* Hardcode for now. Will be configured via CLI */
+        self->gc_threshold = 256 * 1024 * 1024;
+    }
+    interp->gc_sys->gc_private = self;
+
+    Parrot_gc_str_initialize(interp, &self->string_gc);
+}
+
+/*
+=item C<static void gc_ms2_finalize(PARROT_INTERP)>
+
+Finalize GC subsystem.
+
+=cut
+*/
+static void
+gc_ms2_finalize(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_finalize)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+
+    Parrot_gc_str_finalize(interp, &self->string_gc);
+
+    // Parrot_list_destroy(interp, self->objects);
+    // Parrot_list_destroy(interp, self->strings);
+    Parrot_gc_pool_destroy(interp, self->pmc_allocator);
+    Parrot_gc_pool_destroy(interp, self->string_allocator);
+    Parrot_gc_fixed_allocator_destroy(interp, self->fixed_size_allocator);
+}
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static PMC*
+gc_ms2_allocate_pmc_header(PARROT_INTERP, UINTVAL flags)
+{
+    ASSERT_ARGS(gc_ms2_allocate_pmc_header)
+    MarkSweep_GC      *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    List_Item_Header *ptr;
+    PMC              *ret;
+
+    gc_ms2_maybe_mark_and_sweep(interp);
+
+    /* Increase used memory. Not precisely accurate due Pool_Allocator paging */
+    ++interp->gc_sys->stats.header_allocs_since_last_collect;
+    interp->gc_sys->stats.memory_allocated      += sizeof (PMC);
+    interp->gc_sys->stats.mem_used_last_collect += sizeof (PMC);
+
+    ptr = (List_Item_Header *)Parrot_gc_pool_allocate(interp,
+            self->pmc_allocator);
+    LIST_APPEND(self->objects, ptr);
+
+    ret = LLH2Obj_typed(ptr, PMC);
+
+    return ret;
+}
+
+static void
+gc_ms2_free_pmc_header(PARROT_INTERP, ARGFREE(PMC *pmc))
+{
+    ASSERT_ARGS(gc_ms2_free_pmc_header)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    if (pmc) {
+        if (PObj_on_free_list_TEST(pmc))
+            return;
+        Parrot_list_remove(interp, self->objects, Obj2LLH(pmc));
+        PObj_on_free_list_SET(pmc);
+
+        Parrot_pmc_destroy(interp, pmc);
+
+        Parrot_gc_pool_free(interp, self->pmc_allocator, Obj2LLH(pmc));
+
+        --interp->gc_sys->stats.header_allocs_since_last_collect;
+        interp->gc_sys->stats.memory_allocated      -= sizeof (PMC);
+        interp->gc_sys->stats.mem_used_last_collect -= sizeof (PMC);
+    }
+}
+
+/*
+
+=item C<static void gc_ms2_mark_pmc_header(PARROT_INTERP, PMC *pmc)>
+
+mark as grey
+
+=cut
+
+*/
+
+static void
+gc_ms2_mark_pmc_header(PARROT_INTERP, ARGIN(PMC *pmc))
+{
+    ASSERT_ARGS(gc_ms2_mark_pmc_header)
+    MarkSweep_GC      *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    List_Item_Header  *item = Obj2LLH(pmc);
+
+    /* Object was already marked as grey. Or live. Or dead. Skip it */
+    if (PObj_is_live_or_free_TESTALL(pmc) || PObj_constant_TEST(pmc))
+        return;
+
+    /* mark it live */
+    PObj_live_SET(pmc);
+
+    LIST_REMOVE(self->objects, item);
+    LIST_APPEND(self->new_objects, item);
+
+}
+
+/*
+
+=item C<static int gc_ms2_is_pmc_ptr(PARROT_INTERP, void *ptr)>
+
+establish if *ptr is.owned
+
+=cut
+
+*/
+
+static int
+gc_ms2_is_pmc_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+{
+    ASSERT_ARGS(gc_ms2_is_pmc_ptr)
+    MarkSweep_GC      *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    return gc_ms2_is_ptr_owned(interp, ptr, self->pmc_allocator, self->objects);
+}
+
+/*
+
+=item C<static void gc_ms2_sweep_pmc_cb(PARROT_INTERP, PObj *obj)>
+
+destroy pmc *obj
+
+=cut
+
+*/
+
+static void
+gc_ms2_sweep_pmc_cb(PARROT_INTERP, ARGIN(PObj *obj))
+{
+    ASSERT_ARGS(gc_ms2_sweep_pmc_cb)
+    PMC *pmc = (PMC *)obj;
+    Parrot_pmc_destroy(interp, pmc);
+}
+
+/*
+=item C<gc_ms2_allocate_string_header()>
+
+=item C<gc_ms2_free_string_header()>
+
+=item C<static Buffer* gc_ms2_allocate_buffer_header(PARROT_INTERP, size_t
+size)>
+
+=item C<static void gc_ms2_free_buffer_header(PARROT_INTERP, Buffer *s, size_t
+size)>
+
+Allocate/free string/buffer headers.
+
+*/
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static STRING*
+gc_ms2_allocate_string_header(PARROT_INTERP, SHIM(UINTVAL flags))
+{
+    ASSERT_ARGS(gc_ms2_allocate_string_header)
+    MarkSweep_GC     *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    List_Item_Header *ptr;
+    STRING           *ret;
+
+    gc_ms2_maybe_mark_and_sweep(interp);
+
+    /* Increase used memory. Not precisely accurate due Pool_Allocator paging */
+    ++interp->gc_sys->stats.header_allocs_since_last_collect;
+    interp->gc_sys->stats.memory_allocated      += sizeof (STRING);
+    interp->gc_sys->stats.mem_used_last_collect += sizeof (STRING);
+
+    ptr = (List_Item_Header *)Parrot_gc_pool_allocate(interp,
+            self->string_allocator);
+    LIST_APPEND(self->strings, ptr);
+
+    ret = LLH2Obj_typed(ptr, STRING);
+    memset(ret, 0, sizeof (STRING));
+    return ret;
+}
+
+static void
+gc_ms2_free_string_header(PARROT_INTERP, ARGFREE(STRING *s))
+{
+    ASSERT_ARGS(gc_ms2_free_string_header)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    if (s) {
+        if (PObj_on_free_list_TEST(s))
+            return;
+        Parrot_list_remove(interp, self->strings, Obj2LLH(s));
+        PObj_on_free_list_SET(s);
+
+        if (Buffer_bufstart(s) && !PObj_external_TEST(s))
+            Parrot_gc_str_free_buffer_storage(interp, &self->string_gc, (Buffer *)s);
+
+        Parrot_gc_pool_free(interp, self->string_allocator, Obj2LLH(s));
+
+        --interp->gc_sys->stats.header_allocs_since_last_collect;
+        interp->gc_sys->stats.memory_allocated      -= sizeof (STRING);
+        interp->gc_sys->stats.mem_used_last_collect -= sizeof (STRING);
+    }
+}
+
+PARROT_MALLOC
+PARROT_CAN_RETURN_NULL
+static Buffer*
+gc_ms2_allocate_buffer_header(PARROT_INTERP, SHIM(size_t size))
+{
+    ASSERT_ARGS(gc_ms2_allocate_buffer_header)
+    return (Buffer*)gc_ms2_allocate_string_header(interp, 0);
+}
+
+static void
+gc_ms2_free_buffer_header(PARROT_INTERP, ARGFREE(Buffer *s), SHIM(size_t size))
+{
+    ASSERT_ARGS(gc_ms2_free_buffer_header)
+    gc_ms2_free_string_header(interp, (STRING*)s);
+}
+
+/*
+
+=item C<static int gc_ms2_is_string_ptr(PARROT_INTERP, void *ptr)>
+
+establish if string *ptr is owned
+
+=cut
+
+*/
+
+static int
+gc_ms2_is_string_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
+{
+    ASSERT_ARGS(gc_ms2_is_string_ptr)
+    MarkSweep_GC      *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    return gc_ms2_is_ptr_owned(interp, ptr, self->string_allocator, self->strings);
+}
+
+/*
+
+item C<void gc_ms_allocate_string_storage(PARROT_INTERP, STRING *str, size_t
+size)>
+
+=item C<void gc_ms_reallocate_string_storage(PARROT_INTERP, STRING *str, size_t
+size)>
+
+=item C<void gc_ms_allocate_buffer_storage(PARROT_INTERP, Buffer *str, size_t
+size)>
+
+=item C<void gc_ms_reallocate_buffer_storage(PARROT_INTERP, Buffer *str, size_t
+size)>
+
+Functions for allocating strings/buffers storage.
+
+=cut
+*/
+
+static void
+gc_ms2_allocate_string_storage(PARROT_INTERP, ARGIN(STRING *str), size_t size)
+{
+    ASSERT_ARGS(gc_ms2_allocate_string_storage)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    Parrot_gc_str_allocate_string_storage(interp, &self->string_gc, str, size);
+    interp->gc_sys->stats.mem_used_last_collect += size;
+}
+
+static void
+gc_ms2_reallocate_string_storage(PARROT_INTERP, ARGIN(STRING *str), size_t size)
+{
+    ASSERT_ARGS(gc_ms2_reallocate_string_storage)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    Parrot_gc_str_reallocate_string_storage(interp, &self->string_gc, str, size);
+    interp->gc_sys->stats.mem_used_last_collect += size;
+}
+
+static void
+gc_ms2_allocate_buffer_storage(PARROT_INTERP, ARGIN(Buffer *str), size_t size)
+{
+    ASSERT_ARGS(gc_ms2_allocate_buffer_storage)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    Parrot_gc_str_allocate_buffer_storage(interp, &self->string_gc, str, size);
+    interp->gc_sys->stats.mem_used_last_collect += size;
+}
+
+static void
+gc_ms2_reallocate_buffer_storage(PARROT_INTERP, ARGIN(Buffer *str), size_t size)
+{
+    ASSERT_ARGS(gc_ms2_reallocate_buffer_storage)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    Parrot_gc_str_reallocate_buffer_storage(interp, &self->string_gc, str, size);
+    interp->gc_sys->stats.mem_used_last_collect += size;
+}
+
+/*
+
+=item C<static void gc_ms2_mark_pobj_header(PARROT_INTERP, PObj * obj)>
+
+Mark PObj as live.
+
+=cut
+
+*/
+
+static void
+gc_ms2_mark_pobj_header(PARROT_INTERP, ARGIN_NULLOK(PObj * obj))
+{
+    ASSERT_ARGS(gc_ms2_mark_pobj_header)
+    if (obj) {
+        if (PObj_is_PMC_TEST(obj))
+            gc_ms2_mark_pmc_header(interp, (PMC *)obj);
+        else
+            PObj_live_SET(obj);
+    }
+}
+
+/*
+
+=item C<static void gc_ms2_sweep_string_cb(PARROT_INTERP, PObj *obj)>
+
+destroy string *obj
+
+=cut
+
+*/
+
+static void
+gc_ms2_sweep_string_cb(PARROT_INTERP, ARGIN(PObj *obj))
+{
+    ASSERT_ARGS(gc_ms2_sweep_string_cb)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    Buffer       *str  = (Buffer *)obj;
+    /* Compact string pool here. Or get rid of "shared buffers" and just free storage */
+    if (Buffer_bufstart(str) && !PObj_external_TEST(str))
+        Parrot_gc_str_free_buffer_storage(interp, &self->string_gc, str);
+}
+
+
+/*
+
+=item C<static void gc_ms2_iterate_live_strings(PARROT_INTERP,
+string_iterator_callback callback, void *data)>
+
+Iterate over live string invoking callback for each of them. Used during
+compacting of string pool.
+
+=cut
+*/
+static void
+gc_ms2_iterate_live_strings(PARROT_INTERP,
+        string_iterator_callback callback,
+        ARGIN_NULLOK(void *data))
+{
+    ASSERT_ARGS(gc_ms2_iterate_live_strings)
+
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    List_Item_Header *tmp = self->strings->first;
+
+    while (tmp) {
+        Buffer *b = LLH2Obj_typed(tmp, Buffer);
+        callback(interp, b, data);
+        tmp = tmp->next;
+    }
+}
+
+
+static void
+gc_ms2_mark_and_sweep(PARROT_INTERP, UINTVAL flags)
+{
+    ASSERT_ARGS(gc_ms2_mark_and_sweep)
+    MarkSweep_GC      *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    List_Item_Header *tmp;
+    Linked_List      *list;
+    size_t            counter;
+    UNUSED(flags);
+
+    /* GC is blocked */
+    if (self->gc_mark_block_level)
+        return;
+
+    if (flags & GC_finish_FLAG) {
+        /* Ignore it. Will cleanup in gc_ms2_finalize */
+        return;
+    }
+
+    /* Ignore calls from String GC. We know better when to trigger GC */
+    if (flags & GC_strings_cb_FLAG) {
+        return;
+    }
+
+    ++self->gc_mark_block_level;
+
+    /* Allocate list for gray objects */
+    self->new_objects = Parrot_list_new(interp);
+
+    /* Trace "roots" into new_objects */
+    gc_ms2_mark_pmc_header(interp, PMCNULL);
+
+    Parrot_gc_trace_root(interp, NULL, GC_TRACE_FULL);
+    if (interp->pdb && interp->pdb->debugger) {
+        Parrot_gc_trace_root(interp->pdb->debugger, NULL, (Parrot_gc_trace_type)0);
+    }
+
+    /* new_objects are "gray" untill fully marked */
+    /* Additional gray objects will appened to new_objects list */
+    /* So, iterate over them in one go */
+    tmp = self->new_objects->first;
+    while (tmp) {
+        PMC *pmc = LLH2Obj_typed(tmp, PMC);
+        /* if object is a PMC and contains buffers or PMCs, then attach the PMC
+         * to the chained mark list. */
+        if (PObj_is_special_PMC_TEST(pmc)) {
+            if (PObj_custom_mark_TEST(pmc))
+                VTABLE_mark(interp, pmc);
+        }
+
+        if (PMC_metadata(pmc))
+            Parrot_gc_mark_PMC_alive(interp, PMC_metadata(pmc));
+
+        tmp = tmp->next;
+    }
+
+    /* At this point of time new_objects contains only live PMCs */
+    /* objects contains "dead" or "constant" PMCs */
+    /* sweep of new_objects will repaint them white */
+    /* sweep of objects will destroy dead objects leaving only "constant" */
+    gc_ms2_sweep_pool(interp, self->pmc_allocator, self->new_objects, gc_ms2_sweep_pmc_cb);
+    gc_ms2_sweep_pool(interp, self->pmc_allocator, self->objects, gc_ms2_sweep_pmc_cb);
+    gc_ms2_sweep_pool(interp, self->string_allocator, self->strings, gc_ms2_sweep_string_cb);
+
+    /* Replace objects with new_objects. Ignoring "constant" one */
+    list = self->objects;
+    self->objects = self->new_objects;
+    Parrot_list_destroy(interp, list);
+
+    interp->gc_sys->stats.header_allocs_since_last_collect = 0;
+    interp->gc_sys->stats.mem_used_last_collect            = 0;
+    interp->gc_sys->stats.gc_mark_runs++;
+    self->gc_mark_block_level--;
+    /* We swept all dead objects */
+    self->num_early_gc_PMCs                      = 0;
+
+    gc_ms2_compact_memory_pool(interp);
+}
+
+
+
+/*
+=item C<static void gc_ms2_sweep_pool(PARROT_INTERP, Pool_Allocator *pool,
+Linked_List *list, sweep_cb callback)>
+
+Helper function to sweep pool.
+
+=cut
+*/
+static void
+gc_ms2_sweep_pool(PARROT_INTERP,
+        ARGIN(Pool_Allocator *pool),
+        ARGIN(Linked_List *list),
+        ARGIN(sweep_cb callback))
+{
+    ASSERT_ARGS(gc_ms2_sweep_pool)
+    List_Item_Header *tmp = list->first;
+    while (tmp) {
+        List_Item_Header *next = tmp->next;
+        PObj             *obj  = LLH2Obj_typed(tmp, PObj);
+        if (PObj_live_TEST(obj)) {
+            /* Paint live objects white */
+            PObj_live_CLEAR(obj);
+        }
+        else if (!PObj_constant_TEST(obj)) {
+            PObj_on_free_list_SET(obj);
+            LIST_REMOVE(list, tmp);
+
+            callback(interp, obj);
+
+            Parrot_gc_pool_free(interp, pool, tmp);
+        }
+        tmp = next;
+    }
+}
+
+
+
+/*
+=item C<static int gc_ms2_is_ptr_owned(PARROT_INTERP, void *ptr, Pool_Allocator
+*pool, Linked_List *list)>
+
+Helper function to check that we own PObj
+
+=cut
+*/
+
+static int
+gc_ms2_is_ptr_owned(PARROT_INTERP, ARGIN_NULLOK(void *ptr),
+    ARGIN(Pool_Allocator *pool), ARGIN(Linked_List *list))
+{
+    ASSERT_ARGS(gc_ms2_is_ptr_owned)
+    MarkSweep_GC     *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    List_Item_Header *item = Obj2LLH(ptr);
+    PObj             *obj  = (PObj *)ptr;
+
+    if (!obj || !item)
+        return 0;
+
+    if (!Parrot_gc_pool_is_owned(interp, pool, item))
+        return 0;
+
+    /* black or white objects marked already. */
+    if (PObj_is_live_or_free_TESTALL(obj))
+        return 0;
+
+    /* Pool.is_owned isn't precise enough (yet) */
+    if (Parrot_list_contains(interp, list, item))
+        return 1;
+
+    return 0;
+}
+
+
+/*
+
+=item C<static void gc_ms2_block_GC_mark(PARROT_INTERP)>
+
+Blocks the GC from performing its mark phase.
+
+=item C<static void gc_ms2_unblock_GC_mark(PARROT_INTERP)>
+
+Unblocks the GC mark.
+
+=item C<static void gc_ms2_block_GC_sweep(PARROT_INTERP)>
+
+Blocks the GC from performing its sweep phase.
+
+=item C<static void gc_ms2_unblock_GC_sweep(PARROT_INTERP)>
+
+Unblocks GC sweep.
+
+=item C<static unsigned int gc_ms2_is_blocked_GC_mark(PARROT_INTERP)>
+
+Determines if the GC mark is currently blocked.
+
+=item C<static unsigned int gc_ms2_is_blocked_GC_sweep(PARROT_INTERP)>
+
+Determines if the GC sweep is currently blocked.
+
+=cut
+
+*/
+
+static void
+gc_ms2_block_GC_mark(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_block_GC_mark)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    ++self->gc_mark_block_level;
+    Parrot_shared_gc_block(interp);
+}
+
+static void
+gc_ms2_unblock_GC_mark(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_unblock_GC_mark)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    if (self->gc_mark_block_level) {
+        --self->gc_mark_block_level;
+        Parrot_shared_gc_unblock(interp);
+    }
+}
+
+static void
+gc_ms2_block_GC_sweep(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_block_GC_sweep)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    ++self->gc_sweep_block_level;
+}
+
+static void
+gc_ms2_unblock_GC_sweep(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_unblock_GC_sweep)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    if (self->gc_sweep_block_level)
+        --self->gc_sweep_block_level;
+}
+
+static unsigned int
+gc_ms2_is_blocked_GC_mark(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_is_blocked_GC_mark)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    return self->gc_mark_block_level;
+}
+
+static unsigned int
+gc_ms2_is_blocked_GC_sweep(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_is_blocked_GC_sweep)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    return self->gc_sweep_block_level;
+}
+
+
+
+/*
+
+=item C<static void * gc_ms2_allocate_memory_chunk(PARROT_INTERP, size_t size)>
+
+=item C<static void * gc_ms2_reallocate_memory_chunk(PARROT_INTERP, void *from,
+size_t size)>
+
+=item C<static void * gc_ms2_allocate_memory_chunk_zeroed(PARROT_INTERP, size_t
+size)>
+
+=item C<static void * gc_ms2_reallocate_memory_chunk_zeroed(PARROT_INTERP, void
+*data, size_t newsize, size_t oldsize)>
+
+=item C<static void gc_ms2_free_memory_chunk(PARROT_INTERP, void *data)>
+
+=item C<static void failed_allocation(unsigned int line, unsigned long size)>
+
+TODO Write docu.
+
+*/
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void *
+gc_ms2_allocate_memory_chunk(SHIM_INTERP, size_t size)
+{
+    ASSERT_ARGS(gc_ms2_allocate_memory_chunk)
+    void * const ptr = malloc(size);
+#ifdef DETAIL_MEMORY_DEBUG
+    fprintf(stderr, "Allocated %i at %p\n", size, ptr);
+#endif
+    if (!ptr)
+        PANIC_OUT_OF_MEM(size);
+    return ptr;
+}
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void *
+gc_ms2_reallocate_memory_chunk(SHIM_INTERP, ARGFREE(void *from), size_t size)
+{
+    ASSERT_ARGS(gc_ms2_reallocate_memory_chunk)
+    void *ptr;
+#ifdef DETAIL_MEMORY_DEBUG
+    fprintf(stderr, "Freed %p (realloc -- %i bytes)\n", from, size);
+#endif
+    if (from)
+        ptr = realloc(from, size);
+    else
+        ptr = calloc(1, size);
+#ifdef DETAIL_MEMORY_DEBUG
+    fprintf(stderr, "Allocated %i at %p\n", size, ptr);
+#endif
+    if (!ptr)
+        PANIC_OUT_OF_MEM(size);
+    return ptr;
+}
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void *
+gc_ms2_allocate_memory_chunk_zeroed(SHIM_INTERP, size_t size)
+{
+    ASSERT_ARGS(gc_ms2_allocate_memory_chunk_zeroed)
+    void * const ptr = calloc(1, (size_t)size);
+#ifdef DETAIL_MEMORY_DEBUG
+    fprintf(stderr, "Allocated %i at %p\n", size, ptr);
+#endif
+    if (!ptr)
+        PANIC_OUT_OF_MEM(size);
+    return ptr;
+}
+
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void *
+gc_ms2_reallocate_memory_chunk_zeroed(SHIM_INTERP, ARGFREE(void *data),
+        size_t newsize, size_t oldsize)
+{
+    ASSERT_ARGS(gc_ms2_reallocate_memory_chunk_zeroed)
+    void * const ptr = realloc(data, newsize);
+    if (newsize > oldsize)
+        memset((char*)ptr + oldsize, 0, newsize - oldsize);
+    return ptr;
+}
+
+static void
+gc_ms2_free_memory_chunk(SHIM_INTERP, ARGFREE(void *data))
+{
+    ASSERT_ARGS(gc_ms2_free_memory_chunk)
+#ifdef DETAIL_MEMORY_DEBUG
+    fprintf(stderr, "Freed %p\n", data);
+#endif
+    if (data)
+        free(data);
+}
+
+PARROT_DOES_NOT_RETURN
+static void
+failed_allocation(unsigned int line, unsigned long size)
+{
+    ASSERT_ARGS(failed_allocation)
+    fprintf(stderr, "Failed allocation of %lu bytes\n", size);
+    do_panic(NULL, "Out of mem", __FILE__, line);
+}
+
+
+/*
+
+=item C<static void gc_ms2_pmc_needs_early_collection(PARROT_INTERP, PMC *pmc)>
+
+Mark a PMC as needing timely destruction
+
+=cut
+
+*/
+
+static void
+gc_ms2_pmc_needs_early_collection(PARROT_INTERP, ARGMOD(PMC *pmc))
+{
+    ASSERT_ARGS(gc_ms2_pmc_needs_early_collection)
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+    ++self->num_early_gc_PMCs;
+}
+
+/*
+
+=item C<static void gc_ms2_maybe_mark_and_sweep(PARROT_INTERP)>
+
+Maybe M&S. Depends on total allocated memory, memory allocated since last alloc
+and phase of the Moon.
+
+=cut
+
+*/
+static void
+gc_ms2_maybe_mark_and_sweep(PARROT_INTERP)
+{
+    ASSERT_ARGS(gc_ms2_maybe_mark_and_sweep)
+
+    MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+
+    /* Collect every 256M. Hardcode for now. Will be configured via CLI */
+    if (interp->gc_sys->stats.mem_used_last_collect > self->gc_threshold) {
+        gc_ms2_mark_and_sweep(interp, 0);
+    }
+}
+
+/*
+
+=item C<static size_t gc_ms2_count_used_string_memory(PARROT_INTERP, Linked_List
+*list)>
+
+find amount of used string memory
+
+=cut
+
+*/
+
+static size_t
+gc_ms2_count_used_string_memory(PARROT_INTERP, ARGIN(Linked_List *list))
+{
+    ASSERT_ARGS(gc_ms2_count_used_string_memory)
+
+    size_t total_amount = 0;
+
+    List_Item_Header *tmp = list->first;
+    while (tmp) {
+        List_Item_Header *next = tmp->next;
+        PObj             *obj  = LLH2Obj_typed(tmp, PObj);
+        STRING           *str  = (STRING*)obj;
+
+        /* Header size */
+        total_amount += sizeof (List_Item_Header)
+                        + sizeof (STRING*);
+        total_amount += str->bufused;
+
+        tmp = next;
+    }
+
+    return total_amount;
+}
+
+/*
+
+=item C<static size_t gc_ms2_count_used_pmc_memory(PARROT_INTERP, Linked_List
+*list)>
+
+find amount of used pmc memory
+
+=cut
+
+*/
+
+static size_t
+gc_ms2_count_used_pmc_memory(PARROT_INTERP, ARGIN(Linked_List *list))
+{
+    ASSERT_ARGS(gc_ms2_count_used_pmc_memory)
+
+    size_t total_amount = 0;
+
+    List_Item_Header *tmp = list->first;
+    while (tmp) {
+        List_Item_Header *next = tmp->next;
+        PMC              *obj  = LLH2Obj_typed(tmp, PMC);
+
+        /* Header size */
+        total_amount += sizeof (List_Item_Header)
+                        + sizeof (PMC*);
+        total_amount += obj->vtable->attr_size;
+
+        tmp = next;
+    }
+
+    return total_amount;
+}
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Modified: trunk/src/gc/gc_private.h
==============================================================================
--- trunk/src/gc/gc_private.h	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/gc/gc_private.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -17,6 +17,7 @@
 #define PARROT_GC_PRIVATE_H_GUARD
 
 #include "parrot/settings.h"
+#include "variable_size_pool.h"
 
 #if ! DISABLE_GC_DEBUG
 /* Set when walking the system stack. Defined in src/gc/system.c */
@@ -79,8 +80,10 @@
 
 
 typedef enum _gc_sys_type_enum {
-    MS,  /*mark and sweep*/
-    INF  /*infinite memory core*/
+    MS,  /* mark and sweep */
+    INF, /* infinite memory core */
+    TMS, /* tricolor mark and sweep */
+    MS2
 } gc_sys_type_enum;
 
 /* how often to skip a full GC when this pool has nothing free */
@@ -91,6 +94,38 @@
     GC_NEVER_SKIP       /* unused */
 } gc_skip_type_enum;
 
+/** statistics for GC **/
+typedef struct GC_Statistics {
+    size_t  gc_mark_runs;       /* Number of times we've done a mark run */
+    size_t  gc_lazy_mark_runs;  /* Number of successful lazy mark runs */
+    size_t  gc_collect_runs;    /* Number of times we've done a memory
+                                   compaction */
+    size_t  mem_allocs_since_last_collect;      /* The number of memory
+                                                 * allocations from the
+                                                 * system since the last
+                                                 * compaction run */
+    size_t  header_allocs_since_last_collect;   /* The size of header
+                                                 * blocks allocated from
+                                                 * the system since the last
+                                                 * GC run */
+    size_t  memory_allocated;     /* The total amount of memory allocated
+                                   * in fixed and variable size pools.
+                                   * Doesn't count memory for internal
+                                   * structures */
+    size_t  memory_used;          /* The total amount of memory used
+                                   * in fixed and variable size
+                                   * pools. Also includes memory in
+                                   * variable size pools that has been
+                                   * freed but can only be reclaimed
+                                   * by a GC run */
+    size_t  mem_used_last_collect;    /* The total amount of
+                                       * memory used after
+                                       * the last GC run */
+    UINTVAL memory_collected;     /* Total amount of memory copied
+                                     during collection */
+
+} GC_Statistics;
+
 /* Callback for live string. Use Buffer for now... */
 typedef void (*string_iterator_callback)(PARROT_INTERP, Buffer *str, void *data);
 
@@ -115,10 +150,15 @@
     void (*free_pmc_header)(PARROT_INTERP, PMC *);
 
     STRING* (*allocate_string_header)(PARROT_INTERP, UINTVAL flags);
-    void (*free_string_header)(PARROT_INTERP, STRING*);
+    void    (*free_string_header)(PARROT_INTERP, STRING*);
 
     Buffer* (*allocate_bufferlike_header)(PARROT_INTERP, size_t size);
-    void (*free_bufferlike_header)(PARROT_INTERP, Buffer*, size_t size);
+    void    (*free_bufferlike_header)(PARROT_INTERP, Buffer*, size_t size);
+
+    int  (*is_pmc_ptr)(PARROT_INTERP, void*);
+    int  (*is_string_ptr)(PARROT_INTERP, void*);
+    void (*mark_pobj_header)(PARROT_INTERP, PObj*);
+    void (*mark_pmc_header)(PARROT_INTERP, PMC *);
 
     void* (*allocate_pmc_attributes)(PARROT_INTERP, PMC *);
     void (*free_pmc_attributes)(PARROT_INTERP, PMC *);
@@ -154,50 +194,19 @@
     /* Iterate over _live_ strings. Used for string pool compacting */
     void (*iterate_live_strings)(PARROT_INTERP, string_iterator_callback callback, void *data);
 
+    /* Statistic for GC */
+    struct GC_Statistics stats;
+
     /*Function hooks that GC systems can CHOOSE to provide if they need them
      *These will be called via the GC API functions Parrot_gc_func_name
      *e.g. read barrier && write barrier hooks can go here later ...*/
 
-    /* Holds system-specific data structures
-     * unused right now, but this is where it should go if we need them ...
-      union {
-      } gc_private;
-     */
+    /* Holds system-specific data structures */
+    void * gc_private;
 } GC_Subsystem;
 
 
 
-/* This header structure describes a block of memory that is part of a
-   variable-size pool. The allocatable memory follows the header. */
-
-typedef struct Memory_Block {
-    size_t free;                /* Remaining free space. */
-    size_t size;                /* Size of memory. */
-    struct Memory_Block *prev;  /* Pointer to previous block. */
-    struct Memory_Block *next;  /* Pointer to next block. */
-    char *start;                /* Pointer to start of memory. */
-    char *top;                  /* Pointer to free space in memory. */
-    size_t freed;               /* Amount of freed memory.
-                                   Used in compact_pool */
-} Memory_Block;
-
-/* This structure describes a variable-size memory pool. Various such pools
-   hang off the Memory_Pools root structure. */
-
-typedef struct Variable_Size_Pool {
-    Memory_Block *top_block;            /* Pointer to most recent memory block. */
-                                        /* Pool compactor, or NULL. */
-    void (*compact)(PARROT_INTERP, struct Memory_Pools *,
-                                   struct Variable_Size_Pool *);
-    size_t minimum_block_size;          /* Minimum allocation size, to
-                                           prevent fragmentation. */
-    size_t total_allocated;             /* Total bytes allocated to this pool. */
-    size_t guaranteed_reclaimable;      /* Bytes that can definitely be reclaimed. */
-    size_t possibly_reclaimable;        /* Bytes that can possibly be reclaimed
-                                           (above plus COW-freed bytes). */
-    FLOATVAL reclaim_factor;            /* Minimum percentage we will reclaim. */
-} Variable_Size_Pool;
-
 /* This header structure describes an arena: a block of memory that is part of a
    fixed-sized pool. The arena has enough memory for 'total_objects' objects
    of a particular size specified in the pool. */
@@ -296,64 +305,18 @@
                                                    compacted */
 } String_GC;
 
-/* This structure acts as the root for all the various memory pools:
-   variable-sized, fixed-size, and PMC attributes. It also contains
-   various GC-related items. It hangs off the Interp structure. */
-
 typedef struct Memory_Pools {
-    /* Pointers to pools */
-    String_GC            string_gc;             /* TEMPORARY */
-                                                /* String GC susbsytem pointer */
-
-    Fixed_Size_Pool     *string_header_pool;    /* String header pool. */
-    Fixed_Size_Pool     *pmc_pool;              /* PMC object pool. */
-    Fixed_Size_Pool     *constant_pmc_pool;     /* And one for constant PMCs. */
-    Fixed_Size_Pool     *constant_string_header_pool; /* And a constant string
-                                                         header pool. */
-
-    Fixed_Size_Pool    **sized_header_pools;    /* Vector of pools for other
-                                                  fixed-size headers. */
-    size_t               num_sized;             /* Length of that vector. */
-
-    PMC_Attribute_Pool **attrib_pools;          /* Vector of pools for PMC
-                                                   attributes. */
-    size_t               num_attribs;           /* Length of that vector. */
+    String_GC            string_gc;
 
-    /* statistics for GC */
-    size_t  gc_mark_runs;       /* Number of times we've done a mark run */
-    size_t  gc_lazy_mark_runs;  /* Number of successful lazy mark runs */
-    size_t  gc_collect_runs;    /* Number of times we've done a memory
-                                   compaction */
-    size_t  mem_allocs_since_last_collect;      /* The number of memory
-                                                 * allocations from the
-                                                 * system since the last
-                                                 * compaction run */
-    size_t  header_allocs_since_last_collect;   /* The size of header
-                                                 * blocks allocated from
-                                                 * the system since the last
-                                                 * GC run */
-    size_t  memory_allocated;     /* The total amount of memory allocated
-                                   * in fixed and variable size pools.
-                                   * Doesn't count memory for internal
-                                   * structures */
-    size_t  memory_used;          /* The total amount of memory used
-                                   * in fixed and variable size
-                                   * pools. Also includes memory in
-                                   * variable size pools that has been
-                                   * freed but can only be reclaimed
-                                   * by a GC run */
-    size_t  mem_used_last_collect;    /* The total amount of
-                                       * memory used after
-                                       * the last GC run */
-    UINTVAL memory_collected;     /* Total amount of memory copied
-                                     during collection */
-    UINTVAL num_early_gc_PMCs;    /* how many PMCs want immediate destruction */
-    UINTVAL num_early_PMCs_seen;  /* how many such PMCs has GC seen */
-    PMC    *gc_mark_start;        /* first PMC marked during a GC run */
-    PMC    *gc_mark_ptr;          /* last PMC marked during a GC run */
-    PMC    *gc_trace_ptr;         /* last PMC trace_children was called on */
-    int     lazy_gc;              /* flag that indicates whether we should stop
-                                     when we've seen all impatient PMCs */
+    Fixed_Size_Pool     *string_header_pool;
+    Fixed_Size_Pool     *pmc_pool;
+    Fixed_Size_Pool     *constant_pmc_pool;
+    Fixed_Size_Pool     *constant_string_header_pool;
+    Fixed_Size_Pool    **sized_header_pools;
+    size_t               num_sized;
+
+    PMC_Attribute_Pool **attrib_pools;
+    size_t               num_attribs;
 
     /* GC blocking */
     UINTVAL gc_mark_block_level;  /* How many outstanding GC block
@@ -361,19 +324,28 @@
     UINTVAL gc_sweep_block_level; /* How many outstanding GC block
                                      requests are there? */
 
+    PMC    *gc_mark_start;        /* first PMC marked during a GC run */
+    PMC    *gc_mark_ptr;          /* last PMC marked during a GC run */
+    PMC    *gc_trace_ptr;         /* last PMC trace_children was called on */
+    int     lazy_gc;              /* flag that indicates whether we should stop
+                                     when we've seen all impatient PMCs */
+    UINTVAL num_early_gc_PMCs;    /* how many PMCs want immediate destruction */
+    UINTVAL num_early_PMCs_seen;  /* how many such PMCs has GC seen */
+
+    /* private data for the GC subsystem */
+    void *gc_private;             /* GC subsystem data */
 } Memory_Pools;
 
 
 /* HEADERIZER BEGIN: src/gc/system.c */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
-void trace_system_areas(PARROT_INTERP, ARGIN(const Memory_Pools *mem_pools))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
+void trace_system_areas(PARROT_INTERP,
+    ARGIN_NULLOK(const Memory_Pools *mem_pools))
+        __attribute__nonnull__(1);
 
 #define ASSERT_ARGS_trace_system_areas __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(mem_pools))
+       PARROT_ASSERT_ARG(interp))
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/gc/system.c */
 
@@ -430,11 +402,12 @@
         FUNC_MODIFIES(*pool)
         FUNC_MODIFIES(*arena);
 
-void Parrot_append_arena_in_pool(SHIM_INTERP,
+void Parrot_append_arena_in_pool(PARROT_INTERP,
     ARGMOD(Memory_Pools *mem_pools),
     ARGMOD(Fixed_Size_Pool *pool),
     ARGMOD(Fixed_Size_Arena *new_arena),
     size_t size)
+        __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(3)
         __attribute__nonnull__(4)
@@ -460,10 +433,9 @@
         FUNC_MODIFIES(*pool);
 
 int Parrot_gc_trace_root(PARROT_INTERP,
-    ARGMOD(Memory_Pools *mem_pools),
+    ARGMOD_NULLOK(Memory_Pools *mem_pools),
     Parrot_gc_trace_type trace)
         __attribute__nonnull__(1)
-        __attribute__nonnull__(2)
         FUNC_MODIFIES(*mem_pools);
 
 #define ASSERT_ARGS_contained_in_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -487,7 +459,8 @@
        PARROT_ASSERT_ARG(pool) \
     , PARROT_ASSERT_ARG(arena))
 #define ASSERT_ARGS_Parrot_append_arena_in_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools) \
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(mem_pools) \
     , PARROT_ASSERT_ARG(pool) \
     , PARROT_ASSERT_ARG(new_arena))
 #define ASSERT_ARGS_Parrot_gc_clear_live_bits __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -499,8 +472,7 @@
     , PARROT_ASSERT_ARG(mem_pools) \
     , PARROT_ASSERT_ARG(pool))
 #define ASSERT_ARGS_Parrot_gc_trace_root __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(mem_pools))
+       PARROT_ASSERT_ARG(interp))
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/gc/mark_sweep.c */
 
@@ -592,6 +564,10 @@
         __attribute__nonnull__(2)
         FUNC_MODIFIES(*pmc);
 
+void gc_ms_mark_pmc_header(PARROT_INTERP, ARGMOD_NULLOK(PMC *obj))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*obj);
+
 void gc_ms_pmc_needs_early_collection(PARROT_INTERP, ARGMOD(PMC *pmc))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
@@ -609,6 +585,12 @@
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
+size_t Parrot_gc_get_info(PARROT_INTERP,
+    Interpinfo_enum which,
+    ARGIN(GC_Statistics *stats))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(3);
+
 void Parrot_gc_ms_init(PARROT_INTERP)
         __attribute__nonnull__(1);
 
@@ -632,6 +614,8 @@
 #define ASSERT_ARGS_gc_ms_free_pmc_attributes __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(pmc))
+#define ASSERT_ARGS_gc_ms_mark_pmc_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_gc_ms_pmc_needs_early_collection \
      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
@@ -644,6 +628,9 @@
      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_Parrot_gc_get_info __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(stats))
 #define ASSERT_ARGS_Parrot_gc_ms_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_Parrot_gc_ms_needed __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -662,6 +649,16 @@
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/gc/gc_inf.c */
 
+/* HEADERIZER BEGIN: src/gc/gc_ms2.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+void Parrot_gc_ms2_init(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+#define ASSERT_ARGS_Parrot_gc_ms2_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/gc/gc_ms2.c */
 
 /* HEADERIZER BEGIN: src/gc/string_gc.c */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */

Modified: trunk/src/gc/mark_sweep.c
==============================================================================
--- trunk/src/gc/mark_sweep.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/gc/mark_sweep.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -155,7 +155,7 @@
 
 int
 Parrot_gc_trace_root(PARROT_INTERP,
-        ARGMOD(Memory_Pools *mem_pools),
+        ARGMOD_NULLOK(Memory_Pools *mem_pools),
         Parrot_gc_trace_type trace)
 {
     ASSERT_ARGS(Parrot_gc_trace_root)
@@ -170,7 +170,7 @@
     }
 
     /* We have to start somewhere; the interpreter globals is a good place */
-    if (!mem_pools->gc_mark_start) {
+    if (mem_pools && !mem_pools->gc_mark_start) {
         mem_pools->gc_mark_start
             = mem_pools->gc_mark_ptr
             = interp->iglobals;
@@ -229,8 +229,9 @@
     /* quick check to see if we have already marked all impatient PMCs. If we
        have, return 0 and exit here. This will alert other parts of the GC
        that if we are in a lazy run we can just stop it. */
-    if (mem_pools->lazy_gc
-    &&  mem_pools->num_early_PMCs_seen >= mem_pools->num_early_gc_PMCs)
+    if (mem_pools
+        && mem_pools->lazy_gc
+        && mem_pools->num_early_PMCs_seen >= mem_pools->num_early_gc_PMCs)
         return 0;
 
     return 1;
@@ -455,7 +456,7 @@
 */
 
 void
-Parrot_append_arena_in_pool(SHIM_INTERP,
+Parrot_append_arena_in_pool(PARROT_INTERP,
         ARGMOD(Memory_Pools *mem_pools),
         ARGMOD(Fixed_Size_Pool *pool),
         ARGMOD(Fixed_Size_Arena *new_arena), size_t size)
@@ -480,8 +481,8 @@
         new_arena->prev->next = new_arena;
 
     pool->last_Arena = new_arena;
-    mem_pools->header_allocs_since_last_collect += size;
-    mem_pools->memory_allocated += size;
+    interp->gc_sys->stats.header_allocs_since_last_collect += size;
+    interp->gc_sys->stats.memory_allocated += size;
 }
 
 /*

Modified: trunk/src/gc/string_gc.c
==============================================================================
--- trunk/src/gc/string_gc.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/gc/string_gc.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -21,7 +21,7 @@
 #include "parrot/parrot.h"
 #include "gc_private.h"
 
-typedef void (*compact_f) (Interp *, Memory_Pools * const, Variable_Size_Pool *);
+typedef void (*compact_f) (Interp *, GC_Statistics *stats, Variable_Size_Pool *);
 
 #define POOL_SIZE (65536 * 2)
 
@@ -48,14 +48,14 @@
         __attribute__nonnull__(2);
 
 static void alloc_new_block(
-     ARGMOD(Memory_Pools *mem_pools),
+     ARGMOD(GC_Statistics *stats),
     size_t size,
     ARGMOD(Variable_Size_Pool *pool),
     ARGIN(const char *why))
         __attribute__nonnull__(1)
         __attribute__nonnull__(3)
         __attribute__nonnull__(4)
-        FUNC_MODIFIES(*mem_pools)
+        FUNC_MODIFIES(*stats)
         FUNC_MODIFIES(*pool);
 
 PARROT_CANNOT_RETURN_NULL
@@ -65,12 +65,12 @@
         __attribute__nonnull__(2);
 
 static void compact_pool(PARROT_INTERP,
-    ARGMOD(Memory_Pools *mem_pools),
+    ARGMOD(GC_Statistics *stats),
     ARGMOD(Variable_Size_Pool *pool))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(3)
-        FUNC_MODIFIES(*mem_pools)
+        FUNC_MODIFIES(*stats)
         FUNC_MODIFIES(*pool);
 
 static void debug_print_buf(PARROT_INTERP, ARGIN(const Buffer *b))
@@ -79,14 +79,14 @@
 
 static void free_memory_pool(ARGFREE(Variable_Size_Pool *pool));
 static void free_old_mem_blocks(
-     ARGMOD(Memory_Pools *mem_pools),
+     ARGMOD(GC_Statistics *stats),
     ARGMOD(Variable_Size_Pool *pool),
     ARGMOD(Memory_Block *new_block),
     UINTVAL total_size)
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(3)
-        FUNC_MODIFIES(*mem_pools)
+        FUNC_MODIFIES(*stats)
         FUNC_MODIFIES(*pool)
         FUNC_MODIFIES(*new_block);
 
@@ -96,13 +96,13 @@
 PARROT_MALLOC
 PARROT_CANNOT_RETURN_NULL
 static void * mem_allocate(PARROT_INTERP,
-    ARGMOD(Memory_Pools *mem_pools),
+    ARGMOD(GC_Statistics *stats),
     size_t size,
     ARGMOD(Variable_Size_Pool *pool))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(4)
-        FUNC_MODIFIES(*mem_pools)
+        FUNC_MODIFIES(*stats)
         FUNC_MODIFIES(*pool);
 
 static void move_buffer_callback(PARROT_INTERP,
@@ -139,7 +139,7 @@
 #define ASSERT_ARGS_aligned_mem __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(mem))
 #define ASSERT_ARGS_alloc_new_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools) \
+       PARROT_ASSERT_ARG(stats) \
     , PARROT_ASSERT_ARG(pool) \
     , PARROT_ASSERT_ARG(why))
 #define ASSERT_ARGS_buffer_location __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -147,21 +147,21 @@
     , PARROT_ASSERT_ARG(b))
 #define ASSERT_ARGS_compact_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(mem_pools) \
+    , PARROT_ASSERT_ARG(stats) \
     , PARROT_ASSERT_ARG(pool))
 #define ASSERT_ARGS_debug_print_buf __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(b))
 #define ASSERT_ARGS_free_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
 #define ASSERT_ARGS_free_old_mem_blocks __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools) \
+       PARROT_ASSERT_ARG(stats) \
     , PARROT_ASSERT_ARG(pool) \
     , PARROT_ASSERT_ARG(new_block))
 #define ASSERT_ARGS_is_block_almost_full __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(block))
 #define ASSERT_ARGS_mem_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(mem_pools) \
+    , PARROT_ASSERT_ARG(stats) \
     , PARROT_ASSERT_ARG(pool))
 #define ASSERT_ARGS_move_buffer_callback __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
@@ -197,11 +197,11 @@
     ASSERT_ARGS(Parrot_gc_str_initialize)
 
     gc->memory_pool   = new_memory_pool(POOL_SIZE, &compact_pool);
-    alloc_new_block(interp->mem_pools, POOL_SIZE, gc->memory_pool, "init");
+    alloc_new_block(&interp->gc_sys->stats, POOL_SIZE, gc->memory_pool, "init");
 
     /* Constant strings - not compacted */
     gc->constant_string_pool = new_memory_pool(POOL_SIZE, NULL);
-    alloc_new_block(interp->mem_pools, POOL_SIZE, gc->constant_string_pool, "init");
+    alloc_new_block(&interp->gc_sys->stats, POOL_SIZE, gc->constant_string_pool, "init");
 }
 
 /*
@@ -249,7 +249,7 @@
 
     Buffer_bufstart(buffer) = (void *)aligned_mem(buffer,
         (char *)mem_allocate(interp,
-        interp->mem_pools, new_size, gc->memory_pool));
+        &interp->gc_sys->stats, new_size, gc->memory_pool));
 
     /* Save pool used to allocate into buffer header */
     *Buffer_poolptr(buffer) = gc->memory_pool->top_block;
@@ -304,14 +304,14 @@
     &&  (pool->top_block->top  == (char *)Buffer_bufstart(buffer) + old_size)) {
         pool->top_block->free -= needed;
         pool->top_block->top  += needed;
-        interp->mem_pools->memory_used += needed;
+        interp->gc_sys->stats.memory_used += needed;
         Buffer_buflen(buffer)  = newsize;
         return;
     }
 
     copysize = Buffer_buflen(buffer);
 
-    mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
+    mem = (char *)mem_allocate(interp, &interp->gc_sys->stats, new_size, pool);
     mem = aligned_mem(buffer, mem);
 
     /* We shouldn't ever have a 0 from size, but we do. If we can track down
@@ -365,7 +365,7 @@
                 : gc->memory_pool;
 
     new_size = ALIGNED_STRING_SIZE(size);
-    mem      = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
+    mem      = (char *)mem_allocate(interp, &interp->gc_sys->stats, new_size, pool);
     mem     += sizeof (void *);
 
     Buffer_bufstart(str) = str->strstart = mem;
@@ -421,7 +421,7 @@
     &&  pool->top_block->top  == (char *)Buffer_bufstart(str) + old_size) {
         pool->top_block->free -= needed;
         pool->top_block->top  += needed;
-        interp->mem_pools->memory_used += needed;
+        interp->gc_sys->stats.memory_used += needed;
         Buffer_buflen(str) = new_size - sizeof (void *);
         return;
     }
@@ -431,7 +431,7 @@
     /* only copy used memory, not total string buffer */
     copysize = str->bufused;
 
-    mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
+    mem = (char *)mem_allocate(interp, &interp->gc_sys->stats, new_size, pool);
     mem += sizeof (void *);
 
     /* Update Memory_Block usage */
@@ -471,7 +471,7 @@
 Parrot_gc_str_compact_pool(PARROT_INTERP, ARGIN(String_GC *gc))
 {
     ASSERT_ARGS(Parrot_gc_str_compact_pool)
-    compact_pool(interp, interp->mem_pools, gc->memory_pool);
+    compact_pool(interp, &interp->gc_sys->stats, gc->memory_pool);
 }
 
 /*
@@ -552,7 +552,7 @@
 
 /*
 
-=item C<static void alloc_new_block( Memory_Pools *mem_pools, size_t size,
+=item C<static void alloc_new_block( GC_Statistics *stats, size_t size,
 Variable_Size_Pool *pool, const char *why)>
 
 Allocate a new memory block. We allocate either the requested size or the
@@ -565,7 +565,7 @@
 
 static void
 alloc_new_block(
-        ARGMOD(Memory_Pools *mem_pools),
+        ARGMOD(GC_Statistics *stats),
         size_t size,
         ARGMOD(Variable_Size_Pool *pool),
         ARGIN(const char *why))
@@ -600,7 +600,7 @@
     new_block->top   = new_block->start;
 
     /* Note that we've allocated it */
-    mem_pools->memory_allocated += alloc_size;
+    stats->memory_allocated += alloc_size;
 
     /* If this is for a public pool, add it to the list */
     new_block->prev = pool->top_block;
@@ -615,8 +615,8 @@
 
 /*
 
-=item C<static void * mem_allocate(PARROT_INTERP, Memory_Pools *mem_pools,
-size_t size, Variable_Size_Pool *pool)>
+=item C<static void * mem_allocate(PARROT_INTERP, GC_Statistics *stats, size_t
+size, Variable_Size_Pool *pool)>
 
 Allocates memory for headers.
 
@@ -643,7 +643,7 @@
 PARROT_CANNOT_RETURN_NULL
 static void *
 mem_allocate(PARROT_INTERP,
-        ARGMOD(Memory_Pools *mem_pools),
+        ARGMOD(GC_Statistics *stats),
         size_t size,
         ARGMOD(Variable_Size_Pool *pool))
 {
@@ -662,9 +662,9 @@
          * TODO pass required allocation size to the GC system,
          *      so that collection can be skipped if needed
          */
-        if (!mem_pools->gc_mark_block_level
+        if (!Parrot_is_blocked_GC_mark(interp)
         &&  Parrot_gc_ms_needed(interp)) {
-            Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
+            Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG | GC_strings_cb_FLAG);
 
             if (interp->gc_sys->sys_type != INF) {
                 /* Compact the pool if allowed and worthwhile */
@@ -672,7 +672,7 @@
                     /* don't bother reclaiming if it's only a small amount */
                     if ((pool->possibly_reclaimable * pool->reclaim_factor +
                          pool->guaranteed_reclaimable) > size) {
-                        (*pool->compact) (interp, mem_pools, pool);
+                        (*pool->compact) (interp, stats, pool);
                     }
                 }
             }
@@ -686,9 +686,9 @@
              * Mark the block as big block (it has just one item)
              * And don't set big blocks as the top_block.
              */
-            alloc_new_block(mem_pools, size, pool, "compact failed");
+            alloc_new_block(&interp->gc_sys->stats, size, pool, "compact failed");
 
-            ++mem_pools->mem_allocs_since_last_collect;
+            ++interp->gc_sys->stats.mem_allocs_since_last_collect;
 
             if (pool->top_block->free < size) {
                 fprintf(stderr, "out of mem\n");
@@ -701,7 +701,7 @@
     return_val             = pool->top_block->top;
     pool->top_block->top  += size;
     pool->top_block->free -= size;
-    mem_pools->memory_used += size;
+    interp->gc_sys->stats.memory_used += size;
 
     return return_val;
 }
@@ -792,7 +792,7 @@
 
 =over 4
 
-=item C<static void compact_pool(PARROT_INTERP, Memory_Pools *mem_pools,
+=item C<static void compact_pool(PARROT_INTERP, GC_Statistics *stats,
 Variable_Size_Pool *pool)>
 
 Compact the string buffer pool. Does not perform a GC scan, or mark items
@@ -804,7 +804,7 @@
 
 static void
 compact_pool(PARROT_INTERP,
-        ARGMOD(Memory_Pools *mem_pools),
+        ARGMOD(GC_Statistics *stats),
         ARGMOD(Variable_Size_Pool *pool))
 {
     ASSERT_ARGS(compact_pool)
@@ -818,26 +818,26 @@
 
 
     /* Bail if we're blocked */
-    if (mem_pools->gc_sweep_block_level)
+    if (Parrot_is_blocked_GC_sweep(interp))
         return;
 
-    ++mem_pools->gc_sweep_block_level;
+    Parrot_block_GC_sweep(interp);
 
     /* We're collecting */
-    mem_pools->mem_allocs_since_last_collect    = 0;
-    mem_pools->header_allocs_since_last_collect = 0;
-    ++mem_pools->gc_collect_runs;
+    stats->mem_allocs_since_last_collect    = 0;
+    stats->header_allocs_since_last_collect = 0;
+    ++stats->gc_collect_runs;
 
     /* Snag a block big enough for everything */
     total_size = pad_pool_size(pool);
 
     if (total_size == 0) {
-        free_old_mem_blocks(mem_pools, pool, pool->top_block, total_size);
-        --mem_pools->gc_sweep_block_level;
+        free_old_mem_blocks(stats, pool, pool->top_block, total_size);
+        Parrot_unblock_GC_sweep(interp);
         return;
     }
 
-    alloc_new_block(mem_pools, total_size, pool, "inside compact");
+    alloc_new_block(stats, total_size, pool, "inside compact");
 
     cb_data.new_block = pool->top_block;
 
@@ -858,12 +858,12 @@
     /* How much is free. That's the total size minus the amount we used */
     cb_data.new_block->free     = cb_data.new_block->size
                                   - (cb_data.cur_spot - cb_data.new_block->start);
-    mem_pools->memory_collected += (cb_data.cur_spot - cb_data.new_block->start);
-    mem_pools->memory_used      += (cb_data.cur_spot - cb_data.new_block->start);
+    stats->memory_collected += (cb_data.cur_spot - cb_data.new_block->start);
+    stats->memory_used      += (cb_data.cur_spot - cb_data.new_block->start);
 
-    free_old_mem_blocks(mem_pools, pool, cb_data.new_block, total_size);
+    free_old_mem_blocks(stats, pool, cb_data.new_block, total_size);
 
-    --mem_pools->gc_sweep_block_level;
+    Parrot_unblock_GC_sweep(interp);
 }
 
 /*
@@ -1061,7 +1061,7 @@
 
 /*
 
-=item C<static void free_old_mem_blocks( Memory_Pools *mem_pools,
+=item C<static void free_old_mem_blocks( GC_Statistics *stats,
 Variable_Size_Pool *pool, Memory_Block *new_block, UINTVAL total_size)>
 
 The compact_pool operation collects disjointed blocks of memory allocated on a
@@ -1078,7 +1078,7 @@
 
 static void
 free_old_mem_blocks(
-        ARGMOD(Memory_Pools *mem_pools),
+        ARGMOD(GC_Statistics *stats),
         ARGMOD(Variable_Size_Pool *pool),
         ARGMOD(Memory_Block *new_block),
         UINTVAL total_size)
@@ -1099,8 +1099,8 @@
         }
         else {
             /* Note that we don't have it any more */
-            mem_pools->memory_allocated -= cur_block->size;
-            mem_pools->memory_used -= cur_block->size - cur_block->free;
+            stats->memory_allocated -= cur_block->size;
+            stats->memory_used -= cur_block->size - cur_block->free;
 
             /* We know the pool body and pool header are a single chunk, so
              * this is enough to get rid of 'em both */

Modified: trunk/src/gc/system.c
==============================================================================
--- trunk/src/gc/system.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/gc/system.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -39,26 +39,25 @@
         __attribute__nonnull__(1);
 
 PARROT_WARN_UNUSED_RESULT
-static size_t get_max_buffer_address(ARGIN(const Memory_Pools *mem_pools))
-        __attribute__nonnull__(1);
+static size_t get_max_buffer_address(
+    ARGIN_NULLOK(const Memory_Pools *mem_pools));
 
 PARROT_WARN_UNUSED_RESULT
-static size_t get_max_pmc_address(ARGIN(const Memory_Pools *mem_pools))
-        __attribute__nonnull__(1);
+static size_t get_max_pmc_address(
+    ARGIN_NULLOK(const Memory_Pools *mem_pools));
 
 PARROT_WARN_UNUSED_RESULT
-static size_t get_min_buffer_address(ARGIN(const Memory_Pools *mem_pools))
-        __attribute__nonnull__(1);
+static size_t get_min_buffer_address(
+    ARGIN_NULLOK(const Memory_Pools *mem_pools));
 
 PARROT_WARN_UNUSED_RESULT
-static size_t get_min_pmc_address(ARGIN(const Memory_Pools *mem_pools))
-        __attribute__nonnull__(1);
+static size_t get_min_pmc_address(
+    ARGIN_NULLOK(const Memory_Pools *mem_pools));
 
 PARROT_WARN_UNUSED_RESULT
 static int is_buffer_ptr(
-    ARGIN(const Memory_Pools *mem_pools),
+    ARGIN_NULLOK(const Memory_Pools *mem_pools),
     ARGIN(const void *ptr))
-        __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
 PARROT_WARN_UNUSED_RESULT
@@ -69,40 +68,31 @@
         __attribute__nonnull__(2);
 
 static void trace_mem_block(PARROT_INTERP,
-    ARGIN(const Memory_Pools *mem_pools),
+    ARGIN_NULLOK(const Memory_Pools *mem_pools),
     size_t lo_var_ptr,
     size_t hi_var_ptr)
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
+        __attribute__nonnull__(1);
 
 PARROT_NOINLINE
 static void trace_system_stack(PARROT_INTERP,
-    ARGIN(const Memory_Pools *mem_pools))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
+    ARGIN_NULLOK(const Memory_Pools *mem_pools))
+        __attribute__nonnull__(1);
 
 #define ASSERT_ARGS_find_common_mask __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))
-#define ASSERT_ARGS_get_max_buffer_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_get_max_pmc_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_get_min_buffer_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_get_min_pmc_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools))
+#define ASSERT_ARGS_get_max_buffer_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_get_max_pmc_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_get_min_buffer_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_get_min_pmc_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
 #define ASSERT_ARGS_is_buffer_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(mem_pools) \
-    , PARROT_ASSERT_ARG(ptr))
+       PARROT_ASSERT_ARG(ptr))
 #define ASSERT_ARGS_is_pmc_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(mem_pools) \
     , PARROT_ASSERT_ARG(ptr))
 #define ASSERT_ARGS_trace_mem_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(mem_pools))
+       PARROT_ASSERT_ARG(interp))
 #define ASSERT_ARGS_trace_system_stack __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(mem_pools))
+       PARROT_ASSERT_ARG(interp))
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: static */
 
@@ -121,7 +111,7 @@
 */
 
 void
-trace_system_areas(PARROT_INTERP, ARGIN(const Memory_Pools *mem_pools))
+trace_system_areas(PARROT_INTERP, ARGIN_NULLOK(const Memory_Pools *mem_pools))
 {
     ASSERT_ARGS(trace_system_areas)
     {
@@ -244,7 +234,7 @@
 
 PARROT_NOINLINE
 static void
-trace_system_stack(PARROT_INTERP, ARGIN(const Memory_Pools *mem_pools))
+trace_system_stack(PARROT_INTERP, ARGIN_NULLOK(const Memory_Pools *mem_pools))
 {
     ASSERT_ARGS(trace_system_stack)
     /* Create a local variable on the system stack. This represents the
@@ -274,12 +264,15 @@
 
 PARROT_WARN_UNUSED_RESULT
 static size_t
-get_max_buffer_address(ARGIN(const Memory_Pools *mem_pools))
+get_max_buffer_address(ARGIN_NULLOK(const Memory_Pools *mem_pools))
 {
     ASSERT_ARGS(get_max_buffer_address)
     size_t         max        = 0;
     UINTVAL        i;
 
+    if (!mem_pools)
+        return -1;
+
     for (i = 0; i < mem_pools->num_sized; ++i) {
         if (mem_pools->sized_header_pools[i]) {
             if (mem_pools->sized_header_pools[i]->end_arena_memory > max)
@@ -308,12 +301,15 @@
 
 PARROT_WARN_UNUSED_RESULT
 static size_t
-get_min_buffer_address(ARGIN(const Memory_Pools *mem_pools))
+get_min_buffer_address(ARGIN_NULLOK(const Memory_Pools *mem_pools))
 {
     ASSERT_ARGS(get_min_buffer_address)
-    size_t         min        = (size_t) -1;
+    size_t         min        = (size_t) 0;
     UINTVAL        i;
 
+    if (!mem_pools)
+        return 0;
+
     for (i = 0; i < mem_pools->num_sized; ++i) {
         const Fixed_Size_Pool * const pool = mem_pools->sized_header_pools[i];
         if (pool && pool->start_arena_memory) {
@@ -338,10 +334,12 @@
 
 PARROT_WARN_UNUSED_RESULT
 static size_t
-get_max_pmc_address(ARGIN(const Memory_Pools *mem_pools))
+get_max_pmc_address(ARGIN_NULLOK(const Memory_Pools *mem_pools))
 {
     ASSERT_ARGS(get_max_pmc_address)
-    return mem_pools->pmc_pool->end_arena_memory;
+    return mem_pools
+            ? mem_pools->pmc_pool->end_arena_memory
+            : -1;
 }
 
 
@@ -359,10 +357,12 @@
 
 PARROT_WARN_UNUSED_RESULT
 static size_t
-get_min_pmc_address(ARGIN(const Memory_Pools *mem_pools))
+get_min_pmc_address(ARGIN_NULLOK(const Memory_Pools *mem_pools))
 {
     ASSERT_ARGS(get_min_pmc_address)
-    return mem_pools->pmc_pool->start_arena_memory;
+    return mem_pools
+           ? mem_pools->pmc_pool->start_arena_memory
+           : 0;
 }
 
 
@@ -423,7 +423,7 @@
 
 static void
 trace_mem_block(PARROT_INTERP,
-        ARGIN(const Memory_Pools *mem_pools),
+        ARGIN_NULLOK(const Memory_Pools *mem_pools),
         size_t lo_var_ptr, size_t hi_var_ptr)
 {
     ASSERT_ARGS(trace_mem_block)
@@ -450,13 +450,18 @@
     }
 
     /* Get the expected prefix */
-    prefix = mask & buffer_min;
+    prefix = mem_pools
+                ? mask & buffer_min
+                : 0;
 
     for (cur_var_ptr = hi_var_ptr;
         (ptrdiff_t)cur_var_ptr < (ptrdiff_t)lo_var_ptr;
         cur_var_ptr = (size_t)((ptrdiff_t)cur_var_ptr + sizeof (void *))) {
         const size_t ptr = *(size_t *)cur_var_ptr;
 
+        if (!ptr)
+            continue;
+
         /* Do a quick approximate range check by bit-masking */
         if ((ptr & mask) == prefix || !prefix) {
             /* Note that what we find via the stack or registers are not
@@ -464,12 +469,12 @@
              * had their bufstart/vtable destroyed due to the linked list of
              * free headers... */
             if ((pmc_min <= ptr)
-            &&  (ptr     < pmc_max)
-            &&   is_pmc_ptr(mem_pools, (void *)ptr)) {
+            &&  (ptr < pmc_max)
+            &&  interp->gc_sys->is_pmc_ptr(interp, (void *)ptr)) {
                 Parrot_gc_mark_PMC_alive(interp, (PMC *)ptr);
             }
             else if ((buffer_min <= ptr) && (ptr < buffer_max)
-            &&        is_buffer_ptr(mem_pools, (void *)ptr)) {
+            &&        interp->gc_sys->is_string_ptr(interp, (void *)ptr)) {
                 if (PObj_is_string_TEST((PObj *)ptr))
                     Parrot_gc_mark_STRING_alive(interp, (STRING *)ptr);
                 else
@@ -495,11 +500,14 @@
 
 PARROT_WARN_UNUSED_RESULT
 static int
-is_buffer_ptr(ARGIN(const Memory_Pools *mem_pools), ARGIN(const void *ptr))
+is_buffer_ptr(ARGIN_NULLOK(const Memory_Pools *mem_pools), ARGIN(const void *ptr))
 {
     ASSERT_ARGS(is_buffer_ptr)
     UINTVAL        i;
 
+    if (!mem_pools)
+        return 0;
+
     for (i = 0; i < mem_pools->num_sized; ++i) {
         if (mem_pools->sized_header_pools[i]
             &&  contained_in_pool(mem_pools->sized_header_pools[i], ptr))

Added: trunk/src/gc/variable_size_pool.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/gc/variable_size_pool.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,36 @@
+/*
+Copyright (C) 2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/gc/variable_size_pool.h - implementation of allocator variable size objects.
+E.g. strings.
+
+=head1 DESCRIPTION
+
+TODO Add it.
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+#include "variable_size_pool.h"
+
+/* HEADERIZER HFILE: src/gc/variable_size_pool.h */
+
+/* HEADERIZER BEGIN: static */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: static */
+
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
+

Added: trunk/src/gc/variable_size_pool.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/gc/variable_size_pool.h	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,58 @@
+/*
+Copyright (C) 2001-2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/gc/variable_size_pool.h - implementation of allocator variable size objects.
+E.g. strings.
+
+=head1 DESCRIPTION
+
+*/
+
+#ifndef PARROT_GC_VARIABLE_SIZE_POOL_H_GUARD
+#define PARROT_GC_VARIABLE_SIZE_POOL_H_GUARD
+
+#include "parrot/settings.h"
+
+struct GC_Statistics;
+
+typedef struct Memory_Block {
+    size_t free;
+    size_t size;
+    struct Memory_Block *prev;
+    struct Memory_Block *next;
+    char *start;
+    char *top;
+
+    /* Amount of freed memory. Used in compact_pool */
+    size_t freed;
+} Memory_Block;
+
+typedef struct Variable_Size_Pool {
+    Memory_Block *top_block;
+    void (*compact)(PARROT_INTERP, struct GC_Statistics *, struct Variable_Size_Pool *);
+    size_t minimum_block_size;
+    size_t total_allocated; /* total bytes allocated to this pool */
+    size_t guaranteed_reclaimable;     /* bytes that can definitely be reclaimed*/
+    size_t possibly_reclaimable;     /* bytes that can possibly be reclaimed
+                                      * (above plus COW-freed bytes) */
+    FLOATVAL reclaim_factor; /* minimum percentage we will reclaim */
+} Variable_Size_Pool;
+
+/* HEADERIZER BEGIN: src/gc/variable_size_pool.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/gc/variable_size_pool.c */
+
+
+#endif /* PARROT_GC_VARIABLE_SIZE_POOL_H_GUARD */
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Modified: trunk/src/interp/inter_create.c
==============================================================================
--- trunk/src/interp/inter_create.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/interp/inter_create.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -218,6 +218,10 @@
     interp->HLL_info = NULL;
 
     Parrot_initialize_core_vtables(interp);
+
+    /* create the root set registry */
+    interp->gc_registry     = Parrot_pmc_new(interp, enum_class_AddrRegistry);
+
     init_world_once(interp);
 
     /* context data */
@@ -258,9 +262,6 @@
     interp->evc_func_table_size = 0;
     interp->code                = NULL;
 
-    /* create the root set registry */
-    interp->gc_registry     = Parrot_pmc_new(interp, enum_class_AddrRegistry);
-
     /* And a dynamic environment stack */
     /* TODO: We should really consider removing this (TT #876) */
     interp->dynamic_env = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);

Added: trunk/src/list.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/list.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -0,0 +1,241 @@
+/*
+Copyright (C) 2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/list.c - Implementation of double linked lists.
+
+=head1 DESCRIPTION
+
+This code implements double linked list of GCable objects.
+
+=cut
+
+*/
+
+#include "parrot/parrot.h"
+#include "parrot/list.h"
+
+/* HEADERIZER HFILE: include/parrot/list.h */
+
+/* HEADERIZER BEGIN: static */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: static */
+
+/*
+
+=over 4
+
+=item C<struct Linked_List* Parrot_list_new(PARROT_INTERP)>
+
+Allocate a doubly link list
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+struct Linked_List*
+Parrot_list_new(SHIM_INTERP)
+{
+    ASSERT_ARGS(Parrot_list_new)
+
+    Linked_List *res = (Linked_List*)mem_sys_allocate_zeroed(sizeof (Linked_List));
+    return res;
+}
+
+/*
+
+=item C<void Parrot_list_destroy(PARROT_INTERP, Linked_List* list)>
+
+Destroy the specified list (free up memory associated with the list)
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+Parrot_list_destroy(SHIM_INTERP, ARGMOD(Linked_List* list))
+{
+    ASSERT_ARGS(Parrot_list_destroy)
+
+    mem_sys_free(list);
+}
+
+/*
+
+=item C<void Parrot_list_append(PARROT_INTERP, Linked_List *list,
+List_Item_Header *item)>
+
+Append an item to the list
+
+=cut
+
+*/
+
+PARROT_EXPORT
+void
+Parrot_list_append(SHIM_INTERP, ARGMOD(Linked_List *list), ARGMOD(List_Item_Header *item))
+{
+    ASSERT_ARGS(Parrot_list_append)
+
+    item->prev = item->next = NULL;
+
+    if (list->last) {
+        item->prev = list->last;
+        list->last->next = item;
+    }
+
+    list->last = item;
+
+    if (!list->first)
+        list->first = item;
+
+    list->count++;
+#ifndef NDEBUG
+    item->owner = list;
+#endif
+}
+
+/*
+
+=item C<List_Item_Header* Parrot_list_remove(PARROT_INTERP, Linked_List *list,
+List_Item_Header *item)>
+
+Remove an item from the list, returning the (pointer to) item
+
+=cut
+
+*/
+
+PARROT_EXPORT
+List_Item_Header*
+Parrot_list_remove(SHIM_INTERP, ARGMOD(Linked_List *list), ARGMOD(List_Item_Header *item))
+{
+    ASSERT_ARGS(Parrot_list_remove)
+
+    List_Item_Header *next = item->next;
+    List_Item_Header *prev = item->prev;
+
+    PARROT_ASSERT(list == item->owner);
+
+    /* First item */
+    if (list->first == item)
+        list->first = next;
+
+    if (list->last == item)
+        list->last = prev;
+
+    if (prev)
+        prev->next = next;
+    if (next)
+        next->prev = prev;
+
+    list->count--;
+    return item;
+}
+
+/*
+
+=item C<List_Item_Header* Parrot_list_pop(PARROT_INTERP, Linked_List *list)>
+
+Pop an item off the list - i.e. get the first item in the list and remove it.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+List_Item_Header*
+Parrot_list_pop(PARROT_INTERP, ARGIN(Linked_List *list))
+{
+    ASSERT_ARGS(Parrot_list_pop)
+
+    List_Item_Header *ret = list->first;
+    if (ret)
+        LIST_REMOVE(list, ret);
+    return ret;
+}
+
+/*
+
+=item C<INTVAL Parrot_list_check(PARROT_INTERP, Linked_List *list)>
+
+Check the validity of the list
+
+=cut
+
+*/
+
+PARROT_EXPORT
+INTVAL
+Parrot_list_check(SHIM_INTERP, ARGIN(Linked_List *list))
+{
+    ASSERT_ARGS(Parrot_list_check)
+
+    List_Item_Header *tmp = list->first;
+    size_t counter = 0;
+
+    while (tmp) {
+        List_Item_Header *next = tmp->next;
+        PARROT_ASSERT(tmp->owner == list);
+        tmp = next;
+        ++counter;
+        PARROT_ASSERT(counter <= list->count);
+    }
+
+    return 1;
+}
+
+/*
+
+=item C<INTVAL Parrot_list_contains(PARROT_INTERP, Linked_List *list,
+List_Item_Header *item)>
+
+Returns True if the is in the list
+
+=cut
+
+*/
+
+PARROT_EXPORT
+INTVAL
+Parrot_list_contains(SHIM_INTERP, ARGIN(Linked_List *list), ARGIN(List_Item_Header *item))
+{
+    ASSERT_ARGS(Parrot_list_contains)
+
+    List_Item_Header *tmp = list->first;
+
+#ifndef NDEBUG
+    if (item->owner != list)
+        return 0;
+#endif
+
+    while (tmp) {
+        if (tmp == item)
+            return 1;
+        tmp = tmp->next;
+    }
+
+    return 0;
+}
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Modified: trunk/src/main.c
==============================================================================
--- trunk/src/main.c	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/src/main.c	Thu Sep 23 08:34:38 2010	(r49269)
@@ -390,6 +390,8 @@
                 interp->gc_sys->sys_type = MS;
             else if (STREQ(arg, "inf"))
                 interp->gc_sys->sys_type = INF;
+            else if (STREQ(arg, "ms2"))
+                interp->gc_sys->sys_type = MS2;
             else {
                 fprintf(stderr,
                         "main: Unrecognized GC '%s' specified."

Modified: trunk/t/op/gc-leaky-box.t
==============================================================================
--- trunk/t/op/gc-leaky-box.t	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/t/op/gc-leaky-box.t	Thu Sep 23 08:34:38 2010	(r49269)
@@ -25,18 +25,16 @@
 .sub _main :main
     .include 'test_more.pir'
 
-    plan(3)
 
     $S0 = interpinfo .INTERPINFO_GC_SYS_NAME
-    if $S0 == "inf" goto dont_run_hanging_tests
+    if $S0 != "ms" goto dont_run_hanging_tests
 
+    plan(3)
     test_gc_mark_sweep()
 
     goto test_end
   dont_run_hanging_tests:
-    ok(1, "#TODO - Test disabled on gc_inf")
-    ok(1, "#TODO - Test disabled on gc_inf")
-    ok(1, "#TODO - Test disabled on gc_inf")
+    skip_all("Not relevant for this GC")
   test_end:
 .end
 

Modified: trunk/t/op/gc-leaky-call.t
==============================================================================
--- trunk/t/op/gc-leaky-call.t	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/t/op/gc-leaky-call.t	Thu Sep 23 08:34:38 2010	(r49269)
@@ -22,18 +22,16 @@
 .sub _main :main
     .include 'test_more.pir'
 
-    plan(3)
 
     $S0 = interpinfo .INTERPINFO_GC_SYS_NAME
-    if $S0 == "inf" goto dont_run_hanging_tests
+    if $S0 != "ms" goto dont_run_hanging_tests
 
+    plan(3)
     test_gc_mark_sweep()
 
     goto test_end
   dont_run_hanging_tests:
-    ok(1, "#TODO - Test disabled on gc_inf")
-    ok(1, "#TODO - Test disabled on gc_inf")
-    ok(1, "#TODO - Test disabled on gc_inf")
+    skip_all("Not relevant for this GC")
   test_end:
 .end
 

Modified: trunk/t/op/string_mem.t
==============================================================================
--- trunk/t/op/string_mem.t	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/t/op/string_mem.t	Thu Sep 23 08:34:38 2010	(r49269)
@@ -41,12 +41,11 @@
 
     test_stringinfo()
     $S0 = interpinfo .INTERPINFO_GC_SYS_NAME
-    if $S0 == "inf" goto dont_run_hanging_tests
+    if $S0 != "ms" goto dont_run_hanging_tests
     test_pin_unpin()
     goto test_end
   dont_run_hanging_tests:
-    ok(1, "#TODO - Test disabled on gc_inf")
-    ok(1, "#TODO - Test disabled on gc_inf")
+    skip(2, "Test disabled on not GC MS")
   test_end:
 .end
 

Modified: trunk/t/pmc/filehandle.t
==============================================================================
--- trunk/t/pmc/filehandle.t	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/t/pmc/filehandle.t	Thu Sep 23 08:34:38 2010	(r49269)
@@ -736,6 +736,9 @@
 expect 1 exit status: 1
 OUTPUT
 
+SKIP: {
+    skip 'Timely destruction is deprecated. TT#1800' => 1;
+
 pir_output_is( sprintf(<<'CODE', $temp_file), <<'OUTPUT', "timely destruction" );
 .const string temp_file = '%s'
 .sub main :main
@@ -745,16 +748,24 @@
         needs_destroy $P0
     print $P0, "a line\n"
     null $P0            # kill it
+    # Call dummy sub to cleanup CallContext
+    dummy()
     sweep 0            # a lazy GC has to close the PIO
     $P0 = new ['FileHandle']
     $P0.'open'(temp_file, 'r')
     $S0 = $P0.'read'(20)
     print $S0
 .end
+
+.sub dummy
+.end
+
 CODE
 a line
 OUTPUT
 
+}
+
 my (undef, $no_such_file) = create_tempfile( UNLINK => 1, OPEN => 0 );
 
 pir_output_is( sprintf( <<'CODE', $no_such_file, $temp_file ), <<'OUTPUT', "get_bool" );

Modified: trunk/t/pmc/io.t
==============================================================================
--- trunk/t/pmc/io.t	Thu Sep 23 08:14:11 2010	(r49268)
+++ trunk/t/pmc/io.t	Thu Sep 23 08:34:38 2010	(r49269)
@@ -7,7 +7,7 @@
 use lib qw( . lib ../lib ../../lib );
 
 use Test::More;
-use Parrot::Test tests => 32;
+use Parrot::Test tests => 31;
 use Parrot::Test::Util 'create_tempfile';
 
 =head1 NAME
@@ -40,25 +40,6 @@
 
 my (undef, $temp_file) = create_tempfile( UNLINK => 1 );
 
-pir_output_is( sprintf(<<'CODE', $temp_file), <<'OUTPUT', "timely destruction" );
-.const string temp_file = '%s'
-.sub main :main
-    interpinfo $I0, 2    # GC mark runs
-    $P0 = new ['FileHandle']
-    $P0.'open'(temp_file, 'w')
-    needs_destroy $P0
-    print $P0, "a line\n"
-    null $P0            # kill it
-    sweep 0            # a lazy GC has to close the PIO
-    $P0 = new ['FileHandle']
-    $P0.'open'(temp_file, 'r')
-    $S0 = $P0.'read'(20)
-    print $S0
-.end
-CODE
-a line
-OUTPUT
-
 pir_output_is( <<'CODE', <<'OUTPUT', "read on invalid fh should throw exception" );
 .sub main :main
     new $P0, ['FileHandle']


More information about the parrot-commits mailing list