[m-rev.] for review: add support for MPS GC

Fergus Henderson fjh at cs.mu.OZ.AU
Wed Aug 21 20:32:04 AEST 2002


On 31-Jul-2002, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 31-Jul-2002, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> > Add support for interfacing Mercury with the MPS garbage collector.
> > 
> > This change is broken into three parts:
> > 
> > 	1. Import version 1.100.1 of the MPS kit into the Mercury
> > 	   CVS repository, in the directory `mercury/mps_gc'.
> > 
> > 	2. Make some changes to the MPS kit for Mercury,
> > 	   to support fully-conservative collection and tagged pointers,
> > 	   and to wrap it in an interface that is similar to that of
> > 	   the Boehm collector.
> > 
> > 	3. Modify the rest of the Mercury implementation
> > 	   to support linking with the MPS kit instead
> > 	   of the Boehm collector.  This involved defining
> > 	   `mps' as a new GC method and a new grade component.
> 
> This is part 2 of 3.

I have made a number of changes since the version that I originally
posted for review -- some bug fixes and various efficiency improvements
(specializing for small objects, specializing for conservative scanning).

Here's the relative diff.
I will go ahead and commit this now.

--- CHANGES2.old	Wed Jul 31 10:48:42 2002
+++ CHANGES2	Wed Aug 21 20:26:22 2002
@@ -3,18 +3,34 @@
 
 mps_gc/code/fmtme.h:
 mps_gc/code/fmtme.c:
-	New files.  These define a new object format variety for Mercury
+	New files.  These define new object format varieties for Mercury
 	objects.  (An object format variety is used to create an object
 	format, which tells the MPS toolkit how to trace objects and how
 	to determine their size.  For Mercury objects, we add a header
 	which records the size of the object, and we scan all the fields
-	of the objects conservatively.)
+	of the objects conservatively.  We also define formats for
+	fixed-sized objects of 1, 2, 3, 4, 5, or 6 words; this avoids
+	the need to store the size header for small objects.)
 
 mps_gc/code/mpmtypes.h:
 mps_gc/code/mps.h:
 mps_gc/code/format.c:
 	Various minor changes to support the new "Mercury" object format
-	variety.
+	varieties.
+
+mps_gc/code/poolamsc.h:
+mps_gc/code/poolamsc.c:
+mps_gc/code/poolamscf.h:
+mps_gc/code/poolamscf.c:
+	New files.  These define two new pool classes, AMSC and AMSCF,
+	which are variants of the AMS (automatic mark-sweep) class
+	which are specialized for conservative collection.
+	AMSC uses the object format defined in fmtme.{h,c}.
+	AMSCF is specialized for fixed-size objects.
+
+mps_gc/code/mpscamsc.h:
+mps_gc/code/poolamsci.c:
+	New files.  These provide the interface to the two new pool classes.
 
 mps_gc/code/mercury_mps.h:
 mps_gc/code/mercury_mps.c:
@@ -38,10 +54,10 @@
 	Modify to handle fully-conservative collection.
 
 mps_gc/code/poolams.c:
+mps_gc/code/poollo.c:
 	Modify to handle tagged pointers.
 
 mps_gc/code/lockli.c:
 	Fix compile errors that occurred when THREAD_SINGLE
 	was defined.
-
 
diff -u mps_gc/code/comm.gmk mps_gc/code/comm.gmk
--- mps_gc/code/comm.gmk
+++ mps_gc/code/comm.gmk
@@ -177,6 +177,7 @@
 
 AMC = poolamc.c
 AMS = poolams.c poolamsi.c
+AMSC = poolamsc.c poolamscf.c poolamsci.c
 AWL = poolawl.c
 LO = poollo.c
 SNC = poolsnc.c
@@ -220,6 +221,8 @@
 AMCDEP = $(AMC:%.c=$(PFM)/$(VARIETY)/%.d)
 AMSOBJ = $(AMS:%.c=$(PFM)/$(VARIETY)/%.o)
 AMSDEP = $(AMS:%.c=$(PFM)/$(VARIETY)/%.d)
+AMSCOBJ = $(AMSC:%.c=$(PFM)/$(VARIETY)/%.o)
+AMSCDEP = $(AMSC:%.c=$(PFM)/$(VARIETY)/%.d)
 AWLOBJ = $(AWL:%.c=$(PFM)/$(VARIETY)/%.o)
 AWLDEP = $(AWL:%.c=$(PFM)/$(VARIETY)/%.d)
 LOOBJ = $(LO:%.c=$(PFM)/$(VARIETY)/%.o)
@@ -386,7 +389,7 @@
 	$(FMTDYTSTOBJ) $(MPMOBJ) $(AMSOBJ) $(TESTLIBOBJ)
 
 $(PFM)/$(VARIETY)/mercury_mps_ss: $(PFM)/$(VARIETY)/mercury_mps_ss.o \
-	$(MPMOBJ) $(AMSOBJ) $(TESTLIBOBJ) $(MERCURYMPSOBJ)
+	$(MPMOBJ) $(AMSOBJ) $(AMSCOBJ) $(LOOBJ) $(TESTLIBOBJ) $(MERCURYMPSOBJ)
 
 $(PFM)/$(VARIETY)/amssshe: $(PFM)/$(VARIETY)/amssshe.o \
 	$(FMTHETSTOBJ) $(MPMOBJ) $(AMSOBJ) $(TESTLIBOBJ)
@@ -439,8 +442,8 @@
   $(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/table.o \
   $(MPMOBJ) $(AWLOBJ) $(AMSOBJ) $(POOLNOBJ) $(AMCOBJ) $(SNCOBJ) $(MVFFOBJ)
 
-$(PFM)/$(VARIETY)/mps.a: $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(SNCOBJ) $(MVFFOBJ) \
-  $(MERCURYMPSOBJ)
+$(PFM)/$(VARIETY)/mps.a: $(MPMOBJ) $(AMCOBJ) $(AMSCOBJ) $(AMSOBJ) $(SNCOBJ) \
+  $(MVFFOBJ) $(MERCURYMPSOBJ) $(LOOBJ)
 
 $(PFM)/$(VARIETY)/mmdw.a: $(MPMOBJ) $(AMCOBJ) $(LOOBJ) $(SNCOBJ) \
   $(FMTDYOBJ) $(AWLOBJ)
@@ -514,7 +517,7 @@
 ifdef VARIETY
 ifdef TARGET
 # %%PART: Add the dependency file macro for the new part here.
-include $(MPMDEP) $(AMSDEP) $(AMCDEP) $(LODEP) $(SWDEP) \
+include $(MPMDEP) $(AMSDEP) $(AMSCDEP) $(AMCDEP) $(LODEP) $(SWDEP) \
   $(AWLDEP) $(POOLNDEP) $(TESTLIBDEP) $(FMTDYDEP) $(FMTHETSTDEP) \
   $(PLINTHDEP) $(EVENTPROCDEP) $(MERCURYMPSDEP)
 endif
diff -u mps_gc/code/config.h mps_gc/code/config.h
--- mps_gc/code/config.h
+++ mps_gc/code/config.h
@@ -290,6 +290,7 @@
 /* XXX changed to single-threaded version. -fjh */
 /* #define THREAD_MULTI */
 #define THREAD_SINGLE
+/* XXX should we change this to PROTECTION_NONE? -fjh */
 #define PROTECTION
 #define DONGLE_NONE
 #define PROD_CHECK_DEFAULT CheckSHALLOW
diff -u mps_gc/code/fmtme.c mps_gc/code/fmtme.c
--- mps_gc/code/fmtme.c
+++ mps_gc/code/fmtme.c
@@ -7,10 +7,16 @@
  * Portions copyright (c) 2002 Global Graphics Software.
  * See end of file for license.
  *
- * The Mercury format is as follows:
+ * The general Mercury format is as follows:
  *	The first word is the size.
  *	The remaining words contain arbitrary data,
  *	which is scanned conservatively.
+ * There are also fixed-size variants, for objects of up to 6 words.
+ * These variants avoid the need to explicitly store the size.
+ *
+ * XXX Would it be better to handle fixed-size objects by using a
+ * different pool class (instead of AMS) rather than using a
+ * different object format?  [Maybe, but would be a lot more work.]
  */
 
 #include "testlib.h"
@@ -34,9 +40,24 @@
 
 static mps_res_t mercury_scan(mps_ss_t mps_ss, mps_addr_t base,
                   mps_addr_t limit);
+static mps_res_t mercury_scan_fixed(mps_ss_t mps_ss, mps_addr_t base,
+                  mps_addr_t limit);
 static mps_addr_t mercury_skip(mps_addr_t object);
+static mps_addr_t mercury_skip_fixed_1(mps_addr_t object);
+static mps_addr_t mercury_skip_fixed_2(mps_addr_t object);
+static mps_addr_t mercury_skip_fixed_3(mps_addr_t object);
+static mps_addr_t mercury_skip_fixed_4(mps_addr_t object);
+static mps_addr_t mercury_skip_fixed_5(mps_addr_t object);
+static mps_addr_t mercury_skip_fixed_6(mps_addr_t object);
 static void mercury_copy(mps_addr_t old, mps_addr_t new);
+static void mercury_copy_fixed_1(mps_addr_t old, mps_addr_t new);
+static void mercury_copy_fixed_2(mps_addr_t old, mps_addr_t new);
+static void mercury_copy_fixed_3(mps_addr_t old, mps_addr_t new);
+static void mercury_copy_fixed_4(mps_addr_t old, mps_addr_t new);
+static void mercury_copy_fixed_5(mps_addr_t old, mps_addr_t new);
+static void mercury_copy_fixed_6(mps_addr_t old, mps_addr_t new);
 static void mercury_pad(mps_addr_t addr, size_t size);
+static void mercury_pad_fixed(mps_addr_t addr, size_t size);
 
 static struct mps_fmt_mercury_s mercury_fmt_mercury_s =
 {
@@ -44,7 +65,68 @@
   mercury_scan,
   mercury_skip,
   mercury_copy,
-  mercury_pad
+  mercury_pad,
+  HDRSIZE
+};
+
+static struct mps_fmt_mercury_s mercury_fmt_mercury_fixed_1_s =
+{
+  ALIGN,
+  mercury_scan_fixed,
+  mercury_skip_fixed_1,
+  mercury_copy_fixed_1,
+  mercury_pad_fixed,
+  0
+};
+
+static struct mps_fmt_mercury_s mercury_fmt_mercury_fixed_2_s =
+{
+  ALIGN,
+  mercury_scan_fixed,
+  mercury_skip_fixed_2,
+  mercury_copy_fixed_2,
+  mercury_pad_fixed,
+  0
+};
+
+static struct mps_fmt_mercury_s mercury_fmt_mercury_fixed_3_s =
+{
+  ALIGN,
+  mercury_scan_fixed,
+  mercury_skip_fixed_3,
+  mercury_copy_fixed_3,
+  mercury_pad_fixed,
+  0
+};
+
+static struct mps_fmt_mercury_s mercury_fmt_mercury_fixed_4_s =
+{
+  ALIGN,
+  mercury_scan_fixed,
+  mercury_skip_fixed_4,
+  mercury_copy_fixed_4,
+  mercury_pad_fixed,
+  0
+};
+
+static struct mps_fmt_mercury_s mercury_fmt_mercury_fixed_5_s =
+{
+  ALIGN,
+  mercury_scan_fixed,
+  mercury_skip_fixed_5,
+  mercury_copy_fixed_5,
+  mercury_pad_fixed,
+  0
+};
+
+static struct mps_fmt_mercury_s mercury_fmt_mercury_fixed_6_s =
+{
+  ALIGN,
+  mercury_scan_fixed,
+  mercury_skip_fixed_6,
+  mercury_copy_fixed_6,
+  mercury_pad_fixed,
+  0
 };
 
 mps_res_t mercury_scan(mps_ss_t mps_ss,
@@ -59,6 +141,14 @@
   	(Addr *)CLIENT_PTR_TO_BASE_PTR(limit_object));
 }
 
