diff --git a/ghc/includes/Stable.h b/ghc/includes/Stable.h
index 4552439e8779fe7dfa0d6f5bb8fc420450ff9ed0..70c467429046b45e306eb2bc870d65f2d2a49cce 100644
--- a/ghc/includes/Stable.h
+++ b/ghc/includes/Stable.h
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stable.h,v 1.2 1999/02/05 16:02:28 simonm Exp $
+ * $Id: Stable.h,v 1.3 1999/02/26 12:46:45 simonm Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -22,9 +22,9 @@ extern StgStablePtr   splitStablePtr(StgStablePtr sp);
 extern StgStablePtr getStablePtr(StgPtr p);
 
 typedef struct { 
-  StgPtr  addr;			/* either Haskell object or free list */
+  StgPtr  addr;			/* Haskell object, free list, or NULL */
   StgWord weight;		/* used for reference counting */
-  unsigned int keep;		/* set by the garbage collector */
+  StgClosure *sn_obj;		/* the StableName object (or NULL) */
 } snEntry;
 
 extern snEntry *stable_ptr_table;
diff --git a/ghc/rts/GC.c b/ghc/rts/GC.c
index fad50be014f10ccfd16852ed62c63b3bfeb5b021..d823c44d1eaeb1e416fda4869981a53ef46e4535 100644
--- a/ghc/rts/GC.c
+++ b/ghc/rts/GC.c
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.42 1999/02/25 17:52:33 simonm Exp $
+ * $Id: GC.c,v 1.43 1999/02/26 12:46:46 simonm Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -1099,10 +1099,6 @@ loop:
     recordMutable((StgMutClosure *)to);
     return to;
 
-  case STABLE_NAME:
-    stable_ptr_table[((StgStableName *)q)->sn].keep = rtsTrue;
-    return copy(q,sizeofW(StgStableName),step);
-
   case FUN_1_0:
   case FUN_0_1:
   case CONSTR_1_0:
@@ -1140,6 +1136,7 @@ loop:
   case CAF_ENTERED:
   case WEAK:
   case FOREIGN:
+  case STABLE_NAME:
     return copy(q,sizeW_fromITBL(info),step);
 
   case CAF_BLACKHOLE:
diff --git a/ghc/rts/PrimOps.hc b/ghc/rts/PrimOps.hc
index f711d9bb74682291fb9076c99c69b5f5b7ef5b05..33e2d2332d750d2a8585669790f28d27ef216d2c 100644
--- a/ghc/rts/PrimOps.hc
+++ b/ghc/rts/PrimOps.hc
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: PrimOps.hc,v 1.16 1999/02/17 15:57:39 simonm Exp $
+ * $Id: PrimOps.hc,v 1.17 1999/02/26 12:46:48 simonm Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -880,9 +880,15 @@ FN_(makeStableNamezh_fast)
   
   index = RET_STGCALL1(StgWord,lookupStableName,R1.p);
 
-  sn_obj = (StgStableName *) (Hp - sizeofW(StgStableName) + 1);
-  sn_obj->header.info = &STABLE_NAME_info;
-  sn_obj->sn = index;
+  /* Is there already a StableName for this heap object? */
+  if (stable_ptr_table[index].sn_obj == NULL) {
+    sn_obj = (StgStableName *) (Hp - sizeofW(StgStableName) + 1);
+    sn_obj->header.info = &STABLE_NAME_info;
+    sn_obj->sn = index;
+    stable_ptr_table[index].sn_obj = (StgClosure *)sn_obj;
+  } else {
+    (StgClosure *)sn_obj = stable_ptr_table[index].sn_obj;
+  }
 
   TICK_RET_UNBOXED_TUP(1);
   RET_P(sn_obj);
diff --git a/ghc/rts/Stable.c b/ghc/rts/Stable.c
index 9f1414efd4f4345611ac055b735935459e63a87f..206772f3346b04f97f2f8129fb60fe423cf99193 100644
--- a/ghc/rts/Stable.c
+++ b/ghc/rts/Stable.c
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stable.c,v 1.2 1999/02/05 16:02:55 simonm Exp $
+ * $Id: Stable.c,v 1.3 1999/02/26 12:46:48 simonm Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -170,6 +170,7 @@ lookupStableName(StgPtr p)
     (P_)stable_ptr_free  = stable_ptr_free->addr;
     stable_ptr_table[sn].weight = 0;
     stable_ptr_table[sn].addr = p;
+    stable_ptr_table[sn].sn_obj = NULL;
     /* IF_DEBUG(stable,fprintf(stderr,"new stable name %d at
        %p\n",sn,p)); */
     
