[project @ 2000-11-13 14:40:36 by simonmar]
[ghc-hetmet.git] / ghc / rts / Stable.c
index d0dbc59..5b2635b 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Stable.c,v 1.5 1999/07/16 09:53:44 panne Exp $
+ * $Id: Stable.c,v 1.13 2000/09/04 15:17:03 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -107,7 +107,7 @@ unsigned int SPT_size;
  *
  * A stable pointer has a weighted reference count N attached to it
  * (actually in its upper 5 bits), which represents the weight
- * 2^N.  The stable name entry keeps a 32-bit reference count, which
+ * 2^(N-1).  The stable name entry keeps a 32-bit reference count, which
  * represents any weight between 1 and 2^32 (represented as zero).
  * When the weight is 2^32, the stable name table owns "all" of the
  * stable pointers to this object, and the entry can be garbage
@@ -152,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)
 {
@@ -160,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) {
@@ -187,6 +214,9 @@ 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;
 }
@@ -195,13 +225,12 @@ StgStablePtr
 getStablePtr(StgPtr p)
 {
   StgWord sn = lookupStableName(p);
-  StgWord weight, weight_2;
-
+  StgWord weight, n;
   weight = stable_ptr_table[sn].weight;
   if (weight == 0) {
     weight = (StgWord)1 << (BITS_IN(StgWord)-1);
     stable_ptr_table[sn].weight = weight;
-    return (StgStablePtr)(sn + ((BITS_IN(StgWord)-1) << STABLEPTR_WEIGHT_SHIFT));
+    return (StgStablePtr)(sn + (BITS_IN(StgWord) << STABLEPTR_WEIGHT_SHIFT));
   } 
   else if (weight == 1) {
     barf("getStablePtr: too light");
@@ -209,11 +238,11 @@ getStablePtr(StgPtr p)
   else {
     weight /= 2;
     /* find log2(weight) */
-    for (weight_2 = 1; weight != 1; weight_2++) {
+    for (n = 0; weight != 1; n++) {
       weight >>= 1;
     }
-    stable_ptr_table[sn].weight -= 2^weight_2;
-    return (StgStablePtr)(sn + (weight_2 << STABLEPTR_WEIGHT_SHIFT));
+    stable_ptr_table[sn].weight -= 1 << n;
+    return (StgStablePtr)(sn + ((n+1) << STABLEPTR_WEIGHT_SHIFT));
   }
 }
 
@@ -228,7 +257,11 @@ enlargeStablePtrTable(void)
     stable_ptr_table = stgMallocWords(SPT_size * sizeof(snEntry), 
                                      "initStablePtrTable");
     
-    initFreeList(stable_ptr_table,INIT_SPT_SIZE,NULL);
+    /* 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();
   }
   else {
@@ -266,9 +299,10 @@ 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 
      */
@@ -282,11 +316,13 @@ markStablePtrTable(rtsBool full)
          (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));
+       IF_DEBUG(stable, fprintf(stderr,"Stable ptr %d still alive at %p, weight %u\n", p - stable_ptr_table, new, p->weight));
       }
     }
   }
@@ -323,7 +359,8 @@ gcStablePtrTable(rtsBool full)
 
   end_stable_ptr_table = &stable_ptr_table[SPT_size];
 
-  for (p = stable_ptr_table; p < end_stable_ptr_table; p++) {
+  /* 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) {
@@ -347,9 +384,15 @@ gcStablePtrTable(rtsBool full)
          (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;
-         if (new != NULL) {
-           /* Re-hash this stable name */
+         if (new == NULL) {
+           /* The target has been garbage collected.  Remove its
+            * entry from the hash table.
+            */
+           removeHashTable(addrToStableHash, (W_)q, NULL);
+
+         } else {
+           /* Target still alive, Re-hash this stable name 
+            */
            if (full) {
              insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
            } else if (new != q) {
@@ -357,6 +400,11 @@ gcStablePtrTable(rtsBool full)
              insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table));
            }
          }
+
+         /* finally update the address of the target to point to its
+          * new location.
+          */
+         p->addr = new;
        }
       }
     }