+mps_res_t mercury_scan_fixed(mps_ss_t mps_ss,
+                  mps_addr_t base_object,
+                  mps_addr_t limit_object)
+{
+  return TraceScanArea((ScanState)mps_ss,
+  	(Addr *)base_object, (Addr *)limit_object);
+}
+
 static mps_addr_t mercury_skip(mps_addr_t object)
 {
   mps_word_t *base;
@@ -70,6 +160,36 @@
   return (mps_addr_t)((mps_word_t *)object + num_words);
 }
 
+static mps_addr_t mercury_skip_fixed_1(mps_addr_t object)
+{
+  return (mps_addr_t)((mps_word_t *)object + 1);
+}
+
+static mps_addr_t mercury_skip_fixed_2(mps_addr_t object)
+{
+  return (mps_addr_t)((mps_word_t *)object + 2);
+}
+
+static mps_addr_t mercury_skip_fixed_3(mps_addr_t object)
+{
+  return (mps_addr_t)((mps_word_t *)object + 3);
+}
+
+static mps_addr_t mercury_skip_fixed_4(mps_addr_t object)
+{
+  return (mps_addr_t)((mps_word_t *)object + 4);
+}
+
+static mps_addr_t mercury_skip_fixed_5(mps_addr_t object)
+{
+  return (mps_addr_t)((mps_word_t *)object + 5);
+}
+
+static mps_addr_t mercury_skip_fixed_6(mps_addr_t object)
+{
+  return (mps_addr_t)((mps_word_t *)object + 6);
+}
+
 static void mercury_copy(mps_addr_t old, mps_addr_t new)
 {
   mps_word_t *old_base, *new_base;
@@ -89,6 +209,36 @@
   (void)memcpy(new_base, old_base, num_words * sizeof(mps_word_t));
 }
 
+static void mercury_copy_fixed_1(mps_addr_t old, mps_addr_t new)
+{
+  (void)memcpy((mps_word_t *)new, (mps_word_t *)old, 1 * sizeof(mps_word_t));
+}
+
+static void mercury_copy_fixed_2(mps_addr_t old, mps_addr_t new)
+{
+  (void)memcpy((mps_word_t *)new, (mps_word_t *)old, 2 * sizeof(mps_word_t));
+}
+
+static void mercury_copy_fixed_3(mps_addr_t old, mps_addr_t new)
+{
+  (void)memcpy((mps_word_t *)new, (mps_word_t *)old, 3 * sizeof(mps_word_t));
+}
+
+static void mercury_copy_fixed_4(mps_addr_t old, mps_addr_t new)
+{
+  (void)memcpy((mps_word_t *)new, (mps_word_t *)old, 4 * sizeof(mps_word_t));
+}
+
+static void mercury_copy_fixed_5(mps_addr_t old, mps_addr_t new)
+{
+  (void)memcpy((mps_word_t *)new, (mps_word_t *)old, 5 * sizeof(mps_word_t));
+}
+
+static void mercury_copy_fixed_6(mps_addr_t old, mps_addr_t new)
+{
+  (void)memcpy((mps_word_t *)new, (mps_word_t *)old, 6 * sizeof(mps_word_t));
+}
+
 /*
 void mercury_fwd(mps_addr_t old,
             mps_addr_t new)
@@ -117,7 +267,7 @@
 
   /* XXX is `addr' supposed to be a base pointer or a client pointer? */
   /* i.e. does it point at or past the header word? */
-  assert(0);
+  abort();
 #if 1
   p = (mps_word_t *)addr;
 #else
@@ -133,6 +283,15 @@
   }
 }
 
+static void mercury_pad_fixed(mps_addr_t addr, size_t size)
+{
+  /* Make sure the size is aligned. */
+  assert((size & (ALIGN-1)) == 0);
+
+  /* null out the storage */
+  memset((void *)addr, 0, size);
+}
+
 /*
 mps_addr_t mercury_class(mps_addr_t obj)
 {
@@ -149,6 +308,36 @@
   return &mercury_fmt_mercury_s;
 }
 
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_1(void)
+{
+  return &mercury_fmt_mercury_fixed_1_s;
+}
+
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_2(void)
+{
+  return &mercury_fmt_mercury_fixed_2_s;
+}
+
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_3(void)
+{
+  return &mercury_fmt_mercury_fixed_3_s;
+}
+
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_4(void)
+{
+  return &mercury_fmt_mercury_fixed_4_s;
+}
+
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_5(void)
+{
+  return &mercury_fmt_mercury_fixed_5_s;
+}
+
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_6(void)
+{
+  return &mercury_fmt_mercury_fixed_6_s;
+}
+
 /* Format variety-independent version that picks the right format
  * variety and creates it.  */
 
@@ -156,6 +345,43 @@
 {
   return mps_fmt_create_mercury(mps_fmt_o, mps_arena, mercury_fmt_mercury());
 }
+
+mps_res_t mercury_fmt_fixed_1(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena)
+{
+  return mps_fmt_create_mercury(mps_fmt_o, mps_arena,
+  			        mercury_fmt_mercury_fixed_1());
+}
+
+mps_res_t mercury_fmt_fixed_2(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena)
+{
+  return mps_fmt_create_mercury(mps_fmt_o, mps_arena,
+  			        mercury_fmt_mercury_fixed_2());
+}
+
+mps_res_t mercury_fmt_fixed_3(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena)
+{
+  return mps_fmt_create_mercury(mps_fmt_o, mps_arena,
+  			        mercury_fmt_mercury_fixed_3());
+}
+
+mps_res_t mercury_fmt_fixed_4(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena)
+{
+  return mps_fmt_create_mercury(mps_fmt_o, mps_arena,
+  			        mercury_fmt_mercury_fixed_4());
+}
+
+mps_res_t mercury_fmt_fixed_5(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena)
+{
+  return mps_fmt_create_mercury(mps_fmt_o, mps_arena,
+  			        mercury_fmt_mercury_fixed_5());
+}
+
+mps_res_t mercury_fmt_fixed_6(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena)
+{
+  return mps_fmt_create_mercury(mps_fmt_o, mps_arena,
+  			        mercury_fmt_mercury_fixed_6());
+}
+
 
 /* C. COPYRIGHT AND LICENSE
  *
diff -u mps_gc/code/fmtme.h mps_gc/code/fmtme.h
--- mps_gc/code/fmtme.h
+++ mps_gc/code/fmtme.h
@@ -13,22 +13,40 @@
  *	which is scanned conservatively.
  */
 
+#ifndef fmtme_h
+#define fmtme_h
+
 #include "mps.h"
 
-/* Function returning the mercury format structure */
+/* Functions returning the mercury format structures */
 
 mps_fmt_mercury_s *mercury_fmt_mercury(void);
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_1(void);
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_2(void);
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_3(void);
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_4(void);
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_5(void);
+mps_fmt_mercury_s *mercury_fmt_mercury_fixed_6(void);
 
