Commit | Line | Data |
---|---|---|
7f918cf1 CE |
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. | |
5 | * | |
6 | * MLton is released under a BSD-style license. | |
7 | * See the file MLton-LICENSE for details. | |
8 | */ | |
9 | ||
10 | void minorGC (GC_state s) { | |
11 | minorCheneyCopyGC (s); | |
12 | } | |
13 | ||
14 | void majorGC (GC_state s, size_t bytesRequested, bool mayResize) { | |
15 | uintmax_t numGCs; | |
16 | size_t desiredSize; | |
17 | ||
18 | s->lastMajorStatistics.numMinorGCs = 0; | |
19 | numGCs = | |
20 | s->cumulativeStatistics.numCopyingGCs | |
21 | + s->cumulativeStatistics.numMarkCompactGCs; | |
22 | if (0 < numGCs | |
23 | and ((float)(s->cumulativeStatistics.numHashConsGCs) / (float)(numGCs) | |
24 | < s->controls.ratios.hashCons)) | |
25 | s->hashConsDuringGC = TRUE; | |
26 | desiredSize = | |
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); | |
34 | else | |
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. | |
44 | */ | |
45 | if (mayResize) { | |
46 | resizeHeap (s, s->lastMajorStatistics.bytesLive + bytesRequested); | |
47 | } | |
48 | setCardMapAndCrossMap (s); | |
49 | resizeHeapSecondary (s); | |
50 | assert (s->heap.oldGenSize + bytesRequested <= s->heap.size); | |
51 | } | |
52 | ||
53 | void growStackCurrent (GC_state s) { | |
54 | size_t reserved; | |
55 | GC_stack stack; | |
56 | ||
57 | reserved = sizeofStackGrowReserved (s, getStackCurrent(s)); | |
58 | if (DEBUG_STACKS or s->controls.messages) | |
59 | fprintf (stderr, | |
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)); | |
69 | } | |
70 | ||
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. | |
76 | */ | |
77 | if (s->profiling.stack | |
78 | and not (PROFILE_COUNT == s->profiling.kind)) | |
79 | GC_profileEnter (s); | |
80 | } | |
81 | s->amInGC = TRUE; | |
82 | } | |
83 | ||
84 | void leaveGC (GC_state s) { | |
85 | if (s->profiling.isOn) { | |
86 | if (s->profiling.stack | |
87 | and not (PROFILE_COUNT == s->profiling.kind)) | |
88 | GC_profileLeave (s); | |
89 | } | |
90 | s->amInGC = FALSE; | |
91 | } | |
92 | ||
93 | void performGC (GC_state s, | |
94 | size_t oldGenBytesRequested, | |
95 | size_t nurseryBytesRequested, | |
96 | bool forceMajor, | |
97 | bool mayResize) { | |
98 | uintmax_t gcTime; | |
99 | bool stackTopOk; | |
100 | size_t stackBytesRequested; | |
101 | struct rusage ru_start; | |
102 | size_t totalBytesRequested; | |
103 | ||
104 | enterGC (s); | |
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); | |
109 | fprintf (stderr, | |
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)); | |
114 | fprintf (stderr, | |
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)); | |
119 | fprintf (stderr, | |
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))); | |
123 | fprintf (stderr, | |
124 | "[GC:\tand nursery of size %s bytes (%.1f%% of heap),]\n", | |
125 | uintmaxToCommaString(nurserySize), | |
126 | 100.0 * ((double)(nurserySize) / (double)(s->heap.size))); | |
127 | fprintf (stderr, | |
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))); | |
132 | } | |
133 | assert (invariantForGC (s)); | |
134 | if (needGCTime (s)) | |
135 | startTiming (&ru_start); | |
136 | minorGC (s); | |
137 | stackTopOk = invariantForMutatorStack (s); | |
138 | stackBytesRequested = | |
139 | stackTopOk | |
140 | ? 0 | |
141 | : sizeofStackWithMetaData (s, sizeofStackGrowReserved (s, getStackCurrent (s))); | |
142 | totalBytesRequested = | |
143 | oldGenBytesRequested | |
144 | + nurseryBytesRequested | |
145 | + stackBytesRequested; | |
146 | if (forceMajor | |
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)); | |
153 | unless (stackTopOk) | |
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); | |
160 | } else | |
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); | |
164 | fprintf (stderr, | |
165 | "[GC: Finished gc #%s; time %s ms,]\n", | |
166 | uintmaxToCommaString(s->cumulativeStatistics.numGCs), | |
167 | uintmaxToCommaString(gcTime)); | |
168 | fprintf (stderr, | |
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)); | |
173 | fprintf (stderr, | |
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))); | |
177 | fprintf (stderr, | |
178 | "[GC:\tand nursery of size %s bytes (%.1f%% of heap).]\n", | |
179 | uintmaxToCommaString(nurserySize), | |
180 | 100.0 * ((double)(nurserySize) / (double)(s->heap.size))); | |
181 | } | |
182 | /* Send a GC signal. */ | |
183 | if (s->signalsInfo.gcSignalHandled | |
184 | and s->signalHandlerThread != BOGUS_OBJPTR) { | |
185 | if (DEBUG_SIGNALS) | |
186 | fprintf (stderr, "GC Signal pending.\n"); | |
187 | s->signalsInfo.gcSignalPending = TRUE; | |
188 | unless (s->signalsInfo.amInSignalHandler) | |
189 | s->signalsInfo.signalIsPending = TRUE; | |
190 | } | |
191 | if (DEBUG) | |
192 | displayGCState (s, stderr); | |
193 | assert (hasHeapBytesFree (s, oldGenBytesRequested, nurseryBytesRequested)); | |
194 | assert (invariantForGC (s)); | |
195 | leaveGC (s); | |
196 | } | |
197 | ||
198 | void ensureInvariantForMutator (GC_state s, bool force) { | |
199 | if (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); | |
204 | } | |
205 | assert (invariantForMutatorFrontier(s)); | |
206 | assert (invariantForMutatorStack(s)); | |
207 | } | |
208 | ||
209 | /* ensureHasHeapBytesFree (s, oldGen, nursery) | |
210 | */ | |
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)); | |
219 | } | |
220 | ||
221 | void GC_collect (GC_state s, size_t bytesRequested, bool force) { | |
222 | enter (s); | |
223 | /* When the mutator requests zero bytes, it may actually need as | |
224 | * much as GC_HEAP_LIMIT_SLOP. | |
225 | */ | |
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)); | |
233 | leave (s); | |
234 | } |