[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / runtime / storage / SMextn.lc
1 \section[SM-extensions]{Storage Manager Extensions}
2
3 ToDo ADR: Maybe this should be split between SMcopying.lc and
4 SMcompacting.lc?
5
6
7 This is a collection of C functions use in implementing the stable
8 pointer and malloc pointer extensions. 
9
10 The motivation for making this a separate file/section is twofold:
11
12 1) It let's us focus on one thing.
13
14 2) If we don't do this, there will be a huge amount of repetition
15    between the various GC schemes --- a maintenance nightmare.
16
17 The second is the major motivation.  
18
19 There are three main parts to this file:
20
21 1) Code which is common to all GC schemes.
22
23 2) Code for use in a compacting collector used in the 1-space, dual
24    mode and for collecting old generations in generational collectors.
25
26 3) Code for use in a copying collector used in the 2-space, dual mode
27    and for collecting young generations in generational collectors.
28
29 When debugging, it is incredibly helpful to trash part of the heap
30 (say) once you're done with it.
31
32 Remembering that @sm->hp@ points to the next word to be allocated, a
33 typical use is
34
35 \begin{pseudocode}
36 #ifdef DEBUG
37   TrashMem(sm->hp+1, sm->hplim);
38 #endif
39 \end{pseudocode}
40
41 \begin{code} 
42
43 #if defined(GC1s)
44
45 #define  SCAN_REG_DUMP
46 #include "SMinternal.h"
47 REGDUMP(ScanRegDump);
48
49 #else /* GC2s, GCdu, GCap, GCgn */
50
51 #define SCAV_REG_MAP
52 #include "SMinternal.h"
53 REGDUMP(ScavRegDump);
54
55 #endif
56 #include "SMextn.h"
57
58 #ifdef DEBUG
59
60 void
61 TrashMem(from, to)
62   P_ from, to;
63 {
64 /* assertion overly strong - if free_mem == 0, sm->hp == sm->hplim */
65 /*  ASSERT( from <= to ); */
66     if (SM_trace)
67         printf("Trashing from 0x%lx to 0x%lx inclusive\n", (W_) from, (W_) to);
68     while (from <= to) {
69         *from++ = DEALLOCATED_TRASH;
70     }
71 }
72
73 #endif /* DEBUG */
74 \end{code}
75
76 \begin{code}
77
78 #ifndef PAR     /* To end of the file */
79
80 \end{code}
81
82 \downsection
83 \section[SM-extensions-common-code]{Code common to all GC schemes}
84
85 \begin{code}
86 EXTDATA(EmptySPTable_closure);
87
88 void initExtensions( sm )
89   smInfo *sm;
90 {
91   sm->MallocPtrList = NULL;
92 #if defined(GCap) || defined(GCgn)
93   sm->OldMallocPtrList = NULL;
94 #endif
95
96   sm->StablePointerTable = (P_) EmptySPTable_closure;
97 }
98
99 extern void FreeMallocPtr PROTO(( StgMallocPtr mp ));
100 \end{code}
101
102 \begin{code}
103 #if defined(DEBUG)
104 \end{code}
105
106 When a Malloc Pointer is released, there should be absolutely no
107 references to it.  To encourage and dangling references to show
108 themselves, we'll trash its contents when we're done with it.
109
110 \begin{code}
111 #define TRASH_MallocPtr_CLOSURE( mptr ) Trash_MallocPtr_Closure(mptr)
112
113 void
114 Trash_MallocPtr_Closure(mptr)
115   P_ mptr;
116 { int i;
117   for( i = 0; i != MallocPtr_SIZE + _FHS; i++ ) {
118     mptr[ i ] = DEALLOCATED_TRASH;
119   }
120 }
121 \end{code}
122
123 Also, every time we fiddle with the MallocPtr list, we should check it
124 still makes sense.  This function returns @0@ if the list is sensible.
125
126 (Would maintaining a separate Malloc Ptr count allow better testing?)
127
128 \begin{code}
129 void
130 Validate_MallocPtrList( MallocPtrList )
131   P_ MallocPtrList;
132 {
133   P_ MPptr;
134
135   for(MPptr = MallocPtrList; 
136       MPptr != NULL;
137       MPptr = MallocPtr_CLOSURE_LINK(MPptr) ) {
138     CHECK_MallocPtr_CLOSURE(MPptr);
139   }
140 }
141 \end{code}
142
143 \begin{code}
144 #else /* !DEBUG */
145
146 #define TRASH_MallocPtr_CLOSURE( mp ) /* nothing */
147
148 #endif /* !DEBUG */  
149 \end{code}
150
151 \begin{code}
152 #ifdef DEBUG
153
154 #define TRACE_MallocPtr(MPptr) Trace_MallocPtr( MPptr )
155 #define TRACE_MPdies(MPptr) Trace_MPdies()
156 #define TRACE_MPlives(MPptr) Trace_MPlives()
157 #define TRACE_MPforwarded(MPptr, newAddress) Trace_MPforwarded( MPptr, newAddress )
158
159 void
160 Trace_MallocPtr( MPptr )
161   P_ MPptr;
162 {
163   if (SM_trace & 16) {
164     printf("DEBUG: MallocPtr(%lx)=<%lx,_,%lx,%lx,%lx>\n", (W_) MPptr, (W_) MPptr[0], (W_) MPptr[1], (W_) MPptr[2], (W_) MPptr[3]);
165     printf(" Data = %lx, Next = %lx\n", 
166         (W_) MallocPtr_CLOSURE_DATA(MPptr), (W_) MallocPtr_CLOSURE_LINK(MPptr) );
167   }
168 }
169
170 void
171 Trace_MPdies()
172 {
173   if (SM_trace & 16) {
174     printf(" dying\n");
175   }
176 }
177
178 void
179 Trace_MPlives()
180 {
181   if (SM_trace & 16) { 
182     printf(" lived to tell the tale \n"); 
183   }
184 }
185
186 void
187 Trace_MPforwarded( MPPtr, newAddress )
188   P_ MPPtr, newAddress;
189 {
190   if (SM_trace & 16) {
191     printf(" forwarded to %lx\n", (W_) newAddress);
192   }
193 }
194
195 #else
196
197 #define TRACE_MallocPtr(MPptr) /* nothing */
198 #define TRACE_MPdies(MPptr) /* nothing */
199 #define TRACE_MPlives(MPptr) /* nothing */
200 #define TRACE_MPforwarded(MPptr, newAddress) /* nothing */
201
202 #endif /* DEBUG */
203 \end{code}
204
205
206 \section[SM-extensions-compacting-code]{Compacting Collector Code}
207
208
209 \begin{code}
210 #if defined(_INFO_COMPACTING)
211
212 /* Sweep up the dead MallocPtrs */
213
214 /* Note that this has to happen before the linking phase trashes
215    the stable pointer table so that the FreeMallocPtr function can
216    safely call freeStablePointer. 
217 */
218
219 void
220 sweepUpDeadMallocPtrs( MallocPtrList, base, bits )
221   P_ MallocPtrList;
222   P_ base;
223   BitWord *bits;
224 {
225     P_ MPptr, temp;
226     I_ MallocPtr_deaths = 0;
227     long _hp_word, bit_index, bit;
228
229     /* At this point, the MallocPtrList is in an invalid state (since
230        some info ptrs will have been mangled) so we can't validate
231        it. ADR */
232
233     DEBUG_STRING("Reporting Dead Malloc Ptrs:");
234     MPptr = MallocPtrList;
235     while ( MPptr != NULL ) {
236
237       TRACE_MallocPtr(MPptr);
238
239       _hp_word = MPptr - base;
240       bit_index = _hp_word / BITS_IN(BitWord);
241       bit = 1L << (_hp_word & (BITS_IN(BitWord) - 1));
242       if ( !( bits[bit_index] & bit ) ) { /* dead */
243
244         TRACE_MPdies( MPptr );
245         FreeMallocPtr( MallocPtr_CLOSURE_DATA(MPptr) );
246         MallocPtr_deaths++;
247
248         temp = MPptr;
249         MPptr = MallocPtr_CLOSURE_LINK(MPptr);
250         /* Now trash the closure to encourage bugs to show themselves */
251         TRASH_MallocPtr_CLOSURE( temp );
252
253       } else { 
254
255         TRACE_MPlives(MPptr);
256         MPptr = MallocPtr_CLOSURE_LINK(MPptr);
257       }
258     }
259 }
260
261 #endif /* _INFO_COMPACTING */
262 \end{code}
263
264 \section[SM-extensions-copying-code]{Copying Collector Code}
265
266 \begin{code}
267 #if defined(_INFO_COPYING)
268
269 /* ToDo: a possible optimisation would be to maintain a flag that
270    told us whether the SPTable had been updated (with new
271    pointers) and so needs to be GC'd.  A simple way of doing this
272    might be to generalise the MUTUPLE closures to MUGEN closures.
273 */
274 void evacSPTable( sm )
275 smInfo *sm;
276 {
277   DEBUG_STRING("Evacuate Stable Pointer Table:");
278   {
279     P_ evac = sm->StablePointerTable;
280     sm->StablePointerTable = EVACUATE_CLOSURE(evac);
281   }
282 }
283
284
285
286 /* First attempt at Malloc Ptr hackery... Later versions might 
287    do something useful with the two counters. [ADR]      */
288
289 #if defined(DEBUG)
290 #if defined(GCgn)
291
292 EXTDATA_RO(Forward_Ref_New_info);
293 EXTDATA_RO(Forward_Ref_Old_info);
294 EXTDATA_RO(OldRoot_Forward_Ref_info);
295
296 #else
297
298 EXTDATA_RO(Forward_Ref_info);
299
300 #endif
301 #endif
302
303 /* 
304   Call FreeMallocPtr on any dead MPs in oldMPList, add the remainder
305   to new sticking the result into newMPList.
306 */
307 void
308 reportDeadMallocPtrs(oldMPList, new, newMPList)
309   P_ oldMPList;
310   P_ new;
311   P_ *newMPList;
312 {
313     P_ MPptr, temp;
314     I_ MP_no = 0, MP_deaths = 0;
315
316     /* At this point, the MallocPtrList is in an invalid state (since
317        some info ptrs will have been mangled) so we can't validate
318        it. ADR */
319
320     DEBUG_STRING("Updating MallocPtr List and reporting casualties:");
321     MPptr = oldMPList;
322     while ( MPptr != NULL ) {
323       TRACE_MallocPtr(MPptr);
324
325       if ((P_) INFO_PTR(MPptr) == MallocPtr_info ) {
326         /* can't have been forwarded - must be dead */
327
328         TRACE_MPdies(MPptr);
329         FreeMallocPtr( MallocPtr_CLOSURE_DATA(MPptr) );
330         MP_deaths++;
331
332         temp = MPptr;
333         MPptr = MallocPtr_CLOSURE_LINK(MPptr);
334
335         /* Now trash the closure to encourage bugs to show themselves */
336         TRASH_MallocPtr_CLOSURE( temp );
337       } else { /* Must have been forwarded - so it must be live */
338
339         P_ newAddress = (P_) FORWARD_ADDRESS(MPptr);
340
341 #if defined(GCgn)
342         ASSERT( ( (P_) INFO_PTR(MPptr) == Forward_Ref_New_info ) ||
343                 ( (P_) INFO_PTR(MPptr) == Forward_Ref_Old_info ) ||
344                 ( (P_) INFO_PTR(MPptr) == OldRoot_Forward_Ref_info ) );
345 #else
346         ASSERT( (P_) INFO_PTR(MPptr) == Forward_Ref_info );
347 #endif
348
349         TRACE_MPforwarded( MPptr, newAddress );
350         MallocPtr_CLOSURE_LINK(newAddress) = new;
351         new = newAddress;
352         MP_no++;
353         MPptr = MallocPtr_CLOSURE_LINK(MPptr);
354       }
355     }
356
357     VALIDATE_MallocPtrList( new );
358     *newMPList = new;
359 }
360 #endif /* _INFO_COPYING */
361 \end{code}
362
363 \upsection
364
365 \begin{code}
366 #endif /* !PAR */
367 \end{code}