X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FStable.c;h=bf5e6aaf0181928aabd970fea28e17fef1983737;hb=2cb328218760ce7659ed4682bdae904157e0304d;hp=9f1414efd4f4345611ac055b735935459e63a87f;hpb=7f309f1c021e7583f724cce599ce2dd3c439361b;p=ghc-hetmet.git diff --git a/ghc/rts/Stable.c b/ghc/rts/Stable.c index 9f1414e..bf5e6aa 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.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; } } }