ggc-common.c (ggc_rlimit_bound): Cast RLIM_INFINITY to avoid warnings.
[gcc.git] / gcc / ggc-common.c
1 /* Simple garbage collection for the GNU compiler.
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
20
21 /* Generic garbage collection (GC) functions and data, not specific to
22 any particular GC implementation. */
23
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "hashtab.h"
28 #include "ggc.h"
29 #include "toplev.h"
30 #include "params.h"
31
32 #ifdef HAVE_SYS_RESOURCE_H
33 # include <sys/resource.h>
34 #endif
35
36 #ifdef HAVE_MMAP_FILE
37 # include <sys/mman.h>
38 #endif
39
40 #ifdef ENABLE_VALGRIND_CHECKING
41 #include <valgrind.h>
42 #else
43 /* Avoid #ifdef:s when we can help it. */
44 #define VALGRIND_DISCARD(x)
45 #endif
46
47 /* Statistics about the allocation. */
48 static ggc_statistics *ggc_stats;
49
50 struct traversal_state;
51
52 static int ggc_htab_delete PARAMS ((void **, void *));
53 static hashval_t saving_htab_hash PARAMS ((const PTR));
54 static int saving_htab_eq PARAMS ((const PTR, const PTR));
55 static int call_count PARAMS ((void **, void *));
56 static int call_alloc PARAMS ((void **, void *));
57 static int compare_ptr_data PARAMS ((const void *, const void *));
58 static void relocate_ptrs PARAMS ((void *, void *));
59 static void write_pch_globals PARAMS ((const struct ggc_root_tab * const *tab,
60 struct traversal_state *state));
61 static double ggc_rlimit_bound PARAMS ((double));
62
63 /* Maintain global roots that are preserved during GC. */
64
65 /* Process a slot of an htab by deleting it if it has not been marked. */
66
67 static int
68 ggc_htab_delete (slot, info)
69 void **slot;
70 void *info;
71 {
72 const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
73
74 if (! (*r->marked_p) (*slot))
75 htab_clear_slot (*r->base, slot);
76 else
77 (*r->cb) (*slot);
78
79 return 1;
80 }
81
82 /* Iterate through all registered roots and mark each element. */
83
84 void
85 ggc_mark_roots ()
86 {
87 const struct ggc_root_tab *const *rt;
88 const struct ggc_root_tab *rti;
89 const struct ggc_cache_tab *const *ct;
90 const struct ggc_cache_tab *cti;
91 size_t i;
92
93 for (rt = gt_ggc_deletable_rtab; *rt; rt++)
94 for (rti = *rt; rti->base != NULL; rti++)
95 memset (rti->base, 0, rti->stride);
96
97 for (rt = gt_ggc_rtab; *rt; rt++)
98 for (rti = *rt; rti->base != NULL; rti++)
99 for (i = 0; i < rti->nelt; i++)
100 (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
101
102 ggc_mark_stringpool ();
103
104 /* Now scan all hash tables that have objects which are to be deleted if
105 they are not already marked. */
106 for (ct = gt_ggc_cache_rtab; *ct; ct++)
107 for (cti = *ct; cti->base != NULL; cti++)
108 if (*cti->base)
109 {
110 ggc_set_mark (*cti->base);
111 htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti);
112 ggc_set_mark ((*cti->base)->entries);
113 }
114 }
115
116 /* Allocate a block of memory, then clear it. */
117 void *
118 ggc_alloc_cleared (size)
119 size_t size;
120 {
121 void *buf = ggc_alloc (size);
122 memset (buf, 0, size);
123 return buf;
124 }
125
126 /* Resize a block of memory, possibly re-allocating it. */
127 void *
128 ggc_realloc (x, size)
129 void *x;
130 size_t size;
131 {
132 void *r;
133 size_t old_size;
134
135 if (x == NULL)
136 return ggc_alloc (size);
137
138 old_size = ggc_get_size (x);
139 if (size <= old_size)
140 {
141 /* Mark the unwanted memory as unaccessible. We also need to make
142 the "new" size accessible, since ggc_get_size returns the size of
143 the pool, not the size of the individually allocated object, the
144 size which was previously made accessible. Unfortunately, we
145 don't know that previously allocated size. Without that
146 knowledge we have to lose some initialization-tracking for the
147 old parts of the object. An alternative is to mark the whole
148 old_size as reachable, but that would lose tracking of writes
149 after the end of the object (by small offsets). Discard the
150 handle to avoid handle leak. */
151 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size,
152 old_size - size));
153 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size));
154 return x;
155 }
156
157 r = ggc_alloc (size);
158
159 /* Since ggc_get_size returns the size of the pool, not the size of the
160 individually allocated object, we'd access parts of the old object
161 that were marked invalid with the memcpy below. We lose a bit of the
162 initialization-tracking since some of it may be uninitialized. */
163 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size));
164
165 memcpy (r, x, old_size);
166
167 /* The old object is not supposed to be used anymore. */
168 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (x, old_size));
169
170 return r;
171 }
172
173 /* Like ggc_alloc_cleared, but performs a multiplication. */
174 void *
175 ggc_calloc (s1, s2)
176 size_t s1, s2;
177 {
178 return ggc_alloc_cleared (s1 * s2);
179 }
180
181 /* These are for splay_tree_new_ggc. */
182 PTR
183 ggc_splay_alloc (sz, nl)
184 int sz;
185 PTR nl;
186 {
187 if (nl != NULL)
188 abort ();
189 return ggc_alloc (sz);
190 }
191
192 void
193 ggc_splay_dont_free (x, nl)
194 PTR x ATTRIBUTE_UNUSED;
195 PTR nl;
196 {
197 if (nl != NULL)
198 abort ();
199 }
200
201 /* Print statistics that are independent of the collector in use. */
202 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
203 ? (x) \
204 : ((x) < 1024*1024*10 \
205 ? (x) / 1024 \
206 : (x) / (1024*1024))))
207 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
208
209 void
210 ggc_print_common_statistics (stream, stats)
211 FILE *stream ATTRIBUTE_UNUSED;
212 ggc_statistics *stats;
213 {
214 /* Set the pointer so that during collection we will actually gather
215 the statistics. */
216 ggc_stats = stats;
217
218 /* Then do one collection to fill in the statistics. */
219 ggc_collect ();
220
221 /* At present, we don't really gather any interesting statistics. */
222
223 /* Don't gather statistics any more. */
224 ggc_stats = NULL;
225 }
226 \f
227 /* Functions for saving and restoring GCable memory to disk. */
228
229 static htab_t saving_htab;
230
231 struct ptr_data
232 {
233 void *obj;
234 void *note_ptr_cookie;
235 gt_note_pointers note_ptr_fn;
236 gt_handle_reorder reorder_fn;
237 size_t size;
238 void *new_addr;
239 };
240
241 #define POINTER_HASH(x) (hashval_t)((long)x >> 3)
242
243 /* Register an object in the hash table. */
244
245 int
246 gt_pch_note_object (obj, note_ptr_cookie, note_ptr_fn)
247 void *obj;
248 void *note_ptr_cookie;
249 gt_note_pointers note_ptr_fn;
250 {
251 struct ptr_data **slot;
252
253 if (obj == NULL || obj == (void *) 1)
254 return 0;
255
256 slot = (struct ptr_data **)
257 htab_find_slot_with_hash (saving_htab, obj, POINTER_HASH (obj),
258 INSERT);
259 if (*slot != NULL)
260 {
261 if ((*slot)->note_ptr_fn != note_ptr_fn
262 || (*slot)->note_ptr_cookie != note_ptr_cookie)
263 abort ();
264 return 0;
265 }
266
267 *slot = xcalloc (sizeof (struct ptr_data), 1);
268 (*slot)->obj = obj;
269 (*slot)->note_ptr_fn = note_ptr_fn;
270 (*slot)->note_ptr_cookie = note_ptr_cookie;
271 if (note_ptr_fn == gt_pch_p_S)
272 (*slot)->size = strlen (obj) + 1;
273 else
274 (*slot)->size = ggc_get_size (obj);
275 return 1;
276 }
277
278 /* Register an object in the hash table. */
279
280 void
281 gt_pch_note_reorder (obj, note_ptr_cookie, reorder_fn)
282 void *obj;
283 void *note_ptr_cookie;
284 gt_handle_reorder reorder_fn;
285 {
286 struct ptr_data *data;
287
288 if (obj == NULL || obj == (void *) 1)
289 return;
290
291 data = htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj));
292 if (data == NULL
293 || data->note_ptr_cookie != note_ptr_cookie)
294 abort ();
295
296 data->reorder_fn = reorder_fn;
297 }
298
299 /* Hash and equality functions for saving_htab, callbacks for htab_create. */
300
301 static hashval_t
302 saving_htab_hash (p)
303 const PTR p;
304 {
305 return POINTER_HASH (((struct ptr_data *)p)->obj);
306 }
307
308 static int
309 saving_htab_eq (p1, p2)
310 const PTR p1;
311 const PTR p2;
312 {
313 return ((struct ptr_data *)p1)->obj == p2;
314 }
315
316 /* Handy state for the traversal functions. */
317
318 struct traversal_state
319 {
320 FILE *f;
321 struct ggc_pch_data *d;
322 size_t count;
323 struct ptr_data **ptrs;
324 size_t ptrs_i;
325 };
326
327 /* Callbacks for htab_traverse. */
328
329 static int
330 call_count (slot, state_p)
331 void **slot;
332 void *state_p;
333 {
334 struct ptr_data *d = (struct ptr_data *)*slot;
335 struct traversal_state *state = (struct traversal_state *)state_p;
336
337 ggc_pch_count_object (state->d, d->obj, d->size);
338 state->count++;
339 return 1;
340 }
341
342 static int
343 call_alloc (slot, state_p)
344 void **slot;
345 void *state_p;
346 {
347 struct ptr_data *d = (struct ptr_data *)*slot;
348 struct traversal_state *state = (struct traversal_state *)state_p;
349
350 d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size);
351 state->ptrs[state->ptrs_i++] = d;
352 return 1;
353 }
354
355 /* Callback for qsort. */
356
357 static int
358 compare_ptr_data (p1_p, p2_p)
359 const void *p1_p;
360 const void *p2_p;
361 {
362 struct ptr_data *p1 = *(struct ptr_data *const *)p1_p;
363 struct ptr_data *p2 = *(struct ptr_data *const *)p2_p;
364 return (((size_t)p1->new_addr > (size_t)p2->new_addr)
365 - ((size_t)p1->new_addr < (size_t)p2->new_addr));
366 }
367
368 /* Callbacks for note_ptr_fn. */
369
370 static void
371 relocate_ptrs (ptr_p, state_p)
372 void *ptr_p;
373 void *state_p;
374 {
375 void **ptr = (void **)ptr_p;
376 struct traversal_state *state ATTRIBUTE_UNUSED
377 = (struct traversal_state *)state_p;
378 struct ptr_data *result;
379
380 if (*ptr == NULL || *ptr == (void *)1)
381 return;
382
383 result = htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr));
384 if (result == NULL)
385 abort ();
386 *ptr = result->new_addr;
387 }
388
389 /* Write out, after relocation, the pointers in TAB. */
390 static void
391 write_pch_globals (tab, state)
392 const struct ggc_root_tab * const *tab;
393 struct traversal_state *state;
394 {
395 const struct ggc_root_tab *const *rt;
396 const struct ggc_root_tab *rti;
397 size_t i;
398
399 for (rt = tab; *rt; rt++)
400 for (rti = *rt; rti->base != NULL; rti++)
401 for (i = 0; i < rti->nelt; i++)
402 {
403 void *ptr = *(void **)((char *)rti->base + rti->stride * i);
404 struct ptr_data *new_ptr;
405 if (ptr == NULL || ptr == (void *)1)
406 {
407 if (fwrite (&ptr, sizeof (void *), 1, state->f)
408 != 1)
409 fatal_io_error ("can't write PCH file");
410 }
411 else
412 {
413 new_ptr = htab_find_with_hash (saving_htab, ptr,
414 POINTER_HASH (ptr));
415 if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f)
416 != 1)
417 fatal_io_error ("can't write PCH file");
418 }
419 }
420 }
421
422 /* Hold the information we need to mmap the file back in. */
423
424 struct mmap_info
425 {
426 size_t offset;
427 size_t size;
428 void *preferred_base;
429 };
430
431 /* Write out the state of the compiler to F. */
432
433 void
434 gt_pch_save (f)
435 FILE *f;
436 {
437 const struct ggc_root_tab *const *rt;
438 const struct ggc_root_tab *rti;
439 size_t i;
440 struct traversal_state state;
441 char *this_object = NULL;
442 size_t this_object_size = 0;
443 struct mmap_info mmi;
444 size_t page_size = getpagesize();
445
446 gt_pch_save_stringpool ();
447
448 saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free);
449
450 for (rt = gt_ggc_rtab; *rt; rt++)
451 for (rti = *rt; rti->base != NULL; rti++)
452 for (i = 0; i < rti->nelt; i++)
453 (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
454
455 for (rt = gt_pch_cache_rtab; *rt; rt++)
456 for (rti = *rt; rti->base != NULL; rti++)
457 for (i = 0; i < rti->nelt; i++)
458 (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
459
460 /* Prepare the objects for writing, determine addresses and such. */
461 state.f = f;
462 state.d = init_ggc_pch();
463 state.count = 0;
464 htab_traverse (saving_htab, call_count, &state);
465
466 mmi.size = ggc_pch_total_size (state.d);
467
468 /* Try to arrange things so that no relocation is necessary,
469 but don't try very hard. On most platforms, this will always work,
470 and on the rest it's a lot of work to do better. */
471 #if HAVE_MMAP_FILE
472 mmi.preferred_base = mmap (NULL, mmi.size,
473 PROT_READ | PROT_WRITE, MAP_PRIVATE,
474 fileno (state.f), 0);
475 if (mmi.preferred_base == (void *)-1)
476 mmi.preferred_base = NULL;
477 else
478 munmap (mmi.preferred_base, mmi.size);
479 #else /* HAVE_MMAP_FILE */
480 mmi.preferred_base = NULL;
481 #endif /* HAVE_MMAP_FILE */
482
483 ggc_pch_this_base (state.d, mmi.preferred_base);
484
485 state.ptrs = xmalloc (state.count * sizeof (*state.ptrs));
486 state.ptrs_i = 0;
487 htab_traverse (saving_htab, call_alloc, &state);
488 qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data);
489
490 /* Write out all the scalar variables. */
491 for (rt = gt_pch_scalar_rtab; *rt; rt++)
492 for (rti = *rt; rti->base != NULL; rti++)
493 if (fwrite (rti->base, rti->stride, 1, f) != 1)
494 fatal_io_error ("can't write PCH file");
495
496 /* Write out all the global pointers, after translation. */
497 write_pch_globals (gt_ggc_rtab, &state);
498 write_pch_globals (gt_pch_cache_rtab, &state);
499
500 ggc_pch_prepare_write (state.d, state.f);
501
502 /* Pad the PCH file so that the mmaped area starts on a page boundary. */
503 {
504 long o;
505 o = ftell (state.f) + sizeof (mmi);
506 if (o == -1)
507 fatal_io_error ("can't get position in PCH file");
508 mmi.offset = page_size - o % page_size;
509 if (mmi.offset == page_size)
510 mmi.offset = 0;
511 mmi.offset += o;
512 }
513 if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
514 fatal_io_error ("can't write PCH file");
515 if (mmi.offset != 0
516 && fseek (state.f, mmi.offset, SEEK_SET) != 0)
517 fatal_io_error ("can't write padding to PCH file");
518
519 /* Actually write out the objects. */
520 for (i = 0; i < state.count; i++)
521 {
522 if (this_object_size < state.ptrs[i]->size)
523 {
524 this_object_size = state.ptrs[i]->size;
525 this_object = xrealloc (this_object, this_object_size);
526 }
527 memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size);
528 if (state.ptrs[i]->reorder_fn != NULL)
529 state.ptrs[i]->reorder_fn (state.ptrs[i]->obj,
530 state.ptrs[i]->note_ptr_cookie,
531 relocate_ptrs, &state);
532 state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
533 state.ptrs[i]->note_ptr_cookie,
534 relocate_ptrs, &state);
535 ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
536 state.ptrs[i]->new_addr, state.ptrs[i]->size);
537 if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S)
538 memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);
539 }
540 ggc_pch_finish (state.d, state.f);
541
542 free (state.ptrs);
543 htab_delete (saving_htab);
544 }
545
546 /* Read the state of the compiler back in from F. */
547
548 void
549 gt_pch_restore (f)
550 FILE *f;
551 {
552 const struct ggc_root_tab *const *rt;
553 const struct ggc_root_tab *rti;
554 size_t i;
555 struct mmap_info mmi;
556 void *addr;
557
558 /* Delete any deletable objects. This makes ggc_pch_read much
559 faster, as it can be sure that no GCable objects remain other
560 than the ones just read in. */
561 for (rt = gt_ggc_deletable_rtab; *rt; rt++)
562 for (rti = *rt; rti->base != NULL; rti++)
563 memset (rti->base, 0, rti->stride);
564
565 /* Read in all the scalar variables. */
566 for (rt = gt_pch_scalar_rtab; *rt; rt++)
567 for (rti = *rt; rti->base != NULL; rti++)
568 if (fread (rti->base, rti->stride, 1, f) != 1)
569 fatal_io_error ("can't read PCH file");
570
571 /* Read in all the global pointers, in 6 easy loops. */
572 for (rt = gt_ggc_rtab; *rt; rt++)
573 for (rti = *rt; rti->base != NULL; rti++)
574 for (i = 0; i < rti->nelt; i++)
575 if (fread ((char *)rti->base + rti->stride * i,
576 sizeof (void *), 1, f) != 1)
577 fatal_io_error ("can't read PCH file");
578
579 for (rt = gt_pch_cache_rtab; *rt; rt++)
580 for (rti = *rt; rti->base != NULL; rti++)
581 for (i = 0; i < rti->nelt; i++)
582 if (fread ((char *)rti->base + rti->stride * i,
583 sizeof (void *), 1, f) != 1)
584 fatal_io_error ("can't read PCH file");
585
586 if (fread (&mmi, sizeof (mmi), 1, f) != 1)
587 fatal_io_error ("can't read PCH file");
588
589 #if HAVE_MMAP_FILE
590 addr = mmap (mmi.preferred_base, mmi.size,
591 PROT_READ | PROT_WRITE, MAP_PRIVATE,
592 fileno (f), mmi.offset);
593 #else
594 addr = (void *)-1;
595 #endif
596 if (addr == (void *)-1)
597 {
598 addr = xmalloc (mmi.size);
599 if (fseek (f, mmi.offset, SEEK_SET) != 0
600 || fread (&mmi, mmi.size, 1, f) != 1)
601 fatal_io_error ("can't read PCH file");
602 }
603 else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
604 fatal_io_error ("can't read PCH file");
605
606 ggc_pch_read (f, addr);
607
608 if (addr != mmi.preferred_base)
609 {
610 for (rt = gt_ggc_rtab; *rt; rt++)
611 for (rti = *rt; rti->base != NULL; rti++)
612 for (i = 0; i < rti->nelt; i++)
613 {
614 char **ptr = (char **)((char *)rti->base + rti->stride * i);
615 if (*ptr != NULL)
616 *ptr += (size_t)addr - (size_t)mmi.preferred_base;
617 }
618
619 for (rt = gt_pch_cache_rtab; *rt; rt++)
620 for (rti = *rt; rti->base != NULL; rti++)
621 for (i = 0; i < rti->nelt; i++)
622 {
623 char **ptr = (char **)((char *)rti->base + rti->stride * i);
624 if (*ptr != NULL)
625 *ptr += (size_t)addr - (size_t)mmi.preferred_base;
626 }
627
628 sorry ("had to relocate PCH");
629 }
630
631 gt_pch_restore_stringpool ();
632 }
633
634 /* Modify the bound based on rlimits. Keep the smallest number found. */
635 static double
636 ggc_rlimit_bound (limit)
637 double limit;
638 {
639 #if defined(HAVE_GETRLIMIT)
640 struct rlimit rlim;
641 # ifdef RLIMIT_RSS
642 if (getrlimit (RLIMIT_RSS, &rlim) == 0
643 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
644 && rlim.rlim_cur < limit)
645 limit = rlim.rlim_cur;
646 # endif
647 # ifdef RLIMIT_DATA
648 if (getrlimit (RLIMIT_DATA, &rlim) == 0
649 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
650 && rlim.rlim_cur < limit)
651 limit = rlim.rlim_cur;
652 # endif
653 # ifdef RLIMIT_AS
654 if (getrlimit (RLIMIT_AS, &rlim) == 0
655 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
656 && rlim.rlim_cur < limit)
657 limit = rlim.rlim_cur;
658 # endif
659 #endif /* HAVE_GETRLIMIT */
660
661 return limit;
662 }
663
664 /* Heuristic to set a default for GGC_MIN_EXPAND. */
665 int
666 ggc_min_expand_heuristic()
667 {
668 double min_expand = physmem_total();
669
670 /* Adjust for rlimits. */
671 min_expand = ggc_rlimit_bound (min_expand);
672
673 /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding
674 a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB). */
675 min_expand /= 1024*1024*1024;
676 min_expand *= 70;
677 min_expand = MIN (min_expand, 70);
678 min_expand += 30;
679
680 return min_expand;
681 }
682
683 /* Heuristic to set a default for GGC_MIN_HEAPSIZE. */
684 int
685 ggc_min_heapsize_heuristic()
686 {
687 double min_heap_kbytes = physmem_total();
688
689 /* Adjust for rlimits. */
690 min_heap_kbytes = ggc_rlimit_bound (min_heap_kbytes);
691
692 min_heap_kbytes /= 1024; /* convert to Kbytes. */
693
694 /* The heuristic is RAM/8, with a lower bound of 4M and an upper
695 bound of 128M (when RAM >= 1GB). */
696 min_heap_kbytes /= 8;
697 min_heap_kbytes = MAX (min_heap_kbytes, 4 * 1024);
698 min_heap_kbytes = MIN (min_heap_kbytes, 128 * 1024);
699
700 return min_heap_kbytes;
701 }
702
703 void
704 init_ggc_heuristics ()
705 {
706 #ifndef ENABLE_GC_ALWAYS_COLLECT
707 set_param_value ("ggc-min-expand", ggc_min_expand_heuristic());
708 set_param_value ("ggc-min-heapsize", ggc_min_heapsize_heuristic());
709 #endif
710 }