@@ -183,6 +184,7 @@ lookupStableName(StgPtr p)
 static inline void
 freeStableName(snEntry *sn)
 {
+  ASSERT(sn->sn_obj == NULL);
   sn->addr = (P_)stable_ptr_free;
   stable_ptr_free = sn;
 }
@@ -266,26 +268,23 @@ markStablePtrTable(rtsBool full)
    */
   for (p = stable_ptr_table; p < end_stable_ptr_table; p++) {
     q = p->addr;
-    /* internal pointers or NULL are free slots */
+    /* internal pointers or NULL are free slots 
+     */
     if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
       if (p->weight != 0) {
 	new = MarkRoot((StgClosure *)q);
 	/* Update the hash table */
 	if (full) {
-	  insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
+	  insertHashTable(addrToStableHash, (W_)new, 
+			  (void *)(p - stable_ptr_table));
 	  (StgClosure *)p->addr = new;
 	} else if ((P_)new != q) {
 	  removeHashTable(addrToStableHash, (W_)q, NULL);
-	  insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
+	  insertHashTable(addrToStableHash, (W_)new, 
+			  (void *)(p - stable_ptr_table));
 	  (StgClosure *)p->addr = new;
 	}
-	/* IF_DEBUG(stable, fprintf(stderr,"Stable ptr %d still alive
-	   at %p, weight %d\n", p - stable_ptr_table, new,
-	   p->weight)); */
-      }
-      else { 
-	/* reset the keep flag */
-	p->keep = rtsFalse;
+	IF_DEBUG(stable, fprintf(stderr,"Stable ptr %d still alive at %p, weight %d\n", p - stable_ptr_table, new, p->weight));
       }
     }
   }
@@ -297,10 +296,12 @@ markStablePtrTable(rtsBool full)
  * A dead entry has:
  *
  *          - a weight of zero (i.e. 2^32)
- *          - a false keep flag
+ *          - a dead sn_obj
  *
- * The keep flag is set by the garbage collector whenever it
- * encounters a StableName object on the heap.  
+ * Both of these conditions must be true in order to re-use the stable
+ * name table entry.  We can re-use stable name table entries for live
+ * heap objects, as long as the program has no StableName objects that
+ * refer to the entry.
  *
  * The boolean argument 'full' indicates that a major collection is
  * being done, so we might as well throw away the hash table and build
@@ -321,36 +322,40 @@ gcStablePtrTable(rtsBool full)
   end_stable_ptr_table = &stable_ptr_table[SPT_size];
 
   for (p = stable_ptr_table; p < end_stable_ptr_table; p++) {
-    q = p->addr;
 
+    /* Update the pointer to the StableName object, if there is one */
+    if (p->sn_obj != NULL) {
+      p->sn_obj = isAlive(p->sn_obj);
+    }
+
+    q = p->addr;
     if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
 
-      /* We're only interested in Stable Names here. */
+      /* We're only interested in Stable Names here.  The weight != 0
+       * case is handled in markStablePtrTable above.
+       */
       if (p->weight == 0) {
 	
-	if (((StgClosure *)new = isAlive((StgClosure *)q))) {
+	if (p->sn_obj == NULL) {
+	  /* StableName object is dead */
+	  freeStableName(p);
+	  IF_DEBUG(stable, fprintf(stderr,"GC'd Stable name %d\n", p - stable_ptr_table));
+	} 
+	else {
+	  (StgClosure *)new = isAlive((StgClosure *)q);
 	  IF_DEBUG(stable, fprintf(stderr,"Stable name %d still alive at %p, weight %d\n", p - stable_ptr_table, new, p->weight));
 
 	  p->addr = new;
-	  /* Re-hash this stable name */
-	  if (full) {
-	    insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
-	  } else if (new != q) {
-	    removeHashTable(addrToStableHash, (W_)q, NULL);
-	    insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
+	  if (new != NULL) {
+	    /* Re-hash this stable name */
+	    if (full) {
+	      insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
+	    } else if (new != q) {
+	      removeHashTable(addrToStableHash, (W_)q, NULL);
+	      insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
+	    }
 	  }
 	}
-
-	else {
-	  /* If there are still StableName objects in the heap
-	   * pointing to this entry (p->keep == rtsTrue), then
-	   * don't free the entry just yet.
-	   */
-	  if (p->keep)
-	    p->addr = NULL;
-	  else
-	    freeStableName(p);
-	}
       }
     }
   }