diff --git a/src/array.c b/src/array.c
index 151cba7a35d179446881d293ba1b77dedd060d8e..f7c20a7ff2333f5e1b176e4d3b126c166b814130 100644
--- a/src/array.c
+++ b/src/array.c
@@ -23,7 +23,7 @@
 #include "stuff.h"
 #include "bignum.h"
 
-RCSID("$Id: array.c,v 1.67 2000/04/20 02:41:44 hubbe Exp $");
+RCSID("$Id: array.c,v 1.68 2000/04/23 03:01:25 mast Exp $");
 
 struct array empty_array=
 {
@@ -57,12 +57,12 @@ struct array *low_allocate_array(INT32 size,INT32 extra_space)
     return &empty_array;
   }
 
-  GC_ALLOC();
-
   v=(struct array *)malloc(sizeof(struct array)+
 			   (size+extra_space-1)*sizeof(struct svalue));
   if(!v)
     error("Couldn't allocate array, out of memory.\n");
+
+  GC_ALLOC(v);
   
 
   /* for now, we don't know what will go in here */
@@ -104,7 +104,7 @@ static void array_free_no_free(struct array *v)
 
   free((char *)v);
 
-  GC_FREE(v);
+  GC_FREE();
 }
 
 /*
@@ -1817,6 +1817,20 @@ static void gc_check_array(struct array *a)
   }
 }
 
+#ifdef PIKE_DEBUG
+INT32 gc_touch_all_arrays(void)
+{
+  INT32 n = 0;
+  struct array *a = &empty_array;
+  do {
+    debug_gc_touch(a);
+    n++;
+    a=a->next;
+  } while (a != &empty_array);
+  return n;
+}
+#endif
+
 void gc_check_all_arrays(void)
 {
   struct array *a;
diff --git a/src/array.h b/src/array.h
index 5b65711c48a0d73b800802453bb5572a03a87b20..aa0b652fd0798fd36ab70aad8b16ee29c01b8a05 100644
--- a/src/array.h
+++ b/src/array.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: array.h,v 1.18 1999/10/03 21:44:18 hubbe Exp $
+ * $Id: array.h,v 1.19 2000/04/23 03:01:25 mast Exp $
  */
 #ifndef ARRAY_H
 #define ARRAY_H
