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 ); */
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)
117 for( i = 0; i != MallocPtr_SIZE + _FHS; i++ ) {
118 mptr[ i ] = DEALLOCATED_TRASH;
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.
126 (Would maintaining a separate Malloc Ptr count allow better testing?)
130 Validate_MallocPtrList( MallocPtrList )
135 for(MPptr = MallocPtrList;
137 MPptr = MallocPtr_CLOSURE_LINK(MPptr) ) {
138 CHECK_MallocPtr_CLOSURE(MPptr);
146 #define TRASH_MallocPtr_CLOSURE( mp ) /* nothing */
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 )
160 Trace_MallocPtr( MPptr )
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) );
182 printf(" lived to tell the tale \n");
187 Trace_MPforwarded( MPPtr, newAddress )
188 P_ MPPtr, newAddress;
191 printf(" forwarded to %lx\n", (W_) newAddress);
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 */
206 \section[SM-extensions-compacting-code]{Compacting Collector Code}
210 #if defined(_INFO_COMPACTING)
212 /* Sweep up the dead MallocPtrs */
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.
220 sweepUpDeadMallocPtrs( MallocPtrList, base, bits )
226 I_ MallocPtr_deaths = 0;
227 long _hp_word, bit_index, bit;
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
233 DEBUG_STRING("Reporting Dead Malloc Ptrs:");
234 MPptr = MallocPtrList;
235 while ( MPptr != NULL ) {
237 TRACE_MallocPtr(MPptr);
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 */
244 TRACE_MPdies( MPptr );
245 FreeMallocPtr( MallocPtr_CLOSURE_DATA(MPptr) );
249 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
250 /* Now trash the closure to encourage bugs to show themselves */
251 TRASH_MallocPtr_CLOSURE( temp );
255 TRACE_MPlives(MPptr);
256 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
261 #endif /* _INFO_COMPACTING */
264 \section[SM-extensions-copying-code]{Copying Collector Code}
267 #if defined(_INFO_COPYING)
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.
274 void evacSPTable( sm )
277 DEBUG_STRING("Evacuate Stable Pointer Table:");
279 P_ evac = sm->StablePointerTable;
280 sm->StablePointerTable = EVACUATE_CLOSURE(evac);
286 /* First attempt at Malloc Ptr hackery... Later versions might
287 do something useful with the two counters. [ADR] */
292 EXTDATA_RO(Forward_Ref_New_info);
293 EXTDATA_RO(Forward_Ref_Old_info);
294 EXTDATA_RO(OldRoot_Forward_Ref_info);
298 EXTDATA_RO(Forward_Ref_info);
304 Call FreeMallocPtr on any dead MPs in oldMPList, add the remainder
305 to new sticking the result into newMPList.
308 reportDeadMallocPtrs(oldMPList, new, newMPList)
314 I_ MP_no = 0, MP_deaths = 0;
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
320 DEBUG_STRING("Updating MallocPtr List and reporting casualties:");
322 while ( MPptr != NULL ) {
323 TRACE_MallocPtr(MPptr);
325 if ((P_) INFO_PTR(MPptr) == MallocPtr_info ) {
326 /* can't have been forwarded - must be dead */
329 FreeMallocPtr( MallocPtr_CLOSURE_DATA(MPptr) );
333 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
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 */
339 P_ newAddress = (P_) FORWARD_ADDRESS(MPptr);
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 ) );
346 ASSERT( (P_) INFO_PTR(MPptr) == Forward_Ref_info );
349 TRACE_MPforwarded( MPptr, newAddress );
350 MallocPtr_CLOSURE_LINK(newAddress) = new;
353 MPptr = MallocPtr_CLOSURE_LINK(MPptr);
357 VALIDATE_MallocPtrList( new );
360 #endif /* _INFO_COPYING */