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