X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FStable.c;h=815bac7690549ffd5a998e31cc37aef93f09a4a3;hb=47ff06307547e20eff37477a9bc9be80a460917a;hp=52876bd7a65aceb87e493d7d79f27c53978ce7f0;hpb=bc5c802181b513216bc88f0d1ec9574157ee05fe;p=ghc-hetmet.git diff --git a/ghc/rts/Stable.c b/ghc/rts/Stable.c index 52876bd..815bac7 100644 --- a/ghc/rts/Stable.c +++ b/ghc/rts/Stable.c @@ -1,16 +1,18 @@ /* ----------------------------------------------------------------------------- - * $Id: Stable.c,v 1.17 2001/08/14 13:40:09 sewardj Exp $ + * $Id: Stable.c,v 1.29 2004/08/22 15:50:42 panne Exp $ * - * (c) The GHC Team, 1998-1999 + * (c) The GHC Team, 1998-2002 * * Stable names and stable pointers. * * ---------------------------------------------------------------------------*/ +// Make static versions of inline functions in Stable.h: +#define RTS_STABLE_C + #include "PosixSource.h" #include "Rts.h" #include "Hash.h" -#include "StablePriv.h" #include "RtsUtils.h" #include "Storage.h" #include "RtsAPI.h" @@ -70,32 +72,20 @@ There may be additional functions on the C side to allow evaluation, application, etc of a stable pointer. - When Haskell calls C, it normally just passes over primitive integers, - floats, bools, strings, etc. This doesn't cause any problems at all - for garbage collection because the act of passing them makes a copy - from the heap, stack or wherever they are onto the C-world stack. - However, if we were to pass a heap object such as a (Haskell) @String@ - and a garbage collection occured before we finished using it, we'd run - into problems since the heap object might have been moved or even - deleted. - - So, if a C call is able to cause a garbage collection or we want to - store a pointer to a heap object between C calls, we must be careful - when passing heap objects. Our solution is to keep a table of all - objects we've given to the C-world and to make sure that the garbage - collector collects these objects --- updating the table as required to - make sure we can still find the object. */ -snEntry *stable_ptr_table; -snEntry *stable_ptr_free; +snEntry *stable_ptr_table = NULL; +static snEntry *stable_ptr_free = NULL; -unsigned int SPT_size; +static unsigned int SPT_size = 0; /* This hash table maps Haskell objects to stable names, so that every * call to lookupStableName on a given object will return the same * stable name. * + * OLD COMMENTS about reference counting follow. The reference count + * in a stable name entry is now just a counter. + * * Reference counting * ------------------ * A plain stable name entry has a zero reference count, which means @@ -122,11 +112,11 @@ unsigned int SPT_size; * to the weight stored in the table entry. * */ -HashTable *addrToStableHash; +static HashTable *addrToStableHash = NULL; #define INIT_SPT_SIZE 64 -static inline void +STATIC_INLINE void initFreeList(snEntry *table, nat n, snEntry *free) { snEntry *p; @@ -134,7 +124,7 @@ initFreeList(snEntry *table, nat n, snEntry *free) for (p = table + n - 1; p >= table; p--) { p->addr = (P_)free; p->old = NULL; - p->weight = 0; + p->ref = 0; p->sn_obj = NULL; free = p; } @@ -144,12 +134,9 @@ initFreeList(snEntry *table, nat n, snEntry *free) void initStablePtrTable(void) { - /* the table will be allocated the first time makeStablePtr is - * called */ - stable_ptr_table = NULL; - stable_ptr_free = NULL; - addrToStableHash = NULL; - SPT_size = 0; + // Nothing to do: + // the table will be allocated the first time makeStablePtr is + // called, and we want the table to persist through multiple inits. } /* @@ -177,6 +164,7 @@ StgWord lookupStableName(StgPtr p) { StgWord sn; + void* sn_tmp; if (stable_ptr_free == NULL) { enlargeStablePtrTable(); @@ -187,7 +175,8 @@ lookupStableName(StgPtr p) */ p = (StgPtr)removeIndirections((StgClosure*)p); - (void *)sn = lookupHashTable(addrToStableHash,(W_)p); + sn_tmp = lookupHashTable(addrToStableHash,(W_)p); + sn = (StgWord)sn_tmp; if (sn != 0) { ASSERT(stable_ptr_table[sn].addr == p); @@ -195,8 +184,8 @@ lookupStableName(StgPtr p) return sn; } else { sn = stable_ptr_free - stable_ptr_table; - (P_)stable_ptr_free = stable_ptr_free->addr; - stable_ptr_table[sn].weight = 0; + stable_ptr_free = (snEntry*)(stable_ptr_free->addr); + stable_ptr_table[sn].ref = 0; stable_ptr_table[sn].addr = p; stable_ptr_table[sn].sn_obj = NULL; /* IF_DEBUG(stable,fprintf(stderr,"new stable name %d at @@ -209,12 +198,12 @@ lookupStableName(StgPtr p) } } -static inline void +STATIC_INLINE void freeStableName(snEntry *sn) { ASSERT(sn->sn_obj == NULL); if (sn->addr != NULL) { - removeHashTable(addrToStableHash, (W_)sn->addr, NULL); + removeHashTable(addrToStableHash, (W_)sn->addr, NULL); } sn->addr = (P_)stable_ptr_free; stable_ptr_free = sn; @@ -223,26 +212,28 @@ freeStableName(snEntry *sn) StgStablePtr getStablePtr(StgPtr p) { - StgWord sn = lookupStableName(p); - 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) << STABLEPTR_WEIGHT_SHIFT)); - } - else if (weight == 1) { - barf("getStablePtr: too light"); - } - else { - weight /= 2; - /* find log2(weight) */ - for (n = 0; weight != 1; n++) { - weight >>= 1; + StgWord sn; + + sn = lookupStableName(p); + stable_ptr_table[sn].ref++; + return (StgStablePtr)(sn); +} + +void +freeStablePtr(StgStablePtr sp) +{ + snEntry *sn = &stable_ptr_table[(StgWord)sp]; + + ASSERT((StgWord)sp < SPT_size && sn->addr != NULL && sn->ref > 0); + + sn->ref--; + + // If this entry has no StableName attached, then just free it + // immediately. This is important; it might be a while before the + // next major GC which actually collects the entry. + if (sn->sn_obj == NULL && sn->ref == 0) { + freeStableName(sn); } - stable_ptr_table[sn].weight -= 1 << n; - return (StgStablePtr)(sn + ((n+1) << STABLEPTR_WEIGHT_SHIFT)); - } } void @@ -253,8 +244,8 @@ enlargeStablePtrTable(void) if (SPT_size == 0) { // 1st time SPT_size = INIT_SPT_SIZE; - stable_ptr_table = stgMallocWords(SPT_size * sizeof(snEntry), - "initStablePtrTable"); + stable_ptr_table = stgMallocBytes(SPT_size * sizeof(snEntry), + "enlargeStablePtrTable"); /* we don't use index 0 in the stable name table, because that * would conflict with the hash table lookup operations which @@ -267,9 +258,10 @@ enlargeStablePtrTable(void) // 2nd and subsequent times SPT_size *= 2; stable_ptr_table = - stgReallocWords(stable_ptr_table, SPT_size * sizeof(snEntry), + stgReallocBytes(stable_ptr_table, + SPT_size * sizeof(snEntry), "enlargeStablePtrTable"); - + initFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL); } } @@ -277,7 +269,7 @@ enlargeStablePtrTable(void) /* ----------------------------------------------------------------------------- * Treat stable pointers as roots for the garbage collector. * - * A stable pointer is any stable name entry with a weight > 0. We'll + * A stable pointer is any stable name entry with a ref > 0. We'll * take the opportunity to zero the "keep" flags at the same time. * -------------------------------------------------------------------------- */ @@ -304,8 +296,8 @@ markStablePtrTable(evac_fn evac) // the hash table later. p->old = p->addr; - // if the weight is non-zero, treat addr as a root - if (p->weight != 0) { + // if the ref is non-zero, treat addr as a root + if (p->ref != 0) { evac((StgClosure **)&p->addr); } } @@ -346,7 +338,7 @@ threadStablePtrTable( evac_fn evac ) * * A dead entry has: * - * - a weight of zero (i.e. 2^32) + * - a zero reference count * - a dead sn_obj * * Both of these conditions must be true in order to re-use the stable @@ -378,7 +370,7 @@ gcStablePtrTable( void ) if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) { // StableNames only: - if (p->weight == 0) { + if (p->ref == 0) { if (p->sn_obj == NULL) { // StableName object is dead freeStableName(p); @@ -387,8 +379,8 @@ gcStablePtrTable( void ) 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)); + p->addr = (StgPtr)isAlive((StgClosure *)p->addr); + IF_DEBUG(stable, fprintf(stderr,"Stable name %d still alive at %p, ref %d\n", p - stable_ptr_table, p->addr, p->ref)); } } }