1 /* Copyright (C) 2009-2010,2012,2016 Matthew Fluet.
2 * Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 void minorGC (GC_state s
) {
11 minorCheneyCopyGC (s
);
14 void majorGC (GC_state s
, size_t bytesRequested
, bool mayResize
) {
18 s
->lastMajorStatistics
.numMinorGCs
= 0;
20 s
->cumulativeStatistics
.numCopyingGCs
21 + s
->cumulativeStatistics
.numMarkCompactGCs
;
23 and ((float)(s
->cumulativeStatistics
.numHashConsGCs
) / (float)(numGCs
)
24 < s
->controls
.ratios
.hashCons
))
25 s
->hashConsDuringGC
= TRUE
;
27 sizeofHeapDesired (s
, s
->lastMajorStatistics
.bytesLive
+ bytesRequested
, 0);
28 if (not FORCE_MARK_COMPACT
29 and not s
->hashConsDuringGC
// only markCompact can hash cons
30 and s
->heap
.withMapsSize
< s
->sysvals
.ram
31 and (not isHeapInit (&s
->secondaryHeap
)
32 or createHeapSecondary (s
, desiredSize
)))
33 majorCheneyCopyGC (s
);
35 majorMarkCompactGC (s
);
36 s
->hashConsDuringGC
= FALSE
;
37 s
->lastMajorStatistics
.bytesLive
= s
->heap
.oldGenSize
;
38 if (s
->lastMajorStatistics
.bytesLive
> s
->cumulativeStatistics
.maxBytesLive
)
39 s
->cumulativeStatistics
.maxBytesLive
= s
->lastMajorStatistics
.bytesLive
;
40 /* Notice that the s->lastMajorStatistics.bytesLive below is
41 * different than the s->lastMajorStatistics.bytesLive used as an
42 * argument to createHeapSecondary above. Above, it was an
43 * estimate. Here, it is exactly how much was live after the GC.
46 resizeHeap (s
, s
->lastMajorStatistics
.bytesLive
+ bytesRequested
);
48 setCardMapAndCrossMap (s
);
49 resizeHeapSecondary (s
);
50 assert (s
->heap
.oldGenSize
+ bytesRequested
<= s
->heap
.size
);
53 void growStackCurrent (GC_state s
) {
57 reserved
= sizeofStackGrowReserved (s
, getStackCurrent(s
));
58 if (DEBUG_STACKS
or s
->controls
.messages
)
60 "[GC: Growing stack of size %s bytes to size %s bytes, using %s bytes.]\n",
61 uintmaxToCommaString(getStackCurrent(s
)->reserved
),
62 uintmaxToCommaString(reserved
),
63 uintmaxToCommaString(getStackCurrent(s
)->used
));
64 assert (hasHeapBytesFree (s
, sizeofStackWithMetaData (s
, reserved
), 0));
65 stack
= newStack (s
, reserved
, TRUE
);
66 copyStack (s
, getStackCurrent(s
), stack
);
67 getThreadCurrent(s
)->stack
= pointerToObjptr ((pointer
)stack
, s
->heap
.start
);
68 markCard (s
, objptrToPointer (getThreadCurrentObjptr(s
), s
->heap
.start
));
71 void enterGC (GC_state s
) {
72 if (s
->profiling
.isOn
) {
73 /* We don't need to profileEnter for count profiling because it
74 * has already bumped the counter. If we did allow the bump, then
75 * the count would look like function(s) had run an extra time.
77 if (s
->profiling
.stack
78 and not (PROFILE_COUNT
== s
->profiling
.kind
))
84 void leaveGC (GC_state s
) {
85 if (s
->profiling
.isOn
) {
86 if (s
->profiling
.stack
87 and not (PROFILE_COUNT
== s
->profiling
.kind
))
93 void performGC (GC_state s
,
94 size_t oldGenBytesRequested
,
95 size_t nurseryBytesRequested
,
100 size_t stackBytesRequested
;
101 struct rusage ru_start
;
102 size_t totalBytesRequested
;
105 s
->cumulativeStatistics
.numGCs
++;
106 if (DEBUG
or s
->controls
.messages
) {
107 size_t nurserySize
= s
->heap
.size
- ((size_t)(s
->heap
.nursery
- s
->heap
.start
));
108 size_t nurseryUsed
= (size_t)(s
->frontier
- s
->heap
.nursery
);
110 "[GC: Starting gc #%s; requesting %s nursery bytes and %s old-gen bytes,]\n",
111 uintmaxToCommaString(s
->cumulativeStatistics
.numGCs
),
112 uintmaxToCommaString(nurseryBytesRequested
),
113 uintmaxToCommaString(oldGenBytesRequested
));
115 "[GC:\theap at "FMTPTR
" of size %s bytes (+ %s bytes card/cross map),]\n",
116 (uintptr_t)(s
->heap
.start
),
117 uintmaxToCommaString(s
->heap
.size
),
118 uintmaxToCommaString(s
->heap
.withMapsSize
- s
->heap
.size
));
120 "[GC:\twith old-gen of size %s bytes (%.1f%% of heap),]\n",
121 uintmaxToCommaString(s
->heap
.oldGenSize
),
122 100.0 * ((double)(s
->heap
.oldGenSize
) / (double)(s
->heap
.size
)));
124 "[GC:\tand nursery of size %s bytes (%.1f%% of heap),]\n",
125 uintmaxToCommaString(nurserySize
),
126 100.0 * ((double)(nurserySize
) / (double)(s
->heap
.size
)));
128 "[GC:\tand nursery using %s bytes (%.1f%% of heap, %.1f%% of nursery).]\n",
129 uintmaxToCommaString(nurseryUsed
),
130 100.0 * ((double)(nurseryUsed
) / (double)(s
->heap
.size
)),
131 100.0 * ((double)(nurseryUsed
) / (double)(nurserySize
)));
133 assert (invariantForGC (s
));
135 startTiming (&ru_start
);
137 stackTopOk
= invariantForMutatorStack (s
);
138 stackBytesRequested
=
141 : sizeofStackWithMetaData (s
, sizeofStackGrowReserved (s
, getStackCurrent (s
)));
142 totalBytesRequested
=
144 + nurseryBytesRequested
145 + stackBytesRequested
;
147 or totalBytesRequested
> s
->heap
.size
- s
->heap
.oldGenSize
)
148 majorGC (s
, totalBytesRequested
, mayResize
);
149 setGCStateCurrentHeap (s
, oldGenBytesRequested
+ stackBytesRequested
,
150 nurseryBytesRequested
);
151 assert (hasHeapBytesFree (s
, oldGenBytesRequested
+ stackBytesRequested
,
152 nurseryBytesRequested
));
154 growStackCurrent (s
);
155 setGCStateCurrentThreadAndStack (s
);
156 if (needGCTime (s
)) {
157 gcTime
= stopTiming (&ru_start
, &s
->cumulativeStatistics
.ru_gc
);
158 s
->cumulativeStatistics
.maxPauseTime
=
159 max (s
->cumulativeStatistics
.maxPauseTime
, gcTime
);
161 gcTime
= 0; /* Assign gcTime to quell gcc warning. */
162 if (DEBUG
or s
->controls
.messages
) {
163 size_t nurserySize
= s
->heap
.size
- (size_t)(s
->heap
.nursery
- s
->heap
.start
);
165 "[GC: Finished gc #%s; time %s ms,]\n",
166 uintmaxToCommaString(s
->cumulativeStatistics
.numGCs
),
167 uintmaxToCommaString(gcTime
));
169 "[GC:\theap at "FMTPTR
" of size %s bytes (+ %s bytes card/cross map),]\n",
170 (uintptr_t)(s
->heap
.start
),
171 uintmaxToCommaString(s
->heap
.size
),
172 uintmaxToCommaString(s
->heap
.withMapsSize
- s
->heap
.size
));
174 "[GC:\twith old-gen of size %s bytes (%.1f%% of heap),]\n",
175 uintmaxToCommaString(s
->heap
.oldGenSize
),
176 100.0 * ((double)(s
->heap
.oldGenSize
) / (double)(s
->heap
.size
)));
178 "[GC:\tand nursery of size %s bytes (%.1f%% of heap).]\n",
179 uintmaxToCommaString(nurserySize
),
180 100.0 * ((double)(nurserySize
) / (double)(s
->heap
.size
)));
182 /* Send a GC signal. */
183 if (s
->signalsInfo
.gcSignalHandled
184 and s
->signalHandlerThread
!= BOGUS_OBJPTR
) {
186 fprintf (stderr
, "GC Signal pending.\n");
187 s
->signalsInfo
.gcSignalPending
= TRUE
;
188 unless (s
->signalsInfo
.amInSignalHandler
)
189 s
->signalsInfo
.signalIsPending
= TRUE
;
192 displayGCState (s
, stderr
);
193 assert (hasHeapBytesFree (s
, oldGenBytesRequested
, nurseryBytesRequested
));
194 assert (invariantForGC (s
));
198 void ensureInvariantForMutator (GC_state s
, bool force
) {
200 or not (invariantForMutatorFrontier(s
))
201 or not (invariantForMutatorStack(s
))) {
202 /* This GC will grow the stack, if necessary. */
203 performGC (s
, 0, getThreadCurrent(s
)->bytesNeeded
, force
, TRUE
);
205 assert (invariantForMutatorFrontier(s
));
206 assert (invariantForMutatorStack(s
));
209 /* ensureHasHeapBytesFree (s, oldGen, nursery)
211 void ensureHasHeapBytesFree (GC_state s
,
212 size_t oldGenBytesRequested
,
213 size_t nurseryBytesRequested
) {
214 assert (s
->heap
.nursery
<= s
->limitPlusSlop
);
215 assert (s
->frontier
<= s
->limitPlusSlop
);
216 if (not hasHeapBytesFree (s
, oldGenBytesRequested
, nurseryBytesRequested
))
217 performGC (s
, oldGenBytesRequested
, nurseryBytesRequested
, FALSE
, TRUE
);
218 assert (hasHeapBytesFree (s
, oldGenBytesRequested
, nurseryBytesRequested
));
221 void GC_collect (GC_state s
, size_t bytesRequested
, bool force
) {
223 /* When the mutator requests zero bytes, it may actually need as
224 * much as GC_HEAP_LIMIT_SLOP.
226 if (0 == bytesRequested
)
227 bytesRequested
= GC_HEAP_LIMIT_SLOP
;
228 getThreadCurrent(s
)->bytesNeeded
= bytesRequested
;
229 switchToSignalHandlerThreadIfNonAtomicAndSignalPending (s
);
230 ensureInvariantForMutator (s
, force
);
231 assert (invariantForMutatorFrontier(s
));
232 assert (invariantForMutatorStack(s
));