[project @ 2000-04-24 22:05:08 by panne]
[ghc-hetmet.git] / ghc / rts / Stable.c
index 9f1414e..bf5e6aa 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stable.c,v 1.2 1999/02/05 16:02:55 simonm Exp $
+ * $Id: Stable.c,v 1.11 2000/04/24 22:05:08 panne Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -133,7 +133,9 @@ initFreeList(snEntry *table, nat n, snEntry *free)
   snEntry *p;
 
   for (p = table + n - 1; p >= table; p--) {
-    p->addr = (P_)free;
+    p->addr   = (P_)free;
+    p->weight = 0;
+    p->sn_obj = NULL;
     free = p;
   }
   stable_ptr_free = table;
@@ -150,6 +152,27 @@ initStablePtrTable(void)
   SPT_size = 0;
 }
 
+/*
+ * get at the real stuff...remove indirections.
+ *
+ * ToDo: move to a better home.
+ */
+static
+StgClosure*
+removeIndirections(StgClosure* p)
+{
+  StgClosure* q = p;
+
+  while (get_itbl(q)->type == IND ||
+         get_itbl(q)->type == IND_STATIC ||
+         get_itbl(q)->type == IND_OLDGEN ||
+         get_itbl(q)->type == IND_PERM ||
+         get_itbl(q)->type == IND_OLDGEN_PERM ) {
+      q = ((StgInd *)q)->indirectee;
+  }
+  return q;
+}
+
 StgWord
 lookupStableName(StgPtr p)
 {
@@ -158,7 +181,13 @@ lookupStableName(StgPtr p)
   if (stable_ptr_free == NULL) {
     enlargeStablePtrTable();
   }
-    
+
+  /* removing indirections increases the likelihood
+   * of finding a match in the stable name
+   * hash table.
+   */
+  p = (StgPtr)removeIndirections((StgClosure*)p);
+
   (void *)sn = lookupHashTable(addrToStableHash,(W_)p);
   
   if (sn != 0) {
@@ -170,6 +199,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 +213,10 @@ lookupStableName(StgPtr p)
 static inline void
 freeStableName(snEntry *sn)
 {
+  ASSERT(sn->sn_obj == NULL);
+  if (sn->addr != NULL) {
+    removeHashTable(addrToStableHash, (W_)sn->addr, NULL);
+  }
   sn->addr = (P_)stable_ptr_free;
   stable_ptr_free = sn;
 }
@@ -192,10 +226,9 @@ getStablePtr(StgPtr p)
 {
   StgWord sn = lookupStableName(p);
   StgWord weight, weight_2;
-
   weight = stable_ptr_table[sn].weight;
   if (weight == 0) {
-    weight = 1 << (BITS_IN(StgWord)-1);
+    weight = (StgWord)1 << (BITS_IN(StgWord)-1);
     stable_ptr_table[sn].weight = weight;
     return (StgStablePtr)(sn + ((BITS_IN(StgWord)-1) << STABLEPTR_WEIGHT_SHIFT));
   } 
@@ -224,6 +257,10 @@ enlargeStablePtrTable(void)
     stable_ptr_table = stgMallocWords(SPT_size * sizeof(snEntry), 
                                      "initStablePtrTable");
     
+    /* we don't use index 0 in the stable name table, because that
+     * would conflict with the hash table lookup operations which
+     * return NULL if an entry isn't found in the hash table.
+     */
     initFreeList(stable_ptr_table+1,INIT_SPT_SIZE-1,NULL);
     addrToStableHash = allocHashTable();
   }
@@ -262,30 +299,30 @@ markStablePtrTable(rtsBool full)
 
   end_stable_ptr_table = &stable_ptr_table[SPT_size];
 
-  /* Mark all the stable *pointers* (not stable names) 
+  /* Mark all the stable *pointers* (not stable names).
+   * _starting_ at index 1; index 0 is unused.
    */
-  for (p = stable_ptr_table; p < end_stable_ptr_table; p++) {
+  for (p = stable_ptr_table+1; 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));
+         if (!lookupHashTable(addrToStableHash, (W_)new)) {
+           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 +334,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
@@ -320,36 +359,52 @@ 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;
+  /* NOTE: _starting_ at index 1; index 0 is unused. */
+  for (p = stable_ptr_table + 1; p < end_stable_ptr_table; p++) {
+
+    /* 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) {
+         if (new == NULL) {
+           /* The target has been garbage collected.  Remove its
+            * entry from the hash table.
+            */
            removeHashTable(addrToStableHash, (W_)q, NULL);
-           insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
+
+         } else {
+           /* Target still alive, 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.
+         /* finally update the address of the target to point to its
+          * new location.
           */
-         if (p->keep)
-           p->addr = NULL;
-         else
-           freeStableName(p);
+         p->addr = new;
        }
       }
     }