static void rootsStepClosureInit(rootsStepClosure rsc, Globals arena, Trace trace, PoolFixMethod rootFix, mps_roots_stepper_t f, void *p, size_t s) { ScanState ss; /* First initialize the ScanState superclass */ ss = &rsc->ssStruct; ScanStateInit(ss, TraceSetSingle(trace), GlobalsArena(arena), RankAMBIG, trace->white); /* Initialize the fix method in the ScanState */ ss->fix = rootFix; /* Initialize subclass specific data */ rsc->f = f; rsc->p = p; rsc->s = s; rsc->root = NULL; rsc->sig = rootsStepClosureSig; AVERT(rootsStepClosure, rsc); }
void ArenaRestoreProtection(Globals globals) { Ring node, next; Arena arena; arena = GlobalsArena(globals); RING_FOR(node, GlobalsRememberedSummaryRing(globals), next) { RememberedSummaryBlock block = RING_ELT(RememberedSummaryBlock, globalRing, node); size_t i; for(i = 0; i < RememberedSummaryBLOCK; ++ i) { Seg seg; Bool b; if(block->the[i].base == (Addr)0) { AVER(block->the[i].summary == RefSetUNIV); continue; } b = SegOfAddr(&seg, arena, block->the[i].base); if(b && SegBase(seg) == block->the[i].base) { AVER(IsA(GCSeg, seg)); SegSetSummary(seg, block->the[i].summary); } else { /* Either seg has gone or moved, both of which are */ /* client errors. */ NOTREACHED; } } }
void ArenaPark(Globals globals) { TraceId ti; Trace trace; Arena arena; Clock start; AVERT(Globals, globals); arena = GlobalsArena(globals); globals->clamped = TRUE; start = ClockNow(); while(arena->busyTraces != TraceSetEMPTY) { /* Advance all active traces. */ TRACE_SET_ITER(ti, trace, arena->busyTraces, arena) TraceAdvance(trace); if(trace->state == TraceFINISHED) { TraceDestroyFinished(trace); } TRACE_SET_ITER_END(ti, trace, arena->busyTraces, arena); } ArenaAccumulateTime(arena, start, ClockNow()); /* All traces have finished so there must not be an emergency. */ AVER(!ArenaEmergency(arena)); }
Res ArenaStartCollect(Globals globals, int why) { Arena arena; Res res; Trace trace; AVERT(Globals, globals); arena = GlobalsArena(globals); ArenaPark(globals); res = TraceStartCollectAll(&trace, arena, why); if(res != ResOK) goto failStart; ArenaRelease(globals); return ResOK; failStart: ArenaRelease(globals); return res; }
static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) { Arena arena; RememberedSummaryBlock block; AVER(summary != RefSetUNIV); arena = GlobalsArena(global); if(global->rememberedSummaryIndex == 0) { void *p; RememberedSummaryBlock newBlock; int res; res = ControlAlloc(&p, arena, sizeof *newBlock); if(res != ResOK) { return res; } newBlock = p; rememberedSummaryBlockInit(newBlock); RingAppend(GlobalsRememberedSummaryRing(global), &newBlock->globalRing); } block = RING_ELT(RememberedSummaryBlock, globalRing, RingPrev(GlobalsRememberedSummaryRing(global))); AVER(global->rememberedSummaryIndex < RememberedSummaryBLOCK); AVER(block->the[global->rememberedSummaryIndex].base == (Addr)0); AVER(block->the[global->rememberedSummaryIndex].summary == RefSetUNIV); block->the[global->rememberedSummaryIndex].base = base; block->the[global->rememberedSummaryIndex].summary = summary; ++ global->rememberedSummaryIndex; if(global->rememberedSummaryIndex >= RememberedSummaryBLOCK) { AVER(global->rememberedSummaryIndex == RememberedSummaryBLOCK); global->rememberedSummaryIndex = 0; } return ResOK; }
/* ArenaExposeRemember -- park arena and then lift all protection barriers. Parameter 'remember' specifies whether to remember the protection state or not (for later restoration with ArenaRestoreProtection). */ void ArenaExposeRemember(Globals globals, Bool remember) { Seg seg; Arena arena; AVERT(Globals, globals); AVERT(Bool, remember); ArenaPark(globals); arena = GlobalsArena(globals); if(SegFirst(&seg, arena)) { Addr base; do { base = SegBase(seg); if (IsA(GCSeg, seg)) { if(remember) { RefSet summary; summary = SegSummary(seg); if(summary != RefSetUNIV) { Res res = arenaRememberSummaryOne(globals, base, summary); if(res != ResOK) { /* If we got an error then stop trying to remember any protections. */ remember = 0; } } } SegSetSummary(seg, RefSetUNIV); AVER(SegSM(seg) == AccessSetEMPTY); } } while(SegNext(&seg, arena, seg)); } }
static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, void *p, size_t s) { Arena arena; rootsStepClosureStruct rscStruct; rootsStepClosure rsc = &rscStruct; Trace trace; ScanState ss; Rank rank; Res res; Seg seg; AVERT(Globals, arenaGlobals); AVER(FUNCHECK(f)); /* p and s are arbitrary client-provided closure data. */ arena = GlobalsArena(arenaGlobals); /* Scan all the roots with a minimal trace. Invoke the scanner with a */ /* rootsStepClosure, which is a subclass of ScanState and contains the */ /* client-provided closure. Supply a special fix method in order to */ /* call the client closure. This fix method must perform no tracing */ /* operations of its own. */ res = TraceCreate(&trace, arena, TraceStartWhyWALK); /* Have to fail if no trace available. Unlikely due to .assume.parked. */ if (res != ResOK) return res; /* ArenaRootsWalk only passes references to GCable pools to the client. */ /* NOTE: I'm not sure why this is. RB 2012-07-24 */ if (SegFirst(&seg, arena)) { do { if (PoolHasAttr(SegPool(seg), AttrGC)) { res = TraceAddWhite(trace, seg); AVER(res == ResOK); } } while (SegNext(&seg, arena, seg)); } /* Make the roots grey so that they are scanned */ res = RootsIterate(arenaGlobals, rootWalkGrey, trace); /* Make this trace look like any other trace. */ arena->flippedTraces = TraceSetAdd(arena->flippedTraces, trace); rootsStepClosureInit(rsc, arenaGlobals, trace, RootsWalkFix, f, p, s); ss = rootsStepClosure2ScanState(rsc); for(rank = RankAMBIG; rank < RankLIMIT; ++rank) { ss->rank = rank; AVERT(ScanState, ss); res = RootsIterate(arenaGlobals, rootWalk, (void *)ss); if (res != ResOK) break; } /* Turn segments black again. */ if (SegFirst(&seg, arena)) { do { if (PoolHasAttr(SegPool(seg), AttrGC)) { SegSetGrey(seg, TraceSetDel(SegGrey(seg), trace)); SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); } } while (SegNext(&seg, arena, seg)); } rootsStepClosureFinish(rsc); /* Make this trace look like any other finished trace. */ trace->state = TraceFINISHED; TraceDestroy(trace); AVER(!ArenaEmergency(arena)); /* There was no allocation. */ return res; }