[project @ 2001-07-23 17:23:19 by simonmar]
[ghc-hetmet.git] / ghc / rts / Stable.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Stable.c,v 1.15 2001/07/23 17:23:19 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Stable names and stable pointers.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "Rts.h"
11 #include "Hash.h"
12 #include "StablePriv.h"
13 #include "RtsUtils.h"
14 #include "Storage.h"
15 #include "RtsAPI.h"
16 #include "RtsFlags.h"
17
18 /* Comment from ADR's implementation in old RTS:
19
20   This files (together with @ghc/runtime/storage/PerformIO.lhc@ and a
21   small change in @HpOverflow.lc@) consists of the changes in the
22   runtime system required to implement "Stable Pointers". But we're
23   getting a bit ahead of ourselves --- what is a stable pointer and what
24   is it used for?
25
26   When Haskell calls C, it normally just passes over primitive integers,
27   floats, bools, strings, etc.  This doesn't cause any problems at all
28   for garbage collection because the act of passing them makes a copy
29   from the heap, stack or wherever they are onto the C-world stack.
30   However, if we were to pass a heap object such as a (Haskell) @String@
31   and a garbage collection occured before we finished using it, we'd run
32   into problems since the heap object might have been moved or even
33   deleted.
34
35   So, if a C call is able to cause a garbage collection or we want to
36   store a pointer to a heap object between C calls, we must be careful
37   when passing heap objects. Our solution is to keep a table of all
38   objects we've given to the C-world and to make sure that the garbage
39   collector collects these objects --- updating the table as required to
40   make sure we can still find the object.
41
42
43   Of course, all this rather begs the question: why would we want to
44   pass a boxed value?
45
46   One very good reason is to preserve laziness across the language
47   interface. Rather than evaluating an integer or a string because it
48   {\em might\/} be required by the C function, we can wait until the C
49   function actually wants the value and then force an evaluation.
50
51   Another very good reason (the motivating reason!) is that the C code
52   might want to execute an object of sort $IO ()$ for the side-effects
53   it will produce. For example, this is used when interfacing to an X
54   widgets library to allow a direct implementation of callbacks.
55
56
57   The @makeStablePointer :: a -> IO (StablePtr a)@ function
58   converts a value into a stable pointer.  It is part of the @PrimIO@
59   monad, because we want to be sure we don't allocate one twice by
60   accident, and then only free one of the copies.
61
62   \begin{verbatim}
63   makeStablePtr#  :: a -> State# RealWorld -> (# RealWorld, a #)
64   freeStablePtr#  :: StablePtr# a -> State# RealWorld -> State# RealWorld
65   deRefStablePtr# :: StablePtr# a -> State# RealWorld -> 
66         (# State# RealWorld, a #)
67   \end{verbatim}
68
69   There may be additional functions on the C side to allow evaluation,
70   application, etc of a stable pointer.
71
72   When Haskell calls C, it normally just passes over primitive integers,
73   floats, bools, strings, etc.  This doesn't cause any problems at all
74   for garbage collection because the act of passing them makes a copy
75   from the heap, stack or wherever they are onto the C-world stack.
76   However, if we were to pass a heap object such as a (Haskell) @String@
77   and a garbage collection occured before we finished using it, we'd run
78   into problems since the heap object might have been moved or even
79   deleted.
80
81   So, if a C call is able to cause a garbage collection or we want to
82   store a pointer to a heap object between C calls, we must be careful
83   when passing heap objects. Our solution is to keep a table of all
84   objects we've given to the C-world and to make sure that the garbage
85   collector collects these objects --- updating the table as required to
86   make sure we can still find the object.
87 */
88
89 snEntry *stable_ptr_table;
90 snEntry *stable_ptr_free;
91
92 unsigned int SPT_size;
93
94 /* This hash table maps Haskell objects to stable names, so that every
95  * call to lookupStableName on a given object will return the same
96  * stable name.
97  *
98  * Reference counting
99  * ------------------
100  * A plain stable name entry has a zero reference count, which means
101  * the entry will dissappear when the object it points to is
102  * unreachable.  For stable pointers, we need an entry that sticks
103  * around and keeps the object it points to alive, so each stable name
104  * entry has an associated reference count.
105  *
106  * A stable pointer has a weighted reference count N attached to it
107  * (actually in its upper 5 bits), which represents the weight
108  * 2^(N-1).  The stable name entry keeps a 32-bit reference count, which
109  * represents any weight between 1 and 2^32 (represented as zero).
110  * When the weight is 2^32, the stable name table owns "all" of the
111  * stable pointers to this object, and the entry can be garbage
112  * collected if the object isn't reachable.
113  *
114  * A new stable pointer is given the weight log2(W/2), where W is the
115  * weight stored in the table entry.  The new weight in the table is W
116  * - 2^log2(W/2).
117  *
118  * A stable pointer can be "split" into two stable pointers, by
119  * dividing the weight by 2 and giving each pointer half.
120  * When freeing a stable pointer, the weight of the pointer is added
121  * to the weight stored in the table entry.
122  * */
123
124 HashTable *addrToStableHash;
125
126 #define INIT_SPT_SIZE 64
127
128 static inline void
129 initFreeList(snEntry *table, nat n, snEntry *free)
130 {
131   snEntry *p;
132
133   for (p = table + n - 1; p >= table; p--) {
134     p->addr   = (P_)free;
135     p->old    = NULL;
136     p->weight = 0;
137     p->sn_obj = NULL;
138     free = p;
139   }
140   stable_ptr_free = table;
141 }
142
143 void
144 initStablePtrTable(void)
145 {
146   /* the table will be allocated the first time makeStablePtr is
147    * called */
148   stable_ptr_table = NULL;
149   stable_ptr_free  = NULL;
150   addrToStableHash = NULL;
151   SPT_size = 0;
152 }
153
154 /*
155  * get at the real stuff...remove indirections.
156  *
157  * ToDo: move to a better home.
158  */
159 static
160 StgClosure*
161 removeIndirections(StgClosure* p)
162 {
163   StgClosure* q = p;
164
165   while (get_itbl(q)->type == IND ||
166          get_itbl(q)->type == IND_STATIC ||
167          get_itbl(q)->type == IND_OLDGEN ||
168          get_itbl(q)->type == IND_PERM ||
169          get_itbl(q)->type == IND_OLDGEN_PERM ) {
170       q = ((StgInd *)q)->indirectee;
171   }
172   return q;
173 }
174
175 StgWord
176 lookupStableName(StgPtr p)
177 {
178   StgWord sn;
179
180   if (stable_ptr_free == NULL) {
181     enlargeStablePtrTable();
182   }
183
184   /* removing indirections increases the likelihood
185    * of finding a match in the stable name hash table.
186    */
187   p = (StgPtr)removeIndirections((StgClosure*)p);
188
189   (void *)sn = lookupHashTable(addrToStableHash,(W_)p);
190   
191   if (sn != 0) {
192     ASSERT(stable_ptr_table[sn].addr == p);
193     IF_DEBUG(stable,fprintf(stderr,"cached stable name %d at %p\n",sn,p));
194     return sn;
195   } else {
196     sn = stable_ptr_free - stable_ptr_table;
197     (P_)stable_ptr_free  = stable_ptr_free->addr;
198     stable_ptr_table[sn].weight = 0;
199     stable_ptr_table[sn].addr = p;
200     stable_ptr_table[sn].sn_obj = NULL;
201     /* IF_DEBUG(stable,fprintf(stderr,"new stable name %d at
202        %p\n",sn,p)); */
203     
204     /* add the new stable name to the hash table */
205     insertHashTable(addrToStableHash, (W_)p, (void *)sn);
206
207     return sn;
208   }
209 }
210
211 static inline void
212 freeStableName(snEntry *sn)
213 {
214   ASSERT(sn->sn_obj == NULL);
215   if (sn->addr != NULL) {
216     removeHashTable(addrToStableHash, (W_)sn->addr, NULL);
217   }
218   sn->addr = (P_)stable_ptr_free;
219   stable_ptr_free = sn;
220 }
221
222 StgStablePtr
223 getStablePtr(StgPtr p)
224 {
225   StgWord sn = lookupStableName(p);
226   StgWord weight, n;
227   weight = stable_ptr_table[sn].weight;
228   if (weight == 0) {
229     weight = (StgWord)1 << (BITS_IN(StgWord)-1);
230     stable_ptr_table[sn].weight = weight;
231     return (StgStablePtr)(sn + (BITS_IN(StgWord) << STABLEPTR_WEIGHT_SHIFT));
232   } 
233   else if (weight == 1) {
234     barf("getStablePtr: too light");
235   } 
236   else {
237     weight /= 2;
238     /* find log2(weight) */
239     for (n = 0; weight != 1; n++) {
240       weight >>= 1;
241     }
242     stable_ptr_table[sn].weight -= 1 << n;
243     return (StgStablePtr)(sn + ((n+1) << STABLEPTR_WEIGHT_SHIFT));
244   }
245 }
246
247 void
248 enlargeStablePtrTable(void)
249 {
250   nat old_SPT_size = SPT_size;
251   
252   if (SPT_size == 0) {
253     // 1st time
254     SPT_size = INIT_SPT_SIZE;
255     stable_ptr_table = stgMallocWords(SPT_size * sizeof(snEntry), 
256                                       "initStablePtrTable");
257     
258     /* we don't use index 0 in the stable name table, because that
259      * would conflict with the hash table lookup operations which
260      * return NULL if an entry isn't found in the hash table.
261      */
262     initFreeList(stable_ptr_table+1,INIT_SPT_SIZE-1,NULL);
263     addrToStableHash = allocHashTable();
264   }
265   else {
266     // 2nd and subsequent times
267     SPT_size *= 2;
268     stable_ptr_table = 
269       stgReallocWords(stable_ptr_table, SPT_size * sizeof(snEntry),
270                       "enlargeStablePtrTable");
271     
272     initFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL);
273   }
274 }
275
276 /* -----------------------------------------------------------------------------
277  * Treat stable pointers as roots for the garbage collector.
278  *
279  * A stable pointer is any stable name entry with a weight > 0.  We'll
280  * take the opportunity to zero the "keep" flags at the same time.
281  * -------------------------------------------------------------------------- */
282
283 void
284 markStablePtrTable(evac_fn evac)
285 {
286     snEntry *p, *end_stable_ptr_table;
287     StgPtr q;
288     
289     end_stable_ptr_table = &stable_ptr_table[SPT_size];
290     
291     // Mark all the stable *pointers* (not stable names).
292     // _starting_ at index 1; index 0 is unused.
293     for (p = stable_ptr_table+1; p < end_stable_ptr_table; p++) {
294         q = p->addr;
295
296         // internal pointers or NULL are free slots 
297         if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
298
299             // save the current addr away: we need to be able to tell
300             // whether the objects moved in order to be able to update
301             // the hash table later.
302             p->old = p->addr;
303
304             // if the weight is non-zero, treat addr as a root
305             if (p->weight != 0) {
306                 evac((StgClosure **)&p->addr);
307             }
308         }
309     }
310 }
311
312 /* -----------------------------------------------------------------------------
313  * Thread the stable pointer table for compacting GC.
314  * 
315  * Here we must call the supplied evac function for each pointer into
316  * the heap from the stable pointer table, because the compacting
317  * collector may move the object it points to.
318  * -------------------------------------------------------------------------- */
319
320 void
321 threadStablePtrTable( evac_fn evac )
322 {
323     snEntry *p, *end_stable_ptr_table;
324     StgPtr q;
325     
326     end_stable_ptr_table = &stable_ptr_table[SPT_size];
327     
328     for (p = stable_ptr_table+1; p < end_stable_ptr_table; p++) {
329         q = p->addr;
330         
331         // internal pointers or NULL are free slots
332         if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
333             if (p->weight != 0) {
334                 evac((StgClosure **)&p->addr);
335             }
336             if (p->sn_obj != NULL) {
337                 evac((StgClosure **)&p->sn_obj);
338             }
339         }
340     }
341 }
342
343 /* -----------------------------------------------------------------------------
344  * Garbage collect any dead entries in the stable pointer table.
345  *
346  * A dead entry has:
347  *
348  *          - a weight of zero (i.e. 2^32)
349  *          - a dead sn_obj
350  *
351  * Both of these conditions must be true in order to re-use the stable
352  * name table entry.  We can re-use stable name table entries for live
353  * heap objects, as long as the program has no StableName objects that
354  * refer to the entry.
355  * -------------------------------------------------------------------------- */
356
357 void
358 gcStablePtrTable( void )
359 {
360     snEntry *p, *end_stable_ptr_table;
361     StgPtr q;
362     
363     end_stable_ptr_table = &stable_ptr_table[SPT_size];
364     
365     // NOTE: _starting_ at index 1; index 0 is unused.
366     for (p = stable_ptr_table + 1; p < end_stable_ptr_table; p++) {
367         
368         // Update the pointer to the StableName object, if there is one
369         if (p->sn_obj != NULL) {
370             p->sn_obj = isAlive(p->sn_obj);
371         }
372         
373         q = p->addr;
374         if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
375
376             // StableNames only:
377             if (p->weight == 0) {
378                 if (p->sn_obj == NULL) {
379                     // StableName object is dead
380                     freeStableName(p);
381                     IF_DEBUG(stable, fprintf(stderr,"GC'd Stable name %d\n", 
382                                              p - stable_ptr_table));
383                     continue;
384                     
385                 } else {
386                     (StgClosure *)p->addr = isAlive((StgClosure *)p->addr);
387                     IF_DEBUG(stable, fprintf(stderr,"Stable name %d still alive at %p, weight %d\n", p - stable_ptr_table, p->addr, p->weight));
388                 }
389             }
390         }
391     }
392 }
393
394 /* -----------------------------------------------------------------------------
395  * Update the StablePtr/StableName hash table
396  *
397  * The boolean argument 'full' indicates that a major collection is
398  * being done, so we might as well throw away the hash table and build
399  * a new one.  For a minor collection, we just re-hash the elements
400  * that changed.
401  * -------------------------------------------------------------------------- */
402
403 void
404 updateStablePtrTable(rtsBool full)
405 {
406     snEntry *p, *end_stable_ptr_table;
407     
408     if (full && addrToStableHash != NULL) {
409         freeHashTable(addrToStableHash,NULL);
410         addrToStableHash = allocHashTable();
411     }
412     
413     end_stable_ptr_table = &stable_ptr_table[SPT_size];
414     
415     // NOTE: _starting_ at index 1; index 0 is unused.
416     for (p = stable_ptr_table + 1; p < end_stable_ptr_table; p++) {
417         
418         if (p->addr == NULL) {
419             if (p->old != NULL) {
420                 // The target has been garbage collected.  Remove its
421                 // entry from the hash table.
422                 removeHashTable(addrToStableHash, (W_)p->old, NULL);
423                 p->old = NULL;
424             }
425         }
426         else if (p->addr < (P_)stable_ptr_table 
427                  || p->addr >= (P_)end_stable_ptr_table) {
428             // Target still alive, Re-hash this stable name 
429             if (full) {
430                 insertHashTable(addrToStableHash, (W_)p->addr, 
431                                 (void *)(p - stable_ptr_table));
432             } else if (p->addr != p->old) {
433                 removeHashTable(addrToStableHash, (W_)p->old, NULL);
434                 insertHashTable(addrToStableHash, (W_)p->addr, 
435                                 (void *)(p - stable_ptr_table));
436             }
437         }
438     }
439 }