X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FStable.c;h=52876bd7a65aceb87e493d7d79f27c53978ce7f0;hb=c9477f2a34961d1f1fd1b72f5cc6fa4618f70794;hp=9f1414efd4f4345611ac055b735935459e63a87f;hpb=7f309f1c021e7583f724cce599ce2dd3c439361b;p=ghc-hetmet.git diff --git a/ghc/rts/Stable.c b/ghc/rts/Stable.c index 9f1414e..52876bd 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.17 2001/08/14 13:40:09 sewardj Exp $ * * (c) The GHC Team, 1998-1999 * @@ -7,10 +7,10 @@ * * ---------------------------------------------------------------------------*/ +#include "PosixSource.h" #include "Rts.h" #include "Hash.h" #include "StablePriv.h" -#include "GC.h" #include "RtsUtils.h" #include "Storage.h" #include "RtsAPI.h" @@ -66,7 +66,6 @@ deRefStablePtr# :: StablePtr# a -> State# RealWorld -> (# State# RealWorld, a #) \end{verbatim} - There is also a C procedure @FreeStablePtr@ which frees a stable pointer. There may be additional functions on the C side to allow evaluation, application, etc of a stable pointer. @@ -107,7 +106,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 @@ -133,7 +132,10 @@ 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->old = NULL; + 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,12 @@ 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 +198,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 +212,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; } @@ -191,13 +224,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 = 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"); @@ -205,11 +237,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)); } } @@ -219,16 +251,20 @@ enlargeStablePtrTable(void) nat old_SPT_size = SPT_size; if (SPT_size == 0) { - /* 1st time */ + // 1st time SPT_size = INIT_SPT_SIZE; 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(); } else { - /* 2nd and subsequent times */ + // 2nd and subsequent times SPT_size *= 2; stable_ptr_table = stgReallocWords(stable_ptr_table, SPT_size * sizeof(snEntry), @@ -246,49 +282,63 @@ enlargeStablePtrTable(void) * -------------------------------------------------------------------------- */ void -markStablePtrTable(rtsBool full) +markStablePtrTable(evac_fn evac) { - snEntry *p, *end_stable_ptr_table; - StgPtr q; - StgClosure *new; - - if (SPT_size == 0) - return; + snEntry *p, *end_stable_ptr_table; + StgPtr q; + + end_stable_ptr_table = &stable_ptr_table[SPT_size]; + + // Mark all the stable *pointers* (not stable names). + // _starting_ at index 1; index 0 is unused. + for (p = stable_ptr_table+1; p < end_stable_ptr_table; p++) { + q = p->addr; + + // Internal pointers are free slots. If q == NULL, it's a + // stable name where the object has been GC'd, but the + // StableName object (sn_obj) is still alive. + if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) { + + // save the current addr away: we need to be able to tell + // whether the objects moved in order to be able to update + // the hash table later. + p->old = p->addr; + + // if the weight is non-zero, treat addr as a root + if (p->weight != 0) { + evac((StgClosure **)&p->addr); + } + } + } +} - if (full) { - freeHashTable(addrToStableHash,NULL); - addrToStableHash = allocHashTable(); - } +/* ----------------------------------------------------------------------------- + * Thread the stable pointer table for compacting GC. + * + * Here we must call the supplied evac function for each pointer into + * the heap from the stable pointer table, because the compacting + * collector may move the object it points to. + * -------------------------------------------------------------------------- */ - end_stable_ptr_table = &stable_ptr_table[SPT_size]; +void +threadStablePtrTable( evac_fn evac ) +{ + snEntry *p, *end_stable_ptr_table; + StgPtr q; + + end_stable_ptr_table = &stable_ptr_table[SPT_size]; + + for (p = stable_ptr_table+1; p < end_stable_ptr_table; p++) { + + if (p->sn_obj != NULL) { + evac((StgClosure **)&p->sn_obj); + } - /* Mark all the stable *pointers* (not stable names) - */ - for (p = stable_ptr_table; p < end_stable_ptr_table; p++) { - q = p->addr; - /* 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)); - (StgClosure *)p->addr = new; - } else if ((P_)new != q) { - removeHashTable(addrToStableHash, (W_)q, NULL); - insertHashTable(addrToStableHash, (W_)new, (void *)(p - stable_ptr_table)); - (StgClosure *)p->addr = new; + q = p->addr; + if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) { + evac((StgClosure **)&p->addr); } - /* 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; - } } - } } /* ----------------------------------------------------------------------------- @@ -297,10 +347,56 @@ 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. + * -------------------------------------------------------------------------- */ + +void +gcStablePtrTable( void ) +{ + snEntry *p, *end_stable_ptr_table; + StgPtr q; + + end_stable_ptr_table = &stable_ptr_table[SPT_size]; + + // 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); + } + + // Internal pointers are free slots. If q == NULL, it's a + // stable name where the object has been GC'd, but the + // StableName object (sn_obj) is still alive. + q = p->addr; + if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) { + + // StableNames only: + if (p->weight == 0) { + 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)); + continue; + + } else { + (StgClosure *)p->addr = isAlive((StgClosure *)p->addr); + IF_DEBUG(stable, fprintf(stderr,"Stable name %d still alive at %p, weight %d\n", p - stable_ptr_table, p->addr, p->weight)); + } + } + } + } +} + +/* ----------------------------------------------------------------------------- + * Update the StablePtr/StableName hash table * * The boolean argument 'full' indicates that a major collection is * being done, so we might as well throw away the hash table and build @@ -309,49 +405,39 @@ markStablePtrTable(rtsBool full) * -------------------------------------------------------------------------- */ void -gcStablePtrTable(rtsBool full) +updateStablePtrTable(rtsBool full) { - snEntry *p, *end_stable_ptr_table; - StgPtr q, new; - - if (SPT_size == 0) { - return; - } - - end_stable_ptr_table = &stable_ptr_table[SPT_size]; - - for (p = stable_ptr_table; p < end_stable_ptr_table; p++) { - q = p->addr; - - if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) { - - /* We're only interested in Stable Names here. */ - if (p->weight == 0) { + snEntry *p, *end_stable_ptr_table; + + if (full && addrToStableHash != NULL) { + freeHashTable(addrToStableHash,NULL); + addrToStableHash = allocHashTable(); + } + + end_stable_ptr_table = &stable_ptr_table[SPT_size]; + + // NOTE: _starting_ at index 1; index 0 is unused. + for (p = stable_ptr_table + 1; p < end_stable_ptr_table; p++) { - if (((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 (p->addr == NULL) { + if (p->old != NULL) { + // The target has been garbage collected. Remove its + // entry from the hash table. + removeHashTable(addrToStableHash, (W_)p->old, NULL); + p->old = NULL; + } } - - 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); + else if (p->addr < (P_)stable_ptr_table + || p->addr >= (P_)end_stable_ptr_table) { + // Target still alive, Re-hash this stable name + if (full) { + insertHashTable(addrToStableHash, (W_)p->addr, + (void *)(p - stable_ptr_table)); + } else if (p->addr != p->old) { + removeHashTable(addrToStableHash, (W_)p->old, NULL); + insertHashTable(addrToStableHash, (W_)p->addr, + (void *)(p - stable_ptr_table)); + } } - } } - } }