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 if (ForeignObj_CLOSURE_FINALISER(FOptr) != NULL) {
248 (*(void (*)(StgAddr))(ForeignObj_CLOSURE_FINALISER(FOptr)))((StgAddr)ForeignObj_CLOSURE_DATA(FOptr));
253 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
254 /* Now trash the closure to encourage bugs to show themselves */
255 TRASH_ForeignObj_CLOSURE( temp );
259 TRACE_FOlives(FOptr);
260 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
265 #endif /* _INFO_COMPACTING */
268 \section[SM-extensions-copying-code]{Copying Collector Code}
271 #if defined(_INFO_COPYING)
273 /* ToDo: a possible optimisation would be to maintain a flag that
274 told us whether the SPTable had been updated (with new
275 pointers) and so needs to be GC'd. A simple way of doing this
276 might be to generalise the MUTUPLE closures to MUGEN closures.
278 void evacSPTable( sm )
281 DEBUG_STRING("Evacuate Stable Pointer Table:");
283 P_ evac = sm->StablePointerTable;
284 sm->StablePointerTable = EVACUATE_CLOSURE(evac);
290 /* First attempt at Foreign Obj hackery... Later versions might
291 do something useful with the two counters. [ADR] */
296 EXTDATA_RO(Forward_Ref_New_info);
297 EXTDATA_RO(Forward_Ref_Old_info);
298 EXTDATA_RO(OldRoot_Forward_Ref_info);
302 EXTDATA_RO(Forward_Ref_info);
308 Call ForeignObj finalising routine on any dead FOs in oldFOList,
309 add the remainder to new sticking the result into newFOList.
312 reportDeadForeignObjs(oldFOList, new, newFOList)
318 I_ FO_no = 0, FO_deaths = 0;
320 /* At this point, the ForeignObjList is in an invalid state (since
321 some info ptrs will have been mangled) so we can't validate
324 DEBUG_STRING("Updating Foreign Objects List and reporting casualties:");
326 while ( FOptr != NULL ) {
327 TRACE_ForeignObj(FOptr);
329 if ((P_) INFO_PTR(FOptr) == ForeignObj_info ) {
330 /* can't have been forwarded - must be dead */
333 if (ForeignObj_CLOSURE_FINALISER(FOptr) != NULL) {
334 (*(void (*)(StgAddr))(ForeignObj_CLOSURE_FINALISER(FOptr)))((StgAddr)ForeignObj_CLOSURE_DATA(FOptr));
339 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
341 /* Now trash the closure to encourage bugs to show themselves */
342 TRASH_ForeignObj_CLOSURE( temp );
343 } else { /* Must have been forwarded - so it must be live */
345 P_ newAddress = (P_) FORWARD_ADDRESS(FOptr);
348 ASSERT( ( (P_) INFO_PTR(FOptr) == Forward_Ref_New_info ) ||
349 ( (P_) INFO_PTR(FOptr) == Forward_Ref_Old_info ) ||
350 ( (P_) INFO_PTR(FOptr) == OldRoot_Forward_Ref_info ) );
352 ASSERT( (P_) INFO_PTR(FOptr) == Forward_Ref_info );
355 TRACE_FOforwarded( FOptr, newAddress );
356 ForeignObj_CLOSURE_LINK(newAddress) = new;
359 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
363 VALIDATE_ForeignObjList( new );
366 #endif /* _INFO_COPYING */
369 @freeForeigns@ summarily calls the finaliser routines for
370 all live foreign objects, done when closing down.
371 (code is just a rip off of the above).
374 #if defined(_INFO_COPYING)
379 EXTDATA_RO(Forward_Ref_New_info);
380 EXTDATA_RO(Forward_Ref_Old_info);
381 EXTDATA_RO(OldRoot_Forward_Ref_info);
385 EXTDATA_RO(Forward_Ref_info);
391 Call the ForeignObj finalising routine on all the live FOs,
392 used when shutting down.
401 /* At this point, exitSM() has been called, the ForeignObjList is in an invalid state (since
402 some info ptrs will have been mangled) so we can't validate
405 DEBUG_STRING("Freeing all live Foreign Objects:");
407 while ( FOptr != NULL ) {
409 /* I'm not convinced that the situation of having
410 indirections linked into the FO list can ever occur,
411 but chasing indirections doesn't hurt. */
412 while(IS_INDIRECTION(INFO_PTR(FOptr))) {
413 FOptr = (P_) IND_CLOSURE_PTR(FOptr);
415 if ((P_) INFO_PTR(FOptr) == ForeignObj_info ) {
416 TRACE_ForeignObj(FOptr);
418 /* ForeignObjs can have a zapped-out finaliser field, in which
419 case we'll just drop the object silently.
421 if (ForeignObj_CLOSURE_FINALISER(FOptr) != NULL) {
422 (*(void (*)(StgAddr))(ForeignObj_CLOSURE_FINALISER(FOptr)))((StgAddr)ForeignObj_CLOSURE_DATA(FOptr));
427 FOptr = ForeignObj_CLOSURE_LINK(FOptr);
429 /* Now trash the closure to encourage bugs to show themselves */
430 TRASH_ForeignObj_CLOSURE( temp );
432 fprintf(stderr, "Warning: Foreign object list contained unexpected element, bailing out of FO cleanup.\n");
438 #endif /* _INFO_COPYING */