1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2002
5 * Stable names and stable pointers.
7 * ---------------------------------------------------------------------------*/
9 // Make static versions of inline functions in Stable.h:
12 #include "PosixSource.h"
16 #include "OSThreads.h"
20 #include "OSThreads.h"
24 /* Comment from ADR's implementation in old RTS:
26 This files (together with @ghc/runtime/storage/PerformIO.lhc@ and a
27 small change in @HpOverflow.lc@) consists of the changes in the
28 runtime system required to implement "Stable Pointers". But we're
29 getting a bit ahead of ourselves --- what is a stable pointer and what
32 When Haskell calls C, it normally just passes over primitive integers,
33 floats, bools, strings, etc. This doesn't cause any problems at all
34 for garbage collection because the act of passing them makes a copy
35 from the heap, stack or wherever they are onto the C-world stack.
36 However, if we were to pass a heap object such as a (Haskell) @String@
37 and a garbage collection occured before we finished using it, we'd run
38 into problems since the heap object might have been moved or even
41 So, if a C call is able to cause a garbage collection or we want to
42 store a pointer to a heap object between C calls, we must be careful
43 when passing heap objects. Our solution is to keep a table of all
44 objects we've given to the C-world and to make sure that the garbage
45 collector collects these objects --- updating the table as required to
46 make sure we can still find the object.
49 Of course, all this rather begs the question: why would we want to
52 One very good reason is to preserve laziness across the language
53 interface. Rather than evaluating an integer or a string because it
54 {\em might\/} be required by the C function, we can wait until the C
55 function actually wants the value and then force an evaluation.
57 Another very good reason (the motivating reason!) is that the C code
58 might want to execute an object of sort $IO ()$ for the side-effects
59 it will produce. For example, this is used when interfacing to an X
60 widgets library to allow a direct implementation of callbacks.
63 The @makeStablePointer :: a -> IO (StablePtr a)@ function
64 converts a value into a stable pointer. It is part of the @PrimIO@
65 monad, because we want to be sure we don't allocate one twice by
66 accident, and then only free one of the copies.
69 makeStablePtr# :: a -> State# RealWorld -> (# RealWorld, a #)
70 freeStablePtr# :: StablePtr# a -> State# RealWorld -> State# RealWorld
71 deRefStablePtr# :: StablePtr# a -> State# RealWorld ->
72 (# State# RealWorld, a #)
75 There may be additional functions on the C side to allow evaluation,
76 application, etc of a stable pointer.
80 snEntry *stable_ptr_table = NULL;
81 static snEntry *stable_ptr_free = NULL;
83 static unsigned int SPT_size = 0;
86 static Mutex stable_mutex;
89 /* This hash table maps Haskell objects to stable names, so that every
90 * call to lookupStableName on a given object will return the same
93 * OLD COMMENTS about reference counting follow. The reference count
94 * in a stable name entry is now just a counter.
98 * A plain stable name entry has a zero reference count, which means
99 * the entry will dissappear when the object it points to is
100 * unreachable. For stable pointers, we need an entry that sticks
101 * around and keeps the object it points to alive, so each stable name
102 * entry has an associated reference count.
104 * A stable pointer has a weighted reference count N attached to it
105 * (actually in its upper 5 bits), which represents the weight
106 * 2^(N-1). The stable name entry keeps a 32-bit reference count, which
107 * represents any weight between 1 and 2^32 (represented as zero).
108 * When the weight is 2^32, the stable name table owns "all" of the
109 * stable pointers to this object, and the entry can be garbage
110 * collected if the object isn't reachable.
112 * A new stable pointer is given the weight log2(W/2), where W is the
113 * weight stored in the table entry. The new weight in the table is W
116 * A stable pointer can be "split" into two stable pointers, by
117 * dividing the weight by 2 and giving each pointer half.
118 * When freeing a stable pointer, the weight of the pointer is added
119 * to the weight stored in the table entry.
122 static HashTable *addrToStableHash = NULL;
124 #define INIT_SPT_SIZE 64
127 initFreeList(snEntry *table, nat n, snEntry *free)
131 for (p = table + n - 1; p >= table; p--) {
138 stable_ptr_free = table;
142 initStablePtrTable(void)
147 SPT_size = INIT_SPT_SIZE;
148 stable_ptr_table = stgMallocBytes(SPT_size * sizeof(snEntry),
149 "initStablePtrTable");
151 /* we don't use index 0 in the stable name table, because that
152 * would conflict with the hash table lookup operations which
153 * return NULL if an entry isn't found in the hash table.
155 initFreeList(stable_ptr_table+1,INIT_SPT_SIZE-1,NULL);
156 addrToStableHash = allocHashTable();
159 initMutex(&stable_mutex);
164 exitStablePtrTable(void)
166 if (addrToStableHash)
167 freeHashTable(addrToStableHash, NULL);
168 addrToStableHash = NULL;
169 if (stable_ptr_table)
170 stgFree(stable_ptr_table);
171 stable_ptr_table = NULL;
174 closeMutex(&stable_mutex);
179 * get at the real stuff...remove indirections.
181 * ToDo: move to a better home.
185 removeIndirections(StgClosure* p)
189 while (get_itbl(q)->type == IND ||
190 get_itbl(q)->type == IND_STATIC ||
191 get_itbl(q)->type == IND_OLDGEN ||
192 get_itbl(q)->type == IND_PERM ||
193 get_itbl(q)->type == IND_OLDGEN_PERM ) {
194 q = ((StgInd *)q)->indirectee;
200 lookupStableName_(StgPtr p)
205 if (stable_ptr_free == NULL) {
206 enlargeStablePtrTable();
209 /* removing indirections increases the likelihood
210 * of finding a match in the stable name hash table.
212 p = (StgPtr)removeIndirections((StgClosure*)p);
214 sn_tmp = lookupHashTable(addrToStableHash,(W_)p);
215 sn = (StgWord)sn_tmp;
218 ASSERT(stable_ptr_table[sn].addr == p);
219 debugTrace(DEBUG_stable, "cached stable name %ld at %p",sn,p);
222 sn = stable_ptr_free - stable_ptr_table;
223 stable_ptr_free = (snEntry*)(stable_ptr_free->addr);
224 stable_ptr_table[sn].ref = 0;
225 stable_ptr_table[sn].addr = p;
226 stable_ptr_table[sn].sn_obj = NULL;
227 /* debugTrace(DEBUG_stable, "new stable name %d at %p\n",sn,p); */
229 /* add the new stable name to the hash table */
230 insertHashTable(addrToStableHash, (W_)p, (void *)sn);
237 lookupStableName(StgPtr p)
241 initStablePtrTable();
242 ACQUIRE_LOCK(&stable_mutex);
243 res = lookupStableName_(p);
244 RELEASE_LOCK(&stable_mutex);
249 freeStableName(snEntry *sn)
251 ASSERT(sn->sn_obj == NULL);
252 if (sn->addr != NULL) {
253 removeHashTable(addrToStableHash, (W_)sn->addr, NULL);
255 sn->addr = (P_)stable_ptr_free;
256 stable_ptr_free = sn;
260 getStablePtr(StgPtr p)
264 initStablePtrTable();
265 ACQUIRE_LOCK(&stable_mutex);
266 sn = lookupStableName_(p);
267 stable_ptr_table[sn].ref++;
268 RELEASE_LOCK(&stable_mutex);
269 return (StgStablePtr)(sn);
273 freeStablePtr(StgStablePtr sp)
277 initStablePtrTable();
278 ACQUIRE_LOCK(&stable_mutex);
280 sn = &stable_ptr_table[(StgWord)sp];
282 ASSERT((StgWord)sp < SPT_size && sn->addr != NULL && sn->ref > 0);
286 // If this entry has no StableName attached, then just free it
287 // immediately. This is important; it might be a while before the
288 // next major GC which actually collects the entry.
289 if (sn->sn_obj == NULL && sn->ref == 0) {
293 RELEASE_LOCK(&stable_mutex);
297 enlargeStablePtrTable(void)
299 nat old_SPT_size = SPT_size;
301 // 2nd and subsequent times
304 stgReallocBytes(stable_ptr_table,
305 SPT_size * sizeof(snEntry),
306 "enlargeStablePtrTable");
308 initFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL);
311 /* -----------------------------------------------------------------------------
312 * Treat stable pointers as roots for the garbage collector.
314 * A stable pointer is any stable name entry with a ref > 0. We'll
315 * take the opportunity to zero the "keep" flags at the same time.
316 * -------------------------------------------------------------------------- */
319 markStablePtrTable(evac_fn evac)
321 snEntry *p, *end_stable_ptr_table;
324 end_stable_ptr_table = &stable_ptr_table[SPT_size];
326 // Mark all the stable *pointers* (not stable names).
327 // _starting_ at index 1; index 0 is unused.
328 for (p = stable_ptr_table+1; p < end_stable_ptr_table; p++) {
331 // Internal pointers are free slots. If q == NULL, it's a
332 // stable name where the object has been GC'd, but the
333 // StableName object (sn_obj) is still alive.
334 if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
336 // save the current addr away: we need to be able to tell
337 // whether the objects moved in order to be able to update
338 // the hash table later.
341 // if the ref is non-zero, treat addr as a root
343 evac((StgClosure **)&p->addr);
349 /* -----------------------------------------------------------------------------
350 * Thread the stable pointer table for compacting GC.
352 * Here we must call the supplied evac function for each pointer into
353 * the heap from the stable pointer table, because the compacting
354 * collector may move the object it points to.
355 * -------------------------------------------------------------------------- */
358 threadStablePtrTable( evac_fn evac )
360 snEntry *p, *end_stable_ptr_table;
363 end_stable_ptr_table = &stable_ptr_table[SPT_size];
365 for (p = stable_ptr_table+1; p < end_stable_ptr_table; p++) {
367 if (p->sn_obj != NULL) {
368 evac((StgClosure **)&p->sn_obj);
372 if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
373 evac((StgClosure **)&p->addr);
378 /* -----------------------------------------------------------------------------
379 * Garbage collect any dead entries in the stable pointer table.
383 * - a zero reference count
386 * Both of these conditions must be true in order to re-use the stable
387 * name table entry. We can re-use stable name table entries for live
388 * heap objects, as long as the program has no StableName objects that
389 * refer to the entry.
390 * -------------------------------------------------------------------------- */
393 gcStablePtrTable( void )
395 snEntry *p, *end_stable_ptr_table;
398 end_stable_ptr_table = &stable_ptr_table[SPT_size];
400 // NOTE: _starting_ at index 1; index 0 is unused.
401 for (p = stable_ptr_table + 1; p < end_stable_ptr_table; p++) {
403 // Update the pointer to the StableName object, if there is one
404 if (p->sn_obj != NULL) {
405 p->sn_obj = isAlive(p->sn_obj);
408 // Internal pointers are free slots. If q == NULL, it's a
409 // stable name where the object has been GC'd, but the
410 // StableName object (sn_obj) is still alive.
412 if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
416 if (p->sn_obj == NULL) {
417 // StableName object is dead
419 debugTrace(DEBUG_stable, "GC'd Stable name %ld",
420 (long)(p - stable_ptr_table));
424 p->addr = (StgPtr)isAlive((StgClosure *)p->addr);
425 debugTrace(DEBUG_stable,
426 "stable name %ld still alive at %p, ref %ld\n",
427 (long)(p - stable_ptr_table), p->addr, p->ref);
434 /* -----------------------------------------------------------------------------
435 * Update the StablePtr/StableName hash table
437 * The boolean argument 'full' indicates that a major collection is
438 * being done, so we might as well throw away the hash table and build
439 * a new one. For a minor collection, we just re-hash the elements
441 * -------------------------------------------------------------------------- */
444 updateStablePtrTable(rtsBool full)
446 snEntry *p, *end_stable_ptr_table;
448 if (full && addrToStableHash != NULL) {
449 freeHashTable(addrToStableHash,NULL);
450 addrToStableHash = allocHashTable();
453 end_stable_ptr_table = &stable_ptr_table[SPT_size];
455 // NOTE: _starting_ at index 1; index 0 is unused.
456 for (p = stable_ptr_table + 1; p < end_stable_ptr_table; p++) {
458 if (p->addr == NULL) {
459 if (p->old != NULL) {
460 // The target has been garbage collected. Remove its
461 // entry from the hash table.
462 removeHashTable(addrToStableHash, (W_)p->old, NULL);
466 else if (p->addr < (P_)stable_ptr_table
467 || p->addr >= (P_)end_stable_ptr_table) {
468 // Target still alive, Re-hash this stable name
470 insertHashTable(addrToStableHash, (W_)p->addr,
471 (void *)(p - stable_ptr_table));
472 } else if (p->addr != p->old) {
473 removeHashTable(addrToStableHash, (W_)p->old, NULL);
474 insertHashTable(addrToStableHash, (W_)p->addr,
475 (void *)(p - stable_ptr_table));