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 foreign object 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 fprintf(stderr,"Trashing from 0x%lx to 0x%lx inclusive\n", (W_) from, (W_) to);
69 *from++ = DEALLOCATED_TRASH;
78 #if !defined(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->ForeignObjList = NULL;
92 #if defined(GCap) || defined(GCgn)
93 sm->OldForeignObjList = NULL;
96 sm->StablePointerTable = (P_) EmptySPTable_closure;
105 When a Foreign Object is released, there should be absolutely no
106 references to it. To encourage and dangling references to show
107 themselves, we'll trash its contents when we're done with it.
110 #define TRASH_ForeignObj_CLOSURE( mptr ) Trash_ForeignObj_Closure(mptr)
113 Trash_ForeignObj_Closure(mptr)
117 for( i = 0; i < ForeignObj_SIZE + _FHS; i++ ) {
118 mptr[ i ] = DEALLOCATED_TRASH;
123 Also, every time we fiddle with the ForeignObj list, we should check it
124 still makes sense. This function returns @0@ if the list is sensible.
126 (Would maintaining a separate Foreign Obj count allow better testing?)
130 Validate_ForeignObjList( ForeignObjList )
135 for(FOptr = ForeignObjList;
137 FOptr = ForeignObj_CLOSURE_LINK(FOptr) ) {
138 CHECK_ForeignObj_CLOSURE(FOptr);
146 #define TRASH_ForeignObj_CLOSURE( mp ) /* nothing */
154 #define TRACE_ForeignObj(FOptr) Trace_ForeignObj( FOptr )
155 #define TRACE_FOdies(FOptr) Trace_FOdies()
156 #define TRACE_FOlives(FOptr) Trace_FOlives()
157 #define TRACE_FOforwarded(FOptr, newAddress) Trace_FOforwarded( FOptr, newAddress )
160 Trace_ForeignObj( FOptr )
163 if (RTSflags.GcFlags.trace & DEBUG_TRACE_FOREIGNOBJS) {
164 fprintf(stderr,"DEBUG: ForeignObj(%0x)=<%0x,%0x,%0x,%0x>\n", (W_) FOptr, (W_) FOptr[0], (W_) FOptr[1], (W_) FOptr[2], (W_) FOptr[3]);
165 fprintf(stderr," Data = %0x, Finaliser = %0x, Next = %0x\n",
166 (W_) ForeignObj_CLOSURE_DATA(FOptr),
167 (W_) ForeignObj_CLOSURE_FINALISER(FOptr),
168 (W_) ForeignObj_CLOSURE_LINK(FOptr) );
175 if (RTSflags.GcFlags.trace & DEBUG_TRACE_FOREIGNOBJS) {
176 fprintf(stderr, " dying\n");
183 if (RTSflags.GcFlags.trace & DEBUG_TRACE_FOREIGNOBJS) {
184 fprintf(stderr," lived to tell the tale\n");
189 Trace_FOforwarded( FOPtr, newAddress )
190 P_ FOPtr, newAddress;
192 if (RTSflags.GcFlags.trace & DEBUG_TRACE_FOREIGNOBJS) {
193 fprintf(stderr, " forwarded to %lx\n", (W_) newAddress);
199 #define TRACE_ForeignObj(FOptr) /* nothing */
200 #define TRACE_FOdies(FOptr) /* nothing */
201 #define TRACE_FOlives(FOptr) /* nothing */
202 #define TRACE_FOforwarded(FOptr, newAddress) /* nothing */
208 \section[SM-extensions-compacting-code]{Compacting Collector Code}
212 #if defined(_INFO_COMPACTING)
214 /* Sweep up the dead ForeignObjs */
216 /* Note that this has to happen before the linking phase trashes
217 the stable pointer table so that the finaliser functions can
218 safely call freeStablePointer.
222 sweepUpDeadForeignObjs( ForeignObjList, base, bits )
228 I_ ForeignObj_deaths = 0;
229 long _hp_word, bit_index, bit;
231 /* At this point, the ForeignObjList is in an invalid state (since
232 some info ptrs will have been mangled) so we can't validate
235 DEBUG_STRING("Reporting Dead Foreign objects:");
236 FOptr = ForeignObjList;
237 while ( FOptr != NULL ) {
239 TRACE_ForeignObj(FOptr);
241 _hp_word = FOptr - base;
242 bit_index = _hp_word / BITS_IN(BitWord);
243 bit = 1L << (_hp_word & (BITS_IN(BitWord) - 1));
244 if ( !( bits[bit_index] & bit ) ) { /* dead */
246 TRACE_FOdies( FOptr );
247 (*(void (*)(StgAddr))((StgAddr)ForeignObj_CLOSURE_FINALISER(FOptr)))((StgAddr)ForeignObj_CLOSURE_DATA(FOptr));
251 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
252 /* Now trash the closure to encourage bugs to show themselves */
253 TRASH_ForeignObj_CLOSURE( temp );
257 TRACE_FOlives(FOptr);
258 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
263 #endif /* _INFO_COMPACTING */
266 \section[SM-extensions-copying-code]{Copying Collector Code}
269 #if defined(_INFO_COPYING)
271 /* ToDo: a possible optimisation would be to maintain a flag that
272 told us whether the SPTable had been updated (with new
273 pointers) and so needs to be GC'd. A simple way of doing this
274 might be to generalise the MUTUPLE closures to MUGEN closures.
276 void evacSPTable( sm )
279 DEBUG_STRING("Evacuate Stable Pointer Table:");
281 P_ evac = sm->StablePointerTable;
282 sm->StablePointerTable = EVACUATE_CLOSURE(evac);
288 /* First attempt at Foreign Obj hackery... Later versions might
289 do something useful with the two counters. [ADR] */
294 EXTDATA_RO(Forward_Ref_New_info);
295 EXTDATA_RO(Forward_Ref_Old_info);
296 EXTDATA_RO(OldRoot_Forward_Ref_info);
300 EXTDATA_RO(Forward_Ref_info);
306 Call ForeignObj finalising routine on any dead FOs in oldFOList,
307 add the remainder to new sticking the result into newFOList.
310 reportDeadForeignObjs(oldFOList, new, newFOList)
316 I_ FO_no = 0, FO_deaths = 0;
318 /* At this point, the ForeignObjList is in an invalid state (since
319 some info ptrs will have been mangled) so we can't validate
322 DEBUG_STRING("Updating Foreign Objects List and reporting casualties:");
324 while ( FOptr != NULL ) {
325 TRACE_ForeignObj(FOptr);
327 if ((P_) INFO_PTR(FOptr) == ForeignObj_info ) {
328 /* can't have been forwarded - must be dead */
331 (*(void (*)(StgAddr))(ForeignObj_CLOSURE_FINALISER(FOptr)))((StgAddr)ForeignObj_CLOSURE_DATA(FOptr));
335 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
337 /* Now trash the closure to encourage bugs to show themselves */
338 TRASH_ForeignObj_CLOSURE( temp );
339 } else { /* Must have been forwarded - so it must be live */
341 P_ newAddress = (P_) FORWARD_ADDRESS(FOptr);
344 ASSERT( ( (P_) INFO_PTR(FOptr) == Forward_Ref_New_info ) ||
345 ( (P_) INFO_PTR(FOptr) == Forward_Ref_Old_info ) ||
346 ( (P_) INFO_PTR(FOptr) == OldRoot_Forward_Ref_info ) );
348 ASSERT( (P_) INFO_PTR(FOptr) == Forward_Ref_info );
351 TRACE_FOforwarded( FOptr, newAddress );
352 ForeignObj_CLOSURE_LINK(newAddress) = new;
355 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
359 VALIDATE_ForeignObjList( new );
362 #endif /* _INFO_COPYING */
365 @freeForeigns@ summarily calls the finaliser routines for
366 all live foreign objects, done when closing down.
367 (code is just a rip off of the above).
370 #if defined(_INFO_COPYING)
375 EXTDATA_RO(Forward_Ref_New_info);
376 EXTDATA_RO(Forward_Ref_Old_info);
377 EXTDATA_RO(OldRoot_Forward_Ref_info);
381 EXTDATA_RO(Forward_Ref_info);
387 Call the ForeignObj finalising routine on all the live FOs,
388 used when shutting down.
397 /* At this point, exitSM() has been called, the ForeignObjList is in an invalid state (since
398 some info ptrs will have been mangled) so we can't validate
401 DEBUG_STRING("Freeing all live Foreign Objects:");
403 while ( FOptr != NULL ) {
405 /* I'm not convinced that the situation of having
406 indirections linked into the FO list can ever occur,
407 but chasing indirections doesn't hurt. */
408 while(IS_INDIRECTION(INFO_PTR(FOptr))) {
409 FOptr = (P_) IND_CLOSURE_PTR(FOptr);
411 if ((P_) INFO_PTR(FOptr) == ForeignObj_info ) {
412 TRACE_ForeignObj(FOptr);
414 (*(void (*)(StgAddr))(ForeignObj_CLOSURE_FINALISER(FOptr)))((StgAddr)ForeignObj_CLOSURE_DATA(FOptr));
418 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
420 /* Now trash the closure to encourage bugs to show themselves */
421 TRASH_ForeignObj_CLOSURE( temp );
423 fprintf(stderr, "Warning: Foreign object list contained unexpected element, bailing out of FO cleanup.\n");
429 #endif /* _INFO_COPYING */