void minorCheneyCopyGC (GC_state s) { size_t bytesAllocated; size_t bytesCopied; struct rusage ru_start; if (DEBUG_GENERATIONAL) fprintf (stderr, "minorGC nursery = "FMTPTR" frontier = "FMTPTR"\n", (uintptr_t)s->heap.nursery, (uintptr_t)s->frontier); assert (invariantForGC (s)); bytesAllocated = s->frontier - s->heap.nursery; if (bytesAllocated == 0) return; s->cumulativeStatistics.bytesAllocated += bytesAllocated; if (not s->canMinor) { s->heap.oldGenSize += bytesAllocated; bytesCopied = 0; } else { if (detailedGCTime (s)) startTiming (&ru_start); s->cumulativeStatistics.numMinorGCs++; s->forwardState.amInMinorGC = TRUE; if (DEBUG_GENERATIONAL or s->controls.messages) { fprintf (stderr, "[GC: Starting minor Cheney-copy;]\n"); fprintf (stderr, "[GC:\tfrom nursery at "FMTPTR" of size %s bytes.]\n", (uintptr_t)(s->heap.nursery), uintmaxToCommaString(bytesAllocated)); } s->forwardState.toStart = s->heap.start + s->heap.oldGenSize; assert (isFrontierAligned (s, s->forwardState.toStart)); s->forwardState.toLimit = s->forwardState.toStart + bytesAllocated; assert (invariantForGC (s)); s->forwardState.back = s->forwardState.toStart; /* Forward all globals. Would like to avoid doing this once all * the globals have been assigned. */ foreachGlobalObjptr (s, forwardObjptrIfInNursery); forwardInterGenerationalObjptrs (s); foreachObjptrInRange (s, s->forwardState.toStart, &s->forwardState.back, forwardObjptrIfInNursery, TRUE); updateWeaksForCheneyCopy (s); bytesCopied = s->forwardState.back - s->forwardState.toStart; s->cumulativeStatistics.bytesCopiedMinor += bytesCopied; s->heap.oldGenSize += bytesCopied; s->lastMajorStatistics.numMinorGCs++; if (detailedGCTime (s)) stopTiming (&ru_start, &s->cumulativeStatistics.ru_gcMinor); if (DEBUG_GENERATIONAL or s->controls.messages) fprintf (stderr, "[GC: Finished minor Cheney-copy; copied %s bytes.]\n", uintmaxToCommaString(bytesCopied)); } }
/* enter and leave should be called at the start and end of every GC * function that is exported to the outside world. They make sure * that the function is run in a critical section and check the GC * invariant. */ void enter (GC_state s) { if (DEBUG) fprintf (stderr, "enter\n"); /* used needs to be set because the mutator has changed s->stackTop. */ getStackCurrent(s)->used = sizeofGCStateCurrentStackUsed (s); getThreadCurrent(s)->exnStack = s->exnStack; if (DEBUG) displayGCState (s, stderr); beginAtomic (s); assert (invariantForGC (s)); if (DEBUG) fprintf (stderr, "enter ok\n"); }
void performGC (GC_state s, size_t oldGenBytesRequested, size_t nurseryBytesRequested, bool forceMajor, bool mayResize) { uintmax_t gcTime; bool stackTopOk; size_t stackBytesRequested; struct rusage ru_start; size_t totalBytesRequested; enterGC (s); s->cumulativeStatistics.numGCs++; if (DEBUG or s->controls.messages) { size_t nurserySize = s->heap.size - ((size_t)(s->heap.nursery - s->heap.start)); size_t nurseryUsed = (size_t)(s->frontier - s->heap.nursery); fprintf (stderr, "[GC: Starting gc #%s; requesting %s nursery bytes and %s old-gen bytes,]\n", uintmaxToCommaString(s->cumulativeStatistics.numGCs), uintmaxToCommaString(nurseryBytesRequested), uintmaxToCommaString(oldGenBytesRequested)); fprintf (stderr, "[GC:\theap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map),]\n", (uintptr_t)(s->heap.start), uintmaxToCommaString(s->heap.size), uintmaxToCommaString(s->heap.withMapsSize - s->heap.size)); fprintf (stderr, "[GC:\twith old-gen of size %s bytes (%.1f%% of heap),]\n", uintmaxToCommaString(s->heap.oldGenSize), 100.0 * ((double)(s->heap.oldGenSize) / (double)(s->heap.size))); fprintf (stderr, "[GC:\tand nursery of size %s bytes (%.1f%% of heap),]\n", uintmaxToCommaString(nurserySize), 100.0 * ((double)(nurserySize) / (double)(s->heap.size))); fprintf (stderr, "[GC:\tand nursery using %s bytes (%.1f%% of heap, %.1f%% of nursery).]\n", uintmaxToCommaString(nurseryUsed), 100.0 * ((double)(nurseryUsed) / (double)(s->heap.size)), 100.0 * ((double)(nurseryUsed) / (double)(nurserySize))); } assert (invariantForGC (s)); if (needGCTime (s)) startTiming (&ru_start); minorGC (s); stackTopOk = invariantForMutatorStack (s); stackBytesRequested = stackTopOk ? 0 : sizeofStackWithHeader (s, sizeofStackGrowReserved (s, getStackCurrent (s))); totalBytesRequested = oldGenBytesRequested + nurseryBytesRequested + stackBytesRequested; if (forceMajor or totalBytesRequested > s->heap.size - s->heap.oldGenSize) majorGC (s, totalBytesRequested, mayResize); setGCStateCurrentHeap (s, oldGenBytesRequested + stackBytesRequested, nurseryBytesRequested); assert (hasHeapBytesFree (s, oldGenBytesRequested + stackBytesRequested, nurseryBytesRequested)); unless (stackTopOk) growStackCurrent (s); setGCStateCurrentThreadAndStack (s); if (needGCTime (s)) { gcTime = stopTiming (&ru_start, &s->cumulativeStatistics.ru_gc); s->cumulativeStatistics.maxPauseTime = max (s->cumulativeStatistics.maxPauseTime, gcTime); } else gcTime = 0; /* Assign gcTime to quell gcc warning. */ if (DEBUG or s->controls.messages) { size_t nurserySize = s->heap.size - (size_t)(s->heap.nursery - s->heap.start); fprintf (stderr, "[GC: Finished gc #%s; time %s ms,]\n", uintmaxToCommaString(s->cumulativeStatistics.numGCs), uintmaxToCommaString(gcTime)); fprintf (stderr, "[GC:\theap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map),]\n", (uintptr_t)(s->heap.start), uintmaxToCommaString(s->heap.size), uintmaxToCommaString(s->heap.withMapsSize - s->heap.size)); fprintf (stderr, "[GC:\twith old-gen of size %s bytes (%.1f%% of heap),]\n", uintmaxToCommaString(s->heap.oldGenSize), 100.0 * ((double)(s->heap.oldGenSize) / (double)(s->heap.size))); fprintf (stderr, "[GC:\tand nursery of size %s bytes (%.1f%% of heap).]\n", uintmaxToCommaString(nurserySize), 100.0 * ((double)(nurserySize) / (double)(s->heap.size))); } /* Send a GC signal. */ if (s->signalsInfo.gcSignalHandled and s->signalHandlerThread != BOGUS_OBJPTR) { if (DEBUG_SIGNALS) fprintf (stderr, "GC Signal pending.\n"); s->signalsInfo.gcSignalPending = TRUE; unless (s->signalsInfo.amInSignalHandler) s->signalsInfo.signalIsPending = TRUE; } if (DEBUG) displayGCState (s, stderr); assert (hasHeapBytesFree (s, oldGenBytesRequested, nurseryBytesRequested)); assert (invariantForGC (s)); leaveGC (s); }