1 \section[SM-extensions]{Storage Manager Extensions}
3 ToDo ADR: Maybe this should be split between SMcopying.lc and
7 This is a collection of C functions use in implementing the stable
8 pointer and malloc pointer extensions.
10 The motivation for making this a separate file/section is twofold:
12 1) It let's us focus on one thing.
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.
17 The second is the major motivation.
19 There are three main parts to this file:
21 1) Code which is common to all GC schemes.
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.
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.
29 When debugging, it is incredibly helpful to trash part of the heap
30 (say) once you're done with it.
32 Remembering that @sm->hp@ points to the next word to be allocated, a
37 TrashMem(sm->hp+1, sm->hplim);
46 #include "SMinternal.h"
49 #else /* GC2s, GCdu, GCap, GCgn */
52 #include "SMinternal.h"
64 /* assertion overly strong - if free_mem == 0, sm->hp == sm->hplim */
65 /* ASSERT( from <= to ); */
66 if (RTSflags.GcFlags.trace)
67 printf("Trashing from 0x%lx to 0x%lx inclusive\n", (W_) from, (W_) to);
69 *from++ = DEALLOCATED_TRASH;
78 #ifndef PAR /* To end of the file */
83 \section[SM-extensions-common-code]{Code common to all GC schemes}
86 EXTDATA(EmptySPTable_closure);
88 void initExtensions( sm )
91 sm->MallocPtrList = NULL;
92 #if defined(GCap) || defined(GCgn)
93 sm->OldMallocPtrList = NULL;
96 sm->StablePointerTable = (P_) EmptySPTable_closure;
99 extern void FreeMallocPtr PROTO(( StgMallocPtr mp ));
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.
111 #define TRASH_MallocPtr_CLOSURE( mptr ) Trash_MallocPtr_Closure(mptr)
114 Trash_MallocPtr_Closure(mptr)
118 for( i = 0; i < MallocPtr_SIZE + _FHS; i++ ) {
119 mptr[ i ] = DEALLOCATED_TRASH;
124 Also, every time we fiddle with the MallocPtr list, we should check it
125 still makes sense. This function returns @0@ if the list is sensible.
127 (Would maintaining a separate Malloc Ptr count allow better testing?)
131 Validate_MallocPtrList( MallocPtrList )
136 for(MPptr = MallocPtrList;
138 MPptr = MallocPtr_CLOSURE_LINK(MPptr) ) {
139 CHECK_MallocPtr_CLOSURE(MPptr);
147 #define TRASH_MallocPtr_CLOSURE( mp ) /* nothing */
155 #define TRACE_MallocPtr(MPptr) Trace_MallocPtr( MPptr )
156 #define TRACE_MPdies(MPptr) Trace_MPdies()
157 #define TRACE_MPlives(MPptr) Trace_MPlives()
158 #define TRACE_MPforwarded(MPptr, newAddress) Trace_MPforwarded( MPptr, newAddress )
161 Trace_MallocPtr( MPptr )
164 if (RTSflags.GcFlags.trace & DEBUG_TRACE_MALLOCPTRS) {
165 printf("DEBUG: MallocPtr(%lx)=<%lx,_,%lx,%lx,%lx>\n", (W_) MPptr, (W_) MPptr[0], (W_) MPptr[1], (W_) MPptr[2], (W_) MPptr[3]);
166 printf(" Data = %lx, Next = %lx\n",
167 (W_) MallocPtr_CLOSURE_DATA(MPptr), (W_) MallocPtr_CLOSURE_LINK(MPptr) );
174 if (RTSflags.GcFlags.trace & DEBUG_TRACE_MALLOCPTRS) {
182 if (RTSflags.GcFlags.trace & DEBUG_TRACE_MALLOCPTRS) {
183 printf(" lived to tell the tale\n");
188 Trace_MPforwarded( MPPtr, newAddress )
189 P_ MPPtr, newAddress;
191 if (RTSflags.GcFlags.trace & DEBUG_TRACE_MALLOCPTRS) {
192 printf(" forwarded to %lx\n", (W_) newAddress);
198 #define TRACE_MallocPtr(MPptr) /* nothing */
199 #define TRACE_MPdies(MPptr) /* nothing */
200 #define TRACE_MPlives(MPptr) /* nothing */
201 #define TRACE_MPforwarded(MPptr, newAddress) /* nothing */
207 \section[SM-extensions-compacting-code]{Compacting Collector Code}
211 #if defined(_INFO_COMPACTING)
213 /* Sweep up the dead MallocPtrs */
215 /* Note that this has to happen before the linking phase trashes
216 the stable pointer table so that the FreeMallocPtr function can
217 safely call freeStablePointer.
221 sweepUpDeadMallocPtrs( MallocPtrList, base, bits )
227 I_ MallocPtr_deaths = 0;
228 long _hp_word, bit_index, bit;
230 /* At this point, the MallocPtrList is in an invalid state (since
231 some info ptrs will have been mangled) so we can't validate
234 DEBUG_STRING("Reporting Dead Malloc Ptrs:");
235 MPptr = MallocPtrList;
236 while ( MPptr != NULL ) {
238 TRACE_MallocPtr(MPptr);
240 _hp_word = MPptr - base;
241 bit_index = _hp_word / BITS_IN(BitWord);
242 bit = 1L << (_hp_word & (BITS_IN(BitWord) - 1));
243 if ( !( bits[bit_index] & bit ) ) { /* dead */
245 TRACE_MPdies( MPptr );
246 FreeMallocPtr( MallocPtr_CLOSURE_DATA(MPptr) );
250 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
251 /* Now trash the closure to encourage bugs to show themselves */
252 TRASH_MallocPtr_CLOSURE( temp );
256 TRACE_MPlives(MPptr);
257 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
262 #endif /* _INFO_COMPACTING */
265 \section[SM-extensions-copying-code]{Copying Collector Code}
268 #if defined(_INFO_COPYING)
270 /* ToDo: a possible optimisation would be to maintain a flag that
271 told us whether the SPTable had been updated (with new
272 pointers) and so needs to be GC'd. A simple way of doing this
273 might be to generalise the MUTUPLE closures to MUGEN closures.
275 void evacSPTable( sm )
278 DEBUG_STRING("Evacuate Stable Pointer Table:");
280 P_ evac = sm->StablePointerTable;
281 sm->StablePointerTable = EVACUATE_CLOSURE(evac);
287 /* First attempt at Malloc Ptr hackery... Later versions might
288 do something useful with the two counters. [ADR] */
293 EXTDATA_RO(Forward_Ref_New_info);
294 EXTDATA_RO(Forward_Ref_Old_info);
295 EXTDATA_RO(OldRoot_Forward_Ref_info);
299 EXTDATA_RO(Forward_Ref_info);
305 Call FreeMallocPtr on any dead MPs in oldMPList, add the remainder
306 to new sticking the result into newMPList.
309 reportDeadMallocPtrs(oldMPList, new, newMPList)
315 I_ MP_no = 0, MP_deaths = 0;
317 /* At this point, the MallocPtrList is in an invalid state (since
318 some info ptrs will have been mangled) so we can't validate
321 DEBUG_STRING("Updating MallocPtr List and reporting casualties:");
323 while ( MPptr != NULL ) {
324 TRACE_MallocPtr(MPptr);
326 if ((P_) INFO_PTR(MPptr) == MallocPtr_info ) {
327 /* can't have been forwarded - must be dead */
330 FreeMallocPtr( MallocPtr_CLOSURE_DATA(MPptr) );
334 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
336 /* Now trash the closure to encourage bugs to show themselves */
337 TRASH_MallocPtr_CLOSURE( temp );
338 } else { /* Must have been forwarded - so it must be live */
340 P_ newAddress = (P_) FORWARD_ADDRESS(MPptr);
343 ASSERT( ( (P_) INFO_PTR(MPptr) == Forward_Ref_New_info ) ||
344 ( (P_) INFO_PTR(MPptr) == Forward_Ref_Old_info ) ||
345 ( (P_) INFO_PTR(MPptr) == OldRoot_Forward_Ref_info ) );
347 ASSERT( (P_) INFO_PTR(MPptr) == Forward_Ref_info );
350 TRACE_MPforwarded( MPptr, newAddress );
351 MallocPtr_CLOSURE_LINK(newAddress) = new;
354 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
358 VALIDATE_MallocPtrList( new );
361 #endif /* _INFO_COPYING */