1 \section[SM-copying]{Copying Collector Subroutines}
3 This is a collection of C functions used in implementing the copying
6 The motivation for making this a separate file/section is twofold:
8 1) It lets us focus on one thing.
10 2) If we don't do this, there will be a huge amount of repetition
11 between the various GC schemes --- a maintenance nightmare.
13 The second is the major motivation.
17 #if defined(GC2s) || defined(GCdu) || defined(GCap) || defined(GCgn)
21 #include "SMinternal.h"
24 #include "SMcopying.h"
27 Comment stolen from SMscav.lc: When doing a new generation copy
28 collection for Appel's collector only evacuate references that point
29 to the new generation. OldGen must be set to point to the end of old
35 #define MAYBE_EVACUATE_CLOSURE( closure ) \
37 P_ evac = (P_) (closure); \
38 if (evac > OldGen) { \
39 (closure) = EVACUATE_CLOSURE(evac); \
45 #define MAYBE_EVACUATE_CLOSURE( closure ) \
47 P_ evac = (P_) (closure); \
48 (closure) = EVACUATE_CLOSURE(evac); \
56 SetCAFInfoTables(P_ CAFlist)
60 /* Set CAF info tables for evacuation */
61 DEBUG_STRING("Setting Evac & Upd CAFs:");
62 for (CAFptr = CAFlist;
64 CAFptr = (P_) IND_CLOSURE_LINK(CAFptr) ) {
65 INFO_PTR(CAFptr) = (W_) Caf_Evac_Upd_info;
72 EvacuateRoots(P_ roots[], I_ rootno)
76 DEBUG_STRING("Evacuate (Reg) Roots:");
77 for (root = 0; root < rootno; root++) {
78 MAYBE_EVACUATE_CLOSURE( roots[root] );
83 Evacuating events is necessary in GRAN since some TSOs and closures are only
84 pointed at by events we have to schedule later on.
89 EvacuateEvents(STG_NO_ARGS)
91 eventq event = EventHd;
93 # if defined(GRAN) && defined(GRAN_CHECK)
94 if ( RTSflags.GcFlags.giveStats && (RTSflags.GranFlags.debug & 0x40) )
95 fprintf(RTSflags.GcFlags.statsFile,"Evacuating Events ...\n");
98 DEBUG_STRING("Evacuate Events:");
101 if(EVENT_TYPE(event) == RESUMETHREAD ||
102 EVENT_TYPE(event) == MOVETHREAD ||
103 EVENT_TYPE(event) == CONTINUETHREAD ||
104 EVENT_TYPE(event) == STARTTHREAD )
106 MAYBE_EVACUATE_CLOSURE( EVENT_TSO(event) );
108 else if(EVENT_TYPE(event) == MOVESPARK)
110 MAYBE_EVACUATE_CLOSURE( SPARK_NODE(EVENT_SPARK(event)) );
112 else if (EVENT_TYPE(event) == FETCHNODE ||
113 EVENT_TYPE(event) == FETCHREPLY )
116 MAYBE_EVACUATE_CLOSURE( EVENT_TSO(event) );
118 /* In the case of packet fetching, EVENT_NODE(event) points to */
119 /* the packet (currently, malloced). The packet is just a list of */
120 /* closure addresses, with the length of the list at index 1 (the */
121 /* structure of the packet is defined in Pack.lc). */
122 if ( RTSflags.GranFlags.DoGUMMFetching &&
123 (EVENT_TYPE(event)==FETCHREPLY)) {
124 P_ buffer = (P_) EVENT_NODE(event);
125 int size = (int) buffer[PACK_SIZE_LOCN], i;
127 for (i = PACK_HDR_SIZE; i <= size-1; i++) {
128 MAYBE_EVACUATE_CLOSURE( (P_)buffer[i] );
131 MAYBE_EVACUATE_CLOSURE( EVENT_NODE(event) );
133 else if (EVENT_TYPE(event) == GLOBALBLOCK)
135 MAYBE_EVACUATE_CLOSURE( EVENT_TSO(event) );
136 MAYBE_EVACUATE_CLOSURE( EVENT_NODE(event) );
138 else if (EVENT_TYPE(event) == UNBLOCKTHREAD)
140 MAYBE_EVACUATE_CLOSURE( EVENT_TSO(event) );
142 event = EVENT_NEXT(event);
149 #if defined(CONCURRENT)
152 EvacuateSparks(STG_NO_ARGS)
156 I_ pool, total_sparks=0;
158 /* Sparks have been pruned already at this point */
160 # if defined(GRAN) && defined(GRAN_CHECK)
161 if ( RTSflags.GcFlags.giveStats && (RTSflags.GranFlags.debug & 0x40) )
162 fprintf(RTSflags.GcFlags.statsFile,"Evacuating Sparks ...\n");
165 DEBUG_STRING("Evacuate Sparks (GRAN):");
166 for(proc = 0; proc < RTSflags.GranFlags.proc; ++proc) {
167 for(pool = 0; pool < SPARK_POOLS; ++pool) {
168 for(spark = PendingSparksHd[proc][pool];
170 spark = SPARK_NEXT(spark))
172 # if defined(GRAN) && defined(GRAN_CHECK)
173 if ( RTSflags.GcFlags.giveStats &&
174 (RTSflags.GranFlags.debug & 0x40) &&
175 !SHOULD_SPARK(SPARK_NODE(spark)) )
176 fprintf(RTSflags.GcFlags.statsFile,"Qagh {EvacuateSparks}Daq: spark @ 0x%x with node 0x%x shouldn't spark!\n",
177 spark,SPARK_NODE(spark));
179 MAYBE_EVACUATE_CLOSURE(SPARK_NODE(spark));
180 } /* forall spark ... */
181 } /* forall pool ... */
182 } /* forall proc ... */
188 EvacuateSparks(STG_NO_ARGS)
194 DEBUG_STRING("Evacuate Sparks:");
195 for (pool = 0; pool < SPARK_POOLS; pool++) {
196 for (sparkptr = PendingSparksHd[pool];
197 sparkptr < PendingSparksTl[pool]; sparkptr++) {
198 MAYBE_EVACUATE_CLOSURE(*((PP_) sparkptr));
203 #endif /* CONCURRENT */
206 Note: no \tr{evacuate[AB]Stack} for ``parallel'' systems, because they
207 don't have a single main stack.
212 EvacuateAStack(PP_ stackA, PP_ botA /* botA points to bottom-most word */)
216 DEBUG_STRING("Evacuate A Stack:");
217 for (stackptr = stackA;
218 SUBTRACT_A_STK(stackptr, botA) >= 0;
219 stackptr = stackptr + AREL(1)) {
220 MAYBE_EVACUATE_CLOSURE( *((PP_) stackptr) );
226 ToDo: Optimisation which squeezes out update frames which point to
229 Perform collection first
231 Then process B stack removing update frames (bot to top via pointer
232 reversal) that reference garbage closues (test infoptr !=
235 Otherwise closure is live update reference to to-space address
240 EvacuateBStack( stackB, botB, roots )
242 P_ botB; /* botB points to bottom-most word */
249 DEBUG_STRING("Evacuate B Stack:");
251 for (updateFramePtr = stackB; /* stackB points to topmost update frame */
252 SUBTRACT_B_STK(updateFramePtr, botB) > 0;
253 updateFramePtr = GRAB_SuB(updateFramePtr)) {
255 /* Evacuate the thing to be updated */
256 updatee = GRAB_UPDATEE(updateFramePtr);
257 MAYBE_EVACUATE_CLOSURE(updatee);
258 PUSH_UPDATEE(updateFramePtr, updatee);
266 When we do a copying collection, we want to evacuate all of the local
267 entries in the GALA table for which there are outstanding remote
268 pointers (i.e. for which the weight is not MAX_GA_WEIGHT.)
274 EvacuateLocalGAs(rtsBool full)
280 for (gala = liveIndirections; gala != NULL; gala = next) {
282 ASSERT(gala->ga.loc.gc.gtid == mytid);
283 if (gala->ga.weight != MAX_GA_WEIGHT) {
284 /* Remote references exist, so we must evacuate the local closure */
286 MAYBE_EVACUATE_CLOSURE(gala->la);
287 if (!full && gala->preferred && gala->la != old) {
288 (void) removeHashTable(LAtoGALAtable, (W_) old, (void *) gala);
289 insertHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
294 /* Since we have all of the weight, this GA is no longer needed */
295 W_ pga = PackGA(thisPE, gala->ga.loc.gc.slot);
298 fprintf(stderr, "Freeing slot %d\n", gala->ga.loc.gc.slot);
300 gala->next = freeIndirections;
301 freeIndirections = gala;
302 (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala);
303 if (!full && gala->preferred)
304 (void) removeHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
306 gala->ga.weight = 0x0d0d0d0d;
307 gala->la = (P_) 0xbadbad;
311 liveIndirections = prev;
318 EXTDATA_RO(Forward_Ref_info);
321 RebuildGAtables(rtsBool full)
328 prepareFreeMsgBuffers();
330 for (gala = liveRemoteGAs, prev = NULL; gala != NULL; gala = next) {
332 ASSERT(gala->ga.loc.gc.gtid != mytid);
337 * If the old closure has not been forwarded, we let go. Note that this
338 * approach also drops global aliases for PLCs.
341 #if defined(GCgn) || defined(GCap)
342 if (closure > OldGen) {
344 if (!full && gala->preferred)
345 (void) removeHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
347 /* Follow indirection chains to the end, just in case */
348 while (IS_INDIRECTION(INFO_PTR(closure)))
349 closure = (P_) IND_CLOSURE_PTR(closure);
351 /* Change later to incorporate a _FO bit in the INFO_TYPE for GCgn */
353 fall over, until _FO bits are added
355 if (INFO_PTR(closure) != (W_) Forward_Ref_info) {
356 int pe = taskIDtoPE(gala->ga.loc.gc.gtid);
357 W_ pga = PackGA(pe, gala->ga.loc.gc.slot);
359 (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala);
360 freeRemoteGA(pe, &(gala->ga));
361 gala->next = freeGALAList;
364 /* Find the new space object */
365 closure = (P_) FORWARD_ADDRESS(closure);
368 if (!full && gala->preferred)
369 insertHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
373 #if defined(GCgn) || defined(GCap)
375 /* Old generation, minor collection; just keep it */
381 liveRemoteGAs = prev;
383 /* If we have any remaining FREE messages to send off, do so now */
398 DEBUG_SCAN("Scavenging Start", Scav, "ToHp", ToHp);
399 while (Scav <= ToHp) (SCAV_CODE(INFO_PTR(Scav)))();
400 DEBUG_SCAN("Scavenging End", Scav, "ToHp", ToHp);
408 EvacuateCAFs( CAFlist )
413 DEBUG_STRING("Evacuate CAFs:");
414 for (CAFptr = CAFlist;
416 CAFptr = (P_) IND_CLOSURE_LINK(CAFptr)) {
417 EVACUATE_CLOSURE(CAFptr); /* evac & upd OR return */
421 /* ToDo: put GCap EvacuateCAFs code here */
426 EvacAndScavengeCAFs( CAFlist, extra_words, roots )
435 DEBUG_STRING("Evacuate & Scavenge CAFs:");
436 for (CAFptr = CAFlist;
438 CAFptr = (P_) IND_CLOSURE_LINK(CAFptr)) {
440 EVACUATE_CLOSURE(CAFptr); /* evac & upd OR return */
443 DEBUG_SCAN("Scavenging CAF", Scav, "ToHp", ToHp);
444 while (Scav <= ToHp) (SCAV_CODE(INFO_PTR(Scav)))();
445 DEBUG_SCAN("Scavenging End", Scav, "ToHp", ToHp);
447 *extra_words = ToHp - caf_start;
453 #endif /* defined(_INFO_COPYING) */