Line data Source code
1 : /* Simple garbage collection for the GNU compiler.
2 : Copyright (C) 1999-2026 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 3, 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 COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 : /* Generic garbage collection (GC) functions and data, not specific to
21 : any particular GC implementation. */
22 :
23 : #include "config.h"
24 : #define INCLUDE_MALLOC_H
25 : #include "system.h"
26 : #include "coretypes.h"
27 : #include "timevar.h"
28 : #include "diagnostic-core.h"
29 : #include "ggc-internal.h"
30 : #include "hosthooks.h"
31 : #include "plugin.h"
32 : #include "options.h"
33 :
34 : /* When true, protect the contents of the identifier hash table. */
35 : bool ggc_protect_identifiers = true;
36 :
37 : /* Statistics about the allocation. */
38 : static ggc_statistics *ggc_stats;
39 :
40 : struct traversal_state;
41 :
42 : static int compare_ptr_data (const void *, const void *);
43 : static void relocate_ptrs (void *, void *, void *);
44 : static void write_pch_globals (const struct ggc_root_tab * const *tab,
45 : struct traversal_state *state);
46 :
47 : /* Maintain global roots that are preserved during GC. */
48 :
49 : /* This extra vector of dynamically registered root_tab-s is used by
50 : ggc_mark_roots and gives the ability to dynamically add new GGC root
51 : tables, for instance from some plugins; this vector is on the heap
52 : since it is used by GGC internally. */
53 : typedef const struct ggc_root_tab *const_ggc_root_tab_t;
54 : static vec<const_ggc_root_tab_t> extra_root_vec;
55 :
56 : /* Dynamically register a new GGC root table RT. This is useful for
57 : plugins. */
58 :
59 : void
60 131 : ggc_register_root_tab (const struct ggc_root_tab* rt)
61 : {
62 131 : if (rt)
63 131 : extra_root_vec.safe_push (rt);
64 131 : }
65 :
66 : /* Mark all the roots in the table RT. */
67 :
68 : static void
69 41056467 : ggc_mark_root_tab (const_ggc_root_tab_t rt)
70 : {
71 41056467 : size_t i;
72 :
73 298093871 : for ( ; rt->base != NULL; rt++)
74 6968247729 : for (i = 0; i < rt->nelt; i++)
75 6711210325 : (*rt->cb) (*(void **) ((char *)rt->base + rt->stride * i));
76 41056467 : }
77 :
78 : /* Zero out all the roots in the table RT. */
79 :
80 : static void
81 16552840 : ggc_zero_rtab_roots (const_ggc_root_tab_t rt)
82 : {
83 16552840 : size_t i;
84 :
85 122740284 : for ( ; rt->base != NULL; rt++)
86 2626010295 : for (i = 0; i < rt->nelt; i++)
87 2519822851 : (*(void **) ((char *)rt->base + rt->stride * i)) = (void*)0;
88 16552840 : }
89 :
90 : /* Iterate through all registered roots and mark each element. */
91 :
92 : void
93 719140 : ggc_mark_roots (void)
94 : {
95 719140 : const struct ggc_root_tab *const *rt;
96 719140 : const_ggc_root_tab_t rtp, rti;
97 719140 : size_t i;
98 :
99 7912156 : for (rt = gt_ggc_deletable_rtab; *rt; rt++)
100 17187598 : for (rti = *rt; rti->base != NULL; rti++)
101 9994582 : memset (rti->base, 0, rti->stride * rti->nelt);
102 :
103 41260756 : for (rt = gt_ggc_rtab; *rt; rt++)
104 40541616 : ggc_mark_root_tab (*rt);
105 :
106 1233991 : FOR_EACH_VEC_ELT (extra_root_vec, i, rtp)
107 514851 : ggc_mark_root_tab (rtp);
108 :
109 719140 : if (ggc_protect_identifiers)
110 154392 : ggc_mark_stringpool ();
111 :
112 719140 : gt_clear_caches ();
113 :
114 719140 : if (! ggc_protect_identifiers)
115 564748 : ggc_purge_stringpool ();
116 :
117 : /* Some plugins may call ggc_set_mark from here. */
118 719140 : invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL);
119 719140 : }
120 :
121 : /* Allocate a block of memory, then clear it. */
122 : #ifdef HAVE_ATTRIBUTE_ALIAS
123 : extern "C" void *
124 24326161745 : ggc_internal_cleared_alloc_ (size_t size, void (*f)(void *), size_t s, size_t n
125 : MEM_STAT_DECL)
126 : {
127 24326161745 : void *buf = ggc_internal_alloc (size, f, s, n PASS_MEM_STAT);
128 24326161745 : memset (buf, 0, size);
129 24326161745 : return buf;
130 : }
131 :
132 : extern void *
133 : ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s,
134 : size_t n MEM_STAT_DECL)
135 : __attribute__((__alias__ ("ggc_internal_cleared_alloc_")));
136 : extern void *
137 : ggc_internal_cleared_alloc_no_dtor (size_t size, void (*f)(void *),
138 : size_t s, size_t n MEM_STAT_DECL)
139 : __attribute__((__alias__ ("ggc_internal_cleared_alloc_")));
140 : #else
141 : void *
142 : ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s, size_t n
143 : MEM_STAT_DECL)
144 : {
145 : void *buf = ggc_internal_alloc (size, f, s, n PASS_MEM_STAT);
146 : memset (buf, 0, size);
147 : return buf;
148 : }
149 :
150 : #ifdef __GNUC__
151 : __attribute__ ((__noinline__))
152 : #endif
153 : void *
154 : ggc_internal_cleared_alloc_no_dtor (size_t size, void (*f)(void *),
155 : size_t s, size_t n MEM_STAT_DECL)
156 : {
157 : return ggc_internal_cleared_alloc (size, f, s, n PASS_MEM_STAT);
158 : }
159 : #endif
160 :
161 : /* Resize a block of memory, possibly re-allocating it. */
162 : void *
163 3819452675 : ggc_realloc (void *x, size_t size MEM_STAT_DECL)
164 : {
165 3819452675 : void *r;
166 3819452675 : size_t old_size;
167 :
168 3819452675 : if (x == NULL)
169 3119191094 : return ggc_internal_alloc (size PASS_MEM_STAT);
170 :
171 700261581 : old_size = ggc_get_size (x);
172 :
173 700261581 : if (size <= old_size)
174 : {
175 : /* Mark the unwanted memory as unaccessible. We also need to make
176 : the "new" size accessible, since ggc_get_size returns the size of
177 : the pool, not the size of the individually allocated object, the
178 : size which was previously made accessible. Unfortunately, we
179 : don't know that previously allocated size. Without that
180 : knowledge we have to lose some initialization-tracking for the
181 : old parts of the object. An alternative is to mark the whole
182 : old_size as reachable, but that would lose tracking of writes
183 : after the end of the object (by small offsets). Discard the
184 : handle to avoid handle leak. */
185 : VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *) x + size,
186 : old_size - size));
187 : VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, size));
188 : return x;
189 : }
190 :
191 699419820 : r = ggc_internal_alloc (size PASS_MEM_STAT);
192 :
193 : /* Since ggc_get_size returns the size of the pool, not the size of the
194 : individually allocated object, we'd access parts of the old object
195 : that were marked invalid with the memcpy below. We lose a bit of the
196 : initialization-tracking since some of it may be uninitialized. */
197 699419820 : VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, old_size));
198 :
199 699419820 : memcpy (r, x, old_size);
200 :
201 : /* The old object is not supposed to be used anymore. */
202 699419820 : ggc_free (x);
203 :
204 699419820 : return r;
205 : }
206 :
207 : void *
208 0 : ggc_cleared_alloc_htab_ignore_args (size_t c ATTRIBUTE_UNUSED,
209 : size_t n ATTRIBUTE_UNUSED)
210 : {
211 0 : gcc_assert (c * n == sizeof (struct htab));
212 0 : return ggc_cleared_alloc<htab> ();
213 : }
214 :
215 : /* TODO: once we actually use type information in GGC, create a new tag
216 : gt_gcc_ptr_array and use it for pointer arrays. */
217 : void *
218 0 : ggc_cleared_alloc_ptr_array_two_args (size_t c, size_t n)
219 : {
220 0 : gcc_assert (sizeof (void **) == n);
221 0 : return ggc_cleared_vec_alloc<void **> (c);
222 : }
223 :
224 : /* These are for splay_tree_new_ggc. */
225 : void *
226 0 : ggc_splay_alloc (int sz, void *nl)
227 : {
228 0 : gcc_assert (!nl);
229 0 : return ggc_internal_alloc (sz);
230 : }
231 :
232 : void
233 0 : ggc_splay_dont_free (void * x ATTRIBUTE_UNUSED, void *nl)
234 : {
235 0 : gcc_assert (!nl);
236 0 : }
237 :
238 : void
239 0 : ggc_print_common_statistics (FILE *stream ATTRIBUTE_UNUSED,
240 : ggc_statistics *stats)
241 : {
242 : /* Set the pointer so that during collection we will actually gather
243 : the statistics. */
244 0 : ggc_stats = stats;
245 :
246 : /* Then do one collection to fill in the statistics. */
247 0 : ggc_collect ();
248 :
249 : /* At present, we don't really gather any interesting statistics. */
250 :
251 : /* Don't gather statistics any more. */
252 0 : ggc_stats = NULL;
253 0 : }
254 :
255 : /* Functions for saving and restoring GCable memory to disk. */
256 :
257 : struct ptr_data
258 : {
259 : void *obj;
260 : void *note_ptr_cookie;
261 : gt_note_pointers note_ptr_fn;
262 : gt_handle_reorder reorder_fn;
263 : size_t size;
264 : void *new_addr;
265 : };
266 :
267 : #define POINTER_HASH(x) (hashval_t)((intptr_t)x >> 3)
268 :
269 : /* Helper for hashing saving_htab. */
270 :
271 : struct saving_hasher : free_ptr_hash <ptr_data>
272 : {
273 : typedef void *compare_type;
274 : static inline hashval_t hash (const ptr_data *);
275 : static inline bool equal (const ptr_data *, const void *);
276 : };
277 :
278 : inline hashval_t
279 754295209 : saving_hasher::hash (const ptr_data *p)
280 : {
281 754295209 : return POINTER_HASH (p->obj);
282 : }
283 :
284 : inline bool
285 223503301 : saving_hasher::equal (const ptr_data *p1, const void *p2)
286 : {
287 223503301 : return p1->obj == p2;
288 : }
289 :
290 : static hash_table<saving_hasher> *saving_htab;
291 : static vec<void *> callback_vec;
292 : static vec<void *> reloc_addrs_vec;
293 :
294 : /* Register an object in the hash table. */
295 :
296 : int
297 97600525 : gt_pch_note_object (void *obj, void *note_ptr_cookie,
298 : gt_note_pointers note_ptr_fn,
299 : size_t length_override)
300 : {
301 97600525 : struct ptr_data **slot;
302 :
303 97600525 : if (obj == NULL || obj == (void *) 1)
304 : return 0;
305 :
306 82988494 : slot = (struct ptr_data **)
307 82988494 : saving_htab->find_slot_with_hash (obj, POINTER_HASH (obj), INSERT);
308 82988494 : if (*slot != NULL)
309 : {
310 55922848 : gcc_assert ((*slot)->note_ptr_fn == note_ptr_fn
311 : && (*slot)->note_ptr_cookie == note_ptr_cookie);
312 : return 0;
313 : }
314 :
315 27065646 : *slot = XCNEW (struct ptr_data);
316 27065646 : (*slot)->obj = obj;
317 27065646 : (*slot)->note_ptr_fn = note_ptr_fn;
318 27065646 : (*slot)->note_ptr_cookie = note_ptr_cookie;
319 27065646 : if (length_override != (size_t)-1)
320 2057221 : (*slot)->size = length_override;
321 25008425 : else if (note_ptr_fn == gt_pch_p_S)
322 115632 : (*slot)->size = strlen ((const char *)obj) + 1;
323 : else
324 24892793 : (*slot)->size = ggc_get_size (obj);
325 : return 1;
326 : }
327 :
328 : /* Register address of a callback pointer. */
329 : void
330 4280 : gt_pch_note_callback (void *obj, void *base)
331 : {
332 4280 : void *ptr;
333 4280 : memcpy (&ptr, obj, sizeof (void *));
334 4280 : if (ptr != NULL)
335 : {
336 4280 : struct ptr_data *data
337 : = (struct ptr_data *)
338 4280 : saving_htab->find_with_hash (base, POINTER_HASH (base));
339 4280 : gcc_assert (data);
340 4280 : callback_vec.safe_push ((char *) data->new_addr
341 4280 : + ((char *) obj - (char *) base));
342 : }
343 4280 : }
344 :
345 : /* Register an object in the hash table. */
346 :
347 : void
348 103550 : gt_pch_note_reorder (void *obj, void *note_ptr_cookie,
349 : gt_handle_reorder reorder_fn)
350 : {
351 103550 : struct ptr_data *data;
352 :
353 103550 : if (obj == NULL || obj == (void *) 1)
354 : return;
355 :
356 40912 : data = (struct ptr_data *)
357 20456 : saving_htab->find_with_hash (obj, POINTER_HASH (obj));
358 20456 : gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie);
359 : /* The GTY 'reorder' option doesn't make sense if we don't walk pointers,
360 : such as for strings. */
361 20456 : gcc_checking_assert (data->note_ptr_fn != gt_pch_p_S);
362 :
363 20456 : data->reorder_fn = reorder_fn;
364 : }
365 :
366 : /* Handy state for the traversal functions. */
367 :
368 : struct traversal_state
369 : {
370 : FILE *f;
371 : struct ggc_pch_data *d;
372 : size_t count;
373 : struct ptr_data **ptrs;
374 : size_t ptrs_i;
375 : };
376 :
377 : /* Callbacks for htab_traverse. */
378 :
379 : int
380 27065646 : ggc_call_count (ptr_data **slot, traversal_state *state)
381 : {
382 27065646 : struct ptr_data *d = *slot;
383 :
384 27065646 : ggc_pch_count_object (state->d, d->obj, d->size);
385 27065646 : state->count++;
386 27065646 : return 1;
387 : }
388 :
389 : int
390 27065646 : ggc_call_alloc (ptr_data **slot, traversal_state *state)
391 : {
392 27065646 : struct ptr_data *d = *slot;
393 :
394 27065646 : d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size);
395 27065646 : state->ptrs[state->ptrs_i++] = d;
396 27065646 : return 1;
397 : }
398 :
399 : /* Callback for qsort. */
400 :
401 : static int
402 2008675138 : compare_ptr_data (const void *p1_p, const void *p2_p)
403 : {
404 2008675138 : const struct ptr_data *const p1 = *(const struct ptr_data *const *)p1_p;
405 2008675138 : const struct ptr_data *const p2 = *(const struct ptr_data *const *)p2_p;
406 2008675138 : return (((size_t)p1->new_addr > (size_t)p2->new_addr)
407 2008675138 : - ((size_t)p1->new_addr < (size_t)p2->new_addr));
408 : }
409 :
410 : /* Callbacks for note_ptr_fn. */
411 :
412 : static void
413 190023751 : relocate_ptrs (void *ptr_p, void *real_ptr_p, void *state_p)
414 : {
415 190023751 : void **ptr = (void **)ptr_p;
416 190023751 : struct traversal_state *state
417 : = (struct traversal_state *)state_p;
418 190023751 : struct ptr_data *result;
419 :
420 190023751 : if (*ptr == NULL || *ptr == (void *)1)
421 117151465 : return;
422 :
423 167484688 : result = (struct ptr_data *)
424 83742344 : saving_htab->find_with_hash (*ptr, POINTER_HASH (*ptr));
425 83742344 : gcc_assert (result);
426 83742344 : *ptr = result->new_addr;
427 83742344 : if (ptr_p == real_ptr_p)
428 : return;
429 72872286 : if (real_ptr_p == NULL)
430 70283799 : real_ptr_p = ptr_p;
431 72872286 : gcc_assert (real_ptr_p >= state->ptrs[state->ptrs_i]->obj
432 : && ((char *) real_ptr_p + sizeof (void *)
433 : <= ((char *) state->ptrs[state->ptrs_i]->obj
434 : + state->ptrs[state->ptrs_i]->size)));
435 72872286 : void *addr
436 72872286 : = (void *) ((char *) state->ptrs[state->ptrs_i]->new_addr
437 : + ((char *) real_ptr_p
438 72872286 : - (char *) state->ptrs[state->ptrs_i]->obj));
439 72872286 : reloc_addrs_vec.safe_push (addr);
440 : }
441 :
442 : /* Write out, after relocation, the pointers in TAB. */
443 : static void
444 428 : write_pch_globals (const struct ggc_root_tab * const *tab,
445 : struct traversal_state *state)
446 : {
447 428 : const struct ggc_root_tab *const *rt;
448 428 : const struct ggc_root_tab *rti;
449 428 : size_t i;
450 :
451 27249 : for (rt = tab; *rt; rt++)
452 193089 : for (rti = *rt; rti->base != NULL; rti++)
453 4305898 : for (i = 0; i < rti->nelt; i++)
454 : {
455 4139630 : void *ptr = *(void **)((char *)rti->base + rti->stride * i);
456 4139630 : struct ptr_data *new_ptr;
457 4139630 : if (ptr == NULL || ptr == (void *)1)
458 : {
459 2678564 : if (fwrite (&ptr, sizeof (void *), 1, state->f)
460 : != 1)
461 0 : fatal_error (input_location, "cannot write PCH file: %m");
462 : }
463 : else
464 : {
465 2922132 : new_ptr = (struct ptr_data *)
466 1461066 : saving_htab->find_with_hash (ptr, POINTER_HASH (ptr));
467 1461066 : if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f)
468 : != 1)
469 0 : fatal_error (input_location, "cannot write PCH file: %m");
470 : }
471 : }
472 428 : }
473 :
474 : /* Callback for qsort. */
475 :
476 : static int
477 4545759044 : compare_ptr (const void *p1_p, const void *p2_p)
478 : {
479 4545759044 : void *p1 = *(void *const *)p1_p;
480 4545759044 : void *p2 = *(void *const *)p2_p;
481 4545759044 : return (((uintptr_t)p1 > (uintptr_t)p2)
482 4545759044 : - ((uintptr_t)p1 < (uintptr_t)p2));
483 : }
484 :
485 : /* Decode one uleb128 from P, return first byte after it, store
486 : decoded value into *VAL. */
487 :
488 : static unsigned char *
489 0 : read_uleb128 (unsigned char *p, size_t *val)
490 : {
491 0 : unsigned int shift = 0;
492 0 : unsigned char byte;
493 0 : size_t result;
494 :
495 0 : result = 0;
496 0 : do
497 : {
498 0 : byte = *p++;
499 0 : result |= ((size_t) byte & 0x7f) << shift;
500 0 : shift += 7;
501 : }
502 0 : while (byte & 0x80);
503 :
504 0 : *val = result;
505 0 : return p;
506 : }
507 :
508 : /* Store VAL as uleb128 at P, return length in bytes. */
509 :
510 : static size_t
511 145744572 : write_uleb128 (unsigned char *p, size_t val)
512 : {
513 0 : size_t len = 0;
514 150342544 : do
515 : {
516 150342544 : unsigned char byte = (val & 0x7f);
517 150342544 : val >>= 7;
518 150342544 : if (val != 0)
519 : /* More bytes to follow. */
520 4597972 : byte |= 0x80;
521 :
522 150342544 : *p++ = byte;
523 150342544 : ++len;
524 : }
525 150342544 : while (val != 0);
526 145744572 : return len;
527 : }
528 :
529 : /* Hold the information we need to mmap the file back in. */
530 :
531 : struct mmap_info
532 : {
533 : size_t offset;
534 : size_t size;
535 : void *preferred_base;
536 : };
537 :
538 : /* Write out the state of the compiler to F. */
539 :
540 : void
541 428 : gt_pch_save (FILE *f)
542 : {
543 428 : const struct ggc_root_tab *const *rt;
544 428 : const struct ggc_root_tab *rti;
545 428 : size_t i;
546 428 : struct traversal_state state;
547 428 : char *this_object = NULL;
548 428 : size_t this_object_size = 0;
549 428 : struct mmap_info mmi;
550 428 : const size_t mmap_offset_alignment = host_hooks.gt_pch_alloc_granularity ();
551 :
552 428 : gt_pch_save_stringpool ();
553 :
554 428 : timevar_push (TV_PCH_PTR_REALLOC);
555 428 : saving_htab = new hash_table<saving_hasher> (50000);
556 :
557 27249 : for (rt = gt_ggc_rtab; *rt; rt++)
558 193089 : for (rti = *rt; rti->base != NULL; rti++)
559 4305898 : for (i = 0; i < rti->nelt; i++)
560 4139630 : (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
561 :
562 : /* Prepare the objects for writing, determine addresses and such. */
563 428 : state.f = f;
564 428 : state.d = init_ggc_pch ();
565 428 : state.count = 0;
566 27066074 : saving_htab->traverse <traversal_state *, ggc_call_count> (&state);
567 :
568 428 : mmi.size = ggc_pch_total_size (state.d);
569 :
570 : /* Try to arrange things so that no relocation is necessary, but
571 : don't try very hard. On most platforms, this will always work,
572 : and on the rest it's a lot of work to do better.
573 : (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and
574 : HOST_HOOKS_GT_PCH_USE_ADDRESS.) */
575 428 : mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f));
576 : /* If the host cannot supply any suitable address for this, we are stuck. */
577 428 : if (mmi.preferred_base == NULL)
578 0 : fatal_error (input_location,
579 : "cannot write PCH file: required memory segment unavailable");
580 :
581 428 : ggc_pch_this_base (state.d, mmi.preferred_base);
582 :
583 428 : state.ptrs = XNEWVEC (struct ptr_data *, state.count);
584 428 : state.ptrs_i = 0;
585 :
586 27066074 : saving_htab->traverse <traversal_state *, ggc_call_alloc> (&state);
587 428 : timevar_pop (TV_PCH_PTR_REALLOC);
588 :
589 428 : timevar_push (TV_PCH_PTR_SORT);
590 428 : qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data);
591 428 : timevar_pop (TV_PCH_PTR_SORT);
592 :
593 : /* Write out all the scalar variables. */
594 7858 : for (rt = gt_pch_scalar_rtab; *rt; rt++)
595 24042 : for (rti = *rt; rti->base != NULL; rti++)
596 17040 : if (fwrite (rti->base, rti->stride, 1, f) != 1)
597 0 : fatal_error (input_location, "cannot write PCH file: %m");
598 :
599 : /* Write out all the global pointers, after translation. */
600 428 : write_pch_globals (gt_ggc_rtab, &state);
601 :
602 : /* Pad the PCH file so that the mmapped area starts on an allocation
603 : granularity (usually page) boundary. */
604 428 : {
605 428 : long o;
606 428 : o = ftell (state.f) + sizeof (mmi);
607 428 : if (o == -1)
608 0 : fatal_error (input_location, "cannot get position in PCH file: %m");
609 428 : mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment;
610 428 : if (mmi.offset == mmap_offset_alignment)
611 0 : mmi.offset = 0;
612 428 : mmi.offset += o;
613 : }
614 428 : if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
615 0 : fatal_error (input_location, "cannot write PCH file: %m");
616 428 : if (mmi.offset != 0
617 428 : && fseek (state.f, mmi.offset, SEEK_SET) != 0)
618 0 : fatal_error (input_location, "cannot write padding to PCH file: %m");
619 :
620 428 : ggc_pch_prepare_write (state.d, state.f);
621 :
622 : #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
623 : vec<char> vbits = vNULL;
624 : #endif
625 :
626 : /* Actually write out the objects. */
627 27066074 : for (i = 0; i < state.count; i++)
628 : {
629 27065646 : state.ptrs_i = i;
630 27065646 : if (this_object_size < state.ptrs[i]->size)
631 : {
632 6724 : this_object_size = state.ptrs[i]->size;
633 6724 : this_object = XRESIZEVAR (char, this_object, this_object_size);
634 : }
635 : #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
636 : /* obj might contain uninitialized bytes, e.g. in the trailing
637 : padding of the object. Avoid warnings by making the memory
638 : temporarily defined and then restoring previous state. */
639 : int get_vbits = 0;
640 : size_t valid_size = state.ptrs[i]->size;
641 : if (UNLIKELY (RUNNING_ON_VALGRIND))
642 : {
643 : if (vbits.length () < valid_size)
644 : vbits.safe_grow (valid_size, true);
645 : get_vbits = VALGRIND_GET_VBITS (state.ptrs[i]->obj,
646 : vbits.address (), valid_size);
647 : if (get_vbits == 3)
648 : {
649 : /* We assume that first part of obj is addressable, and
650 : the rest is unaddressable. Find out where the boundary is
651 : using binary search. */
652 : size_t lo = 0, hi = valid_size;
653 : while (hi > lo)
654 : {
655 : size_t mid = (lo + hi) / 2;
656 : get_vbits = VALGRIND_GET_VBITS ((char *) state.ptrs[i]->obj
657 : + mid, vbits.address (),
658 : 1);
659 : if (get_vbits == 3)
660 : hi = mid;
661 : else if (get_vbits == 1)
662 : lo = mid + 1;
663 : else
664 : break;
665 : }
666 : if (get_vbits == 1 || get_vbits == 3)
667 : {
668 : valid_size = lo;
669 : get_vbits = VALGRIND_GET_VBITS (state.ptrs[i]->obj,
670 : vbits.address (),
671 : valid_size);
672 : }
673 : }
674 : if (get_vbits == 1)
675 : VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (state.ptrs[i]->obj,
676 : state.ptrs[i]->size));
677 : }
678 : #endif
679 27065646 : memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size);
680 27065646 : if (state.ptrs[i]->reorder_fn != NULL)
681 20456 : state.ptrs[i]->reorder_fn (state.ptrs[i]->obj,
682 : state.ptrs[i]->note_ptr_cookie,
683 : relocate_ptrs, &state);
684 27065646 : gt_note_pointers note_ptr_fn = state.ptrs[i]->note_ptr_fn;
685 27065646 : gcc_checking_assert (note_ptr_fn != NULL);
686 : /* 'gt_pch_p_S' enables certain special handling, but otherwise
687 : corresponds to no 'note_ptr_fn'. */
688 27065646 : if (note_ptr_fn == gt_pch_p_S)
689 : note_ptr_fn = NULL;
690 24892793 : if (note_ptr_fn != NULL)
691 24892793 : note_ptr_fn (state.ptrs[i]->obj, state.ptrs[i]->note_ptr_cookie,
692 : relocate_ptrs, &state);
693 27065646 : ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
694 27065646 : state.ptrs[i]->new_addr, state.ptrs[i]->size);
695 27065646 : if (state.ptrs[i]->reorder_fn != NULL
696 27045190 : || note_ptr_fn != NULL)
697 24892793 : memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);
698 : #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
699 : if (UNLIKELY (get_vbits == 1))
700 : {
701 : (void) VALGRIND_SET_VBITS (state.ptrs[i]->obj, vbits.address (),
702 : valid_size);
703 : if (valid_size != state.ptrs[i]->size)
704 : VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *)
705 : state.ptrs[i]->obj
706 : + valid_size,
707 : state.ptrs[i]->size
708 : - valid_size));
709 : }
710 : #endif
711 : }
712 : #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
713 : vbits.release ();
714 : #endif
715 :
716 428 : reloc_addrs_vec.qsort (compare_ptr);
717 :
718 428 : size_t reloc_addrs_size = 0;
719 428 : void *last_addr = NULL;
720 428 : unsigned char uleb128_buf[sizeof (size_t) * 2];
721 72873570 : for (void *addr : reloc_addrs_vec)
722 : {
723 72872286 : gcc_assert ((uintptr_t) addr >= (uintptr_t) mmi.preferred_base
724 : && ((uintptr_t) addr + sizeof (void *)
725 : <= (uintptr_t) mmi.preferred_base + mmi.size));
726 72872286 : if (addr == last_addr)
727 0 : continue;
728 72872286 : if (last_addr == NULL)
729 428 : last_addr = mmi.preferred_base;
730 72872286 : size_t diff = (uintptr_t) addr - (uintptr_t) last_addr;
731 72872286 : reloc_addrs_size += write_uleb128 (uleb128_buf, diff);
732 72872286 : last_addr = addr;
733 : }
734 428 : if (fwrite (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1)
735 0 : fatal_error (input_location, "cannot write PCH file: %m");
736 428 : last_addr = NULL;
737 72873570 : for (void *addr : reloc_addrs_vec)
738 : {
739 72872286 : if (addr == last_addr)
740 0 : continue;
741 72872286 : if (last_addr == NULL)
742 428 : last_addr = mmi.preferred_base;
743 72872286 : size_t diff = (uintptr_t) addr - (uintptr_t) last_addr;
744 72872286 : reloc_addrs_size = write_uleb128 (uleb128_buf, diff);
745 72872286 : if (fwrite (uleb128_buf, 1, reloc_addrs_size, f) != reloc_addrs_size)
746 0 : fatal_error (input_location, "cannot write PCH file: %m");
747 : last_addr = addr;
748 : }
749 :
750 428 : ggc_pch_finish (state.d, state.f);
751 :
752 428 : gt_pch_fixup_stringpool ();
753 :
754 428 : unsigned num_callbacks = callback_vec.length ();
755 428 : void (*pch_save) (FILE *) = >_pch_save;
756 428 : if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
757 428 : || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
758 856 : || (num_callbacks
759 856 : && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
760 428 : f) != num_callbacks))
761 0 : fatal_error (input_location, "cannot write PCH file: %m");
762 :
763 428 : XDELETE (state.ptrs);
764 428 : XDELETE (this_object);
765 428 : delete saving_htab;
766 428 : saving_htab = NULL;
767 428 : callback_vec.release ();
768 428 : reloc_addrs_vec.release ();
769 428 : }
770 :
771 : /* Read the state of the compiler back in from F. */
772 :
773 : void
774 350 : gt_pch_restore (FILE *f)
775 : {
776 350 : const struct ggc_root_tab *const *rt;
777 350 : const struct ggc_root_tab *rti;
778 350 : size_t i;
779 350 : struct mmap_info mmi;
780 350 : int result;
781 :
782 : /* We are about to reload the line maps along with the rest of the PCH
783 : data, which means that the (loaded) ones cannot be guaranteed to be
784 : in any valid state for reporting diagnostics that happen during the
785 : load. Save the current table (and use it during the loading process
786 : below). */
787 350 : class line_maps *save_line_table = line_table;
788 :
789 : /* Delete any deletable objects. This makes ggc_pch_read much
790 : faster, as it can be sure that no GCable objects remain other
791 : than the ones just read in. */
792 4710 : for (rt = gt_ggc_deletable_rtab; *rt; rt++)
793 10716 : for (rti = *rt; rti->base != NULL; rti++)
794 6356 : memset (rti->base, 0, rti->stride);
795 :
796 : /* Read in all the scalar variables. */
797 6116 : for (rt = gt_pch_scalar_rtab; *rt; rt++)
798 19754 : for (rti = *rt; rti->base != NULL; rti++)
799 13988 : if (fread (rti->base, rti->stride, 1, f) != 1)
800 0 : fatal_error (input_location, "cannot read PCH file: %m");
801 :
802 : /* Read in all the global pointers, in 6 easy loops. */
803 : bool error_reading_pointers = false;
804 22450 : for (rt = gt_ggc_rtab; *rt; rt++)
805 158788 : for (rti = *rt; rti->base != NULL; rti++)
806 3526320 : for (i = 0; i < rti->nelt; i++)
807 3389632 : if (fread ((char *)rti->base + rti->stride * i,
808 : sizeof (void *), 1, f) != 1)
809 0 : error_reading_pointers = true;
810 :
811 : /* Stash the newly read-in line table pointer - it does not point to
812 : anything meaningful yet, so swap the old one back in. */
813 350 : class line_maps *new_line_table = line_table;
814 350 : line_table = save_line_table;
815 350 : if (error_reading_pointers)
816 0 : fatal_error (input_location, "cannot read PCH file: %m");
817 :
818 350 : if (fread (&mmi, sizeof (mmi), 1, f) != 1)
819 0 : fatal_error (input_location, "cannot read PCH file: %m");
820 :
821 350 : void *orig_preferred_base = mmi.preferred_base;
822 350 : result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
823 : fileno (f), mmi.offset);
824 :
825 : /* We could not mmap or otherwise allocate the required memory at the
826 : address needed. */
827 350 : if (result < 0)
828 : {
829 0 : sorry_at (input_location, "PCH allocation failure");
830 : /* There is no point in continuing from here, we will only end up
831 : with a crashed (most likely hanging) compiler. */
832 0 : exit (-1);
833 : }
834 :
835 : /* (0) We allocated memory, but did not mmap the file, so we need to read
836 : the data in manually. (>0) Otherwise the mmap succeed for the address
837 : we wanted. */
838 350 : if (result == 0)
839 : {
840 0 : if (fseek (f, mmi.offset, SEEK_SET) != 0
841 0 : || fread (mmi.preferred_base, mmi.size, 1, f) != 1)
842 0 : fatal_error (input_location, "cannot read PCH file: %m");
843 : }
844 350 : else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
845 0 : fatal_error (input_location, "cannot read PCH file: %m");
846 :
847 350 : size_t reloc_addrs_size;
848 350 : if (fread (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1)
849 0 : fatal_error (input_location, "cannot read PCH file: %m");
850 :
851 350 : if (orig_preferred_base != mmi.preferred_base)
852 : {
853 0 : uintptr_t bias
854 0 : = (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base;
855 :
856 : /* Adjust all the global pointers by bias. */
857 0 : line_table = new_line_table;
858 0 : for (rt = gt_ggc_rtab; *rt; rt++)
859 0 : for (rti = *rt; rti->base != NULL; rti++)
860 0 : for (i = 0; i < rti->nelt; i++)
861 : {
862 0 : char *addr = (char *)rti->base + rti->stride * i;
863 0 : char *p;
864 0 : memcpy (&p, addr, sizeof (void *));
865 0 : if ((uintptr_t) p >= (uintptr_t) orig_preferred_base
866 0 : && (uintptr_t) p < (uintptr_t) orig_preferred_base + mmi.size)
867 : {
868 0 : p = (char *) ((uintptr_t) p + bias);
869 0 : memcpy (addr, &p, sizeof (void *));
870 : }
871 : }
872 0 : new_line_table = line_table;
873 0 : line_table = save_line_table;
874 :
875 : /* And adjust all the pointers in the image by bias too. */
876 0 : char *addr = (char *) mmi.preferred_base;
877 0 : unsigned char uleb128_buf[4096], *uleb128_ptr = uleb128_buf;
878 0 : while (reloc_addrs_size != 0)
879 : {
880 0 : size_t this_size
881 0 : = MIN (reloc_addrs_size,
882 : (size_t) (4096 - (uleb128_ptr - uleb128_buf)));
883 0 : if (fread (uleb128_ptr, 1, this_size, f) != this_size)
884 0 : fatal_error (input_location, "cannot read PCH file: %m");
885 0 : unsigned char *uleb128_end = uleb128_ptr + this_size;
886 0 : if (this_size != reloc_addrs_size)
887 0 : uleb128_end -= 2 * sizeof (size_t);
888 0 : uleb128_ptr = uleb128_buf;
889 0 : while (uleb128_ptr < uleb128_end)
890 : {
891 : size_t diff;
892 0 : uleb128_ptr = read_uleb128 (uleb128_ptr, &diff);
893 0 : addr = (char *) ((uintptr_t) addr + diff);
894 :
895 0 : char *p;
896 0 : memcpy (&p, addr, sizeof (void *));
897 0 : gcc_assert ((uintptr_t) p >= (uintptr_t) orig_preferred_base
898 : && ((uintptr_t) p
899 : < (uintptr_t) orig_preferred_base + mmi.size));
900 0 : p = (char *) ((uintptr_t) p + bias);
901 0 : memcpy (addr, &p, sizeof (void *));
902 : }
903 0 : reloc_addrs_size -= this_size;
904 0 : if (reloc_addrs_size == 0)
905 : break;
906 0 : this_size = uleb128_end + 2 * sizeof (size_t) - uleb128_ptr;
907 0 : memcpy (uleb128_buf, uleb128_ptr, this_size);
908 0 : uleb128_ptr = uleb128_buf + this_size;
909 : }
910 : }
911 350 : else if (fseek (f, (mmi.offset + mmi.size + sizeof (reloc_addrs_size)
912 350 : + reloc_addrs_size), SEEK_SET) != 0)
913 0 : fatal_error (input_location, "cannot read PCH file: %m");
914 :
915 350 : ggc_pch_read (f, mmi.preferred_base);
916 :
917 350 : void (*pch_save) (FILE *);
918 350 : unsigned num_callbacks;
919 350 : if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
920 350 : || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
921 0 : fatal_error (input_location, "cannot read PCH file: %m");
922 350 : if (pch_save != >_pch_save)
923 : {
924 0 : uintptr_t binbias = (uintptr_t) >_pch_save - (uintptr_t) pch_save;
925 0 : void **ptrs = XNEWVEC (void *, num_callbacks);
926 0 : unsigned i;
927 0 : uintptr_t bias
928 0 : = (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base;
929 :
930 0 : if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
931 0 : fatal_error (input_location, "cannot read PCH file: %m");
932 0 : for (i = 0; i < num_callbacks; ++i)
933 : {
934 0 : void *ptr = (void *) ((uintptr_t) ptrs[i] + bias);
935 0 : memcpy (&pch_save, ptr, sizeof (pch_save));
936 0 : pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + binbias);
937 0 : memcpy (ptr, &pch_save, sizeof (pch_save));
938 : }
939 0 : XDELETE (ptrs);
940 : }
941 350 : else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
942 0 : fatal_error (input_location, "cannot read PCH file: %m");
943 :
944 350 : gt_pch_restore_stringpool ();
945 :
946 : /* Barring corruption of the PCH file, the restored line table should be
947 : complete and usable. */
948 350 : line_table = new_line_table;
949 350 : }
950 :
951 : /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
952 : Select no address whatsoever, and let gt_pch_save choose what it will with
953 : malloc, presumably. */
954 :
955 : void *
956 0 : default_gt_pch_get_address (size_t size ATTRIBUTE_UNUSED,
957 : int fd ATTRIBUTE_UNUSED)
958 : {
959 0 : return NULL;
960 : }
961 :
962 : /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is not present.
963 : Allocate SIZE bytes with malloc. Return 0 if the address we got is the
964 : same as base, indicating that the memory has been allocated but needs to
965 : be read in from the file. Return -1 if the address differs, to relocation
966 : of the PCH file would be required. */
967 :
968 : int
969 0 : default_gt_pch_use_address (void *&base, size_t size, int fd ATTRIBUTE_UNUSED,
970 : size_t offset ATTRIBUTE_UNUSED)
971 : {
972 0 : void *addr = xmalloc (size);
973 0 : return (addr == base) - 1;
974 : }
975 :
976 : /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS. Return the
977 : alignment required for allocating virtual memory. Usually this is the
978 : same as pagesize. */
979 :
980 : size_t
981 428 : default_gt_pch_alloc_granularity (void)
982 : {
983 428 : return getpagesize ();
984 : }
985 :
986 : #if HAVE_MMAP_FILE
987 : /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is present.
988 : We temporarily allocate SIZE bytes, and let the kernel place the data
989 : wherever it will. If it worked, that's our spot, if not we're likely
990 : to be in trouble. */
991 :
992 : void *
993 0 : mmap_gt_pch_get_address (size_t size, int fd)
994 : {
995 0 : void *ret;
996 :
997 0 : ret = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
998 0 : if (ret == (void *) MAP_FAILED)
999 : ret = NULL;
1000 : else
1001 0 : munmap ((caddr_t) ret, size);
1002 :
1003 0 : return ret;
1004 : }
1005 :
1006 : /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is present.
1007 : Map SIZE bytes of FD+OFFSET at BASE. Return 1 if we succeeded at
1008 : mapping the data at BASE, -1 if we couldn't.
1009 :
1010 : This version assumes that the kernel honors the START operand of mmap
1011 : even without MAP_FIXED if START through START+SIZE are not currently
1012 : mapped with something. */
1013 :
1014 : int
1015 0 : mmap_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
1016 : {
1017 0 : void *addr;
1018 :
1019 : /* We're called with size == 0 if we're not planning to load a PCH
1020 : file at all. This allows the hook to free any static space that
1021 : we might have allocated at link time. */
1022 0 : if (size == 0)
1023 : return -1;
1024 :
1025 0 : addr = mmap ((caddr_t) base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
1026 : fd, offset);
1027 :
1028 0 : return addr == base ? 1 : -1;
1029 : }
1030 : #endif /* HAVE_MMAP_FILE */
1031 :
1032 : #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
1033 :
1034 : /* Modify the bound based on rlimits. */
1035 : static double
1036 : ggc_rlimit_bound (double limit)
1037 : {
1038 : #if defined(HAVE_GETRLIMIT)
1039 : struct rlimit rlim;
1040 : # if defined (RLIMIT_AS)
1041 : /* RLIMIT_AS is what POSIX says is the limit on mmap. Presumably
1042 : any OS which has RLIMIT_AS also has a working mmap that GCC will use. */
1043 : if (getrlimit (RLIMIT_AS, &rlim) == 0
1044 : && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
1045 : && rlim.rlim_cur < limit)
1046 : limit = rlim.rlim_cur;
1047 : # elif defined (RLIMIT_DATA)
1048 : /* ... but some older OSs bound mmap based on RLIMIT_DATA, or we
1049 : might be on an OS that has a broken mmap. (Others don't bound
1050 : mmap at all, apparently.) */
1051 : if (getrlimit (RLIMIT_DATA, &rlim) == 0
1052 : && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
1053 : && rlim.rlim_cur < limit
1054 : /* Darwin has this horribly bogus default setting of
1055 : RLIMIT_DATA, to 6144Kb. No-one notices because RLIMIT_DATA
1056 : appears to be ignored. Ignore such silliness. If a limit
1057 : this small was actually effective for mmap, GCC wouldn't even
1058 : start up. */
1059 : && rlim.rlim_cur >= 8 * ONE_M)
1060 : limit = rlim.rlim_cur;
1061 : # endif /* RLIMIT_AS or RLIMIT_DATA */
1062 : #endif /* HAVE_GETRLIMIT */
1063 :
1064 : return limit;
1065 : }
1066 :
1067 : /* Heuristic to set a default for GGC_MIN_EXPAND. */
1068 : static int
1069 : ggc_min_expand_heuristic (void)
1070 : {
1071 : double min_expand = physmem_total ();
1072 :
1073 : /* Adjust for rlimits. */
1074 : min_expand = ggc_rlimit_bound (min_expand);
1075 :
1076 : /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding
1077 : a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB). */
1078 : min_expand /= ONE_G;
1079 : min_expand *= 70;
1080 : min_expand = MIN (min_expand, 70);
1081 : min_expand += 30;
1082 :
1083 : return min_expand;
1084 : }
1085 :
1086 : /* Heuristic to set a default for GGC_MIN_HEAPSIZE. */
1087 : static int
1088 : ggc_min_heapsize_heuristic (void)
1089 : {
1090 : double phys_kbytes = physmem_total ();
1091 : double limit_kbytes = ggc_rlimit_bound (phys_kbytes * 2);
1092 :
1093 : phys_kbytes /= ONE_K; /* Convert to Kbytes. */
1094 : limit_kbytes /= ONE_K;
1095 :
1096 : /* The heuristic is RAM/8, with a lower bound of 4M and an upper
1097 : bound of 128M (when RAM >= 1GB). */
1098 : phys_kbytes /= 8;
1099 :
1100 : #if defined(HAVE_GETRLIMIT) && defined (RLIMIT_RSS)
1101 : /* Try not to overrun the RSS limit while doing garbage collection.
1102 : The RSS limit is only advisory, so no margin is subtracted. */
1103 : {
1104 : struct rlimit rlim;
1105 : if (getrlimit (RLIMIT_RSS, &rlim) == 0
1106 : && rlim.rlim_cur != (rlim_t) RLIM_INFINITY)
1107 : phys_kbytes = MIN (phys_kbytes, rlim.rlim_cur / ONE_K);
1108 : }
1109 : # endif
1110 :
1111 : /* Don't blindly run over our data limit; do GC at least when the
1112 : *next* GC would be within 20Mb of the limit or within a quarter of
1113 : the limit, whichever is larger. If GCC does hit the data limit,
1114 : compilation will fail, so this tries to be conservative. */
1115 : limit_kbytes = MAX (0, limit_kbytes - MAX (limit_kbytes / 4, 20 * ONE_K));
1116 : limit_kbytes = (limit_kbytes * 100) / (110 + ggc_min_expand_heuristic ());
1117 : phys_kbytes = MIN (phys_kbytes, limit_kbytes);
1118 :
1119 : phys_kbytes = MAX (phys_kbytes, 4 * ONE_K);
1120 : phys_kbytes = MIN (phys_kbytes, 128 * ONE_K);
1121 :
1122 : return phys_kbytes;
1123 : }
1124 : #endif
1125 :
1126 : void
1127 285722 : init_ggc_heuristics (void)
1128 : {
1129 : #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
1130 : param_ggc_min_expand = ggc_min_expand_heuristic ();
1131 : param_ggc_min_heapsize = ggc_min_heapsize_heuristic ();
1132 : #endif
1133 285722 : }
1134 :
1135 : /* GGC memory usage. */
1136 : class ggc_usage: public mem_usage
1137 : {
1138 : public:
1139 : /* Default constructor. */
1140 0 : ggc_usage (): m_freed (0), m_collected (0), m_overhead (0) {}
1141 : /* Constructor. */
1142 : ggc_usage (size_t allocated, size_t times, size_t peak,
1143 : size_t freed, size_t collected, size_t overhead)
1144 : : mem_usage (allocated, times, peak),
1145 : m_freed (freed), m_collected (collected), m_overhead (overhead) {}
1146 :
1147 : /* Equality operator. */
1148 : inline bool
1149 : operator== (const ggc_usage &second) const
1150 : {
1151 : return (get_balance () == second.get_balance ()
1152 : && m_peak == second.m_peak
1153 : && m_times == second.m_times);
1154 : }
1155 :
1156 : /* Comparison operator. */
1157 : inline bool
1158 : operator< (const ggc_usage &second) const
1159 : {
1160 : if (*this == second)
1161 : return false;
1162 :
1163 : return (get_balance () == second.get_balance () ?
1164 : (m_peak == second.m_peak ? m_times < second.m_times
1165 : : m_peak < second.m_peak)
1166 : : get_balance () < second.get_balance ());
1167 : }
1168 :
1169 : /* Register overhead of ALLOCATED and OVERHEAD bytes. */
1170 : inline void
1171 0 : register_overhead (size_t allocated, size_t overhead)
1172 : {
1173 0 : m_allocated += allocated;
1174 0 : m_overhead += overhead;
1175 0 : m_times++;
1176 : }
1177 :
1178 : /* Release overhead of SIZE bytes. */
1179 : inline void
1180 0 : release_overhead (size_t size)
1181 : {
1182 0 : m_freed += size;
1183 : }
1184 :
1185 : /* Sum the usage with SECOND usage. */
1186 : ggc_usage
1187 : operator+ (const ggc_usage &second)
1188 : {
1189 : return ggc_usage (m_allocated + second.m_allocated,
1190 : m_times + second.m_times,
1191 : m_peak + second.m_peak,
1192 : m_freed + second.m_freed,
1193 : m_collected + second.m_collected,
1194 : m_overhead + second.m_overhead);
1195 : }
1196 :
1197 : /* Dump usage with PREFIX, where TOTAL is sum of all rows. */
1198 : inline void
1199 : dump (const char *prefix, ggc_usage &total) const
1200 : {
1201 : size_t balance = get_balance ();
1202 : fprintf (stderr,
1203 : "%-48s " PRsa (9) ":%5.1f%%" PRsa (9) ":%5.1f%%"
1204 : PRsa (9) ":%5.1f%%" PRsa (9) ":%5.1f%%" PRsa (9) "\n",
1205 : prefix,
1206 : SIZE_AMOUNT (balance), get_percent (balance, total.get_balance ()),
1207 : SIZE_AMOUNT (m_collected),
1208 : get_percent (m_collected, total.m_collected),
1209 : SIZE_AMOUNT (m_freed), get_percent (m_freed, total.m_freed),
1210 : SIZE_AMOUNT (m_overhead),
1211 : get_percent (m_overhead, total.m_overhead),
1212 : SIZE_AMOUNT (m_times));
1213 : }
1214 :
1215 : /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
1216 : inline void
1217 : dump (mem_location *loc, ggc_usage &total) const
1218 : {
1219 : char *location_string = loc->to_string ();
1220 :
1221 : dump (location_string, total);
1222 :
1223 : free (location_string);
1224 : }
1225 :
1226 : /* Dump footer. */
1227 : inline void
1228 : dump_footer ()
1229 : {
1230 : dump ("Total", *this);
1231 : }
1232 :
1233 : /* Get balance which is GGC allocation leak. */
1234 : inline size_t
1235 : get_balance () const
1236 : {
1237 : return m_allocated + m_overhead - m_collected - m_freed;
1238 : }
1239 :
1240 : typedef std::pair<mem_location *, ggc_usage *> mem_pair_t;
1241 :
1242 : /* Compare wrapper used by qsort method. */
1243 : static int
1244 : compare (const void *first, const void *second)
1245 : {
1246 : const mem_pair_t mem1 = *(const mem_pair_t *) first;
1247 : const mem_pair_t mem2 = *(const mem_pair_t *) second;
1248 :
1249 : size_t balance1 = mem1.second->get_balance ();
1250 : size_t balance2 = mem2.second->get_balance ();
1251 :
1252 : return balance1 == balance2 ? 0 : (balance1 < balance2 ? 1 : -1);
1253 : }
1254 :
1255 : /* Dump header with NAME. */
1256 : static inline void
1257 : dump_header (const char *name)
1258 : {
1259 : fprintf (stderr, "%-48s %11s%17s%17s%16s%17s\n", name, "Leak", "Garbage",
1260 : "Freed", "Overhead", "Times");
1261 : }
1262 :
1263 : /* Freed memory in bytes. */
1264 : size_t m_freed;
1265 : /* Collected memory in bytes. */
1266 : size_t m_collected;
1267 : /* Overhead memory in bytes. */
1268 : size_t m_overhead;
1269 : };
1270 :
1271 : /* GCC memory description. */
1272 : static mem_alloc_description<ggc_usage> ggc_mem_desc;
1273 :
1274 : /* Dump per-site memory statistics. */
1275 :
1276 : void
1277 0 : dump_ggc_loc_statistics ()
1278 : {
1279 0 : if (! GATHER_STATISTICS)
1280 0 : return;
1281 :
1282 : ggc_collect (GGC_COLLECT_FORCE);
1283 :
1284 : ggc_mem_desc.dump (GGC_ORIGIN);
1285 : }
1286 :
1287 : /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */
1288 : void
1289 0 : ggc_record_overhead (size_t allocated, size_t overhead, void *ptr MEM_STAT_DECL)
1290 : {
1291 0 : ggc_usage *usage = ggc_mem_desc.register_descriptor (ptr, GGC_ORIGIN, false
1292 : FINAL_PASS_MEM_STAT);
1293 :
1294 0 : ggc_mem_desc.register_object_overhead (usage, allocated + overhead, ptr);
1295 0 : usage->register_overhead (allocated, overhead);
1296 0 : }
1297 :
1298 : /* Notice that the pointer has been freed. */
1299 : void
1300 0 : ggc_free_overhead (void *ptr)
1301 : {
1302 0 : ggc_mem_desc.release_object_overhead (ptr);
1303 0 : }
1304 :
1305 : /* After live values has been marked, walk all recorded pointers and see if
1306 : they are still live. */
1307 : void
1308 0 : ggc_prune_overhead_list (void)
1309 : {
1310 0 : typedef hash_map<const void *, std::pair<ggc_usage *, size_t > > map_t;
1311 :
1312 0 : map_t::iterator it = ggc_mem_desc.m_reverse_object_map->begin ();
1313 :
1314 0 : for (; it != ggc_mem_desc.m_reverse_object_map->end (); ++it)
1315 0 : if (!ggc_marked_p ((*it).first))
1316 : {
1317 0 : (*it).second.first->m_collected += (*it).second.second;
1318 0 : ggc_mem_desc.m_reverse_object_map->remove ((*it).first);
1319 : }
1320 0 : }
1321 :
1322 : /* Print memory used by heap if this info is available. */
1323 :
1324 : void
1325 4958993 : report_heap_memory_use ()
1326 : {
1327 : #if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
1328 : #ifdef HAVE_MALLINFO2
1329 : #define MALLINFO_FN mallinfo2
1330 : #else
1331 : #define MALLINFO_FN mallinfo
1332 : #endif
1333 4958993 : if (!quiet_flag)
1334 0 : fprintf (stderr, " {heap " PRsa (0) "}",
1335 0 : SIZE_AMOUNT (MALLINFO_FN ().arena));
1336 : #endif
1337 4958993 : }
1338 :
1339 : /* Forcibly clear all GTY roots. */
1340 :
1341 : void
1342 256621 : ggc_common_finalize ()
1343 : {
1344 256621 : const struct ggc_root_tab *const *rt;
1345 256621 : const_ggc_root_tab_t rti;
1346 :
1347 3466569 : for (rt = gt_ggc_deletable_rtab; *rt; rt++)
1348 7979784 : for (rti = *rt; rti->base != NULL; rti++)
1349 4769836 : memset (rti->base, 0, rti->stride * rti->nelt);
1350 :
1351 16809461 : for (rt = gt_ggc_rtab; *rt; rt++)
1352 16552840 : ggc_zero_rtab_roots (*rt);
1353 :
1354 4448159 : for (rt = gt_pch_scalar_rtab; *rt; rt++)
1355 14325743 : for (rti = *rt; rti->base != NULL; rti++)
1356 10134205 : memset (rti->base, 0, rti->stride * rti->nelt);
1357 256621 : }
|