Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | /* Copyright (C) 2009-2012 Matthew Fluet. |
2 | * Copyright (C) 2005-2008 Henry Cejtin, Matthew Fluet, Suresh | |
3 | * Jagannathan, and Stephen Weeks. | |
4 | * | |
5 | * MLton is released under a BSD-style license. | |
6 | * See the file MLton-LICENSE for details. | |
7 | */ | |
8 | ||
9 | void displayHeap (__attribute__ ((unused)) GC_state s, | |
10 | GC_heap heap, | |
11 | FILE *stream) { | |
12 | fprintf(stream, | |
13 | "\t\tnursery = "FMTPTR"\n" | |
14 | "\t\toldGenSize = %"PRIuMAX"\n" | |
15 | "\t\tsize = %"PRIuMAX"\n" | |
16 | "\t\tstart = "FMTPTR"\n" | |
17 | "\t\twithMapsSize = %"PRIuMAX"\n", | |
18 | (uintptr_t)heap->nursery, | |
19 | (uintmax_t)heap->oldGenSize, | |
20 | (uintmax_t)heap->size, | |
21 | (uintptr_t)heap->start, | |
22 | (uintmax_t)heap->withMapsSize); | |
23 | } | |
24 | ||
25 | ||
26 | void initHeap (__attribute__ ((unused)) GC_state s, | |
27 | GC_heap h) { | |
28 | h->nursery = NULL; | |
29 | h->oldGenSize = 0; | |
30 | h->size = 0; | |
31 | h->start = NULL; | |
32 | h->withMapsSize = 0; | |
33 | } | |
34 | ||
35 | /* sizeofHeapDesired (s, l, cs) | |
36 | * | |
37 | * returns the desired heap size for a heap with l bytes live, | |
38 | * given that the current heap size is cs. | |
39 | */ | |
40 | size_t sizeofHeapDesired (GC_state s, size_t liveSize, size_t currentSize) { | |
41 | size_t liveMapsSize, liveWithMapsSize; | |
42 | size_t currentMapsSize, currentWithMapsSize; | |
43 | size_t resSize, resWithMapsSize; | |
44 | size_t syslimSize, syslimWithMapsSize; | |
45 | LOCAL_USED_FOR_ASSERT size_t syslimMapsSize; | |
46 | double ratio; | |
47 | ||
48 | syslimWithMapsSize = alignDown (SIZE_MAX, s->sysvals.pageSize); | |
49 | syslimSize = invertSizeofCardMapAndCrossMap (s, syslimWithMapsSize); | |
50 | syslimMapsSize = sizeofCardMapAndCrossMap (s, syslimSize); | |
51 | assert (syslimSize + syslimMapsSize <= syslimWithMapsSize); | |
52 | ||
53 | liveSize = align (liveSize, s->sysvals.pageSize); | |
54 | if (syslimSize < liveSize) | |
55 | die ("Out of memory with system-limit heap size %s.\n", | |
56 | uintmaxToCommaString(syslimSize)); | |
57 | liveMapsSize = sizeofCardMapAndCrossMap (s, liveSize); | |
58 | liveWithMapsSize = liveSize + liveMapsSize; | |
59 | ||
60 | assert (isAligned (currentSize, s->sysvals.pageSize)); | |
61 | currentMapsSize = sizeofCardMapAndCrossMap (s, currentSize); | |
62 | currentWithMapsSize = currentSize + currentMapsSize; | |
63 | ||
64 | ratio = (double)s->sysvals.ram / (double)liveWithMapsSize; | |
65 | ||
66 | if (ratio >= s->controls.ratios.live + s->controls.ratios.grow) { | |
67 | /* Cheney copying fits in RAM with desired ratios.live. */ | |
68 | resWithMapsSize = (size_t)(liveWithMapsSize * s->controls.ratios.live); | |
69 | /* If the heap is currently close in size to what we want, leave | |
70 | * it alone. Favor growing over shrinking. | |
71 | */ | |
72 | if (0.5 * currentWithMapsSize <= resWithMapsSize | |
73 | and resWithMapsSize <= 1.1 * currentWithMapsSize) { | |
74 | resWithMapsSize = currentWithMapsSize; | |
75 | } else { | |
76 | resWithMapsSize = align (resWithMapsSize, s->sysvals.pageSize); | |
77 | } | |
78 | } else if (s->controls.ratios.grow >= s->controls.ratios.copy | |
79 | and ratio >= 2.0 * s->controls.ratios.copy) { | |
80 | /* Split RAM in half. Round down by pageSize so that the total | |
81 | * amount of space taken isn't greater than RAM once rounding | |
82 | * happens. This is so resizeHeapSecondary doesn't get confused | |
83 | * and free a semispace in a misguided attempt to avoid paging. | |
84 | */ | |
85 | resWithMapsSize = alignDown (s->sysvals.ram / 2, s->sysvals.pageSize); | |
86 | } else if (ratio >= s->controls.ratios.copy + s->controls.ratios.grow) { | |
87 | /* Cheney copying fits in RAM. */ | |
88 | resWithMapsSize = s->sysvals.ram - (size_t)(s->controls.ratios.grow * liveWithMapsSize); | |
89 | /* If the heap isn't too much smaller than what we want, leave it | |
90 | * alone. On the other hand, if it is bigger we want to leave | |
91 | * resWithMapsSize as is so that the heap is shrunk, to try to | |
92 | * avoid paging. | |
93 | */ | |
94 | if (1.0 * currentWithMapsSize <= resWithMapsSize | |
95 | and resWithMapsSize <= 1.1 * currentWithMapsSize) { | |
96 | resWithMapsSize = currentWithMapsSize; | |
97 | } else { | |
98 | resWithMapsSize = align (resWithMapsSize, s->sysvals.pageSize); | |
99 | } | |
100 | } else if (ratio >= s->controls.ratios.markCompact) { | |
101 | /* Mark compact fits in RAM. It doesn't matter what the current | |
102 | * size is. If the heap is currently smaller, we are using | |
103 | * copying and should switch to mark-compact. If the heap is | |
104 | * currently bigger, we want to shrink back to RAM to avoid | |
105 | * paging. | |
106 | */ | |
107 | resWithMapsSize = s->sysvals.ram; | |
108 | } else { /* Required live ratio. */ | |
109 | double resWithMapsSizeD = liveWithMapsSize * (double)(s->controls.ratios.markCompact); | |
110 | if (resWithMapsSizeD > (double)syslimWithMapsSize) { | |
111 | resWithMapsSize = syslimWithMapsSize; | |
112 | } else { | |
113 | resWithMapsSize = align ((size_t)resWithMapsSizeD, s->sysvals.pageSize); | |
114 | } | |
115 | /* If the current heap is bigger than resWithMapsSize, then | |
116 | * shrinking always sounds like a good idea. However, depending | |
117 | * on what pages the VM keeps around, growing could be very | |
118 | * expensive, if it involves paging the entire heap. Hopefully | |
119 | * the copy loop in growHeap will make the right thing happen. | |
120 | */ | |
121 | } | |
122 | if (s->controls.fixedHeap > 0) { | |
123 | if (resWithMapsSize > s->controls.fixedHeap / 2) | |
124 | resWithMapsSize = s->controls.fixedHeap; | |
125 | else | |
126 | resWithMapsSize = s->controls.fixedHeap / 2; | |
127 | if (resWithMapsSize < liveWithMapsSize) | |
128 | die ("Out of memory with fixed heap size %s.", | |
129 | uintmaxToCommaString(s->controls.fixedHeap)); | |
130 | } else if (s->controls.maxHeap > 0) { | |
131 | if (resWithMapsSize > s->controls.maxHeap) | |
132 | resWithMapsSize = s->controls.maxHeap; | |
133 | if (resWithMapsSize < liveWithMapsSize) | |
134 | die ("Out of memory with max heap size %s.", | |
135 | uintmaxToCommaString(s->controls.maxHeap)); | |
136 | } | |
137 | resSize = invertSizeofCardMapAndCrossMap (s, resWithMapsSize); | |
138 | assert (isAligned (resSize, s->sysvals.pageSize)); | |
139 | if (DEBUG_RESIZING) | |
140 | fprintf (stderr, "%s = sizeofHeapDesired (%s, %s)\n", | |
141 | uintmaxToCommaString(resSize), | |
142 | uintmaxToCommaString(liveSize), | |
143 | uintmaxToCommaString(currentSize)); | |
144 | assert (resSize >= liveSize); | |
145 | return resSize; | |
146 | } | |
147 | ||
148 | void releaseHeap (GC_state s, GC_heap h) { | |
149 | if (NULL == h->start) | |
150 | return; | |
151 | if (DEBUG or s->controls.messages) | |
152 | fprintf (stderr, | |
153 | "[GC: Releasing heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map).]\n", | |
154 | (uintptr_t)(h->start), | |
155 | uintmaxToCommaString(h->size), | |
156 | uintmaxToCommaString(h->withMapsSize - h->size)); | |
157 | GC_release (h->start, h->withMapsSize); | |
158 | initHeap (s, h); | |
159 | } | |
160 | ||
161 | /* shrinkHeap (s, h, keepSize) | |
162 | */ | |
163 | void shrinkHeap (GC_state s, GC_heap h, size_t keepSize) { | |
164 | assert (keepSize <= h->size); | |
165 | if (0 == keepSize) { | |
166 | releaseHeap (s, h); | |
167 | return; | |
168 | } | |
169 | keepSize = align (keepSize, s->sysvals.pageSize); | |
170 | if (keepSize < h->size) { | |
171 | size_t keepWithMapsSize; | |
172 | keepWithMapsSize = keepSize + sizeofCardMapAndCrossMap (s, keepSize); | |
173 | if (DEBUG or s->controls.messages) { | |
174 | fprintf (stderr, | |
175 | "[GC: Shrinking heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map)]\n", | |
176 | (uintptr_t)(h->start), | |
177 | uintmaxToCommaString(h->size), | |
178 | uintmaxToCommaString(h->withMapsSize - h->size)); | |
179 | fprintf (stderr, | |
180 | "[GC:\tto size %s bytes (+ %s bytes card/cross map).]\n", | |
181 | uintmaxToCommaString(keepSize), | |
182 | uintmaxToCommaString(keepWithMapsSize - keepSize)); | |
183 | } | |
184 | assert (isAligned (keepWithMapsSize, s->sysvals.pageSize)); | |
185 | assert (keepWithMapsSize <= h->withMapsSize); | |
186 | GC_release (h->start + keepWithMapsSize, h->withMapsSize - keepWithMapsSize); | |
187 | h->size = keepSize; | |
188 | h->withMapsSize = keepWithMapsSize; | |
189 | } | |
190 | } | |
191 | ||
192 | /* createHeap (s, h, desiredSize, minSize) | |
193 | * | |
194 | * allocates a heap of the size necessary to work with desiredSize | |
195 | * live data, and ensures that at least minSize is available. It | |
196 | * returns TRUE if it is able to allocate the space, and returns FALSE | |
197 | * if it is unable. | |
198 | */ | |
199 | bool createHeap (GC_state s, GC_heap h, | |
200 | size_t desiredSize, | |
201 | size_t minSize) { | |
202 | size_t newSize; | |
203 | size_t newWithMapsSize; | |
204 | ||
205 | if (DEBUG_MEM) | |
206 | fprintf (stderr, "createHeap desired size = %s min size = %s\n", | |
207 | uintmaxToCommaString(desiredSize), | |
208 | uintmaxToCommaString(minSize)); | |
209 | if (desiredSize < minSize) | |
210 | desiredSize = minSize; | |
211 | minSize = align (minSize, s->sysvals.pageSize); | |
212 | desiredSize = align (desiredSize, s->sysvals.pageSize); | |
213 | assert (isHeapInit (h) and NULL == h->start); | |
214 | /* Biased binary search (between minSize and desiredSize) for a | |
215 | * successful mmap. | |
216 | * Toggle back and forth between high and low addresses to decrease | |
217 | * the chance of virtual memory fragmentation; important for large | |
218 | * heaps. | |
219 | * Always try a NULL address last. | |
220 | */ | |
221 | size_t factor = 16; | |
222 | const size_t maxFactor = s->sysvals.pageSize; | |
223 | size_t lowSize = minSize; | |
224 | size_t highSize = desiredSize; | |
225 | newSize = highSize; | |
226 | unsigned int loopCount = 0; | |
227 | while (lowSize <= highSize) { | |
228 | pointer newStart; | |
229 | ||
230 | newWithMapsSize = newSize + sizeofCardMapAndCrossMap (s, newSize); | |
231 | ||
232 | assert (isAligned (newWithMapsSize, s->sysvals.pageSize)); | |
233 | ||
234 | const unsigned int addressCountLog2 = 5; | |
235 | const unsigned int addressCount = 0x1 << addressCountLog2; | |
236 | const size_t addressStep = (size_t)0x1 << (ADDRESS_BITS - addressCountLog2); | |
237 | #if ADDRESS_BITS == POINTER_BITS | |
238 | const size_t addressHigh = 0; | |
239 | #else | |
240 | const size_t addressHigh = (size_t)0x1 << ADDRESS_BITS; | |
241 | #endif | |
242 | static bool addressScanDir = TRUE; | |
243 | for (unsigned int i = 1; i <= addressCount; i++) { | |
244 | size_t address = (size_t)i * addressStep; | |
245 | if (addressScanDir) | |
246 | address = addressHigh - address; | |
247 | /* Always use 0 in the last step. */ | |
248 | if (i == addressCount) | |
249 | address = 0; | |
250 | ||
251 | newStart = GC_mmapAnon ((pointer)address, newWithMapsSize); | |
252 | unless ((void*)-1 == newStart) { | |
253 | addressScanDir = not addressScanDir; | |
254 | h->start = newStart; | |
255 | h->size = newSize; | |
256 | h->withMapsSize = newWithMapsSize; | |
257 | if (h->size > s->cumulativeStatistics.maxHeapSize) | |
258 | s->cumulativeStatistics.maxHeapSize = h->size; | |
259 | assert (minSize <= h->size and h->size <= desiredSize); | |
260 | if (DEBUG or s->controls.messages) | |
261 | fprintf (stderr, | |
262 | "[GC: Created heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map).]\n", | |
263 | (uintptr_t)(h->start), | |
264 | uintmaxToCommaString(h->size), | |
265 | uintmaxToCommaString(h->withMapsSize - h->size)); | |
266 | return TRUE; | |
267 | } | |
268 | } | |
269 | size_t prevSize = newSize; | |
270 | size_t prevWithMapsSize = newWithMapsSize; | |
271 | highSize = newSize - s->sysvals.pageSize; | |
272 | newSize = align((factor-1) * (highSize / factor) + (lowSize / factor), s->sysvals.pageSize); | |
273 | if (s->controls.messages) { | |
274 | fprintf (stderr, | |
275 | "[GC: Creating heap of size %s bytes (+ %s bytes card/cross map) cannot be satisfied,]\n", | |
276 | uintmaxToCommaString (prevSize), | |
277 | uintmaxToCommaString (prevWithMapsSize - prevSize)); | |
278 | fprintf (stderr, | |
279 | "[GC:\tbacking off by %s bytes with minimum size of %s bytes.]\n", | |
280 | uintmaxToCommaString (prevSize - newSize), | |
281 | uintmaxToCommaString (minSize)); | |
282 | } | |
283 | if (factor < maxFactor | |
284 | and ++loopCount % 64 == 0) { | |
285 | factor += factor; | |
286 | } | |
287 | } | |
288 | return FALSE; | |
289 | } | |
290 | ||
291 | /* createHeapSecondary (s, desiredSize) | |
292 | */ | |
293 | bool createHeapSecondary (GC_state s, size_t desiredSize) { | |
294 | size_t desiredWithMapsSize; | |
295 | size_t minSize, minWithMapsSize; | |
296 | desiredWithMapsSize = desiredSize + sizeofCardMapAndCrossMap (s, desiredSize); | |
297 | if ((s->controls.fixedHeap > 0 | |
298 | and s->heap.withMapsSize + desiredWithMapsSize > s->controls.fixedHeap) | |
299 | or (s->controls.maxHeap > 0 | |
300 | and s->heap.withMapsSize + desiredWithMapsSize > s->controls.maxHeap)) | |
301 | return FALSE; | |
302 | minSize = align (s->heap.oldGenSize, s->sysvals.pageSize); | |
303 | minWithMapsSize = minSize + sizeofCardMapAndCrossMap (s, minSize); | |
304 | if (minWithMapsSize > SIZE_MAX - s->heap.withMapsSize) | |
305 | return FALSE; | |
306 | return createHeap (s, &s->secondaryHeap, desiredSize, s->heap.oldGenSize); | |
307 | } | |
308 | ||
309 | /* remapHeap (s, h, desiredSize, minSize) | |
310 | */ | |
311 | #if not HAS_REMAP | |
312 | bool remapHeap (__attribute__ ((unused)) GC_state s, | |
313 | __attribute__ ((unused)) GC_heap h, | |
314 | __attribute__ ((unused)) size_t desiredSize, | |
315 | __attribute__ ((unused)) size_t minSize) { | |
316 | return FALSE; | |
317 | } | |
318 | #else | |
319 | bool remapHeap (GC_state s, GC_heap h, | |
320 | size_t desiredSize, | |
321 | size_t minSize) { | |
322 | ||
323 | size_t newSize; | |
324 | size_t newWithMapsSize; | |
325 | int result; | |
326 | ||
327 | if (DEBUG_MEM) | |
328 | fprintf (stderr, "remapHeap desired size = %s min size = %s\n", | |
329 | uintmaxToCommaString(desiredSize), | |
330 | uintmaxToCommaString(minSize)); | |
331 | assert (minSize <= desiredSize); | |
332 | assert (desiredSize >= h->size); | |
333 | minSize = align (minSize, s->sysvals.pageSize); | |
334 | desiredSize = align (desiredSize, s->sysvals.pageSize); | |
335 | ||
336 | /* Biased binary search (between minSize and desiredSize) for a | |
337 | * successful mremap. | |
338 | */ | |
339 | size_t factor = 16; | |
340 | size_t lowSize = minSize; | |
341 | size_t highSize = desiredSize; | |
342 | newSize = highSize; | |
343 | result = FALSE; | |
344 | while (lowSize <= highSize) { | |
345 | pointer newStart; | |
346 | ||
347 | newWithMapsSize = newSize + sizeofCardMapAndCrossMap (s, newSize); | |
348 | ||
349 | assert (isAligned (newWithMapsSize, s->sysvals.pageSize)); | |
350 | ||
351 | newStart = GC_mremap (h->start, h->withMapsSize, newWithMapsSize); | |
352 | if ((void*)-1 != newStart) { | |
353 | pointer origStart = h->start; | |
354 | size_t origSize = h->size; | |
355 | size_t origWithMapsSize = h->withMapsSize; | |
356 | h->start = newStart; | |
357 | h->size = newSize; | |
358 | h->withMapsSize = newWithMapsSize; | |
359 | if (h->size > s->cumulativeStatistics.maxHeapSize) | |
360 | s->cumulativeStatistics.maxHeapSize = h->size; | |
361 | assert (minSize <= h->size and h->size <= desiredSize); | |
362 | if (DEBUG or s->controls.messages) { | |
363 | fprintf (stderr, | |
364 | "[GC: Remapped heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map)]\n", | |
365 | (uintptr_t)origStart, | |
366 | uintmaxToCommaString(origSize), | |
367 | uintmaxToCommaString(origWithMapsSize - origSize)); | |
368 | fprintf (stderr, | |
369 | "[GC:\tto heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map).]\n", | |
370 | (uintptr_t)(h->start), | |
371 | uintmaxToCommaString(h->size), | |
372 | uintmaxToCommaString(h->withMapsSize - h->size)); | |
373 | } | |
374 | lowSize = newSize + s->sysvals.pageSize; | |
375 | newSize = align((factor-1) * (highSize / factor) + (lowSize / factor), s->sysvals.pageSize); | |
376 | result = TRUE; | |
377 | } else { | |
378 | size_t prevSize = newSize; | |
379 | size_t prevWithMapsSize = newWithMapsSize; | |
380 | highSize = newSize - s->sysvals.pageSize; | |
381 | newSize = align((factor-1) * (highSize / factor) + (lowSize / factor), s->sysvals.pageSize); | |
382 | if (s->controls.messages) { | |
383 | fprintf (stderr, | |
384 | "[GC: Remapping heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map)]\n", | |
385 | (uintptr_t)(h->start), | |
386 | uintmaxToCommaString (h->size), | |
387 | uintmaxToCommaString (h->withMapsSize - h->size)); | |
388 | fprintf (stderr, | |
389 | "[GC:\tto heap of size %s bytes (+ %s bytes card/cross map) cannot be satisfied,]\n", | |
390 | uintmaxToCommaString (prevSize), | |
391 | uintmaxToCommaString (prevWithMapsSize - prevSize)); | |
392 | if (result) { | |
393 | fprintf (stderr, | |
394 | "[GC:\tbacking off by %s bytes.]\n", | |
395 | uintmaxToCommaString (prevSize - newSize)); | |
396 | } else { | |
397 | fprintf (stderr, | |
398 | "[GC:\tbacking off by %s bytes with minimum size of %s bytes.]\n", | |
399 | uintmaxToCommaString (prevSize - newSize), | |
400 | uintmaxToCommaString (minSize)); | |
401 | } | |
402 | } | |
403 | } | |
404 | } | |
405 | return result; | |
406 | } | |
407 | #endif | |
408 | ||
409 | enum { | |
410 | COPY_CHUNK_SIZE = 0x2000000, /* 32M */ | |
411 | }; | |
412 | ||
413 | /* growHeap (s, desiredSize, minSize) | |
414 | */ | |
415 | void growHeap (GC_state s, size_t desiredSize, size_t minSize) { | |
416 | GC_heap curHeapp; | |
417 | struct GC_heap newHeap; | |
418 | GC_heap newHeapp; | |
419 | ||
420 | bool useCurrent; | |
421 | pointer origStart; | |
422 | size_t liveSize; | |
423 | ||
424 | assert (isAligned (desiredSize, s->sysvals.pageSize)); | |
425 | assert (isAligned (minSize, s->sysvals.pageSize)); | |
426 | assert (desiredSize >= s->heap.size); | |
427 | if (DEBUG_RESIZING or s->controls.messages) { | |
428 | fprintf (stderr, | |
429 | "[GC: Growing heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map),]\n", | |
430 | (uintptr_t)s->heap.start, | |
431 | uintmaxToCommaString(s->heap.size), | |
432 | uintmaxToCommaString(s->heap.withMapsSize - s->heap.size)); | |
433 | fprintf (stderr, | |
434 | "[GC:\tto desired size of %s bytes (+ %s bytes card/cross map)]\n", | |
435 | uintmaxToCommaString(desiredSize), | |
436 | uintmaxToCommaString(sizeofCardMapAndCrossMap (s, desiredSize))); | |
437 | fprintf (stderr, | |
438 | "[GC:\tand minimum size of %s bytes (+ %s bytes card/cross map).]\n", | |
439 | uintmaxToCommaString(minSize), | |
440 | uintmaxToCommaString(sizeofCardMapAndCrossMap (s, minSize))); | |
441 | } | |
442 | if (minSize <= s->heap.size) { | |
443 | useCurrent = TRUE; | |
444 | /* Demand proper growth from remapHeap and/or createHeap. */ | |
445 | minSize = s->heap.size + s->sysvals.pageSize; | |
446 | } else { | |
447 | useCurrent = FALSE; | |
448 | } | |
449 | curHeapp = &s->heap; | |
450 | newHeapp = &newHeap; | |
451 | origStart = curHeapp->start; | |
452 | liveSize = curHeapp->oldGenSize; | |
453 | assert (liveSize <= curHeapp->size); | |
454 | if (remapHeap (s, curHeapp, desiredSize, minSize)) { | |
455 | goto done; | |
456 | } | |
457 | if (!useCurrent) | |
458 | shrinkHeap (s, curHeapp, liveSize); | |
459 | initHeap (s, newHeapp); | |
460 | /* Allocate a space of the desired size. */ | |
461 | if (minSize + sizeofCardMapAndCrossMap (s, minSize) <= SIZE_MAX - curHeapp->withMapsSize | |
462 | and createHeap (s, newHeapp, desiredSize, minSize)) { | |
463 | pointer from; | |
464 | pointer to; | |
465 | size_t remaining; | |
466 | ||
467 | from = curHeapp->start + liveSize; | |
468 | to = newHeapp->start + liveSize; | |
469 | remaining = liveSize; | |
470 | shrinkHeap (s, curHeapp, remaining); | |
471 | copy: | |
472 | assert (remaining == (size_t)(from - curHeapp->start) | |
473 | and from >= curHeapp->start | |
474 | and to >= newHeapp->start); | |
475 | if (remaining < COPY_CHUNK_SIZE) { | |
476 | GC_memcpy (curHeapp->start, newHeapp->start, remaining); | |
477 | releaseHeap (s, curHeapp); | |
478 | } else { | |
479 | remaining -= COPY_CHUNK_SIZE; | |
480 | from -= COPY_CHUNK_SIZE; | |
481 | to -= COPY_CHUNK_SIZE; | |
482 | GC_memcpy (from, to, COPY_CHUNK_SIZE); | |
483 | shrinkHeap (s, curHeapp, remaining); | |
484 | goto copy; | |
485 | } | |
486 | newHeapp->oldGenSize = liveSize; | |
487 | *curHeapp = *newHeapp; | |
488 | } else if (useCurrent) { | |
489 | if (DEBUG_RESIZING or s->controls.messages) { | |
490 | fprintf (stderr, | |
491 | "[GC: Using heap at "FMTPTR" of size %s bytes (+ %s bytes card/cross map).]\n", | |
492 | (uintptr_t)s->heap.start, | |
493 | uintmaxToCommaString(s->heap.size), | |
494 | uintmaxToCommaString(s->heap.withMapsSize - s->heap.size)); | |
495 | } | |
496 | } else if (s->controls.mayPageHeap) { | |
497 | /* Page the heap to disk and try again. */ | |
498 | void *data; | |
499 | ||
500 | if (DEBUG or s->controls.messages) { | |
501 | fprintf (stderr, | |
502 | "[GC: Writing heap at "FMTPTR" of size %s bytes to disk.]\n", | |
503 | (uintptr_t)curHeapp->start, | |
504 | uintmaxToCommaString(liveSize)); | |
505 | } | |
506 | data = GC_diskBack_write (curHeapp->start, liveSize); | |
507 | releaseHeap (s, curHeapp); | |
508 | if (createHeap (s, curHeapp, desiredSize, minSize)) { | |
509 | if (DEBUG or s->controls.messages) { | |
510 | fprintf (stderr, | |
511 | "[GC: Reading heap to "FMTPTR" of size %s bytes from disk.]\n", | |
512 | (uintptr_t)(curHeapp->start), | |
513 | uintmaxToCommaString(liveSize)); | |
514 | } | |
515 | GC_diskBack_read (data, curHeapp->start, liveSize); | |
516 | GC_diskBack_close (data); | |
517 | curHeapp->oldGenSize = liveSize; | |
518 | } else { | |
519 | GC_diskBack_close (data); | |
520 | goto oom; | |
521 | } | |
522 | } else { | |
523 | goto oom; | |
524 | } | |
525 | done: | |
526 | unless (origStart == s->heap.start) { | |
527 | translateHeap (s, origStart, s->heap.start, s->heap.oldGenSize); | |
528 | } | |
529 | return; | |
530 | oom: | |
531 | if (s->controls.messages) | |
532 | GC_displayMem (); | |
533 | die ("Out of memory. Unable to allocate heap with %s bytes.\n", | |
534 | uintmaxToCommaString(minSize)); | |
535 | } | |
536 | ||
537 | /* resizeHeap (s, minSize) | |
538 | */ | |
539 | void resizeHeap (GC_state s, size_t minSize) { | |
540 | size_t desiredSize; | |
541 | ||
542 | if (DEBUG_RESIZING) | |
543 | fprintf (stderr, "resizeHeap minSize = %s size = %s\n", | |
544 | uintmaxToCommaString(minSize), | |
545 | uintmaxToCommaString(s->heap.size)); | |
546 | desiredSize = sizeofHeapDesired (s, minSize, s->heap.size); | |
547 | assert (isAligned (desiredSize, s->sysvals.pageSize)); | |
548 | assert (minSize <= desiredSize); | |
549 | minSize = align (minSize, s->sysvals.pageSize); | |
550 | if (desiredSize <= s->heap.size) { | |
551 | shrinkHeap (s, &s->heap, desiredSize); | |
552 | } else { | |
553 | releaseHeap (s, &s->secondaryHeap); | |
554 | growHeap (s, desiredSize, minSize); | |
555 | } | |
556 | assert (s->heap.size >= minSize); | |
557 | } | |
558 | ||
559 | /* resizeHeapSecondary (s) | |
560 | */ | |
561 | void resizeHeapSecondary (GC_state s) { | |
562 | size_t primarySize, primaryWithMapsSize; | |
563 | size_t secondarySize; | |
564 | ||
565 | primarySize = s->heap.size; | |
566 | primaryWithMapsSize = s->heap.withMapsSize; | |
567 | secondarySize = s->secondaryHeap.size; | |
568 | if (DEBUG_RESIZING) | |
569 | fprintf (stderr, "secondaryHeapResize\n"); | |
570 | if (0 == secondarySize) | |
571 | return; | |
572 | if (2 * primaryWithMapsSize > s->sysvals.ram) | |
573 | /* Holding on to secondaryHeap might cause paging. So don't. */ | |
574 | releaseHeap (s, &s->secondaryHeap); | |
575 | else if (secondarySize < primarySize) { | |
576 | unless (remapHeap (s, &s->secondaryHeap, primarySize, primarySize)) | |
577 | releaseHeap (s, &s->secondaryHeap); | |
578 | } else if (secondarySize > primarySize) | |
579 | shrinkHeap (s, &s->secondaryHeap, primarySize); | |
580 | assert (0 == s->secondaryHeap.size | |
581 | or s->heap.size == s->secondaryHeap.size); | |
582 | } |