@@ -148,6 +148,7 @@ void array_replace(struct array *a,
 void check_array(struct array *a);
 void check_all_arrays(void);
 void gc_mark_array_as_referenced(struct array *a);
+INT32 gc_touch_all_arrays(void);
 void gc_check_all_arrays(void);
 void gc_mark_all_arrays(void);
 void gc_free_all_unreferenced_arrays(void);
diff --git a/src/gc.c b/src/gc.c
index e4b02096e02bacd98eef199eec7fc31ba54e1c38..e541d534b5b07fc1f6d222f69afd863e03d72bb5 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -29,7 +29,7 @@ struct callback *gc_evaluator_callback=0;
 
 #include "block_alloc.h"
 
-RCSID("$Id: gc.c,v 1.78 2000/04/22 02:23:56 hubbe Exp $");
+RCSID("$Id: gc.c,v 1.79 2000/04/23 03:01:25 mast Exp $");
 
 /* Run garbage collect approximate every time we have
  * 20 percent of all arrays, objects and programs is
@@ -42,7 +42,7 @@ RCSID("$Id: gc.c,v 1.78 2000/04/22 02:23:56 hubbe Exp $");
 #define MULTIPLIER 0.9
 #define MARKER_CHUNK_SIZE 1023
 
-INT32 num_objects =0;
+INT32 num_objects = 1;		/* Account for empty_array. */
 INT32 num_allocs =0;
 INT32 alloc_threshold = MIN_ALLOC_THRESHOLD;
 int Pike_in_gc = 0;
@@ -129,6 +129,7 @@ static void *found_in=0;
 static int found_in_type=0;
 void *gc_svalue_location=0;
 char *fatal_after_gc=0;
+static int gc_debug = 0;
 
 #define DESCRIBE_MEM 1
 #define DESCRIBE_NO_REFS 2
@@ -387,6 +388,19 @@ void low_describe_something(void *a,
       fprintf(stderr,"%*s**Parent identifier: %d\n",indent,"",((struct object *)a)->parent_identifier);
       fprintf(stderr,"%*s**Program id: %ld\n",indent,"",((struct object *)a)->program_id);
 
+      if (((struct object *)a)->next == ((struct object *)a))
+	fprintf(stderr, "%*s**The object is fake.\n",indent,"");
+
+      if(!p)
+      {
+	fprintf(stderr,"%*s**The object is destructed.\n",indent,"");
+	p=id_to_program(((struct object *)a)->program_id);
+      }
+      if (p) {
+	fprintf(stderr,"%*s**Attempting to describe program object was instantiated from:\n",indent,"");
+	low_describe_something(p, T_PROGRAM, indent, depth, flags);
+      }
+
       if( ((struct object *)a)->parent)
       {
 	fprintf(stderr,"%*s**Describing object's parent:\n",indent,"");
@@ -396,14 +410,7 @@ void low_describe_something(void *a,
       }else{
 	fprintf(stderr,"%*s**There is no parent (any longer?)\n",indent,"");
       }
-      if(!p)
-      {
-	fprintf(stderr,"%*s**The object is destructed.\n",indent,"");
-	p=id_to_program(((struct object *)a)->program_id);
-
-	if(!p) break;
-      }
-      fprintf(stderr,"%*s**Attempting to describe program object was instantiated from:\n",indent,"");
+      break;
       
     case T_PROGRAM:
     {
@@ -566,13 +573,49 @@ void debug_describe_svalue(struct svalue *s)
   describe_something(s->u.refs,s->type,0,2,0);
 }
 
+void debug_gc_touch(void *a)
+{
+  struct marker *m;
+  if (!a) fatal("real_gc_check(): Got null pointer.\n");
+
+  m = find_marker(a);
+  if (Pike_in_gc == GC_PASS_PRETOUCH) {
+    if (m) {
+      fprintf(stderr,"**Object touched twice.\n");
+      describe(a);
+      fatal("Object touched twice.\n");
+    }
+    get_marker(a)->flags |= GC_TOUCHED;
+  }
+  else if (Pike_in_gc == GC_PASS_POSTTOUCH) {
+    if (m) {
+      if (!(m->flags & GC_TOUCHED)) {
+	fprintf(stderr,"**An existing but untouched marker found for object in linked lists. flags: %x.\n", m->flags);
+	describe(a);
+	fatal("An existing but untouched marker found for object in linked lists.\n");
+      }
+      if ((m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED) {
+	fprintf(stderr,"**An object to garb is still around. flags: %x.\n", m->flags);
+	fprintf(stderr,"    has %ld references, while gc() found %ld + %ld external.\n",(long)*(INT32 *)a,(long)m->refs,(long)m->xrefs);
+	describe(a);
+	locate_references(a);
+	fprintf(stderr,"##### Continuing search for more bugs....\n");
+	fatal_after_gc="An object to garb is still around.\n";
+      }
+    }
+  }
+  else
+    fatal("debug_gc_touch() used in invalid gc pass.\n");
+}
+
 #endif /* PIKE_DEBUG */
 
 INT32 real_gc_check(void *a)
 {
-  struct marker *m=get_marker(a);
+  struct marker *m;
 
 #ifdef PIKE_DEBUG
+  if (!a) fatal("real_gc_check(): Got null pointer.\n");
   if(check_for)
   {
     if(check_for == a)
@@ -580,9 +623,10 @@ INT32 real_gc_check(void *a)
       gdb_gc_stop_here(a);
     }
 
-    if(check_for == (void *)1 && gc_do_free(a))
+    m=get_marker(a);
+    if(check_for == (void *)1 &&
+       m && (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED)
     {
-      struct marker *m=get_marker(a);
       int t=attempt_to_identify(a);
       if(t != T_STRING && t != T_UNKNOWN)
       {
@@ -601,8 +645,10 @@ INT32 real_gc_check(void *a)
     return 0;
   }
 
-  if (Pike_in_gc /100 != 1)
-    fatal("gc check attempted in pass %d.\n", Pike_in_gc);
+  if (Pike_in_gc != GC_PASS_CHECK)
+    fatal("gc check attempted in invalid pass.\n");
+
+  m = get_marker(a);
 
   if(m->saved_refs != -1)
     if(m->saved_refs != *(INT32 *)a) {
@@ -669,9 +715,15 @@ static void exit_gc(void)
 #ifdef PIKE_DEBUG
 void locate_references(void *a)
 {
+  int tmp, orig_in_gc = Pike_in_gc;
   void *orig_check_for=check_for;
   if(!Pike_in_gc)
     init_gc();
+  Pike_in_gc = GC_PASS_LOCATE;
+
+  /* Disable debug, this may help reduce recursion bugs */
+  tmp=d_flag;
+  d_flag=0;
 
   fprintf(stderr,"**Looking for references:\n");
   
@@ -717,8 +769,10 @@ void locate_references(void *a)
   }
 #endif
 
+  Pike_in_gc = orig_in_gc;
   if(!Pike_in_gc)
     exit_gc();
+  d_flag=tmp;
 }
 #endif
 
@@ -727,11 +781,13 @@ void locate_references(void *a)
 int debug_gc_is_referenced(void *a)
 {
   struct marker *m;
-  m=get_marker(a);
+  if (!a) fatal("real_gc_check(): Got null pointer.\n");
 
+  m=get_marker(a);
   if(m->refs + m->xrefs > *(INT32 *)a ||
      (!(m->refs < *(INT32 *)a) && m->xrefs)  ||
-     (Pike_in_gc < 300 && m->saved_refs != -1 && m->saved_refs != *(INT32 *)a))
+     (Pike_in_gc >= GC_PASS_CHECK && Pike_in_gc <= GC_PASS_MARK &&
+      m->saved_refs != -1 && m->saved_refs != *(INT32 *)a))
   {
     INT32 refs=m->refs;
     INT32 xrefs=m->xrefs;
@@ -744,7 +800,7 @@ int debug_gc_is_referenced(void *a)
 	    (long)xrefs);
 
     if(m->saved_refs != *(INT32 *)a)
-      fprintf(stderr,"**In pass one it had %ld refs!!!\n",(long)m->saved_refs);
+      fprintf(stderr,"**In check pass it had %ld refs!!!\n",(long)m->saved_refs);
 
     describe_something(a, t, 0,2,0);
 
@@ -764,6 +820,7 @@ int debug_gc_is_referenced(void *a)
 int gc_external_mark3(void *a, void *in, char *where)
 {
   struct marker *m;
+  if (!a) fatal("real_gc_check(): Got null pointer.\n");
 
   if(check_for)
   {
@@ -783,9 +840,10 @@ int gc_external_mark3(void *a, void *in, char *where)
       return 1;
     }
 
-    if(check_for == (void *)1 && gc_do_free(a))
+    m=get_marker(a);
+    if(check_for == (void *)1 &&
+       m && (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED)
     {
-      struct marker *m=get_marker(a);
       int t=attempt_to_identify(a);
       if(t != T_STRING && t != T_UNKNOWN)
       {
@@ -816,13 +874,14 @@ int gc_external_mark3(void *a, void *in, char *where)
 int gc_mark(void *a)
 {
   struct marker *m;
-  m=get_marker(debug_malloc_pass(a));
 
 #ifdef PIKE_DEBUG
-  if (Pike_in_gc /100 != 2)
-    fatal("gc mark attempted in pass %d.\n", Pike_in_gc);
+  if (!a) fatal("real_gc_check(): Got null pointer.\n");
+  if (Pike_in_gc != GC_PASS_MARK)
+    fatal("gc mark attempted in invalid pass.\n");
 #endif
 
+  m = get_marker(debug_malloc_pass(a));
   if(m->flags & GC_REFERENCED)
   {
     return 0;
@@ -836,8 +895,10 @@ int gc_mark(void *a)
 int debug_gc_do_free(void *a)
 {
   struct marker *m;
+  if (!a) fatal("real_gc_check(): Got null pointer.\n");
 
-  m=get_marker(debug_malloc_pass(a));
+  m=find_marker(debug_malloc_pass(a));
+  if (!m) return 0;		/* Object created after mark pass. */
 
   if( (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED &&
       (m->flags & GC_XREFERENCED) )
@@ -849,12 +910,12 @@ int debug_gc_do_free(void *a)
     {
       fprintf(stderr,
 	      "**gc_is_referenced failed, object has %ld references,\n"
-	      "** while gc() found %ld + %ld external. (type=%d, flags=%d)\n",
+	      "** while gc() found %ld + %ld external. (type=%d, flags=%x)\n",
 	      (long)*(INT32 *)a,(long)refs,(long)xrefs,t,m->flags);
       describe_something(a, t, 4,1,0);
 
       locate_references(a);
-      
+
       fatal("GC failed object (has %d, found %d + %d external)\n",
 	    *(INT32 *)a,
 	    refs,
@@ -879,7 +940,11 @@ void do_gc(void)
 #endif
 
   if(Pike_in_gc) return;
-  Pike_in_gc=10; /* before pass 1 */
+  init_gc();
+  Pike_in_gc=GC_PASS_PREPARE;
+#ifdef PIKE_DEBUG
+  gc_debug = d_flag;
+#endif
 
   /* Make sure there will be no callback to this while we're in the
    * gc. That can be fatal since this function links objects back to
@@ -915,10 +980,21 @@ void do_gc(void)
   objects_freed*=multiplier;
   objects_freed += (double) num_objects;
 
+#ifdef PIKE_DEBUG
+  if (gc_debug) {
+    INT32 n;
+    Pike_in_gc = GC_PASS_PRETOUCH;
+    n = gc_touch_all_arrays();
+    n += gc_touch_all_multisets();
+    n += gc_touch_all_mappings();
+    n += gc_touch_all_programs();
+    n += gc_touch_all_objects();
+    if (n != num_objects)
+      fatal("Object count wrong before gc; expected %d, got %d.\n", num_objects, n);
+  }
+#endif
 
-  init_gc();
-
-  Pike_in_gc=100; /* pass one */
+  Pike_in_gc=GC_PASS_CHECK;
   /* First we count internal references */
   gc_check_all_arrays();
   gc_check_all_multisets();
@@ -935,12 +1011,12 @@ void do_gc(void)
   }
 #endif
 
-  /* These callbacks are mainly for pass 1, but can also
-   * do things that are normally associated with pass 2
+  /* These callbacks are mainly for the check pass, but can also
+   * do things that are normally associated with the mark pass
    */
   call_callback(& gc_callbacks, (void *)0);
 
-  Pike_in_gc=200; /* pass two */
+  Pike_in_gc=GC_PASS_MARK;
   /* Next we mark anything with external references */
   gc_mark_all_arrays();
   run_queue(&gc_mark_queue);
@@ -959,21 +1035,19 @@ void do_gc(void)
 #ifdef PIKE_DEBUG
   check_for=(void *)1;
 #endif
-  Pike_in_gc=350; /* pass 3.5 */
+  Pike_in_gc=GC_PASS_FREE;
   /* Now we free the unused stuff */
-
-
   gc_free_all_unreferenced_arrays();
   gc_free_all_unreferenced_multisets();
   gc_free_all_unreferenced_mappings();
   gc_free_all_unreferenced_programs();
-  Pike_in_gc=300;
+  Pike_in_gc=GC_PASS_DESTROY;	/* Pike code allowed in this pass. */
   /* This is intended to happen before the freeing done above. But
    * it's put here for the time being, since the problem of non-object
    * objects getting external references from destroy code isn't
    * solved yet. */
   destroyed = gc_destroy_all_unreferenced_objects();
-  Pike_in_gc=350;
+  Pike_in_gc=GC_PASS_FREE;
   destructed = gc_free_all_unreferenced_objects();
 
 #ifdef PIKE_DEBUG
@@ -984,11 +1058,27 @@ void do_gc(void)
   if(fatal_after_gc) fatal(fatal_after_gc);
 #endif
 
+  Pike_in_gc=GC_PASS_DESTRUCT;
+  destruct_objects_to_destruct();
+
+#ifdef PIKE_DEBUG
+  if (gc_debug) {
+    INT32 n;
+    Pike_in_gc=GC_PASS_POSTTOUCH;
+    n = gc_touch_all_arrays();
+    n += gc_touch_all_multisets();
+    n += gc_touch_all_mappings();
+    n += gc_touch_all_programs();
+    n += gc_touch_all_objects();
+    if (n != num_objects)
+      fatal("Object count wrong after gc; expected %d, got %d.\n", num_objects, n);
+    if(fatal_after_gc) fatal(fatal_after_gc);
+  }
+#endif
+
+  Pike_in_gc=0;
   exit_gc();
 
-  Pike_in_gc=400;
-  destruct_objects_to_destruct();
-  
   objects_freed -= (double) num_objects;
 
   tmp=(double)num_objects;
@@ -1026,7 +1116,6 @@ void do_gc(void)
 #else
   if(d_flag > 3) ADD_GC_CALLBACK();
 #endif
-  Pike_in_gc=0;
 }
 
 
@@ -1057,4 +1146,3 @@ void f__gc_status(INT32 args)
 
   f_aggregate_mapping(14);
 }
-
diff --git a/src/gc.h b/src/gc.h
index 00cd2a2039bfbd96862279f16e2e2f21e8bee932..b60cc46499fbd991b39d7427dba95901a45fdc5c 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -1,5 +1,5 @@
 /*
- * $Id: gc.h,v 1.37 2000/04/20 01:49:43 mast Exp $
+ * $Id: gc.h,v 1.38 2000/04/23 03:01:25 mast Exp $
  */
 #ifndef GC_H
 #define GC_H
@@ -23,21 +23,29 @@ extern void *gc_svalue_location;
 
 #define ADD_GC_CALLBACK() gc_evaluator_callback=add_to_callback(&evaluator_callbacks,(callback_func)do_gc,0,0)
 
-#ifdef ALWAYS_GC
-#define GC_ALLOC() do{ num_objects++; num_allocs++;  if(!gc_evaluator_callback) ADD_GC_CALLBACK(); } while(0)
-#else
-#define GC_ALLOC()  do{							\
+#define LOW_GC_ALLOC(OBJ) do {						\
  extern int d_flag;							\
  num_objects++;								\
  num_allocs++;								\
  DO_IF_DEBUG(								\
    if(d_flag) CHECK_INTERPRETER_LOCK();					\
-   if(Pike_in_gc > 1 && Pike_in_gc < 4 && Pike_in_gc != 5)		\
+   if(Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc <= GC_PASS_MARK)	\
      fatal("Allocating new objects within gc is not allowed!\n");	\
  )									\
- if(num_allocs == alloc_threshold && !gc_evaluator_callback)		\
-   ADD_GC_CALLBACK();							\
- } while(0)
+ if (Pike_in_gc) remove_marker(OBJ);					\
+} while (0)
+
+#ifdef ALWAYS_GC
+#define GC_ALLOC(OBJ) do{						\
+  LOW_GC_ALLOC(OBJ);							\
+  if(!gc_evaluator_callback) ADD_GC_CALLBACK();				\
+} while(0)
+#else
+#define GC_ALLOC(OBJ)  do{						\
+  LOW_GC_ALLOC(OBJ);							\
+  if(num_allocs == alloc_threshold && !gc_evaluator_callback)		\
+    ADD_GC_CALLBACK();							\
+} while(0)
 #endif
 
 struct marker
@@ -69,6 +77,7 @@ int debug_gc_check(void *x, TYPE_T t, void *data);
 void describe_something(void *a, int t, int indent, int depth, int flags);
 void describe(void *x);
 void debug_describe_svalue(struct svalue *s);
+void debug_gc_touch(void *a);
 INT32 real_gc_check(void *a);
 void locate_references(void *a);
 int debug_gc_is_referenced(void *a);
@@ -85,19 +94,19 @@ void f__gc_status(INT32 args);
 #define gc_check(VP) real_gc_check(debug_malloc_pass(VP))
 
 #ifdef PIKE_DEBUG
-#define LOW_GC_FREE(OBJ) do {						\
+
+#define LOW_GC_FREE() do {						\
   extern int d_flag;							\
   if(d_flag) CHECK_INTERPRETER_LOCK();					\
   num_objects-- ;							\
   if(num_objects < 0)							\
     fatal("Panic!! less than zero objects!\n");				\
-  if (Pike_in_gc) remove_marker(OBJ);					\
 }while(0)
 
-#define GC_FREE(OBJ) do {						\
-  if(Pike_in_gc >2 && Pike_in_gc <4)					\
+#define GC_FREE() do {							\
+  if(Pike_in_gc == GC_PASS_MARK)					\
     fatal("Freeing objects within gc is not allowed!\n");		\
-  LOW_GC_FREE(OBJ);							\
+  LOW_GC_FREE();							\
 }while(0)
 
 #else
@@ -105,11 +114,8 @@ void f__gc_status(INT32 args);
 #define debug_gc_check_short_svalue(S,N,T,V) gc_check_short_svalue((S),N)
 #define debug_gc_xmark_svalues(S,N,X) gc_xmark_svalues((S),N)
 #define debug_gc_check(VP,T,V) gc_check((VP))
-#define LOW_GC_FREE(OBJ) do {						\
-  num_objects-- ;							\
-  if (Pike_in_gc) remove_marker(OBJ);					\
-}while(0)
-#define GC_FREE(OBJ) LOW_GC_FREE(OBJ)
+#define LOW_GC_FREE() do {num_objects-- ; }while(0)
+#define GC_FREE() LOW_GC_FREE()
 #endif
 
 
@@ -122,10 +128,20 @@ void f__gc_status(INT32 args);
 #define GC_REFERENCED 1
 #define GC_XREFERENCED 2
 #define GC_CHECKED 4
-#ifdef PIKE_DEBUG
 #define GC_OBJ_DESTROY_CHECK 8
 #define GC_DO_FREE_OBJ 16
-#endif
+#define GC_TOUCHED 32
+
+#define GC_PASS_PREPARE		 50
+#define GC_PASS_PRETOUCH	 90
+#define GC_PASS_CHECK		100
+#define GC_PASS_MARK		200
+#define GC_PASS_DESTROY		300
+#define GC_PASS_FREE		400
+#define GC_PASS_DESTRUCT	500
+#define GC_PASS_POSTTOUCH	600
+
+#define GC_PASS_LOCATE -1
 
 #ifdef PIKE_DEBUG
 #define gc_is_referenced(X) debug_gc_is_referenced(debug_malloc_pass(X))
diff --git a/src/mapping.c b/src/mapping.c
index 1fdfd11eb076ff31945ca45eeba0d4b263f44e24..859b101c6474b940820b81667bac46c507221814 100644
--- a/src/mapping.c
+++ b/src/mapping.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: mapping.c,v 1.78 2000/04/20 01:49:43 mast Exp $");
+RCSID("$Id: mapping.c,v 1.79 2000/04/23 03:01:25 mast Exp $");
 #include "main.h"
 #include "object.h"
 #include "mapping.h"
@@ -63,7 +63,7 @@ DO_IF_DEBUG(								\
 									\
   if(m->next) m->next->prev = m->prev;					\
 									\
-  GC_FREE(m);
+  GC_FREE();
 
 
 #undef COUNT_OTHER
@@ -131,7 +131,7 @@ static void init_mapping(struct mapping *m, INT32 size)
     e=MAPPING_DATA_SIZE(hashsize, size);
 
     md=(struct mapping_data *)xalloc(e);
-    
+
     m->data=md;
     md->hashsize=hashsize;
     
@@ -170,10 +170,10 @@ struct mapping *debug_allocate_mapping(int size)
 {
   struct mapping *m;
 
-  GC_ALLOC();
-
   m=alloc_mapping();
 
+  GC_ALLOC(m);
+
   INITIALIZE_PROT(m);
   init_mapping(m,size);
 
@@ -1878,6 +1878,19 @@ static void gc_check_mapping(struct mapping *m)
   }
 }
 
+#ifdef PIKE_DEBUG
+INT32 gc_touch_all_mappings(void)
+{
+  INT32 n = 0;
+  struct mapping *m;
+  for (m = first_mapping; m; m = m->next) {
+    debug_gc_touch(m);
+    n++;
+  }
+  return n;
+}
+#endif
+
 void gc_check_all_mappings(void)
 {
   struct mapping *m;
diff --git a/src/mapping.h b/src/mapping.h
index 5099b7becd38aa42e7184ba8bfd1648630816bdd..b68d318b2586d0954d553e87116ecfc18e2981d4 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: mapping.h,v 1.23 2000/03/28 17:57:37 grubba Exp $
+ * $Id: mapping.h,v 1.24 2000/04/23 03:01:25 mast Exp $
  */
 #ifndef MAPPING_H
 #define MAPPING_H
@@ -145,6 +145,7 @@ void mapping_search_no_free(struct svalue *to,
 void check_mapping(struct mapping *m);
 void check_all_mappings(void);
 void gc_mark_mapping_as_referenced(struct mapping *m);
+INT32 gc_touch_all_mappings(void);
 void gc_check_all_mappings(void);
 void gc_mark_all_mappings(void);
 void gc_free_all_unreferenced_mappings(void);
diff --git a/src/multiset.c b/src/multiset.c
index 4cbca589753fa55a367bc5c802d2a1aa3ee529fd..6d0f6a3534c4c1af5b5995f38b5b38b00d6a4d85 100644
--- a/src/multiset.c
+++ b/src/multiset.c
@@ -16,7 +16,7 @@
 #include "gc.h"
 #include "security.h"
 
-RCSID("$Id: multiset.c,v 1.19 2000/04/20 01:49:43 mast Exp $");
+RCSID("$Id: multiset.c,v 1.20 2000/04/23 03:01:25 mast Exp $");
 
 struct multiset *first_multiset;
 
@@ -31,8 +31,8 @@ int multiset_member(struct multiset *l, struct svalue *ind)
 struct multiset *allocate_multiset(struct array *ind)
 {
   struct multiset *l;
-  GC_ALLOC();
   l=ALLOC_STRUCT(multiset);
+  GC_ALLOC(l);
   l->next = first_multiset;
   l->prev = 0;
   l->refs = 1;
@@ -66,7 +66,7 @@ void really_free_multiset(struct multiset *l)
   if(l->next)  l->next->prev = l->prev;
     
   free((char *)l);
-  GC_FREE(l);
+  GC_FREE();
 }
 
 
@@ -291,6 +291,19 @@ void gc_mark_multiset_as_referenced(struct multiset *l)
     gc_mark_array_as_referenced(l->ind);
 }
 
+#ifdef PIKE_DEBUG
+INT32 gc_touch_all_multisets(void)
+{
+  INT32 n = 0;
+  struct multiset *l;
+  for(l=first_multiset;l;l=l->next) {
+    debug_gc_touch(l);
+    n++;
+  }
+  return n;
+}
+#endif
+
 void gc_check_all_multisets(void)
 {
   struct multiset *l;
diff --git a/src/multiset.h b/src/multiset.h
index 87c4a1aeaedbe6bc8582177766aaf10d2a04fcaa..a84f7c5a5d98de9ab729ff27c59feef6c35486f9 100644
--- a/src/multiset.h
+++ b/src/multiset.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: multiset.h,v 1.9 1999/04/13 20:10:06 hubbe Exp $
+ * $Id: multiset.h,v 1.10 2000/04/23 03:01:25 mast Exp $
  */
 #ifndef MULTISET_H
 #define MULTISET_H
@@ -51,6 +51,7 @@ void f_aggregate_multiset(INT32 args);
 struct multiset *copy_multiset_recursively(struct multiset *l,
 				   struct processing *p);
 void gc_mark_multiset_as_referenced(struct multiset *l);
+INT32 gc_touch_all_multisets(void);
 void gc_check_all_multisets(void);
 void gc_mark_all_multisets(void);
 void gc_free_all_unreferenced_multisets(void);
diff --git a/src/object.c b/src/object.c
index 12fbce252a1782ee65987e9e63f6719534d64cae..1953e5e25418a4182f379381a4b500b23eb1d1d2 100644
--- a/src/object.c
+++ b/src/object.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: object.c,v 1.119 2000/04/22 02:25:10 hubbe Exp $");
+RCSID("$Id: object.c,v 1.120 2000/04/23 03:01:25 mast Exp $");
 #include "object.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
@@ -84,10 +84,10 @@ struct object *low_clone(struct program *p)
   p->num_clones++;
 #endif /* PROFILING */
 
-  GC_ALLOC();
-
   o=(struct object *)xalloc( ((long)(((struct object *)0)->storage))+p->storage_needed);
 
+  GC_ALLOC(o);
+
 #ifdef DEBUG_MALLOC
   if(!debug_malloc_copy_names(o, p)) 
   {
@@ -471,7 +471,7 @@ void low_destruct(struct object *o,int do_free)
 
 #ifdef PIKE_DEBUG
   if(d_flag > 20) do_debug();
-  if(Pike_in_gc >= 100 && Pike_in_gc < 300)
+  if(Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc <= GC_PASS_MARK)
     fatal("Destructing object inside gc()\n");
 #endif
 
@@ -561,7 +561,7 @@ void destruct_objects_to_destruct(void)
   struct object *o, *next;
 
 #ifdef PIKE_DEBUG
-  if (Pike_in_gc >= 100 && Pike_in_gc < 400)
+  if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc != GC_PASS_DESTRUCT)
     fatal("Can't meddle with the object link list in gc pass %d.\n", Pike_in_gc);
 #endif
 
@@ -572,7 +572,7 @@ void destruct_objects_to_destruct(void)
     
     /* link */
     DOUBLELINK(first_object,o);
-    
+
     /* call destroy, keep one ref */
     add_ref(o);
     call_destroy(o,0);
@@ -612,10 +612,9 @@ void really_free_object(struct object *o)
   if(o->prog)
   {
     DOUBLELINK(objects_to_destruct,o);
-    if (Pike_in_gc) {
-      remove_marker(o);
-      if (Pike_in_gc < 400) return; /* Done last in gc(). */
-    }
+    if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_DESTRUCT)
+      /* destruct_objects_to_destruct() done last in gc() instead. */
+      return;
     if(!destruct_object_evaluator_callback)
     {
       destruct_object_evaluator_callback=
@@ -636,7 +635,7 @@ void really_free_object(struct object *o)
 
     free((char *)o);
 
-    GC_FREE(o);
+    GC_FREE();
   }
 }
 
@@ -1207,10 +1206,24 @@ static inline void gc_check_object(struct object *o)
   }
 }
 
-void gc_check_all_objects(void)
+#ifdef PIKE_DEBUG
+INT32 gc_touch_all_objects(void)
 {
+  INT32 n = 0;
   struct object *o;
+  for (o = first_object; o; o = o->next) {
+    debug_gc_touch(o);
+    n++;
+  }
+  if (objects_to_destruct)
+    fatal("Shouldn't have any objects to destruct in touch pass.\n");
+  return n;
+}
+#endif
 
+void gc_check_all_objects(void)
+{
+  struct object *o;
   for(o=first_object;o;o=o->next)
     gc_check_object(o);
 }
@@ -1281,17 +1294,13 @@ int gc_free_all_unreferenced_objects(void)
     if(gc_do_free(o))
     {
 #ifdef PIKE_DEBUG
-      if (!(get_marker(o)->flags & GC_DO_FREE_OBJ) ||
-	  !(get_marker(o)->flags & GC_OBJ_DESTROY_CHECK)) {
+      if (!(get_marker(o)->flags & (GC_OBJ_DESTROY_CHECK|GC_DO_FREE_OBJ))) {
 	extern char *fatal_after_gc;
-	fprintf(stderr,"**Object unexpectedly marked for gc. flags: %d\n",
+	fprintf(stderr,"**Object unexpectedly marked for gc. flags: %x\n",
 		get_marker(o)->flags);
 	describe(o);
 	locate_references(o);
-	fprintf(stderr,"##### Continuing search for more bugs....\n");
-	fatal_after_gc="Object unexpectedly marked for gc.\n";
-	next=o->next;		/* Leave it alone and continue. */
-	continue;
+	fatal("Object unexpectedly marked for gc.\n");
       }
 #endif
       low_destruct(o,1);
diff --git a/src/object.h b/src/object.h
index 30048971e506f2f7421fd29c3c098595b0ab6d7d..e3562fea391ef9184d6b23bd3c7694029643e429 100644
--- a/src/object.h
+++ b/src/object.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: object.h,v 1.44 2000/04/20 01:49:44 mast Exp $
+ * $Id: object.h,v 1.45 2000/04/23 03:01:25 mast Exp $
  */
 #ifndef OBJECT_H
 #define OBJECT_H
@@ -94,6 +94,7 @@ void cleanup_objects(void);
 struct array *object_indices(struct object *o);
 struct array *object_values(struct object *o);
 void gc_mark_object_as_referenced(struct object *o);
+INT32 gc_touch_all_objects(void);
 void gc_check_all_objects(void);
 void gc_mark_all_objects(void);
 int gc_destroy_all_unreferenced_objects(void);
diff --git a/src/program.c b/src/program.c
index de0d0ac8772cfa3df2c9bbb0f507f4eb3fd9b7f9..335830241c2ceab6e9f0b6bcc0237abcb160584d 100644
--- a/src/program.c
+++ b/src/program.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: program.c,v 1.231 2000/04/20 01:49:44 mast Exp $");
+RCSID("$Id: program.c,v 1.232 2000/04/23 03:01:26 mast Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -689,7 +689,7 @@ struct program *low_allocate_program(void)
   MEMSET(p, 0, sizeof(struct program));
   p->alignment_needed=1;
 
-  GC_ALLOC();
+  GC_ALLOC(p);
   p->refs=1;
   p->id=++current_program_id;
 
@@ -784,7 +784,7 @@ void low_start_new_program(struct program *p,
 #else
   fake_object=ALLOC_STRUCT(object);
 #endif
-  GC_ALLOC();
+  GC_ALLOC(fake_object);
 
   fake_object->next=fake_object;
   fake_object->prev=fake_object;
@@ -971,7 +971,7 @@ void really_free_program(struct program *p)
   FREE_PROT(p);
   dmfree((char *)p);
 
-  GC_FREE(p);
+  GC_FREE();
 }
 
 #ifdef PIKE_DEBUG
@@ -3561,6 +3561,25 @@ static void gc_check_program(struct program *p)
 #endif
 }
 
+#ifdef PIKE_DEBUG
+INT32 gc_touch_all_programs(void)
+{
+  INT32 n = 0;
+  struct program *p;
+  struct program_state *ps;
+  for (p = first_program; p; p = p->next) {
+    debug_gc_touch(p);
+    n++;
+  }
+  /* Count the fake objects. They're not part of the gc, but they're
+   * still counted by the gc. */
+  if (fake_object) n++;
+  for (ps = previous_program_state; ps; ps = ps->previous)
+    if (ps->fake_object) n++;
+  return n;
+}
+#endif
+
 void gc_check_all_programs(void)
 {
   struct program *p;
diff --git a/src/program.h b/src/program.h
index ceb71467425c1744aa591a71a3e68776466fade4..2f52cfc2063264b1c1721da5105514df616f9cef 100644
--- a/src/program.h
+++ b/src/program.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: program.h,v 1.86 2000/04/08 02:01:09 hubbe Exp $
+ * $Id: program.h,v 1.87 2000/04/23 03:01:26 mast Exp $
  */
 #ifndef PROGRAM_H
 #define PROGRAM_H
@@ -453,6 +453,7 @@ void check_all_programs(void);
 void init_program(void);
 void cleanup_program(void);
 void gc_mark_program_as_referenced(struct program *p);
+INT32 gc_touch_all_programs(void);
 void gc_check_all_programs(void);
 void gc_mark_all_programs(void);
 void gc_free_all_unreferenced_programs(void);
diff --git a/src/svalue.c b/src/svalue.c
index 57c31792773064e76f70cdf23e798012ad85e34b..fbd8357213123f858f9605cb9f826bf77add35bf 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -23,7 +23,7 @@
 #include "queue.h"
 #include "bignum.h"
 
-RCSID("$Id: svalue.c,v 1.71 2000/04/19 16:05:19 mast Exp $");
+RCSID("$Id: svalue.c,v 1.72 2000/04/23 03:01:26 mast Exp $");
 
 struct svalue dest_ob_zero = { T_INT, 0 };
 
@@ -1411,7 +1411,7 @@ void debug_gc_mark_svalues(struct svalue *s, int num)
       else
       {
 	describe(s->u.object);
-	fatal("Unfreed destructed object in GC pass 2??\n");
+	fatal("Unfreed destructed object in GC mark pass??\n");
       }
 #endif
       break;
@@ -1425,7 +1425,7 @@ void debug_gc_mark_short_svalue(union anything *u, TYPE_T type)
   {
 #ifdef PIKE_DEBUG
     case T_STRING:
-      if(d_flag) gc_mark(debug_malloc_pass(u->string));
+      if(d_flag && u->refs) gc_mark(debug_malloc_pass(u->string));
       break;
 #endif
 
@@ -1470,7 +1470,7 @@ void debug_gc_mark_short_svalue(union anything *u, TYPE_T type)
     else
     {
       describe(u->object);
-      fatal("Unfreed destructed object in GC pass 2??\n");
+      fatal("Unfreed destructed object in GC mark pass??\n");
     }
 #endif
     break;
diff --git a/src/threads.h b/src/threads.h
index f907dd782e7c20930df45a26ca17c628dfb5608f..268dcccf06f05f2fc5bd95e6483cd19bd7229eb1 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -1,5 +1,5 @@
 /*
- * $Id: threads.h,v 1.88 2000/04/21 23:07:10 hubbe Exp $
+ * $Id: threads.h,v 1.89 2000/04/23 03:01:26 mast Exp $
  */
 #ifndef THREADS_H
 #define THREADS_H
@@ -57,9 +57,6 @@ struct object;
 extern size_t thread_stack_size;
 extern struct object *thread_id;
 
-/* Used by debug code. Avoid pulling in gc.h only for this. */
-extern int Pike_in_gc;
-
 #define DEFINE_MUTEX(X) PIKE_MUTEX_T X
 
 
@@ -504,9 +501,10 @@ struct thread_state {
 #define THREADS_ALLOW() do { \
      struct thread_state *_tmp=OBJ2THREAD(thread_id); \
      DO_IF_DEBUG({ \
+       extern int Pike_in_gc; \
        if(thread_for_id(th_self()) != thread_id) \
 	 fatal("thread_for_id() (or thread_id) failed! %p != %p\n",thread_for_id(th_self()),thread_id); \
-       if (Pike_in_gc >=100 && Pike_in_gc <300) \
+       if (Pike_in_gc >= 100 && Pike_in_gc != 300 && Pike_in_gc != 500) \
 	 fatal("Threads allowed during garbage collection.\n"); \
      }) \
      if(num_threads > 1 && !threads_disabled) { \
@@ -539,9 +537,10 @@ struct thread_state {
 #define THREADS_ALLOW_UID() do { \
      struct thread_state *_tmp_uid=OBJ2THREAD(thread_id); \
      DO_IF_DEBUG({ \
+       extern int Pike_in_gc; \
        if(thread_for_id(th_self()) != thread_id) \
 	 fatal("thread_for_id() (or thread_id) failed! %p != %p\n",thread_for_id(th_self()),thread_id); \
-       if (Pike_in_gc >=100 && Pike_in_gc <300) \
+       if (Pike_in_gc >= 100 && Pike_in_gc != 300 && Pike_in_gc != 500) \
 	 fatal("Threads allowed during garbage collection.\n"); \
      }) \
      if(num_threads > 1 && !threads_disabled) { \