\section[SM-copying]{Copying Collector Subroutines} This is a collection of C functions used in implementing the copying collectors. The motivation for making this a separate file/section is twofold: 1) It lets us focus on one thing. 2) If we don't do this, there will be a huge amount of repetition between the various GC schemes --- a maintenance nightmare. The second is the major motivation. \begin{code} #if defined(GC2s) || defined(GCdu) || defined(GCap) || defined(GCgn) /* to the end */ #define SCAV_REG_MAP #include "SMinternal.h" REGDUMP(ScavRegDump); #include "SMcopying.h" \end{code} Comment stolen from SMscav.lc: When doing a new generation copy collection for Appel's collector only evacuate references that point to the new generation. OldGen must be set to point to the end of old space. \begin{code} #ifdef GCap #define MAYBE_EVACUATE_CLOSURE( closure ) \ do { \ P_ evac = (P_) (closure); \ if (evac > OldGen) { \ (closure) = EVACUATE_CLOSURE(evac); \ } \ } while (0) #else #define MAYBE_EVACUATE_CLOSURE( closure ) \ do { \ P_ evac = (P_) (closure); \ (closure) = EVACUATE_CLOSURE(evac); \ } while (0) #endif \end{code} \begin{code} void SetCAFInfoTables(P_ CAFlist) { P_ CAFptr; /* Set CAF info tables for evacuation */ DEBUG_STRING("Setting Evac & Upd CAFs:"); for (CAFptr = CAFlist; CAFptr != NULL; CAFptr = (P_) IND_CLOSURE_LINK(CAFptr) ) { INFO_PTR(CAFptr) = (W_) Caf_Evac_Upd_info; } } \end{code} \begin{code} void EvacuateRoots(P_ roots[], I_ rootno) { I_ root; DEBUG_STRING("Evacuate (Reg) Roots:"); for (root = 0; root < rootno; root++) { MAYBE_EVACUATE_CLOSURE( roots[root] ); } } \end{code} \begin{code} #ifdef CONCURRENT void EvacuateSparks(STG_NO_ARGS) { PP_ sparkptr; int pool; DEBUG_STRING("Evacuate Sparks:"); for (pool = 0; pool < SPARK_POOLS; pool++) { for (sparkptr = PendingSparksHd[pool]; sparkptr < PendingSparksTl[pool]; sparkptr++) { MAYBE_EVACUATE_CLOSURE(*((PP_) sparkptr)); } } } #endif \end{code} Note: no \tr{evacuate[AB]Stack} for ``parallel'' systems, because they don't have a single main stack. \begin{code} #ifndef PAR void EvacuateAStack(PP_ stackA, PP_ botA /* botA points to bottom-most word */) { PP_ stackptr; DEBUG_STRING("Evacuate A Stack:"); for (stackptr = stackA; SUBTRACT_A_STK(stackptr, botA) >= 0; stackptr = stackptr + AREL(1)) { MAYBE_EVACUATE_CLOSURE( *((PP_) stackptr) ); } } #endif /* not PAR */ \end{code} ToDo: Optimisation which squeezes out update frames which point to garbage closures. Perform collection first Then process B stack removing update frames (bot to top via pointer reversal) that reference garbage closues (test infoptr != EVACUATED_INFOPTR) Otherwise closure is live update reference to to-space address \begin{code} #ifndef PAR void EvacuateBStack( stackB, botB, roots ) P_ stackB; P_ botB; /* botB points to bottom-most word */ I_ *roots; { I_ bstk_roots; P_ updateFramePtr; P_ updatee; DEBUG_STRING("Evacuate B Stack:"); bstk_roots = 0; for (updateFramePtr = stackB; /* stackB points to topmost update frame */ SUBTRACT_B_STK(updateFramePtr, botB) > 0; updateFramePtr = GRAB_SuB(updateFramePtr)) { /* Evacuate the thing to be updated */ updatee = GRAB_UPDATEE(updateFramePtr); MAYBE_EVACUATE_CLOSURE(updatee); PUSH_UPDATEE(updateFramePtr, updatee); bstk_roots++; } *roots = bstk_roots; } #endif /* not PAR */ \end{code} When we do a copying collection, we want to evacuate all of the local entries in the GALA table for which there are outstanding remote pointers (i.e. for which the weight is not MAX_GA_WEIGHT.) \begin{code} #ifdef PAR void EvacuateLocalGAs(rtsBool full) { GALA *gala; GALA *next; GALA *prev = NULL; for (gala = liveIndirections; gala != NULL; gala = next) { next = gala->next; ASSERT(gala->ga.loc.gc.gtid == mytid); if (gala->ga.weight != MAX_GA_WEIGHT) { /* Remote references exist, so we must evacuate the local closure */ P_ old = gala->la; MAYBE_EVACUATE_CLOSURE(gala->la); if (!full && gala->preferred && gala->la != old) { (void) removeHashTable(LAtoGALAtable, (W_) old, (void *) gala); insertHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala); } gala->next = prev; prev = gala; } else { /* Since we have all of the weight, this GA is no longer needed */ W_ pga = PackGA(thisPE, gala->ga.loc.gc.slot); #ifdef FREE_DEBUG fprintf(stderr, "Freeing slot %d\n", gala->ga.loc.gc.slot); #endif gala->next = freeIndirections; freeIndirections = gala; (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala); if (!full && gala->preferred) (void) removeHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala); #ifdef DEBUG gala->ga.weight = 0x0d0d0d0d; gala->la = (P_) 0xbadbad; #endif } } liveIndirections = prev; } \end{code} \begin{code} EXTDATA_RO(Forward_Ref_info); void RebuildGAtables(rtsBool full) { GALA *gala; GALA *next; GALA *prev; P_ closure; prepareFreeMsgBuffers(); for (gala = liveRemoteGAs, prev = NULL; gala != NULL; gala = next) { next = gala->next; ASSERT(gala->ga.loc.gc.gtid != mytid); closure = gala->la; /* * If the old closure has not been forwarded, we let go. Note that this * approach also drops global aliases for PLCs. */ #if defined(GCgn) || defined(GCap) if (closure > OldGen) { #endif if (!full && gala->preferred) (void) removeHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala); /* Follow indirection chains to the end, just in case */ while (IS_INDIRECTION(INFO_PTR(closure))) closure = (P_) IND_CLOSURE_PTR(closure); /* Change later to incorporate a _FO bit in the INFO_TYPE for GCgn */ #ifdef GCgn fall over, until _FO bits are added #endif if (INFO_PTR(closure) != (W_) Forward_Ref_info) { int pe = taskIDtoPE(gala->ga.loc.gc.gtid); W_ pga = PackGA(pe, gala->ga.loc.gc.slot); (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala); freeRemoteGA(pe, &(gala->ga)); gala->next = freeGALAList; freeGALAList = gala; } else { /* Find the new space object */ closure = (P_) FORWARD_ADDRESS(closure); gala->la = closure; if (!full && gala->preferred) insertHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala); gala->next = prev; prev = gala; } #if defined(GCgn) || defined(GCap) } else { /* Old generation, minor collection; just keep it */ gala->next = prev; prev = gala; } #endif } liveRemoteGAs = prev; /* If we have any remaining FREE messages to send off, do so now */ sendFreeMessages(); if (full) RebuildLAGAtable(); } #endif \end{code} \begin{code} void Scavenge(void) { DEBUG_SCAN("Scavenging Start", Scav, "ToHp", ToHp); while (Scav <= ToHp) (SCAV_CODE(INFO_PTR(Scav)))(); DEBUG_SCAN("Scavenging End", Scav, "ToHp", ToHp); } \end{code} \begin{code} #ifdef GCdu void EvacuateCAFs( CAFlist ) P_ CAFlist; { P_ CAFptr; DEBUG_STRING("Evacuate CAFs:"); for (CAFptr = CAFlist; CAFptr != NULL; CAFptr = (P_) IND_CLOSURE_LINK(CAFptr)) { EVACUATE_CLOSURE(CAFptr); /* evac & upd OR return */ } } /* ToDo: put GCap EvacuateCAFs code here */ #else /* not GCdu */ void EvacAndScavengeCAFs( CAFlist, extra_words, roots ) P_ CAFlist; I_ *extra_words; I_ *roots; { I_ caf_roots = 0; P_ caf_start = ToHp; P_ CAFptr; DEBUG_STRING("Evacuate & Scavenge CAFs:"); for (CAFptr = CAFlist; CAFptr != NULL; CAFptr = (P_) IND_CLOSURE_LINK(CAFptr)) { EVACUATE_CLOSURE(CAFptr); /* evac & upd OR return */ caf_roots++; DEBUG_SCAN("Scavenging CAF", Scav, "ToHp", ToHp); while (Scav <= ToHp) (SCAV_CODE(INFO_PTR(Scav)))(); DEBUG_SCAN("Scavenging End", Scav, "ToHp", ToHp); } *extra_words = ToHp - caf_start; *roots = caf_roots; } #endif /* !GCdu */ #endif /* defined(_INFO_COPYING) */ \end{code}