Mercurial > hg > CbC > CbC_gcc
annotate gcc/ggc-common.c @ 116:367f9f4f266e
fix gimple.h
author | mir3636 |
---|---|
date | Tue, 28 Nov 2017 20:22:01 +0900 (2017-11-28) |
parents | 04ced10e8804 |
children | 84e7813d76e9 |
rev | line source |
---|---|
0 | 1 /* Simple garbage collection for the GNU compiler. |
111 | 2 Copyright (C) 1999-2017 Free Software Foundation, Inc. |
0 | 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 #include "system.h" | |
25 #include "coretypes.h" | |
111 | 26 #include "timevar.h" |
27 #include "diagnostic-core.h" | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
28 #include "ggc-internal.h" |
0 | 29 #include "params.h" |
30 #include "hosthooks.h" | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
31 #include "plugin.h" |
0 | 32 |
33 /* When set, ggc_collect will do collection. */ | |
34 bool ggc_force_collect; | |
35 | |
36 /* When true, protect the contents of the identifier hash table. */ | |
37 bool ggc_protect_identifiers = true; | |
38 | |
39 /* Statistics about the allocation. */ | |
40 static ggc_statistics *ggc_stats; | |
41 | |
42 struct traversal_state; | |
43 | |
44 static int compare_ptr_data (const void *, const void *); | |
45 static void relocate_ptrs (void *, void *); | |
46 static void write_pch_globals (const struct ggc_root_tab * const *tab, | |
47 struct traversal_state *state); | |
48 | |
49 /* Maintain global roots that are preserved during GC. */ | |
50 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
51 /* This extra vector of dynamically registered root_tab-s is used by |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
52 ggc_mark_roots and gives the ability to dynamically add new GGC root |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
53 tables, for instance from some plugins; this vector is on the heap |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
54 since it is used by GGC internally. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
55 typedef const struct ggc_root_tab *const_ggc_root_tab_t; |
111 | 56 static vec<const_ggc_root_tab_t> extra_root_vec; |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
57 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
58 /* Dynamically register a new GGC root table RT. This is useful for |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
59 plugins. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
60 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
61 void |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
62 ggc_register_root_tab (const struct ggc_root_tab* rt) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
63 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
64 if (rt) |
111 | 65 extra_root_vec.safe_push (rt); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
66 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
67 |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
68 /* Mark all the roots in the table RT. */ |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
69 |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
70 static void |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
71 ggc_mark_root_tab (const_ggc_root_tab_t rt) |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
72 { |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
73 size_t i; |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
74 |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
75 for ( ; rt->base != NULL; rt++) |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
76 for (i = 0; i < rt->nelt; i++) |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
77 (*rt->cb) (*(void **) ((char *)rt->base + rt->stride * i)); |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
78 } |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
79 |
0 | 80 /* Iterate through all registered roots and mark each element. */ |
81 | |
82 void | |
83 ggc_mark_roots (void) | |
84 { | |
85 const struct ggc_root_tab *const *rt; | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
86 const_ggc_root_tab_t rtp, rti; |
0 | 87 size_t i; |
88 | |
89 for (rt = gt_ggc_deletable_rtab; *rt; rt++) | |
90 for (rti = *rt; rti->base != NULL; rti++) | |
91 memset (rti->base, 0, rti->stride); | |
92 | |
93 for (rt = gt_ggc_rtab; *rt; rt++) | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
94 ggc_mark_root_tab (*rt); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
95 |
111 | 96 FOR_EACH_VEC_ELT (extra_root_vec, i, rtp) |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
97 ggc_mark_root_tab (rtp); |
0 | 98 |
99 if (ggc_protect_identifiers) | |
100 ggc_mark_stringpool (); | |
101 | |
111 | 102 gt_clear_caches (); |
0 | 103 |
104 if (! ggc_protect_identifiers) | |
105 ggc_purge_stringpool (); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
106 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
107 /* Some plugins may call ggc_set_mark from here. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
108 invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL); |
0 | 109 } |
110 | |
111 /* Allocate a block of memory, then clear it. */ | |
112 void * | |
111 | 113 ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s, size_t n |
114 MEM_STAT_DECL) | |
0 | 115 { |
111 | 116 void *buf = ggc_internal_alloc (size, f, s, n PASS_MEM_STAT); |
0 | 117 memset (buf, 0, size); |
118 return buf; | |
119 } | |
120 | |
121 /* Resize a block of memory, possibly re-allocating it. */ | |
122 void * | |
111 | 123 ggc_realloc (void *x, size_t size MEM_STAT_DECL) |
0 | 124 { |
125 void *r; | |
126 size_t old_size; | |
127 | |
128 if (x == NULL) | |
111 | 129 return ggc_internal_alloc (size PASS_MEM_STAT); |
0 | 130 |
131 old_size = ggc_get_size (x); | |
132 | |
133 if (size <= old_size) | |
134 { | |
135 /* Mark the unwanted memory as unaccessible. We also need to make | |
136 the "new" size accessible, since ggc_get_size returns the size of | |
137 the pool, not the size of the individually allocated object, the | |
138 size which was previously made accessible. Unfortunately, we | |
139 don't know that previously allocated size. Without that | |
140 knowledge we have to lose some initialization-tracking for the | |
141 old parts of the object. An alternative is to mark the whole | |
142 old_size as reachable, but that would lose tracking of writes | |
143 after the end of the object (by small offsets). Discard the | |
144 handle to avoid handle leak. */ | |
145 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *) x + size, | |
146 old_size - size)); | |
147 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, size)); | |
148 return x; | |
149 } | |
150 | |
111 | 151 r = ggc_internal_alloc (size PASS_MEM_STAT); |
0 | 152 |
153 /* Since ggc_get_size returns the size of the pool, not the size of the | |
154 individually allocated object, we'd access parts of the old object | |
155 that were marked invalid with the memcpy below. We lose a bit of the | |
156 initialization-tracking since some of it may be uninitialized. */ | |
157 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, old_size)); | |
158 | |
159 memcpy (r, x, old_size); | |
160 | |
161 /* The old object is not supposed to be used anymore. */ | |
162 ggc_free (x); | |
163 | |
164 return r; | |
165 } | |
166 | |
167 void * | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
168 ggc_cleared_alloc_htab_ignore_args (size_t c ATTRIBUTE_UNUSED, |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
169 size_t n ATTRIBUTE_UNUSED) |
0 | 170 { |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
171 gcc_assert (c * n == sizeof (struct htab)); |
111 | 172 return ggc_cleared_alloc<htab> (); |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
173 } |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
174 |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
175 /* TODO: once we actually use type information in GGC, create a new tag |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
176 gt_gcc_ptr_array and use it for pointer arrays. */ |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
177 void * |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
178 ggc_cleared_alloc_ptr_array_two_args (size_t c, size_t n) |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
179 { |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
180 gcc_assert (sizeof (PTR *) == n); |
111 | 181 return ggc_cleared_vec_alloc<PTR *> (c); |
0 | 182 } |
183 | |
184 /* These are for splay_tree_new_ggc. */ | |
185 void * | |
111 | 186 ggc_splay_alloc (int sz, void *nl) |
0 | 187 { |
188 gcc_assert (!nl); | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
189 return ggc_internal_alloc (sz); |
0 | 190 } |
191 | |
192 void | |
193 ggc_splay_dont_free (void * x ATTRIBUTE_UNUSED, void *nl) | |
194 { | |
195 gcc_assert (!nl); | |
196 } | |
197 | |
198 /* Print statistics that are independent of the collector in use. */ | |
199 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \ | |
200 ? (x) \ | |
201 : ((x) < 1024*1024*10 \ | |
202 ? (x) / 1024 \ | |
203 : (x) / (1024*1024)))) | |
204 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M')) | |
205 | |
206 void | |
207 ggc_print_common_statistics (FILE *stream ATTRIBUTE_UNUSED, | |
208 ggc_statistics *stats) | |
209 { | |
210 /* Set the pointer so that during collection we will actually gather | |
211 the statistics. */ | |
212 ggc_stats = stats; | |
213 | |
214 /* Then do one collection to fill in the statistics. */ | |
215 ggc_collect (); | |
216 | |
217 /* At present, we don't really gather any interesting statistics. */ | |
218 | |
219 /* Don't gather statistics any more. */ | |
220 ggc_stats = NULL; | |
221 } | |
222 | |
223 /* Functions for saving and restoring GCable memory to disk. */ | |
224 | |
225 struct ptr_data | |
226 { | |
227 void *obj; | |
228 void *note_ptr_cookie; | |
229 gt_note_pointers note_ptr_fn; | |
230 gt_handle_reorder reorder_fn; | |
231 size_t size; | |
232 void *new_addr; | |
111 | 233 }; |
234 | |
235 #define POINTER_HASH(x) (hashval_t)((intptr_t)x >> 3) | |
236 | |
237 /* Helper for hashing saving_htab. */ | |
238 | |
239 struct saving_hasher : free_ptr_hash <ptr_data> | |
240 { | |
241 typedef void *compare_type; | |
242 static inline hashval_t hash (const ptr_data *); | |
243 static inline bool equal (const ptr_data *, const void *); | |
0 | 244 }; |
245 | |
111 | 246 inline hashval_t |
247 saving_hasher::hash (const ptr_data *p) | |
248 { | |
249 return POINTER_HASH (p->obj); | |
250 } | |
251 | |
252 inline bool | |
253 saving_hasher::equal (const ptr_data *p1, const void *p2) | |
254 { | |
255 return p1->obj == p2; | |
256 } | |
257 | |
258 static hash_table<saving_hasher> *saving_htab; | |
0 | 259 |
260 /* Register an object in the hash table. */ | |
261 | |
262 int | |
263 gt_pch_note_object (void *obj, void *note_ptr_cookie, | |
111 | 264 gt_note_pointers note_ptr_fn) |
0 | 265 { |
266 struct ptr_data **slot; | |
267 | |
268 if (obj == NULL || obj == (void *) 1) | |
269 return 0; | |
270 | |
271 slot = (struct ptr_data **) | |
111 | 272 saving_htab->find_slot_with_hash (obj, POINTER_HASH (obj), INSERT); |
0 | 273 if (*slot != NULL) |
274 { | |
275 gcc_assert ((*slot)->note_ptr_fn == note_ptr_fn | |
276 && (*slot)->note_ptr_cookie == note_ptr_cookie); | |
277 return 0; | |
278 } | |
279 | |
280 *slot = XCNEW (struct ptr_data); | |
281 (*slot)->obj = obj; | |
282 (*slot)->note_ptr_fn = note_ptr_fn; | |
283 (*slot)->note_ptr_cookie = note_ptr_cookie; | |
284 if (note_ptr_fn == gt_pch_p_S) | |
285 (*slot)->size = strlen ((const char *)obj) + 1; | |
286 else | |
287 (*slot)->size = ggc_get_size (obj); | |
288 return 1; | |
289 } | |
290 | |
291 /* Register an object in the hash table. */ | |
292 | |
293 void | |
294 gt_pch_note_reorder (void *obj, void *note_ptr_cookie, | |
295 gt_handle_reorder reorder_fn) | |
296 { | |
297 struct ptr_data *data; | |
298 | |
299 if (obj == NULL || obj == (void *) 1) | |
300 return; | |
301 | |
302 data = (struct ptr_data *) | |
111 | 303 saving_htab->find_with_hash (obj, POINTER_HASH (obj)); |
0 | 304 gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie); |
305 | |
306 data->reorder_fn = reorder_fn; | |
307 } | |
308 | |
309 /* Handy state for the traversal functions. */ | |
310 | |
311 struct traversal_state | |
312 { | |
313 FILE *f; | |
314 struct ggc_pch_data *d; | |
315 size_t count; | |
316 struct ptr_data **ptrs; | |
317 size_t ptrs_i; | |
318 }; | |
319 | |
320 /* Callbacks for htab_traverse. */ | |
321 | |
111 | 322 int |
323 ggc_call_count (ptr_data **slot, traversal_state *state) | |
0 | 324 { |
111 | 325 struct ptr_data *d = *slot; |
0 | 326 |
327 ggc_pch_count_object (state->d, d->obj, d->size, | |
111 | 328 d->note_ptr_fn == gt_pch_p_S); |
0 | 329 state->count++; |
330 return 1; | |
331 } | |
332 | |
111 | 333 int |
334 ggc_call_alloc (ptr_data **slot, traversal_state *state) | |
0 | 335 { |
111 | 336 struct ptr_data *d = *slot; |
0 | 337 |
338 d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size, | |
111 | 339 d->note_ptr_fn == gt_pch_p_S); |
0 | 340 state->ptrs[state->ptrs_i++] = d; |
341 return 1; | |
342 } | |
343 | |
344 /* Callback for qsort. */ | |
345 | |
346 static int | |
347 compare_ptr_data (const void *p1_p, const void *p2_p) | |
348 { | |
349 const struct ptr_data *const p1 = *(const struct ptr_data *const *)p1_p; | |
350 const struct ptr_data *const p2 = *(const struct ptr_data *const *)p2_p; | |
351 return (((size_t)p1->new_addr > (size_t)p2->new_addr) | |
352 - ((size_t)p1->new_addr < (size_t)p2->new_addr)); | |
353 } | |
354 | |
355 /* Callbacks for note_ptr_fn. */ | |
356 | |
357 static void | |
358 relocate_ptrs (void *ptr_p, void *state_p) | |
359 { | |
360 void **ptr = (void **)ptr_p; | |
361 struct traversal_state *state ATTRIBUTE_UNUSED | |
362 = (struct traversal_state *)state_p; | |
363 struct ptr_data *result; | |
364 | |
365 if (*ptr == NULL || *ptr == (void *)1) | |
366 return; | |
367 | |
368 result = (struct ptr_data *) | |
111 | 369 saving_htab->find_with_hash (*ptr, POINTER_HASH (*ptr)); |
0 | 370 gcc_assert (result); |
371 *ptr = result->new_addr; | |
372 } | |
373 | |
374 /* Write out, after relocation, the pointers in TAB. */ | |
375 static void | |
376 write_pch_globals (const struct ggc_root_tab * const *tab, | |
377 struct traversal_state *state) | |
378 { | |
379 const struct ggc_root_tab *const *rt; | |
380 const struct ggc_root_tab *rti; | |
381 size_t i; | |
382 | |
383 for (rt = tab; *rt; rt++) | |
384 for (rti = *rt; rti->base != NULL; rti++) | |
385 for (i = 0; i < rti->nelt; i++) | |
386 { | |
387 void *ptr = *(void **)((char *)rti->base + rti->stride * i); | |
388 struct ptr_data *new_ptr; | |
389 if (ptr == NULL || ptr == (void *)1) | |
390 { | |
391 if (fwrite (&ptr, sizeof (void *), 1, state->f) | |
392 != 1) | |
111 | 393 fatal_error (input_location, "can%'t write PCH file: %m"); |
0 | 394 } |
395 else | |
396 { | |
397 new_ptr = (struct ptr_data *) | |
111 | 398 saving_htab->find_with_hash (ptr, POINTER_HASH (ptr)); |
0 | 399 if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f) |
400 != 1) | |
111 | 401 fatal_error (input_location, "can%'t write PCH file: %m"); |
0 | 402 } |
403 } | |
404 } | |
405 | |
406 /* Hold the information we need to mmap the file back in. */ | |
407 | |
408 struct mmap_info | |
409 { | |
410 size_t offset; | |
411 size_t size; | |
412 void *preferred_base; | |
413 }; | |
414 | |
415 /* Write out the state of the compiler to F. */ | |
416 | |
417 void | |
418 gt_pch_save (FILE *f) | |
419 { | |
420 const struct ggc_root_tab *const *rt; | |
421 const struct ggc_root_tab *rti; | |
422 size_t i; | |
423 struct traversal_state state; | |
424 char *this_object = NULL; | |
425 size_t this_object_size = 0; | |
426 struct mmap_info mmi; | |
111 | 427 const size_t mmap_offset_alignment = host_hooks.gt_pch_alloc_granularity (); |
0 | 428 |
429 gt_pch_save_stringpool (); | |
430 | |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
431 timevar_push (TV_PCH_PTR_REALLOC); |
111 | 432 saving_htab = new hash_table<saving_hasher> (50000); |
0 | 433 |
434 for (rt = gt_ggc_rtab; *rt; rt++) | |
435 for (rti = *rt; rti->base != NULL; rti++) | |
436 for (i = 0; i < rti->nelt; i++) | |
437 (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i)); | |
438 | |
439 /* Prepare the objects for writing, determine addresses and such. */ | |
440 state.f = f; | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
441 state.d = init_ggc_pch (); |
0 | 442 state.count = 0; |
111 | 443 saving_htab->traverse <traversal_state *, ggc_call_count> (&state); |
0 | 444 |
445 mmi.size = ggc_pch_total_size (state.d); | |
446 | |
447 /* Try to arrange things so that no relocation is necessary, but | |
448 don't try very hard. On most platforms, this will always work, | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
449 and on the rest it's a lot of work to do better. |
0 | 450 (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and |
451 HOST_HOOKS_GT_PCH_USE_ADDRESS.) */ | |
452 mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f)); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
453 |
0 | 454 ggc_pch_this_base (state.d, mmi.preferred_base); |
455 | |
456 state.ptrs = XNEWVEC (struct ptr_data *, state.count); | |
457 state.ptrs_i = 0; | |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
458 |
111 | 459 saving_htab->traverse <traversal_state *, ggc_call_alloc> (&state); |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
460 timevar_pop (TV_PCH_PTR_REALLOC); |
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
461 |
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
462 timevar_push (TV_PCH_PTR_SORT); |
0 | 463 qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data); |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
464 timevar_pop (TV_PCH_PTR_SORT); |
0 | 465 |
466 /* Write out all the scalar variables. */ | |
467 for (rt = gt_pch_scalar_rtab; *rt; rt++) | |
468 for (rti = *rt; rti->base != NULL; rti++) | |
469 if (fwrite (rti->base, rti->stride, 1, f) != 1) | |
111 | 470 fatal_error (input_location, "can%'t write PCH file: %m"); |
0 | 471 |
472 /* Write out all the global pointers, after translation. */ | |
473 write_pch_globals (gt_ggc_rtab, &state); | |
474 | |
475 /* Pad the PCH file so that the mmapped area starts on an allocation | |
476 granularity (usually page) boundary. */ | |
477 { | |
478 long o; | |
479 o = ftell (state.f) + sizeof (mmi); | |
480 if (o == -1) | |
111 | 481 fatal_error (input_location, "can%'t get position in PCH file: %m"); |
0 | 482 mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment; |
483 if (mmi.offset == mmap_offset_alignment) | |
484 mmi.offset = 0; | |
485 mmi.offset += o; | |
486 } | |
487 if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1) | |
111 | 488 fatal_error (input_location, "can%'t write PCH file: %m"); |
0 | 489 if (mmi.offset != 0 |
490 && fseek (state.f, mmi.offset, SEEK_SET) != 0) | |
111 | 491 fatal_error (input_location, "can%'t write padding to PCH file: %m"); |
0 | 492 |
493 ggc_pch_prepare_write (state.d, state.f); | |
494 | |
111 | 495 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS |
496 vec<char> vbits = vNULL; | |
497 #endif | |
498 | |
0 | 499 /* Actually write out the objects. */ |
500 for (i = 0; i < state.count; i++) | |
501 { | |
502 if (this_object_size < state.ptrs[i]->size) | |
503 { | |
504 this_object_size = state.ptrs[i]->size; | |
505 this_object = XRESIZEVAR (char, this_object, this_object_size); | |
506 } | |
111 | 507 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS |
508 /* obj might contain uninitialized bytes, e.g. in the trailing | |
509 padding of the object. Avoid warnings by making the memory | |
510 temporarily defined and then restoring previous state. */ | |
511 int get_vbits = 0; | |
512 size_t valid_size = state.ptrs[i]->size; | |
513 if (__builtin_expect (RUNNING_ON_VALGRIND, 0)) | |
514 { | |
515 if (vbits.length () < valid_size) | |
516 vbits.safe_grow (valid_size); | |
517 get_vbits = VALGRIND_GET_VBITS (state.ptrs[i]->obj, | |
518 vbits.address (), valid_size); | |
519 if (get_vbits == 3) | |
520 { | |
521 /* We assume that first part of obj is addressable, and | |
522 the rest is unaddressable. Find out where the boundary is | |
523 using binary search. */ | |
524 size_t lo = 0, hi = valid_size; | |
525 while (hi > lo) | |
526 { | |
527 size_t mid = (lo + hi) / 2; | |
528 get_vbits = VALGRIND_GET_VBITS ((char *) state.ptrs[i]->obj | |
529 + mid, vbits.address (), | |
530 1); | |
531 if (get_vbits == 3) | |
532 hi = mid; | |
533 else if (get_vbits == 1) | |
534 lo = mid + 1; | |
535 else | |
536 break; | |
537 } | |
538 if (get_vbits == 1 || get_vbits == 3) | |
539 { | |
540 valid_size = lo; | |
541 get_vbits = VALGRIND_GET_VBITS (state.ptrs[i]->obj, | |
542 vbits.address (), | |
543 valid_size); | |
544 } | |
545 } | |
546 if (get_vbits == 1) | |
547 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (state.ptrs[i]->obj, | |
548 state.ptrs[i]->size)); | |
549 } | |
550 #endif | |
0 | 551 memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size); |
552 if (state.ptrs[i]->reorder_fn != NULL) | |
553 state.ptrs[i]->reorder_fn (state.ptrs[i]->obj, | |
554 state.ptrs[i]->note_ptr_cookie, | |
555 relocate_ptrs, &state); | |
556 state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj, | |
557 state.ptrs[i]->note_ptr_cookie, | |
558 relocate_ptrs, &state); | |
559 ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj, | |
560 state.ptrs[i]->new_addr, state.ptrs[i]->size, | |
561 state.ptrs[i]->note_ptr_fn == gt_pch_p_S); | |
562 if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S) | |
563 memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size); | |
111 | 564 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS |
565 if (__builtin_expect (get_vbits == 1, 0)) | |
566 { | |
567 (void) VALGRIND_SET_VBITS (state.ptrs[i]->obj, vbits.address (), | |
568 valid_size); | |
569 if (valid_size != state.ptrs[i]->size) | |
570 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *) | |
571 state.ptrs[i]->obj | |
572 + valid_size, | |
573 state.ptrs[i]->size | |
574 - valid_size)); | |
575 } | |
576 #endif | |
0 | 577 } |
111 | 578 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS |
579 vbits.release (); | |
580 #endif | |
581 | |
0 | 582 ggc_pch_finish (state.d, state.f); |
583 gt_pch_fixup_stringpool (); | |
584 | |
111 | 585 XDELETE (state.ptrs); |
586 XDELETE (this_object); | |
587 delete saving_htab; | |
588 saving_htab = NULL; | |
0 | 589 } |
590 | |
591 /* Read the state of the compiler back in from F. */ | |
592 | |
593 void | |
594 gt_pch_restore (FILE *f) | |
595 { | |
596 const struct ggc_root_tab *const *rt; | |
597 const struct ggc_root_tab *rti; | |
598 size_t i; | |
599 struct mmap_info mmi; | |
600 int result; | |
601 | |
602 /* Delete any deletable objects. This makes ggc_pch_read much | |
603 faster, as it can be sure that no GCable objects remain other | |
604 than the ones just read in. */ | |
605 for (rt = gt_ggc_deletable_rtab; *rt; rt++) | |
606 for (rti = *rt; rti->base != NULL; rti++) | |
607 memset (rti->base, 0, rti->stride); | |
608 | |
609 /* Read in all the scalar variables. */ | |
610 for (rt = gt_pch_scalar_rtab; *rt; rt++) | |
611 for (rti = *rt; rti->base != NULL; rti++) | |
612 if (fread (rti->base, rti->stride, 1, f) != 1) | |
111 | 613 fatal_error (input_location, "can%'t read PCH file: %m"); |
0 | 614 |
615 /* Read in all the global pointers, in 6 easy loops. */ | |
616 for (rt = gt_ggc_rtab; *rt; rt++) | |
617 for (rti = *rt; rti->base != NULL; rti++) | |
618 for (i = 0; i < rti->nelt; i++) | |
619 if (fread ((char *)rti->base + rti->stride * i, | |
620 sizeof (void *), 1, f) != 1) | |
111 | 621 fatal_error (input_location, "can%'t read PCH file: %m"); |
0 | 622 |
623 if (fread (&mmi, sizeof (mmi), 1, f) != 1) | |
111 | 624 fatal_error (input_location, "can%'t read PCH file: %m"); |
0 | 625 |
626 result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size, | |
627 fileno (f), mmi.offset); | |
628 if (result < 0) | |
111 | 629 fatal_error (input_location, "had to relocate PCH"); |
0 | 630 if (result == 0) |
631 { | |
632 if (fseek (f, mmi.offset, SEEK_SET) != 0 | |
633 || fread (mmi.preferred_base, mmi.size, 1, f) != 1) | |
111 | 634 fatal_error (input_location, "can%'t read PCH file: %m"); |
0 | 635 } |
636 else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) | |
111 | 637 fatal_error (input_location, "can%'t read PCH file: %m"); |
0 | 638 |
639 ggc_pch_read (f, mmi.preferred_base); | |
640 | |
641 gt_pch_restore_stringpool (); | |
642 } | |
643 | |
644 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present. | |
645 Select no address whatsoever, and let gt_pch_save choose what it will with | |
646 malloc, presumably. */ | |
647 | |
648 void * | |
649 default_gt_pch_get_address (size_t size ATTRIBUTE_UNUSED, | |
650 int fd ATTRIBUTE_UNUSED) | |
651 { | |
652 return NULL; | |
653 } | |
654 | |
655 /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is not present. | |
656 Allocate SIZE bytes with malloc. Return 0 if the address we got is the | |
657 same as base, indicating that the memory has been allocated but needs to | |
658 be read in from the file. Return -1 if the address differs, to relocation | |
659 of the PCH file would be required. */ | |
660 | |
661 int | |
662 default_gt_pch_use_address (void *base, size_t size, int fd ATTRIBUTE_UNUSED, | |
663 size_t offset ATTRIBUTE_UNUSED) | |
664 { | |
665 void *addr = xmalloc (size); | |
666 return (addr == base) - 1; | |
667 } | |
668 | |
669 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS. Return the | |
670 alignment required for allocating virtual memory. Usually this is the | |
671 same as pagesize. */ | |
672 | |
673 size_t | |
674 default_gt_pch_alloc_granularity (void) | |
675 { | |
111 | 676 return getpagesize (); |
0 | 677 } |
678 | |
679 #if HAVE_MMAP_FILE | |
680 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is present. | |
681 We temporarily allocate SIZE bytes, and let the kernel place the data | |
682 wherever it will. If it worked, that's our spot, if not we're likely | |
683 to be in trouble. */ | |
684 | |
685 void * | |
686 mmap_gt_pch_get_address (size_t size, int fd) | |
687 { | |
688 void *ret; | |
689 | |
690 ret = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | |
691 if (ret == (void *) MAP_FAILED) | |
692 ret = NULL; | |
693 else | |
694 munmap ((caddr_t) ret, size); | |
695 | |
696 return ret; | |
697 } | |
698 | |
699 /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is present. | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
700 Map SIZE bytes of FD+OFFSET at BASE. Return 1 if we succeeded at |
0 | 701 mapping the data at BASE, -1 if we couldn't. |
702 | |
703 This version assumes that the kernel honors the START operand of mmap | |
704 even without MAP_FIXED if START through START+SIZE are not currently | |
705 mapped with something. */ | |
706 | |
707 int | |
708 mmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) | |
709 { | |
710 void *addr; | |
711 | |
712 /* We're called with size == 0 if we're not planning to load a PCH | |
713 file at all. This allows the hook to free any static space that | |
714 we might have allocated at link time. */ | |
715 if (size == 0) | |
716 return -1; | |
717 | |
718 addr = mmap ((caddr_t) base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, | |
719 fd, offset); | |
720 | |
721 return addr == base ? 1 : -1; | |
722 } | |
723 #endif /* HAVE_MMAP_FILE */ | |
724 | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
725 #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
726 |
0 | 727 /* Modify the bound based on rlimits. */ |
728 static double | |
729 ggc_rlimit_bound (double limit) | |
730 { | |
731 #if defined(HAVE_GETRLIMIT) | |
732 struct rlimit rlim; | |
733 # if defined (RLIMIT_AS) | |
734 /* RLIMIT_AS is what POSIX says is the limit on mmap. Presumably | |
735 any OS which has RLIMIT_AS also has a working mmap that GCC will use. */ | |
736 if (getrlimit (RLIMIT_AS, &rlim) == 0 | |
737 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY | |
738 && rlim.rlim_cur < limit) | |
739 limit = rlim.rlim_cur; | |
740 # elif defined (RLIMIT_DATA) | |
741 /* ... but some older OSs bound mmap based on RLIMIT_DATA, or we | |
742 might be on an OS that has a broken mmap. (Others don't bound | |
743 mmap at all, apparently.) */ | |
744 if (getrlimit (RLIMIT_DATA, &rlim) == 0 | |
745 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY | |
746 && rlim.rlim_cur < limit | |
747 /* Darwin has this horribly bogus default setting of | |
748 RLIMIT_DATA, to 6144Kb. No-one notices because RLIMIT_DATA | |
749 appears to be ignored. Ignore such silliness. If a limit | |
750 this small was actually effective for mmap, GCC wouldn't even | |
751 start up. */ | |
752 && rlim.rlim_cur >= 8 * 1024 * 1024) | |
753 limit = rlim.rlim_cur; | |
754 # endif /* RLIMIT_AS or RLIMIT_DATA */ | |
755 #endif /* HAVE_GETRLIMIT */ | |
756 | |
757 return limit; | |
758 } | |
759 | |
760 /* Heuristic to set a default for GGC_MIN_EXPAND. */ | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
761 static int |
0 | 762 ggc_min_expand_heuristic (void) |
763 { | |
111 | 764 double min_expand = physmem_total (); |
0 | 765 |
766 /* Adjust for rlimits. */ | |
767 min_expand = ggc_rlimit_bound (min_expand); | |
768 | |
769 /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding | |
770 a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB). */ | |
771 min_expand /= 1024*1024*1024; | |
772 min_expand *= 70; | |
773 min_expand = MIN (min_expand, 70); | |
774 min_expand += 30; | |
775 | |
776 return min_expand; | |
777 } | |
778 | |
779 /* Heuristic to set a default for GGC_MIN_HEAPSIZE. */ | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
780 static int |
0 | 781 ggc_min_heapsize_heuristic (void) |
782 { | |
111 | 783 double phys_kbytes = physmem_total (); |
0 | 784 double limit_kbytes = ggc_rlimit_bound (phys_kbytes * 2); |
785 | |
786 phys_kbytes /= 1024; /* Convert to Kbytes. */ | |
787 limit_kbytes /= 1024; | |
788 | |
789 /* The heuristic is RAM/8, with a lower bound of 4M and an upper | |
790 bound of 128M (when RAM >= 1GB). */ | |
791 phys_kbytes /= 8; | |
792 | |
793 #if defined(HAVE_GETRLIMIT) && defined (RLIMIT_RSS) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
794 /* Try not to overrun the RSS limit while doing garbage collection. |
0 | 795 The RSS limit is only advisory, so no margin is subtracted. */ |
796 { | |
797 struct rlimit rlim; | |
798 if (getrlimit (RLIMIT_RSS, &rlim) == 0 | |
799 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY) | |
800 phys_kbytes = MIN (phys_kbytes, rlim.rlim_cur / 1024); | |
801 } | |
802 # endif | |
803 | |
804 /* Don't blindly run over our data limit; do GC at least when the | |
805 *next* GC would be within 20Mb of the limit or within a quarter of | |
806 the limit, whichever is larger. If GCC does hit the data limit, | |
807 compilation will fail, so this tries to be conservative. */ | |
808 limit_kbytes = MAX (0, limit_kbytes - MAX (limit_kbytes / 4, 20 * 1024)); | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
809 limit_kbytes = (limit_kbytes * 100) / (110 + ggc_min_expand_heuristic ()); |
0 | 810 phys_kbytes = MIN (phys_kbytes, limit_kbytes); |
811 | |
812 phys_kbytes = MAX (phys_kbytes, 4 * 1024); | |
813 phys_kbytes = MIN (phys_kbytes, 128 * 1024); | |
814 | |
815 return phys_kbytes; | |
816 } | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
817 #endif |
0 | 818 |
819 void | |
820 init_ggc_heuristics (void) | |
821 { | |
822 #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
823 set_default_param_value (GGC_MIN_EXPAND, ggc_min_expand_heuristic ()); |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
824 set_default_param_value (GGC_MIN_HEAPSIZE, ggc_min_heapsize_heuristic ()); |
0 | 825 #endif |
826 } | |
827 | |
111 | 828 /* GGC memory usage. */ |
829 struct ggc_usage: public mem_usage | |
0 | 830 { |
111 | 831 /* Default constructor. */ |
832 ggc_usage (): m_freed (0), m_collected (0), m_overhead (0) {} | |
833 /* Constructor. */ | |
834 ggc_usage (size_t allocated, size_t times, size_t peak, | |
835 size_t freed, size_t collected, size_t overhead) | |
836 : mem_usage (allocated, times, peak), | |
837 m_freed (freed), m_collected (collected), m_overhead (overhead) {} | |
838 | |
839 /* Comparison operator. */ | |
840 inline bool | |
841 operator< (const ggc_usage &second) const | |
842 { | |
843 return (get_balance () == second.get_balance () ? | |
844 (m_peak == second.m_peak ? m_times < second.m_times | |
845 : m_peak < second.m_peak) | |
846 : get_balance () < second.get_balance ()); | |
847 } | |
848 | |
849 /* Register overhead of ALLOCATED and OVERHEAD bytes. */ | |
850 inline void | |
851 register_overhead (size_t allocated, size_t overhead) | |
852 { | |
853 m_allocated += allocated; | |
854 m_overhead += overhead; | |
855 m_times++; | |
856 } | |
857 | |
858 /* Release overhead of SIZE bytes. */ | |
859 inline void | |
860 release_overhead (size_t size) | |
861 { | |
862 m_freed += size; | |
863 } | |
864 | |
865 /* Sum the usage with SECOND usage. */ | |
866 ggc_usage | |
867 operator+ (const ggc_usage &second) | |
868 { | |
869 return ggc_usage (m_allocated + second.m_allocated, | |
870 m_times + second.m_times, | |
871 m_peak + second.m_peak, | |
872 m_freed + second.m_freed, | |
873 m_collected + second.m_collected, | |
874 m_overhead + second.m_overhead); | |
875 } | |
876 | |
877 /* Dump usage with PREFIX, where TOTAL is sum of all rows. */ | |
878 inline void | |
879 dump (const char *prefix, ggc_usage &total) const | |
880 { | |
881 long balance = get_balance (); | |
882 fprintf (stderr, | |
883 "%-48s %10li:%5.1f%%%10li:%5.1f%%" | |
884 "%10li:%5.1f%%%10li:%5.1f%%%10li\n", | |
885 prefix, (long)m_collected, | |
886 get_percent (m_collected, total.m_collected), | |
887 (long)m_freed, get_percent (m_freed, total.m_freed), | |
888 (long)balance, get_percent (balance, total.get_balance ()), | |
889 (long)m_overhead, get_percent (m_overhead, total.m_overhead), | |
890 (long)m_times); | |
891 } | |
892 | |
893 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */ | |
894 inline void | |
895 dump (mem_location *loc, ggc_usage &total) const | |
896 { | |
897 char *location_string = loc->to_string (); | |
898 | |
899 dump (location_string, total); | |
900 | |
901 free (location_string); | |
902 } | |
903 | |
904 /* Dump footer. */ | |
905 inline void | |
906 dump_footer () | |
907 { | |
908 print_dash_line (); | |
909 dump ("Total", *this); | |
910 print_dash_line (); | |
911 } | |
912 | |
913 /* Get balance which is GGC allocation leak. */ | |
914 inline long | |
915 get_balance () const | |
916 { | |
917 return m_allocated + m_overhead - m_collected - m_freed; | |
918 } | |
919 | |
920 typedef std::pair<mem_location *, ggc_usage *> mem_pair_t; | |
921 | |
922 /* Compare wrapper used by qsort method. */ | |
923 static int | |
924 compare (const void *first, const void *second) | |
925 { | |
926 const mem_pair_t f = *(const mem_pair_t *)first; | |
927 const mem_pair_t s = *(const mem_pair_t *)second; | |
928 | |
929 return (*f.second) < (*s.second); | |
930 } | |
931 | |
932 /* Compare rows in final GGC summary dump. */ | |
933 static int | |
934 compare_final (const void *first, const void *second) | |
935 { | |
936 typedef std::pair<mem_location *, ggc_usage *> mem_pair_t; | |
937 | |
938 const ggc_usage *f = ((const mem_pair_t *)first)->second; | |
939 const ggc_usage *s = ((const mem_pair_t *)second)->second; | |
940 | |
941 size_t a = f->m_allocated + f->m_overhead - f->m_freed; | |
942 size_t b = s->m_allocated + s->m_overhead - s->m_freed; | |
943 | |
944 return a == b ? 0 : (a < b ? 1 : -1); | |
945 } | |
946 | |
947 /* Dump header with NAME. */ | |
948 static inline void | |
949 dump_header (const char *name) | |
950 { | |
951 fprintf (stderr, "%-48s %11s%17s%17s%16s%17s\n", name, "Garbage", "Freed", | |
952 "Leak", "Overhead", "Times"); | |
953 print_dash_line (); | |
954 } | |
955 | |
956 /* Freed memory in bytes. */ | |
957 size_t m_freed; | |
958 /* Collected memory in bytes. */ | |
959 size_t m_collected; | |
960 /* Overhead memory in bytes. */ | |
961 size_t m_overhead; | |
0 | 962 }; |
963 | |
111 | 964 /* GCC memory description. */ |
965 static mem_alloc_description<ggc_usage> ggc_mem_desc; | |
0 | 966 |
111 | 967 /* Dump per-site memory statistics. */ |
0 | 968 |
111 | 969 void |
970 dump_ggc_loc_statistics (bool final) | |
0 | 971 { |
111 | 972 if (! GATHER_STATISTICS) |
973 return; | |
0 | 974 |
111 | 975 ggc_force_collect = true; |
976 ggc_collect (); | |
0 | 977 |
111 | 978 ggc_mem_desc.dump (GGC_ORIGIN, final ? ggc_usage::compare_final : NULL); |
0 | 979 |
111 | 980 ggc_force_collect = false; |
0 | 981 } |
982 | |
983 /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */ | |
984 void | |
111 | 985 ggc_record_overhead (size_t allocated, size_t overhead, void *ptr MEM_STAT_DECL) |
0 | 986 { |
111 | 987 ggc_usage *usage = ggc_mem_desc.register_descriptor (ptr, GGC_ORIGIN, false |
988 FINAL_PASS_MEM_STAT); | |
0 | 989 |
111 | 990 ggc_mem_desc.register_object_overhead (usage, allocated + overhead, ptr); |
991 usage->register_overhead (allocated, overhead); | |
0 | 992 } |
993 | |
111 | 994 /* Notice that the pointer has been freed. */ |
995 void | |
996 ggc_free_overhead (void *ptr) | |
0 | 997 { |
111 | 998 ggc_mem_desc.release_object_overhead (ptr); |
0 | 999 } |
1000 | |
1001 /* After live values has been marked, walk all recorded pointers and see if | |
1002 they are still live. */ | |
1003 void | |
1004 ggc_prune_overhead_list (void) | |
1005 { | |
111 | 1006 typedef hash_map<const void *, std::pair<ggc_usage *, size_t > > map_t; |
0 | 1007 |
111 | 1008 map_t::iterator it = ggc_mem_desc.m_reverse_object_map->begin (); |
0 | 1009 |
111 | 1010 for (; it != ggc_mem_desc.m_reverse_object_map->end (); ++it) |
1011 if (!ggc_marked_p ((*it).first)) | |
1012 (*it).second.first->m_collected += (*it).second.second; | |
0 | 1013 |
111 | 1014 delete ggc_mem_desc.m_reverse_object_map; |
1015 ggc_mem_desc.m_reverse_object_map = new map_t (13, false, false); | |
0 | 1016 } |