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