OSDN Git Service

* doc/invoke.texi (ggc-min-expand, ggc-min-heapsize): Document
[pf3gnuchains/gcc-fork.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_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_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_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 }