-/* Format variety-independent version that picks the right format
- * variety and creates it.  */
+/* Format variety-independent versions that pick the right format
+ * variety and create it.  */
 
 mps_res_t mercury_fmt(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
+mps_res_t mercury_fmt_fixed_1(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
+mps_res_t mercury_fmt_fixed_2(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
+mps_res_t mercury_fmt_fixed_3(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
+mps_res_t mercury_fmt_fixed_4(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
+mps_res_t mercury_fmt_fixed_5(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
+mps_res_t mercury_fmt_fixed_6(mps_fmt_t *mps_fmt_o, mps_arena_t mps_arena);
 
 #define ALIGN   	(sizeof(mps_word_t))
+#define HDRSIZE   	(1 * sizeof(mps_word_t))
 #define TAGMASK   	(sizeof(mps_word_t) - 1)
 
 #define BASE_PTR_TO_CLIENT_PTR(p)((mps_word_t *)(p) + 1)
 #define CLIENT_PTR_TO_BASE_PTR(p)((mps_word_t *)((mps_word_t)p & ~TAGMASK) - 1)
+
+#endif /* fmtme_h */
 
 /* C. COPYRIGHT AND LICENSE
  *
diff -u mps_gc/code/mercury_mps.c mps_gc/code/mercury_mps.c
--- mps_gc/code/mercury_mps.c
+++ mps_gc/code/mercury_mps.c
@@ -2,14 +2,14 @@
  * memory pool system kit.
  *
  * Copyright (c) 2002 Fergus Henderson and The University of Melbourne.
- * Portions Copyright (c) 2001 Ravenbrook Limited.  
+ * Portions copyright (c) 2001 Ravenbrook Limited.  
  * Portions copyright (c) 2002 Global Graphics Software.
  * See end of file for license.
  *
  * .design: Adapted from amsss.c.
- *	Uses a new "Mercury" object format.
+ *	Uses a new set of "Mercury" object formats.
  *	Conservative scanning.
- *	Parts of the interface designed to mimmick the
+ *	Parts of the interface designed to mimick the
  *	interface of the Boehm (et al) conservative collector.
  * DONE:
  *	- test writing to fields [done]
@@ -17,16 +17,30 @@
  *	- put the test code into a separate file [done]
  *	- define header file and abstract out the appropriate interfaces [done]
  *	- use GC_stackbottom, GC_init [done]
+ *	- register main thread's stack as roots [done]
+ *	- add extra pools for small fixed-size objects [done]
+ *	- add extra pools for atomic objects [done]
+ *	- register global data as roots [done, for Linux]
  * TODO:
- *	- add extra pools for small fixed-size objects
- *	- add extra pools for atomic objects
- *	- register main thread's stack as roots
- *	- register global data as roots
- *	- register global data in shared libraries as roots
+ *	- port to non-Linux systems:
+ *	  register global data as roots for non-Linux systems
+ *	- handle shared libraries:
+ *	  register global data in shared libraries as roots
+ *	- handle multi-threading
+ *	- align double-precision floats properly
+ *	- handle GC_MALLOC_UNCOLLECTABLE() properly
+ *	- try using mps_alloc() in MERCURY_MPS_ALLOC_FIXED()
+ *	- avoid using GC_REALLOC(); instead provide a different
+ *	  interface where the old size is passed in
+ *	- small-object optimizations in the inline allocation case
  */
 
+#if 0
 #include "testlib.h"
+#endif
 #include "mpscams.h"
+#include "mpscamsc.h"
+#include "mpsclo.h"
 #include "mpsavm.h"
 #include "mpstd.h"
 #ifdef MPS_OS_W3
@@ -40,28 +54,41 @@
 #include <math.h>
 #include <string.h>
 #include <assert.h>
+#include <stdio.h>
 
 static void mercury_init_cell(mps_addr_t addr, size_t size);
 
 mps_arena_t	mercury_mps_arena;
-mps_ap_t	mercury_mps_ap; /* XXX should be thread-local */
+mps_ap_t	mercury_mps_aps[MERCURY_NUM_POOLS]; /* XXX s.b. thread-local */
 mps_thr_t	mercury_mps_thread; /* XXX should be thread-local */
 mps_root_t	mercury_mps_stack; /* XXX should be thread-local */
-mps_fmt_t	mercury_mps_format;
+mps_root_t	mercury_mps_global_data;
+mps_fmt_t	mercury_mps_formats[MERCURY_NUM_FMTS];
 mps_chain_t	mercury_mps_chain;
-mps_pool_t	mercury_mps_pool;
+mps_pool_t	mercury_mps_pools[MERCURY_NUM_POOLS];
 
 void *GC_stackbottom;
 
 static mps_pool_debug_option_s freecheckOptions =
   { NULL, 0, (void *)"Dead", 4 };
 
-/* One generation, with a capacity of 160k,
+/* One generation, with a capacity of 16M,
    and an expected mortality rate of 90%. */
-static mps_gen_param_s chain_params[1] = { { 160, 0.90 } };
+static mps_gen_param_s chain_params[1] = { { 16 * 1024, 0.90 } };
 
 /* check -- Test a return code, and exit on error */
 
+static void error (const char *format, ...) {
+  va_list args;
+  fprintf(stderr, "MPS error: ");
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  fputc('\n', stderr);
+  va_end(args);
+  exit(EXIT_FAILURE);
+  assert(0);
+}
+
 static void check(mps_res_t res, const char *s)
 {
   if (res != MPS_RES_OK) {
@@ -69,41 +96,140 @@
   }
 }
 
+/*
+ * XXX This is Linux-specific. 
+ * Unfortunately there is no portable way to do this.
+ * The Boehm collector has a whole rat's nest of ifdefs for this;
+ * see boehm_gc/include/private/gcconfig.h.
+ */
+extern int __data_start[];
+extern int _end[];
+#define DATASTART __data_start
+#define DATAEND _end
+
 void mercury_mps_init(size_t initial_vm_size, mps_bool_t debug)
 {
+  int pool, fmt, wordsz;
+
+  /* Create the arena */
   check(mps_arena_create(&mercury_mps_arena, mps_arena_class_vm(),
   		       initial_vm_size),
         "arena_create");
-  check(mps_thread_reg(&mercury_mps_thread, mercury_mps_arena), "thread_reg");
 
+  /* Register the main thread, and its stack.
+     XXX These should be per-thread. */
+  check(mps_thread_reg(&mercury_mps_thread, mercury_mps_arena), "thread_reg");
   check(mps_root_create_reg(&mercury_mps_stack, mercury_mps_arena,
 			    MPS_RANK_AMBIG, 0, mercury_mps_thread,
 			    mps_stack_scan_ambig, GC_stackbottom, 0),
       "Root Create\n");
-  check(mercury_fmt(&mercury_mps_format, mercury_mps_arena), "fmt_create");
+
+  /* Register the global data as a root. */
+  check(mps_root_create_table(&mercury_mps_global_data, mercury_mps_arena,
+			    MPS_RANK_AMBIG, 0,
+			    (mps_addr_t *)DATASTART,
+			    (mps_addr_t *)DATAEND - (mps_addr_t *)DATASTART),
+      "Root Create\n");
+
+  /* Create the Mercury object formats. */
+  check(mercury_fmt(&mercury_mps_formats[MERCURY_FMT_GENERAL],
+  		    mercury_mps_arena), "fmt_create");
+  check(mercury_fmt_fixed_1(&mercury_mps_formats[MERCURY_FMT_SMALL_1],
+  		    mercury_mps_arena), "fmt_create");
+  check(mercury_fmt_fixed_2(&mercury_mps_formats[MERCURY_FMT_SMALL_2],
+  		    mercury_mps_arena), "fmt_create");
+  check(mercury_fmt_fixed_3(&mercury_mps_formats[MERCURY_FMT_SMALL_3],
+  		    mercury_mps_arena), "fmt_create");
+  check(mercury_fmt_fixed_4(&mercury_mps_formats[MERCURY_FMT_SMALL_4],
+  		    mercury_mps_arena), "fmt_create");
+  check(mercury_fmt_fixed_5(&mercury_mps_formats[MERCURY_FMT_SMALL_5],
+  		    mercury_mps_arena), "fmt_create");
+  check(mercury_fmt_fixed_6(&mercury_mps_formats[MERCURY_FMT_SMALL_6],
+  		    mercury_mps_arena), "fmt_create");
+
+  /* Create the different pools. */
   check(mps_chain_create(&mercury_mps_chain, mercury_mps_arena, 1,
 			 chain_params),
         "chain_create");
   if (debug) {
-    check(mps_pool_create(&mercury_mps_pool, mercury_mps_arena,
-    			mps_class_ams_debug(), &freecheckOptions,
-			mercury_mps_format, mercury_mps_chain, TRUE),
+    check(mps_pool_create(&mercury_mps_pools[MERCURY_POOL_GENERAL],
+    			  mercury_mps_arena, mps_class_ams_debug(),
+			  &freecheckOptions,
+			  mercury_mps_formats[MERCURY_FMT_GENERAL],
+			  mercury_mps_chain, 1 /* allow_ambig=TRUE */),
           "pool_create(ams_debug,ambig)");
+    for (pool = MERCURY_POOL_SMALL_1, fmt = MERCURY_FMT_SMALL_1;
+         pool <= MERCURY_POOL_SMALL_6 && fmt <= MERCURY_FMT_SMALL_6;
+	 pool++, fmt++)
+    {
+      check(mps_pool_create(&mercury_mps_pools[pool],
+    			  mercury_mps_arena, mps_class_ams_debug(),
+			  &freecheckOptions,
+			  mercury_mps_formats[fmt],
+			  mercury_mps_chain, 1 /* allow_ambig=TRUE */),
+          "pool_create(ams,ambig)");
+    }
   } else {
-    check(mps_pool_create(&mercury_mps_pool, mercury_mps_arena, mps_class_ams(),
-    			mercury_mps_format, mercury_mps_chain, TRUE),
+#if 1
+    check(mps_pool_create(&mercury_mps_pools[MERCURY_POOL_GENERAL],
+    			  mercury_mps_arena, mps_class_amsc(),
+			  mercury_mps_formats[MERCURY_FMT_GENERAL],
+			  mercury_mps_chain, 1 /* allow_ambig=TRUE */),
+          "pool_create(ams,ambig)");
+#else
+    check(mps_pool_create(&mercury_mps_pools[MERCURY_POOL_GENERAL],
+    			  mercury_mps_arena, mps_class_ams(),
+			  mercury_mps_formats[MERCURY_FMT_GENERAL],
+			  mercury_mps_chain, 1 /* allow_ambig=TRUE */),
+          "pool_create(ams,ambig)");
+#endif
+    for (wordsz = 1, pool = MERCURY_POOL_SMALL_1, fmt = MERCURY_FMT_SMALL_1;
+         wordsz <= 6 /* MERCURY_POOL_SMALL_6, MERCURY_FMT_SMALL_6 */;
+	 wordsz++, pool++, fmt++)
+    {
+#if 0
+      check(mps_pool_create(&mercury_mps_pools[pool], mercury_mps_arena,
+			  mps_class_amscf(),
+			  mercury_mps_formats[fmt],
+			  mercury_mps_chain, wordsz),
+          "pool_create(ams,ambig)");
+#else
+      check(mps_pool_create(&mercury_mps_pools[pool], mercury_mps_arena,
+			  mps_class_ams(), mercury_mps_formats[fmt],
+			  mercury_mps_chain, 1 /* allow_ambig=TRUE */),
           "pool_create(ams,ambig)");
+#endif
+    }
+  }
+  check(mps_pool_create(&mercury_mps_pools[MERCURY_POOL_ATOMIC],
+  			mercury_mps_arena, mps_class_lo(),
+			mercury_mps_formats[MERCURY_FMT_GENERAL]),
+          "pool_create(lo)");
+
+  
+  /* Create the allocation points, one for each pool.
+     XXX These should also be per-thread. */
+  for (pool = 0; pool < MERCURY_NUM_POOLS; pool++) {
+	  check(mps_ap_create(&mercury_mps_aps[pool], mercury_mps_pools[pool],
+	  	MPS_RANK_AMBIG), "ap_create");
   }
-  check(mps_ap_create(&mercury_mps_ap, mercury_mps_pool, MPS_RANK_AMBIG),
-        "ap_create");
 }
 
 void mercury_mps_finish(void)
 {
-  mps_ap_destroy(mercury_mps_ap);
-  mps_pool_destroy(mercury_mps_pool);
+  int pool, format;
+
+  for (pool = 0; pool < MERCURY_NUM_POOLS; pool++) {
+	  mps_ap_destroy(mercury_mps_aps[pool]);
+  }
+  for (pool = 0; pool < MERCURY_NUM_POOLS; pool++) {
+	  mps_pool_destroy(mercury_mps_pools[pool]);
+  }
   mps_chain_destroy(mercury_mps_chain);
-  mps_fmt_destroy(mercury_mps_format);
+  for (format = 0; format < MERCURY_NUM_FMTS; format++) {
+	  mps_fmt_destroy(mercury_mps_formats[format]);
+  }
+  mps_root_destroy(mercury_mps_global_data);
   mps_root_destroy(mercury_mps_stack);
   mps_thread_dereg(mercury_mps_thread);
   mps_arena_destroy(mercury_mps_arena);
@@ -128,23 +254,44 @@
   }
 }
 
-/* Allocate a cell containing the specified number of words.
-   The pointer returned will be word-aligned. */
+/* Documented in mercury_mps.h */
 mps_addr_t mercury_mps_alloc(size_t num_words)
 {
-  size_t size = (num_words + 1) * sizeof(mps_word_t);
   mps_addr_t p;
-  mps_res_t res;
-
-  do {
-    MPS_RESERVE_BLOCK(res, p, mercury_mps_ap, size);
-    if (res) {
-      check(res, "MPS_RESERVE_BLOCK");
-    }
-    mercury_init_cell(p, size);
-  } while(!mps_commit(mercury_mps_ap, p, size));
+  switch(num_words) {
+    default:
+      MERCURY_MPS_ALLOC(p, MERCURY_POOL_GENERAL, num_words);
+      return p;
+    case 1:
+      MERCURY_MPS_ALLOC_FIXED(p, MERCURY_POOL_SMALL_1, num_words);
+      return p;
+    case 2:
+      MERCURY_MPS_ALLOC_FIXED(p, MERCURY_POOL_SMALL_2, num_words);
+      return p;
+    case 3:
+      /* XXX problem with size-3 pools, use size-4 instead */
+      MERCURY_MPS_ALLOC_FIXED(p, MERCURY_POOL_SMALL_4, 4);
+      return p;
+    case 4:
+      MERCURY_MPS_ALLOC_FIXED(p, MERCURY_POOL_SMALL_4, num_words);
+      return p;
+#if 0
+    case 5:
+      MERCURY_MPS_ALLOC_FIXED(p, MERCURY_POOL_SMALL_5, num_words);
+      return p;
+    case 6:
+      MERCURY_MPS_ALLOC_FIXED(p, MERCURY_POOL_SMALL_6, num_words);
+      return p;
+#endif
+  }
+}
 
-  return (mps_addr_t)BASE_PTR_TO_CLIENT_PTR(p);
+/* Documented in mercury_mps.h */
+mps_addr_t mercury_mps_alloc_atomic(size_t num_words)
+{
+  mps_addr_t p;
+  MERCURY_MPS_ALLOC(p, MERCURY_POOL_ATOMIC, num_words);
+  return p;
 }
 
 /* C. COPYRIGHT AND LICENSE
diff -u mps_gc/code/mercury_mps.h mps_gc/code/mercury_mps.h
--- mps_gc/code/mercury_mps.h
+++ mps_gc/code/mercury_mps.h
@@ -4,14 +4,42 @@
  * Copyright (c) 2002 Fergus Henderson and The University of Melbourne.
  */
 
+#ifndef mercury_mps_h
+#define mercury_mps_h
+
 #include "mps.h"
 
+enum MercuryPoolKind {
+	MERCURY_POOL_GENERAL,
+	MERCURY_POOL_SMALL_1,
+	MERCURY_POOL_SMALL_2,
+	MERCURY_POOL_SMALL_3,
+	MERCURY_POOL_SMALL_4,
+	MERCURY_POOL_SMALL_5,
+	MERCURY_POOL_SMALL_6,
+	MERCURY_POOL_ATOMIC,
+	MERCURY_NUM_POOLS
+};
+
+enum MercuryFormatKind {
+	MERCURY_FMT_GENERAL,
+	MERCURY_FMT_SMALL_1,
+	MERCURY_FMT_SMALL_2,
+	MERCURY_FMT_SMALL_3,
+	MERCURY_FMT_SMALL_4,
+	MERCURY_FMT_SMALL_5,
+	MERCURY_FMT_SMALL_6,
+	MERCURY_NUM_FMTS
+};
+
 extern mps_arena_t	mercury_mps_arena;
-extern mps_ap_t		mercury_mps_ap; /* XXX should be thread-local */
-extern mps_thr_t	mercury_mps_thread; /* XXX should be thread-local */
-extern mps_fmt_t	mercury_mps_format;
+extern mps_ap_t		mercury_mps_aps[MERCURY_NUM_POOLS];
+					/* XXX should be thread-local */
+extern mps_thr_t	mercury_mps_thread; /* XXX thread-local */
+extern mps_root_t	mercury_mps_stack; /* XXX should be thread-local */
+extern mps_fmt_t	mercury_mps_formats[MERCURY_NUM_FMTS];
 extern mps_chain_t	mercury_mps_chain;
-extern mps_pool_t	mercury_mps_pool;
+extern mps_pool_t	mercury_mps_pools[MERCURY_NUM_POOLS];
 
 /* Allocate and initialize the MPS data structures.
    The initial_vm_size argument specifies the initial virtual memory
@@ -25,9 +53,67 @@
 
 /* Allocate a cell containing the specified number of words.
    The pointer returned will be word-aligned.
+   Fields of the cell will be conservatively scanned by the
+   garbage collector.
    Requires mercury_mps_init() to have been called first.  */
 mps_addr_t mercury_mps_alloc(size_t num_words);
 
+/* Like mps_alloc(), except that the memory will not be scanned
+   by the garbage collector (hence it must not contain pointers).  */
+mps_addr_t mercury_mps_alloc_atomic(size_t num_words);
+
+#define MERCURY_MPS_ALLOC(dest, pool, num_words) \
+	do { \
+	  size_t mma_size = ((num_words) + 1) * sizeof(mps_word_t); \
+	  mps_addr_t mma_p; \
+	  mps_res_t mma_res; \
+	  \
+	  do { \
+	    MPS_RESERVE_BLOCK(mma_res, mma_p, mercury_mps_aps[pool], \
+	    	mma_size); \
+	    if (mma_res) { \
+	      check(mma_res, "MPS_RESERVE_BLOCK"); \
+	    } \
+	    mercury_init_cell(mma_p, mma_size); \
+	  } while(!mps_commit(mercury_mps_aps[pool], mma_p, mma_size)); \
+	  \
+	  (dest) = (mps_addr_t)BASE_PTR_TO_CLIENT_PTR(mma_p); \
+	} while (0)
+
+#if 1
+#define MERCURY_MPS_ALLOC_FIXED(dest, pool, num_words) \
+	do { \
+	  size_t mma_size = (num_words) * sizeof(mps_word_t); \
+	  mps_addr_t mma_p; \
+	  mps_res_t mma_res; \
+	  \
+	  do { \
+	    MPS_RESERVE_BLOCK(mma_res, mma_p, mercury_mps_aps[pool], \
+	    	mma_size); \
+	    if (mma_res) { \
+	      check(mma_res, "MPS_RESERVE_BLOCK"); \
+	    } \
+	  } while(!mps_commit(mercury_mps_aps[pool], mma_p, mma_size)); \
+	  \
+	  (dest) = mma_p; \
+	} while (0)
+#else
+/* tried using mps_alloc() here rather than reserve/commit -- didn't work */
+#define MERCURY_MPS_ALLOC_FIXED(dest, pool, num_words) \
+	do { \
+	  size_t mma_size = (num_words) * sizeof(mps_word_t); \
+	  mps_addr_t mma_p; \
+	  mps_res_t mma_res; \
+	  \
+	  mma_res = mps_alloc(&mma_p, mercury_mps_pools[pool], mma_size); \
+	  if (mma_res) { \
+	    check(mma_res, "MPS_RESERVE_BLOCK"); \
+	  } \
+	  \
+	  (dest) = mma_p; \
+	} while (0)
+#endif
+
 /*
 ** Define some wrappers around the MPS interface that make it a bit
 ** more like the Boehm collector's interface.
@@ -42,13 +128,13 @@
   mercury_mps_alloc(((bytes) + sizeof(mps_word_t) - 1) / sizeof(mps_word_t))
 
 /* XXX only word-aligned, not double-word-aligned */
-/* XXX should allocate in an atomic pool */
 #define GC_MALLOC_ATOMIC(bytes) \
-  mercury_mps_alloc(((bytes) + sizeof(mps_word_t) - 1) / sizeof(mps_word_t))
+  mercury_mps_alloc_atomic(((bytes) + sizeof(mps_word_t) - 1) / \
+  	sizeof(mps_word_t))
 
-/* XXX should be inline */
+/* XXX should use small-object pools */
 #define GC_MALLOC_WORDS(ptr, num_wds) \
-  ((ptr) = mercury_mps_alloc(num_wds))
+  MERCURY_MPS_ALLOC((ptr), MERCURY_POOL_GENERAL, (num_wds))
 
 /* XXX FIXME should ensure that it doesn't get collected */
 #define GC_MALLOC_UNCOLLECTABLE(bytes) \
@@ -67,3 +153,4 @@
   (mps_arena_collect(mercury_mps_arena), \
    mps_arena_release(mercury_mps_arena))
 
+#endif /* mercury_mps_h */
diff -u mps_gc/code/mercury_mps_ss.c mps_gc/code/mercury_mps_ss.c
--- mps_gc/code/mercury_mps_ss.c
+++ mps_gc/code/mercury_mps_ss.c
@@ -34,12 +34,23 @@
 
 /* make -- object allocation and init */
 
-static mps_addr_t make(void)
+static mps_addr_t make(mps_addr_t *refs, size_t nr_refs)
 {
   size_t length = (rnd() % 20) + 1, size = (length+1) * sizeof(mps_word_t);
-  mps_addr_t p;
+  mps_word_t *p;
+  int i;
 
-  p = mercury_mps_alloc(length);
+  if (rnd() & 1)
+    p = (mps_word_t *)mercury_mps_alloc(length);
+  else
+    p = (mps_word_t *)mercury_mps_alloc_atomic(length);
+
+  for(i = 0; i < length; ++i) {
+    if(rnd() & 1)
+      p[i] = rnd() | 0x1001; /* random odd int */
+    else
+      p[i] = (mps_word_t)refs[rnd() % nr_refs]; /* random ptr */
+  }
 
   totalSize += size;
   return (mps_addr_t) ((mps_word_t)p | (rnd() & TAGMASK));
@@ -67,16 +78,14 @@
 
 static void *test(void *arg, size_t haveAmbigous)
 {
-  mps_pool_t pool;
   mps_root_t exactRoot, ambigRoot;
   size_t lastStep = 0, i, r;
   unsigned long objs;
   mps_ap_t busy_ap;
   mps_addr_t busy_init;
 
-  pool = (mps_pool_t)arg;
-
-  die(mps_ap_create(&busy_ap, pool, MPS_RANK_AMBIG), "BufferCreate 2");
+  die(mps_ap_create(&busy_ap, mercury_mps_pools[MERCURY_POOL_GENERAL],
+  	MPS_RANK_AMBIG), "BufferCreate 2");
 
   for(i = 0; i < exactRootsCOUNT; ++i)
     exactRoots[i] = objNULL;
@@ -118,15 +127,15 @@
       if (exactRoots[i] != objNULL)
         cdie(mercury_check(exactRoots[i]), "dying root check");
 #endif
-      exactRoots[i] = make();
-#if 1
+      exactRoots[i] = make(exactRoots, exactRootsCOUNT);
+#if 0
       if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL)
         mercury_write(exactRoots[(exactRootsCOUNT-1) - i],
                     exactRoots, exactRootsCOUNT);
 #endif
     } else {
       i = (r >> 1) % ambigRootsCOUNT;
-      ambigRoots[(ambigRootsCOUNT-1) - i] = make();
+      ambigRoots[(ambigRootsCOUNT-1) - i] = make(exactRoots, exactRootsCOUNT);
       /* Create random interior pointers */
       ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 5);
     }
@@ -134,8 +143,10 @@
     if (rnd() % initTestFREQ == 0)
       *(int*)busy_init = -1; /* check that the buffer is still there */
 
-    if (rnd() % splatTestFREQ == 0)
-      mps_pool_check_free_space(pool);
+    if (rnd() % splatTestFREQ == 0) {
+      mps_pool_check_free_space(mercury_mps_pools[MERCURY_POOL_ATOMIC]);
+      mps_pool_check_free_space(mercury_mps_pools[MERCURY_POOL_GENERAL]);
+    }
 
     ++objs;
     if (objs % 256 == 0) {
@@ -163,12 +174,12 @@
 
   printf("\nAMS Debug\n");
   mercury_mps_init(testArenaSIZE, TRUE);
-  mps_tramp(&r, test, mercury_mps_pool, 1);
+  mps_tramp(&r, test, NULL, 1);
   mercury_mps_finish();
 
   printf("\nAMS\n");
   mercury_mps_init(testArenaSIZE, FALSE);
-  mps_tramp(&r, test, mercury_mps_pool, 1);
+  mps_tramp(&r, test, NULL, 1);
   mercury_mps_finish();
 
   fflush(stdout); /* synchronize */
diff -u mps_gc/code/mps.h mps_gc/code/mps.h
--- mps_gc/code/mps.h
+++ mps_gc/code/mps.h
@@ -226,6 +226,7 @@
   mps_fmt_skip_t  skip;
   mps_fmt_copy_t  copy;
   mps_fmt_pad_t   pad;
+  size_t          headerSize;
 } mps_fmt_mercury_s;
 
 
diff -u mps_gc/code/mpsi.c mps_gc/code/mpsi.c
--- mps_gc/code/mpsi.c
+++ mps_gc/code/mpsi.c
@@ -633,7 +633,7 @@
                      (FormatCopyMethod)mps_fmt_mercury->copy,
                      (FormatPadMethod)mps_fmt_mercury->pad,
 		     NULL, /* class */
-                     (Size)sizeof(mps_word_t));
+                     (Size)mps_fmt_mercury->headerSize);
 
   ArenaLeave(arena);
 
only in patch2:
--- mps_gc/code/protlii3.c	21 Aug 2002 08:43:38 -0000	1.1.1.1
+++ mps_gc/code/protlii3.c	4 Aug 2002 14:24:03 -0000
@@ -77,10 +77,23 @@
  *  sensible
  */
 
+#include <stdio.h>
+#include <unistd.h>
+void sig_printf(const char *fmt, ...) {
+  char buf[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  write(2, buf, strlen(buf));
+  va_end(args);
+}
+
 static void sigHandle(int sig, struct sigcontext context)  /* .sigh.args */
 {
   AVER(sig == SIGSEGV);
 
+  if (0) sig_printf("sigHandle(%d)\n", sig);
+
   if(context.trapno == TRAPNO_PAGE_FAULT) {  /* .sigh.context */
     AccessSet mode;
     Addr base, limit;
@@ -96,15 +109,20 @@
     base = (Addr)context.cr2;   /* .sigh.addr */
     limit = AddrAdd(base, (Size)sizeof(Addr));
 
+    if (0) sig_printf("sigHandle: base = %p\n", (void *)base);
+
     /* Offer each protection structure the opportunity to handle the */
     /* exception.  If it succeeds, then allow the mutator to continue. */
 
-    if(ArenaAccess(base, mode, &mfContext))
+    if(ArenaAccess(base, mode, &mfContext)) {
+      if (0) sig_printf("sigHandle: handled\n");
       return;
+    }
   }
 
   /* The exception was not handled by any known protection structure, */
   /* so throw it to the previously installed handler. */
+  if (0) sig_printf("sigHandle: rethrow\n");
 
   /* @@@@ This is really weak. */
   /* Need to implement rest of the contract of sigaction */
@@ -114,10 +132,12 @@
   switch ((int)sigNext.sa_handler) {
   case (int)SIG_DFL:
   case (int)SIG_IGN:
+    if (0) sig_printf("sigHandle: abort\n");
     abort();
     NOTREACHED;
     break;
   default:
+    if (0) sig_printf("sigHandle: call handler\n");
     (*(__real_lii3_sighandler_t)sigNext.sa_handler)(sig, context);
     break;
   }
only in patch2:
--- mps_gc/code/poollo.c	21 Aug 2002 08:43:38 -0000	1.1.1.1
+++ mps_gc/code/poollo.c	2 Aug 2002 08:35:38 -0000
@@ -727,9 +727,12 @@
 
   switch(ss->rank) {
   case RankAMBIG:
+    /* XXX This test disabled, to allow tagged pointers. -fjh. */
+#if 0
     if(!AddrIsAligned(base, PoolAlignment(pool))) {
       return ResOK;
     }
+#endif
   /* fall through */
 
   case RankEXACT:
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mps_gc/code/poolamsci.c	7 Aug 2002 04:10:44 -0000
@@ -0,0 +1,66 @@
+/* poolamsic.c: CONSERVATIVE AUTOMATIC MARK & SWEEP POOL CLASS C INTERFACE
+ *
+ * $Id: //info.ravenbrook.com/project/mps/version/1.100/code/poolamsi.c#1 $
+ * Copyright (c) 2001 Ravenbrook Limited.  See end of file for license.
+ */
+
+#include "mpscamsc.h"
+#include "mps.h"
+#include "poolamsc.h"
+#include "poolamscf.h"
+
+/* mps_class_amsc -- return the AMSC pool class descriptor */
+
+mps_class_t mps_class_amsc(void)
+{
+  return (mps_class_t)AMSCPoolClassGet();
+}
+
+/* mps_class_amscf -- return the AMSCF pool class descriptor */
+
+mps_class_t mps_class_amscf(void)
+{
+  return (mps_class_t)AMSCFPoolClassGet();
+}
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
+ * All rights reserved.  This is an open source license.  Contact
+ * Ravenbrook for commercial licensing options.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software.  The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions.  For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mps_gc/code/poolamscf.h	7 Aug 2002 03:40:34 -0000
@@ -0,0 +1,75 @@
+/* poolamscf.h: CONSERVATIVE AUTOMATIC MARK & SWEEP POOL CLASS INTERFACE
+ *
+ * Copyright (C) 2002 Fergus Henderson and The University of Melbourne.
+ * Portions copyright (c) 2001 Ravenbrook Limited.  See end of file for license.
+ * Portions copyright (C) 2002 Global Graphics Software.
+ *
+ * .purpose: Internal interface to AMSC functionality.  */
+
+#ifndef poolamscf_h
+#define poolamscf_h
+
+#include "mpmtypes.h"
+#include "mpmst.h"
+#include "ring.h"
+#include "bt.h"
+#include "poolams.h"
+#include <stdarg.h>
+
+
+typedef struct AMSCFStruct *AMSCF;
+
+extern Bool AMSCFCheck(AMSCF ams);
+
+extern Res AMSCFScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg);
+extern Res AMSCFFix(Pool pool, ScanState ss, Seg seg, Ref *refIO);
+
+typedef PoolClass AMSCFPoolClass;
+typedef PoolClassStruct AMSCFPoolClassStruct;
+
+extern AMSCFPoolClass AMSCFPoolClassGet(void);
+
+
+#endif /* poolamscf_h */
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
+ * All rights reserved.  This is an open source license.  Contact
+ * Ravenbrook for commercial licensing options.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software.  The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions.  For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mps_gc/code/poolamscf.c	7 Aug 2002 23:55:56 -0000
@@ -0,0 +1,478 @@
+/* poolamscf.c: FIXED-SIZE CONSERVATIVE AUTOMATIC MARK & SWEEP POOL CLASS
+ *
+ * Copyright (c) 2002 Fergus Henderson and The University of Melbourne.
+ *
+ * $Id: //info.ravenbrook.com/project/mps/version/1.100/code/poolams.c#2 $
+ * Portions Copyright (c) 2001 Ravenbrook Limited.  See end of file for license.
+ * Portions copyright (c) 2002 Global Graphics Software.
+ *
+ *
+ * .design: See <design/poolams/>.
+ *
+ */
+
+#include "mps.h"
+#include "fmtme.h"
+#include "poolamscf.h"
+#include "mpm.h"
+#include "mpmtypes.h"
+#include <stdarg.h>
+
+/* AMSCFStruct -- structure for a conservative fixed-size subclass */
+
+typedef struct AMSCFStruct {
+  AMSStruct amsStruct;          /* AMS structure */
+  size_t num_words;		/* The object size for objects in this pool */
+} AMSCFStruct;
+
+#define AMS2AMSCF(ams)  PARENT(AMSCFStruct, amsStruct, ams)
+#define AMSCF2AMS(amsd) (&((amsd)->amsStruct))
+
+static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos);
+
+/* amsIterate -- applies amsScanObject to each object in a segment
+ *
+ * amsIterate(seg, f, closure) applies f to all the objects in the
+ * segment.  It skips the buffer, if any (from BufferScanLimit to
+ * BufferLimit).  */
+
+static Res amsIterate(Seg seg, void *closure)
+{
+  Res res;
+  AMS ams;
+  AMSCF amscf;
+  AMSSeg amsseg;
+  Align alignment;
+  Index i;
+  Addr p, next, limit;
+  Buffer buffer;
+
+  AVERT(Seg, seg);
+  /* Can't check closure */
+
+  amsseg = Seg2AMSSeg(seg);
+  AVERT(AMSSeg, amsseg);
+  ams = amsseg->ams;
+  AVERT(AMS, ams);
+  amscf = AMS2AMSCF(ams);
+  AVERT(AMSCF, amscf);
+  alignment = PoolAlignment(AMS2Pool(ams));
+
+  /* If we're using the alloc table as a white table, we can't use it to */
+  /* determine where there are objects. */
+  AVER(!(ams->shareAllocTable && amsseg->colourTablesInUse));
+
+  p = SegBase(seg);
+  limit = SegLimit(seg);
+  buffer = SegBuffer(seg);
+
+  while (p < limit) { /* loop over the objects in the segment */
+    if (buffer != NULL
+        && p == BufferScanLimit(buffer) && p != BufferLimit(buffer)) {
+      /* skip buffer */
+      next = BufferLimit(buffer);
+      AVER(AddrIsAligned(next, alignment));
+    } else {
+      AVER((buffer == NULL)
+	   || (p < BufferScanLimit(buffer))
+	   || (p >= BufferLimit(buffer)));  /* not in the buffer */
+
+      i = AMS_ADDR_INDEX(seg, p);
+      if (!AMS_ALLOCED(seg, i)) { /* no object here */
+        if (amsseg->allocTableInUse) {
+          Index dummy, nextIndex;
+          Bool more;
+
+          /* Find out how large the free block is. */
+          more = BTFindLongResRange(&dummy, &nextIndex, amsseg->allocTable,
+                                    i, amsseg->grains, 1);
+          AVER(more && dummy == i);
+          next = AMS_INDEX_ADDR(seg, nextIndex);
+        } else {
+          /* If there's no allocTable, this is the free block at the end. */
+          next = limit;
+        }
+      } else { /* there is an object here */
+#if 0
+        if (format->skip != NULL) {
+            next = (*format->skip)(AddrAdd(p, format->headerSize));
+            next = AddrSub(next, format->headerSize);
+        } else {
+          next = AddrAdd(p, alignment);
+        }
+#else
+	next = AddrAdd(p, amscf->num_words * sizeof(mps_word_t));
+#endif
+        AVER(AddrIsAligned(next, alignment));
+	res = amsScanObject(seg, i, p, next, closure);
+	if (res != ResOK)
+	  return res;
+      }
+    }
+    AVER(next > p); /* make sure we make progress */
+    p = next;
+  }
+  AVER(p == limit);
+  return ResOK;
+}
+
+
+/* amsScanObject -- scan a single object */
+
+struct amsScanClosureStruct {
+  ScanState ss;
+  Bool scanAllObjects;
+};
+
+typedef struct amsScanClosureStruct *amsScanClosure;
+
+static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos)
+{
+  amsScanClosure closure;
+  AMSSeg amsseg;
+  Res res;
+
+  amsseg = Seg2AMSSeg(seg);
+  /* seg & amsseg have already been checked, in amsIterate. */
+  AVER(i < amsseg->grains);
+  AVER(p != 0);
+  AVER(p < next);
+  AVER(clos != NULL);
+  closure = (amsScanClosure)clos;
+  AVERT(ScanState, closure->ss);
+  AVER(BoolCheck(closure->scanAllObjects));
+
+  /* @@@@ This isn't quite right for multiple traces. */
+  if (closure->scanAllObjects || AMS_IS_GREY(seg, i)) {
+#if 0
+    res = (*format->scan)(closure->ss,
+                          AddrAdd(p, format->headerSize),
+                          AddrAdd(next, format->headerSize));
+#else
+    res = TraceScanArea((ScanState)closure->ss, (Addr *)p, (Addr *)next);
+#endif
+    if (res != ResOK)
+      return res;
+    closure->ss->scannedSize += AddrOffset(p, next);
+    if (!closure->scanAllObjects) {
+      Index j = AMS_ADDR_INDEX(seg, next);
+      AVER(!AMS_IS_INVALID_COLOUR(seg, i));
+      AMS_GREY_BLACKEN(seg, i);
+      if (i+1 < j)
+        AMS_RANGE_WHITE_BLACKEN(seg, i+1, j);
+    }
+  }
+
+  return ResOK;
+}
+
+
+/* AMSScan -- the pool class segment scanning method
+ *
+ * See <design/poolams/#scan>
+ */
+Res AMSCFScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
+{
+  Res res;
+  AMS ams;
+  AMSCF amscf;
+  Arena arena;
+  AMSSeg amsseg;
+  struct amsScanClosureStruct closureStruct;
+  Align alignment;
+
+  AVER(totalReturn != NULL);
+  AVERT(ScanState, ss);
+  AVERT(Pool, pool);
+  ams = Pool2AMS(pool);
+  AVERT(AMS, ams);
+  amscf = AMS2AMSCF(ams);
+  AVERT(AMSCF, amscf);
+  arena = PoolArena(pool);
+  AVER(SegCheck(seg));
+  amsseg = Seg2AMSSeg(seg);
+  AVERT(AMSSeg, amsseg);
+
+  /* Check that we're not in the grey mutator phase (see */
+  /* <design/poolams/#not-req.grey>). */
+  AVER(TraceSetSub(ss->traces, arena->flippedTraces));
+
+  closureStruct.scanAllObjects =
+    (TraceSetDiff(ss->traces, SegWhite(seg)) != TraceSetEMPTY);
+  closureStruct.ss = ss;
+  /* @@@@ This isn't quite right for multiple traces. */
+  if (closureStruct.scanAllObjects) {
+    /* The whole seg (except the buffer) is grey for some trace. */
+    res = amsIterate(seg, &closureStruct);
+    if (res != ResOK) {
+      *totalReturn = FALSE;
+      return res;
+    }
+    *totalReturn = TRUE;
+  } else {
+    AVER(amsseg->marksChanged); /* something must have changed */
+    AVER(amsseg->colourTablesInUse);
+    alignment = PoolAlignment(AMS2Pool(ams));
+    do { /* <design/poolams/#scan.iter> */
+      amsseg->marksChanged = FALSE; /* <design/poolams/#marked.scan> */
+      /* <design/poolams/#ambiguous.middle> */
+      if (amsseg->ambiguousFixes) {
+        res = amsIterate(seg, &closureStruct);
+        if (res != ResOK) {
+          /* <design/poolams/#marked.scan.fail> */
+          amsseg->marksChanged = TRUE;
+          *totalReturn = FALSE;
+          return res;
+        }
+      } else {
+        Index i, j = 0;
+        Addr p, next;
+
+        while(j < amsseg->grains
+              && AMSFindGrey(&i, &j, seg, j, amsseg->grains)) {
+          AVER(!AMS_IS_INVALID_COLOUR(seg, i));
+          p = AMS_INDEX_ADDR(seg, i);
+#if 0
+          clientP = AddrAdd(p, format->headerSize);
+          if (format->skip != NULL) {
+            clientNext = (*format->skip)(clientP);
+            next = AddrSub(clientNext, format->headerSize);
+          } else {
+            clientNext = AddrAdd(clientP, alignment);
+            next = AddrAdd(p, alignment);
+          }
+#else
+	  next = AddrAdd(p, amscf->num_words * sizeof(mps_word_t));
+#endif
+          j = AMS_ADDR_INDEX(seg, next);
+#if 0
+          res = (*format->scan)(ss, clientP, clientNext);
+#else
+          res = TraceScanArea(ss, (Addr *)p, (Addr *)next);
+#endif
+          if (res != ResOK) {
+            /* <design/poolams/#marked.scan.fail> */
+            amsseg->marksChanged = TRUE;
+            *totalReturn = FALSE;
+            return res;
+          }
+          /* Check that there haven't been any ambiguous fixes during the */
+          /* scan, because AMSFindGrey won't work otherwise. */
+          AVER_CRITICAL(!amsseg->ambiguousFixes);
+          ss->scannedSize += AddrOffset(p, next);
+          AMS_GREY_BLACKEN(seg, i);
+          if (i+1 < j)
+            AMS_RANGE_WHITE_BLACKEN(seg, i+1, j);
+        }
+      }
+    } while(amsseg->marksChanged);
+    *totalReturn = FALSE;
+  }
+
+  return ResOK;
+}
+
+
+/* AMSCFFix -- the pool class fixing method */
+
+Res AMSCFFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
+{
+  AMSSeg amsseg;
+  AMS ams;
+  AMSCF amscf;
+  Index i;                      /* the index of the fixed grain */
+  Addr base;
+
+  AVERT_CRITICAL(Pool, pool);
+  AVERT_CRITICAL(ScanState, ss);
+  AVERT_CRITICAL(Seg, seg);
+  AVER_CRITICAL(refIO != NULL);
+
+  amsseg = Seg2AMSSeg(seg);
+  AVERT_CRITICAL(AMSSeg, amsseg);
+  /* It's a white seg, so it must have colour tables. */
+  AVER_CRITICAL(amsseg->colourTablesInUse);
+
+  /* @@@@ We should check that we're not in the grey mutator phase */
+  /* (see <design/poolams/#not-req.grey>), but there's no way of */
+  /* doing that here (this can be called from RootScan, during flip). */
+
+  base = *refIO;
+  /* can get an ambiguous reference too close to the base of the
+   * segment, so when we subtract the header we are not in the
+   * segment any longer.  This isn't a real reference,
+   * so we can just skip it.  */
+  if (base < SegBase(seg)) {
+      return ResOK;
+  }
+
+  i = AMS_ADDR_INDEX(seg, base);
+  AVER_CRITICAL(!AMS_IS_INVALID_COLOUR(seg, i));
+
+  ss->wasMarked = TRUE;
+
+  switch (ss->rank) {
+  case RankAMBIG:
+    if (Pool2AMS(pool)->shareAllocTable)
+      /* In this state, the pool doesn't support ambiguous references (see */
+      /* .ambiguous.noshare), so this is not a reference. */
+      break;
+#if 0 /* Note: this test disabled for Mercury,
+             since we need to handle tagged pointers. -fjh */
+    /* not a real pointer if not aligned */
+    if (!AddrIsAligned(base, PoolAlignment(pool)))
+      break;
+#endif
+    /* not a real pointer if not allocated */
+    if (!AMS_ALLOCED(seg, i))
+      break;
+    amsseg->ambiguousFixes = TRUE;
+    /* falls through */
+  case RankEXACT:
+  case RankFINAL:
+  case RankWEAK:
+#if 0 /* Note: this test disabled for Mercury,
+               since we need to handle tagged pointers. -fjh */
+    AVER_CRITICAL(AddrIsAligned(base, PoolAlignment(pool)));
+#endif
+    AVER_CRITICAL(AMS_ALLOCED(seg, i));
+    if (AMS_IS_WHITE(seg, i)) {
+      ss->wasMarked = FALSE;
+      if (ss->rank == RankWEAK) { /* then splat the reference */
+        *refIO = (Ref)0;
+      } else {
+        ++ss->preservedInPlaceCount; /* Size updated on reclaim */
+        if (SegRankSet(seg) == RankSetEMPTY && ss->rank != RankAMBIG) {
+          /* <design/poolams/#fix.to-black> */
+          Addr next;
+
+#if 0
+          ShieldExpose(PoolArena(pool), seg);
+          clientNext = (*pool->format->skip)(clientRef);
+          ShieldCover(PoolArena(pool), seg);
+          next = AddrSub(clientNext, HDRSIZE);
+#else
+	  ams = Pool2AMS(pool);
+	  AVERT_CRITICAL(AMS, ams);
+	  amscf = AMS2AMSCF(ams);
+	  AVERT_CRITICAL(AMSCF, amscf);
+	  next = AddrAdd(base, amscf->num_words * sizeof(mps_word_t));
+#endif
+          /* Part of the object might be grey, because of ambiguous */
+          /* fixes, but that's OK, because scan will ignore that. */
+          AMS_RANGE_WHITE_BLACKEN(seg, i, AMS_ADDR_INDEX(seg, next));
+        } else { /* turn it grey */
+          AMS_WHITE_GREYEN(seg, i);
+          SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces));
+          /* mark it for scanning - <design/poolams/#marked.fix> */
+          amsseg->marksChanged = TRUE;
+        }
+      }
+    }
+    break;
+  default:
+    NOTREACHED;
+  }
+
+  return ResOK;
+}
+
+/* AMSCFInit -- the pool class initialization method
+ *
+ *  Takes additional arguments:
+ *  	- the format of the objects allocated in the pool
+ *  	  (this is pretty much ignored - we just use their size)
+ *  	- the chain of generations in this pool
+ *  	- whether or not this pool must support ambiguous references
+ *  	- the size of the objects allocated in the pool
+ */
+static Res AMSCFInit(Pool pool, va_list args)
+{
+  Res res;
+  Format format;
+  Chain chain;
+  Bool support_ambiguous;
+  int object_size_in_words;
+
+  AVERT(Pool, pool);
+
+  format = va_arg(args, Format);
+  chain = va_arg(args, Chain);
+  object_size_in_words = va_arg(args, int);
+  support_ambiguous = TRUE;
+
+  AMS2AMSCF(Pool2AMS(pool))->num_words = object_size_in_words;
+
+  /* .ambiguous.noshare: If the pool is required to support ambiguous */
+  /* references, the alloc and white tables cannot be shared. */
+  res = AMSInitInternal(Pool2AMS(pool), format, chain, support_ambiguous);
+  if (res == ResOK) {
+    EVENT_PPP(PoolInitAMS, pool, PoolArena(pool), format);
+  }
+  return res;
+}
+
+
+/* AMSCFPoolClass -- the class definition for the conservative version */
+
+DEFINE_CLASS(AMSCFPoolClass, this)
+{
+  INHERIT_CLASS(this, AMSPoolClass);
+  this->init = AMSCFInit;
+  this->scan = AMSCFScan;
+  this->fix = AMSCFFix;
+  this->name = "AMSCF";
+  this->size = sizeof(AMSCFStruct);
+}
+
+
+/* AMSCFCheck -- the check method for an AMSCF */
+
+Bool AMSCFCheck(AMSCF amscf)
+{
+  /* XXX FIXME */
+
+  return TRUE;
+}
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
+ * All rights reserved.  This is an open source license.  Contact
+ * Ravenbrook for commercial licensing options.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software.  The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions.  For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mps_gc/code/poolamsc.h	7 Aug 2002 03:11:41 -0000
@@ -0,0 +1,75 @@
+/* poolamsc.h: CONSERVATIVE AUTOMATIC MARK & SWEEP POOL CLASS INTERFACE
+ *
+ * Copyright (C) 2002 Fergus Henderson and The University of Melbourne.
+ * Portions copyright (c) 2001 Ravenbrook Limited.  See end of file for license.
+ * Portions copyright (C) 2002 Global Graphics Software.
+ *
+ * .purpose: Internal interface to AMSC functionality.  */
+
+#ifndef poolamsc_h
+#define poolamsc_h
+
+#include "mpmtypes.h"
+#include "mpmst.h"
+#include "ring.h"
+#include "bt.h"
+#include "poolams.h"
+#include <stdarg.h>
+
+
+typedef struct AMSCStruct *AMSC;
+
+extern Bool AMSCCheck(AMSC ams);
+
+extern Res AMSCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg);
+extern Res AMSCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO);
+
+typedef PoolClass AMSCPoolClass;
+typedef PoolClassStruct AMSCPoolClassStruct;
+
+extern AMSCPoolClass AMSCPoolClassGet(void);
+
+
+#endif /* poolamsc_h */
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
+ * All rights reserved.  This is an open source license.  Contact
+ * Ravenbrook for commercial licensing options.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software.  The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions.  For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mps_gc/code/poolamsc.c	7 Aug 2002 03:12:31 -0000
@@ -0,0 +1,452 @@
+/* poolamsc.c: CONSERVATIVE AUTOMATIC MARK & SWEEP POOL CLASS
+ *
+ * Copyright (c) 2002 Fergus Henderson and The University of Melbourne.
+ *
+ * $Id: //info.ravenbrook.com/project/mps/version/1.100/code/poolams.c#2 $
+ * Portions Copyright (c) 2001 Ravenbrook Limited.  See end of file for license.
+ * Portions copyright (c) 2002 Global Graphics Software.
+ *
+ *
+ * .design: See <design/poolams/>.
+ *
+ */
+
+#include "mps.h"
+#include "fmtme.h"
+#include "poolamsc.h"
+#include "mpm.h"
+#include "mpmtypes.h"
+#include <stdarg.h>
+
+/* AMSCStruct -- structure for a conservative subclass */
+
+typedef struct AMSCStruct {
+  AMSStruct amsStruct;         /* AMS structure */
+} AMSCStruct;
+
+#define AMS2AMSC(ams)  PARENT(AMSCStruct, amsStruct, ams)
+#define AMSC2AMS(amsd) (&((amsd)->amsStruct))
+
+#define NUMWORDS(p) (*(mps_word_t *)p)
+
+/* AMSObjectFunction is the type of the method that an */
+/* amsIterate applies to each object in a segment. */
+typedef Res (*AMSObjectFunction)(
+  /* the segment */              Seg seg,
+  /* the object grain index */   Index i,
+  /* the address of the object */Addr p,
+  /*  "   "   after the object */Addr next,
+  /* the iteration closure */    void *closure);
+
+#define AMSObjectFunctionCheck(f) \
+  ((f) != NULL) /* that's the best we can do */
+
+static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos);
+
+/* amsIterate -- applies a function to each object in a segment
+ *
+ * amsIterate(seg, f, closure) applies f to all the objects in the
+ * segment.  It skips the buffer, if any (from BufferScanLimit to
+ * BufferLimit).  */
+
+static Res amsIterate(Seg seg, void *closure)
+{
+  Res res;
+  AMS ams;
+  AMSSeg amsseg;
+  Align alignment;
+  Index i;
+  Addr p, next, limit;
+  Buffer buffer;
+
+  AVERT(Seg, seg);
+  /* Can't check closure */
+
+  amsseg = Seg2AMSSeg(seg);
+  AVERT(AMSSeg, amsseg);
+  ams = amsseg->ams;
+  AVERT(AMS, ams);
+  alignment = PoolAlignment(AMS2Pool(ams));
+
+  /* If we're using the alloc table as a white table, we can't use it to */
+  /* determine where there are objects. */
+  AVER(!(ams->shareAllocTable && amsseg->colourTablesInUse));
+
+  p = SegBase(seg);
+  limit = SegLimit(seg);
+  buffer = SegBuffer(seg);
+
+  while (p < limit) { /* loop over the objects in the segment */
+    if (buffer != NULL
+        && p == BufferScanLimit(buffer) && p != BufferLimit(buffer)) {
+      /* skip buffer */
+      next = BufferLimit(buffer);
+      AVER(AddrIsAligned(next, alignment));
+    } else {
+      AVER((buffer == NULL)
+	   || (p < BufferScanLimit(buffer))
+	   || (p >= BufferLimit(buffer)));  /* not in the buffer */
+
+      i = AMS_ADDR_INDEX(seg, p);
+      if (!AMS_ALLOCED(seg, i)) { /* no object here */
+        if (amsseg->allocTableInUse) {
+          Index dummy, nextIndex;
+          Bool more;
+
+          /* Find out how large the free block is. */
+          more = BTFindLongResRange(&dummy, &nextIndex, amsseg->allocTable,
+                                    i, amsseg->grains, 1);
+          AVER(more && dummy == i);
+          next = AMS_INDEX_ADDR(seg, nextIndex);
+        } else {
+          /* If there's no allocTable, this is the free block at the end. */
+          next = limit;
+        }
+      } else { /* there is an object here */
+#if 0
+        if (format->skip != NULL) {
+            next = (*format->skip)(AddrAdd(p, format->headerSize));
+            next = AddrSub(next, format->headerSize);
+        } else {
+          next = AddrAdd(p, alignment);
+        }
+#else
+	next = AddrAdd(p, NUMWORDS(p) * sizeof(mps_word_t));
+#endif
+        AVER(AddrIsAligned(next, alignment));
+	res = amsScanObject(seg, i, p, next, closure);
+	if (res != ResOK)
+	  return res;
+      }
+    }
+    AVER(next > p); /* make sure we make progress */
+    p = next;
+  }
+  AVER(p == limit);
+  return ResOK;
+}
+
+
+/* amsScanObject -- scan a single object
+ *
+ * This is the object function passed to amsIterate by AMSScan.  */
+
+struct amsScanClosureStruct {
+  ScanState ss;
+  Bool scanAllObjects;
+};
+
+typedef struct amsScanClosureStruct *amsScanClosure;
+
+static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos)
+{
+  amsScanClosure closure;
+  AMSSeg amsseg;
+  Res res;
+
+  amsseg = Seg2AMSSeg(seg);
+  /* seg & amsseg have already been checked, in amsIterate. */
+  AVER(i < amsseg->grains);
+  AVER(p != 0);
+  AVER(p < next);
+  AVER(clos != NULL);
+  closure = (amsScanClosure)clos;
+  AVERT(ScanState, closure->ss);
+  AVER(BoolCheck(closure->scanAllObjects));
+
+  /* @@@@ This isn't quite right for multiple traces. */
+  if (closure->scanAllObjects || AMS_IS_GREY(seg, i)) {
+#if 0
+    res = (*format->scan)(closure->ss,
+                          AddrAdd(p, format->headerSize),
+                          AddrAdd(next, format->headerSize));
+#else
+    res = TraceScanArea((ScanState)closure->ss, (Addr *)p, (Addr *)next);
+#endif
+    if (res != ResOK)
+      return res;
+    closure->ss->scannedSize += AddrOffset(p, next);
+    if (!closure->scanAllObjects) {
+      Index j = AMS_ADDR_INDEX(seg, next);
+      AVER(!AMS_IS_INVALID_COLOUR(seg, i));
+      AMS_GREY_BLACKEN(seg, i);
+      if (i+1 < j)
+        AMS_RANGE_WHITE_BLACKEN(seg, i+1, j);
+    }
+  }
+
+  return ResOK;
+}
+
+
+/* AMSScan -- the pool class segment scanning method
+ *
+ * See <design/poolams/#scan>
+ */
+Res AMSCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
+{
+  Res res;
+  AMS ams;
+  Arena arena;
+  AMSSeg amsseg;
+  struct amsScanClosureStruct closureStruct;
+  Align alignment;
+
+  AVER(totalReturn != NULL);
+  AVERT(ScanState, ss);
+  AVERT(Pool, pool);
+  ams = Pool2AMS(pool);
+  AVERT(AMS, ams);
+  arena = PoolArena(pool);
+  AVER(SegCheck(seg));
+  amsseg = Seg2AMSSeg(seg);
+  AVERT(AMSSeg, amsseg);
+
+  /* Check that we're not in the grey mutator phase (see */
+  /* <design/poolams/#not-req.grey>). */
+  AVER(TraceSetSub(ss->traces, arena->flippedTraces));
+
+  closureStruct.scanAllObjects =
+    (TraceSetDiff(ss->traces, SegWhite(seg)) != TraceSetEMPTY);
+  closureStruct.ss = ss;
+  /* @@@@ This isn't quite right for multiple traces. */
+  if (closureStruct.scanAllObjects) {
+    /* The whole seg (except the buffer) is grey for some trace. */
+    res = amsIterate(seg, &closureStruct);
+    if (res != ResOK) {
+      *totalReturn = FALSE;
+      return res;
+    }
+    *totalReturn = TRUE;
+  } else {
+    AVER(amsseg->marksChanged); /* something must have changed */
+    AVER(amsseg->colourTablesInUse);
+    alignment = PoolAlignment(AMS2Pool(ams));
+    do { /* <design/poolams/#scan.iter> */
+      amsseg->marksChanged = FALSE; /* <design/poolams/#marked.scan> */
+      /* <design/poolams/#ambiguous.middle> */
+      if (amsseg->ambiguousFixes) {
+        res = amsIterate(seg, &closureStruct);
+        if (res != ResOK) {
+          /* <design/poolams/#marked.scan.fail> */
+          amsseg->marksChanged = TRUE;
+          *totalReturn = FALSE;
+          return res;
+        }
+      } else {
+        Index i, j = 0;
+        Addr p, next;
+
+        while(j < amsseg->grains
+              && AMSFindGrey(&i, &j, seg, j, amsseg->grains)) {
+          Addr clientP;
+          AVER(!AMS_IS_INVALID_COLOUR(seg, i));
+          p = AMS_INDEX_ADDR(seg, i);
+#if 0
+          clientP = AddrAdd(p, format->headerSize);
+          if (format->skip != NULL) {
+            clientNext = (*format->skip)(clientP);
+            next = AddrSub(clientNext, format->headerSize);
+          } else {
+            clientNext = AddrAdd(clientP, alignment);
+            next = AddrAdd(p, alignment);
+          }
+#else
+          clientP = AddrAdd(p, HDRSIZE);
+	  next = AddrAdd(p, NUMWORDS(p) * sizeof(mps_word_t));
+#endif
+          j = AMS_ADDR_INDEX(seg, next);
+#if 0
+          res = (*format->scan)(ss, clientP, clientNext);
+#else
+          res = TraceScanArea(ss, (Addr *)clientP, (Addr *)next);
+#endif
+          if (res != ResOK) {
+            /* <design/poolams/#marked.scan.fail> */
+            amsseg->marksChanged = TRUE;
+            *totalReturn = FALSE;
+            return res;
+          }
+          /* Check that there haven't been any ambiguous fixes during the */
+          /* scan, because AMSFindGrey won't work otherwise. */
+          AVER_CRITICAL(!amsseg->ambiguousFixes);
+          ss->scannedSize += AddrOffset(p, next);
+          AMS_GREY_BLACKEN(seg, i);
+          if (i+1 < j)
+            AMS_RANGE_WHITE_BLACKEN(seg, i+1, j);
+        }
+      }
+    } while(amsseg->marksChanged);
+    *totalReturn = FALSE;
+  }
+
+  return ResOK;
+}
+
+
+/* AMSCFix -- the pool class fixing method */
+
+Res AMSCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
+{
+  AMSSeg amsseg;
+  Index i;                      /* the index of the fixed grain */
+  Addr base;
+  Ref clientRef;
+
+  AVERT_CRITICAL(Pool, pool);
+#if 0
+  AVER_CRITICAL(CHECKT(AMSC, Pool2AMSC(pool)));
+#endif
+  AVERT_CRITICAL(ScanState, ss);
+  AVERT_CRITICAL(Seg, seg);
+  AVER_CRITICAL(refIO != NULL);
+
+  amsseg = Seg2AMSSeg(seg);
+  AVERT_CRITICAL(AMSSeg, amsseg);
+  /* It's a white seg, so it must have colour tables. */
+  AVER_CRITICAL(amsseg->colourTablesInUse);
+
+  /* @@@@ We should check that we're not in the grey mutator phase */
+  /* (see <design/poolams/#not-req.grey>), but there's no way of */
+  /* doing that here (this can be called from RootScan, during flip). */
+
+  clientRef = *refIO;
+  base = AddrSub((Addr)clientRef, HDRSIZE);
+  /* can get an ambiguous reference too close to the base of the
+   * segment, so when we subtract the header we are not in the
+   * segment any longer.  This isn't a real reference,
+   * so we can just skip it.  */
+  if (base < SegBase(seg)) {
+      return ResOK;
+  }
+
+  i = AMS_ADDR_INDEX(seg, base);
+  AVER_CRITICAL(!AMS_IS_INVALID_COLOUR(seg, i));
+
+  ss->wasMarked = TRUE;
+
+  switch (ss->rank) {
+  case RankAMBIG:
+    if (Pool2AMS(pool)->shareAllocTable)
+      /* In this state, the pool doesn't support ambiguous references (see */
+      /* .ambiguous.noshare), so this is not a reference. */
+      break;
+#if 0 /* Note: this test disabled for Mercury,
+             since we need to handle tagged pointers. -fjh */
+    /* not a real pointer if not aligned */
+    if (!AddrIsAligned(base, PoolAlignment(pool)))
+      break;
+#endif
+    /* not a real pointer if not allocated */
+    if (!AMS_ALLOCED(seg, i))
+      break;
+    amsseg->ambiguousFixes = TRUE;
+    /* falls through */
+  case RankEXACT:
+  case RankFINAL:
+  case RankWEAK:
+#if 0 /* Note: this test disabled for Mercury,
+               since we need to handle tagged pointers. -fjh */
+    AVER_CRITICAL(AddrIsAligned(base, PoolAlignment(pool)));
+#endif
+    AVER_CRITICAL(AMS_ALLOCED(seg, i));
+    if (AMS_IS_WHITE(seg, i)) {
+      ss->wasMarked = FALSE;
+      if (ss->rank == RankWEAK) { /* then splat the reference */
+        *refIO = (Ref)0;
+      } else {
+        ++ss->preservedInPlaceCount; /* Size updated on reclaim */
+        if (SegRankSet(seg) == RankSetEMPTY && ss->rank != RankAMBIG) {
+          /* <design/poolams/#fix.to-black> */
+          Addr clientNext, next;
+
+          ShieldExpose(PoolArena(pool), seg);
+#if 0
+          clientNext = (*pool->format->skip)(clientRef);
+#else
+	  clientNext = AddrAdd(clientRef,
+		  NUMWORDS(AddrSub(clientRef, HDRSIZE)) * sizeof(mps_word_t));
+#endif
+          ShieldCover(PoolArena(pool), seg);
+          next = AddrSub(clientNext, HDRSIZE);
+          /* Part of the object might be grey, because of ambiguous */
+          /* fixes, but that's OK, because scan will ignore that. */
+          AMS_RANGE_WHITE_BLACKEN(seg, i, AMS_ADDR_INDEX(seg, next));
+        } else { /* turn it grey */
+          AMS_WHITE_GREYEN(seg, i);
+          SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces));
+          /* mark it for scanning - <design/poolams/#marked.fix> */
+          amsseg->marksChanged = TRUE;
+        }
+      }
+    }
+    break;
+  default:
+    NOTREACHED;
+  }
+
+  return ResOK;
+}
+
+/* AMSCPoolClass -- the class definition for the conservative version */
+
+DEFINE_CLASS(AMSCPoolClass, this)
+{
+  INHERIT_CLASS(this, AMSPoolClass);
+  this->scan = AMSCScan;
+  this->fix = AMSCFix;
+  this->name = "AMSC";
+  this->size = sizeof(AMSCStruct);
+}
+
+
+/* AMSCCheck -- the check method for an AMS */
+
+Bool AMSCCheck(AMSC amsc)
+{
+  /* XXX FIXME */
+
+  return TRUE;
+}
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
+ * All rights reserved.  This is an open source license.  Contact
+ * Ravenbrook for commercial licensing options.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software.  The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions.  For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mps_gc/code/mpscamsc.h	7 Aug 2002 03:38:26 -0000
@@ -0,0 +1,59 @@
+/* mpscams.h: MEMORY POOL SYSTEM CLASS "AMSC" and "AMSCF"
+ *
+ * Copyright (c) 2002 Fergus Henderson and The University of Melbourne.
+ * Portions copyright (c) 2001 Ravenbrook Limited.  See end of file for license.
+ * Portions copyright (C) 2002 Global Graphics Software.
+ */
+
+#ifndef mpscamsc_h
+#define mpscamsc_h
+
+#include "mps.h"
+
+extern mps_class_t mps_class_amsc(void);
+
+extern mps_class_t mps_class_amscf(void);
+
+#endif /* mpscamsc_h */
+
+
+/* C. COPYRIGHT AND LICENSE
+ *
+ * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
+ * All rights reserved.  This is an open source license.  Contact
+ * Ravenbrook for commercial licensing options.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Redistributions in any form must be accompanied by information on how
+ * to obtain complete source code for this software and any accompanying
+ * software that uses this software.  The source code must either be
+ * included in the distribution or be available for no more than the cost
+ * of distribution plus a nominal fee, and must be freely redistributable
+ * under reasonable conditions.  For an executable file, complete source
+ * code means the source code for all modules it contains. It does not
+ * include source code for modules or files that typically accompany the
+ * major components of the operating system on which the executable file
+ * runs.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
only in patch2:
--- mps_gc/code/lii4gc.gmk	21 Aug 2002 08:43:36 -0000	1.1.1.1
+++ mps_gc/code/lii4gc.gmk	8 Aug 2002 07:53:49 -0000
@@ -10,8 +10,10 @@
 
 PFMDEFS = -D_REENTRANT
 
+#PROT = protli.c protlii3.c proti3.c prmci3li.c
+PROT = protan.c prmcan.c
 MPMPF = mpsliban.c mpsioan.c ${THREADSRC} vmli.c \
-        protli.c protlii3.c proti3.c prmci3li.c sslii3.c span.c
+        $(PROT) sslii3.c span.c
 SWPF = than.c vmli.c protsw.c prmcan.c ssan.c
 
 LIBS = -lm ${THREADLIB}

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list