/* -----------------------------------------------------------------------------
- * $Id: Stable.c,v 1.3 1999/02/26 12:46:48 simonm Exp $
+ * $Id: Stable.c,v 1.13 2000/09/04 15:17:03 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
*
* 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
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;
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)
{
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) {
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;
}
getStablePtr(StgPtr p)
{
StgWord sn = lookupStableName(p);
- StgWord weight, weight_2;
-
+ StgWord weight, n;
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));
+ return (StgStablePtr)(sn + (BITS_IN(StgWord) << STABLEPTR_WEIGHT_SHIFT));
}
else if (weight == 1) {
barf("getStablePtr: too light");
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));
}
}
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();
}
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
*/
(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));
}
}
}
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) {
(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) {
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;
}
}
}