00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023 #include "rtl.h"
00024 #include "tree.h"
00025 #include "tm_p.h"
00026 #include "flags.h"
00027 #include "varray.h"
00028 #include "ggc.h"
00029 #include "timevar.h"
00030 #include "params.h"
00031
00032
00033
00034
00035 #undef GGC_POISON
00036
00037
00038 #undef GGC_BALANCE
00039
00040
00041 #undef GGC_ALWAYS_VERIFY
00042
00043 #ifdef ENABLE_GC_CHECKING
00044 #define GGC_POISON
00045 #define GGC_ALWAYS_VERIFY
00046 #endif
00047
00048 #ifndef HOST_BITS_PER_PTR
00049 #define HOST_BITS_PER_PTR HOST_BITS_PER_LONG
00050 #endif
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 #define PTR_KEY(p) ((size_t)p << (HOST_BITS_PER_PTR - 8) \
00068 | ((size_t)p & 0xff00) << (HOST_BITS_PER_PTR - 24) \
00069 | (size_t)p >> 16)
00070
00071
00072
00073 struct ggc_mem
00074 {
00075
00076 struct ggc_mem *sub[2];
00077
00078 unsigned int mark : 1;
00079 unsigned int context : 7;
00080 unsigned int size : 24;
00081
00082
00083 union {
00084 HOST_WIDEST_INT i;
00085 #ifdef HAVE_LONG_DOUBLE
00086 long double d;
00087 #else
00088 double d;
00089 #endif
00090 } u;
00091 };
00092
00093 static struct globals
00094 {
00095
00096 struct ggc_mem *root;
00097
00098
00099 size_t allocated;
00100
00101
00102 size_t objects;
00103
00104
00105 size_t allocated_last_gc;
00106
00107
00108 int context;
00109 } G;
00110
00111
00112
00113 static void tree_insert PARAMS ((struct ggc_mem *));
00114 static int tree_lookup PARAMS ((struct ggc_mem *));
00115 static void clear_marks PARAMS ((struct ggc_mem *));
00116 static void sweep_objs PARAMS ((struct ggc_mem **));
00117 static void ggc_pop_context_1 PARAMS ((struct ggc_mem *, int));
00118
00119
00120 extern void debug_ggc_tree PARAMS ((struct ggc_mem *, int));
00121
00122 #ifdef GGC_BALANCE
00123 extern void debug_ggc_balance PARAMS ((void));
00124 #endif
00125 static void tally_leaves PARAMS ((struct ggc_mem *, int, size_t *, size_t *));
00126
00127
00128
00129 static inline void
00130 tree_insert (v)
00131 struct ggc_mem *v;
00132 {
00133 size_t v_key = PTR_KEY (v);
00134 struct ggc_mem *p, **pp;
00135
00136 for (pp = &G.root, p = *pp; p ; p = *pp)
00137 {
00138 size_t p_key = PTR_KEY (p);
00139 pp = &p->sub[v_key < p_key];
00140 }
00141 *pp = v;
00142 }
00143
00144
00145
00146 static inline int
00147 tree_lookup (v)
00148 struct ggc_mem *v;
00149 {
00150 size_t v_key = PTR_KEY (v);
00151 struct ggc_mem *p = G.root;
00152
00153 while (p)
00154 {
00155 size_t p_key = PTR_KEY (p);
00156 if (p == v)
00157 return 1;
00158 p = p->sub[v_key < p_key];
00159 }
00160
00161 return 0;
00162 }
00163
00164
00165
00166 void *
00167 ggc_alloc (size)
00168 size_t size;
00169 {
00170 struct ggc_mem *x;
00171
00172 x = (struct ggc_mem *) xmalloc (offsetof (struct ggc_mem, u) + size);
00173 x->sub[0] = NULL;
00174 x->sub[1] = NULL;
00175 x->mark = 0;
00176 x->context = G.context;
00177 x->size = size;
00178
00179 #ifdef GGC_POISON
00180 memset (&x->u, 0xaf, size);
00181 #endif
00182
00183 tree_insert (x);
00184 G.allocated += size;
00185 G.objects += 1;
00186
00187 return &x->u;
00188 }
00189
00190
00191
00192 int
00193 ggc_set_mark (p)
00194 const void *p;
00195 {
00196 struct ggc_mem *x;
00197
00198 x = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
00199 #ifdef GGC_ALWAYS_VERIFY
00200 if (! tree_lookup (x))
00201 abort ();
00202 #endif
00203
00204 if (x->mark)
00205 return 1;
00206
00207 x->mark = 1;
00208 G.allocated += x->size;
00209 G.objects += 1;
00210
00211 return 0;
00212 }
00213
00214
00215
00216 int
00217 ggc_marked_p (p)
00218 const void *p;
00219 {
00220 struct ggc_mem *x;
00221
00222 x = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
00223 #ifdef GGC_ALWAYS_VERIFY
00224 if (! tree_lookup (x))
00225 abort ();
00226 #endif
00227
00228 return x->mark;
00229 }
00230
00231
00232
00233 size_t
00234 ggc_get_size (p)
00235 const void *p;
00236 {
00237 struct ggc_mem *x
00238 = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
00239 return x->size;
00240 }
00241
00242
00243
00244 static void
00245 clear_marks (x)
00246 struct ggc_mem *x;
00247 {
00248 x->mark = 0;
00249 if (x->sub[0])
00250 clear_marks (x->sub[0]);
00251 if (x->sub[1])
00252 clear_marks (x->sub[1]);
00253 }
00254
00255
00256
00257 static void
00258 sweep_objs (root)
00259 struct ggc_mem **root;
00260 {
00261 struct ggc_mem *x = *root;
00262 if (!x)
00263 return;
00264
00265 sweep_objs (&x->sub[0]);
00266 sweep_objs (&x->sub[1]);
00267
00268 if (! x->mark && x->context >= G.context)
00269 {
00270 struct ggc_mem *l, *r;
00271
00272 l = x->sub[0];
00273 r = x->sub[1];
00274 if (!l)
00275 *root = r;
00276 else if (!r)
00277 *root = l;
00278 else if (!l->sub[1])
00279 {
00280 *root = l;
00281 l->sub[1] = r;
00282 }
00283 else if (!r->sub[0])
00284 {
00285 *root = r;
00286 r->sub[0] = l;
00287 }
00288 else
00289 {
00290 *root = l;
00291 do {
00292 root = &l->sub[1];
00293 } while ((l = *root) != NULL);
00294 *root = r;
00295 }
00296
00297 #ifdef GGC_POISON
00298 memset (&x->u, 0xA5, x->size);
00299 #endif
00300
00301 free (x);
00302 }
00303 }
00304
00305
00306
00307 void
00308 ggc_collect ()
00309 {
00310
00311
00312
00313 size_t allocated_last_gc =
00314 MAX (G.allocated_last_gc, (size_t)PARAM_VALUE (GGC_MIN_HEAPSIZE) * 1024);
00315
00316 size_t min_expand = allocated_last_gc * PARAM_VALUE (GGC_MIN_EXPAND) / 100;
00317
00318 if (G.allocated < allocated_last_gc + min_expand)
00319 return;
00320
00321 #ifdef GGC_BALANCE
00322 debug_ggc_balance ();
00323 #endif
00324
00325 timevar_push (TV_GC);
00326 if (!quiet_flag)
00327 fprintf (stderr, " {GC %luk -> ", (unsigned long)G.allocated / 1024);
00328
00329 G.allocated = 0;
00330 G.objects = 0;
00331
00332 clear_marks (G.root);
00333 ggc_mark_roots ();
00334 sweep_objs (&G.root);
00335
00336 G.allocated_last_gc = G.allocated;
00337
00338 timevar_pop (TV_GC);
00339
00340 if (!quiet_flag)
00341 fprintf (stderr, "%luk}", (unsigned long) G.allocated / 1024);
00342
00343 #ifdef GGC_BALANCE
00344 debug_ggc_balance ();
00345 #endif
00346 }
00347
00348
00349
00350 void
00351 init_ggc ()
00352 {
00353 }
00354
00355
00356
00357
00358 void
00359 ggc_push_context ()
00360 {
00361 G.context++;
00362
00363
00364
00365 if (G.context >= 128)
00366 abort ();
00367 }
00368
00369
00370
00371
00372 void
00373 ggc_pop_context ()
00374 {
00375 G.context--;
00376 if (G.root)
00377 ggc_pop_context_1 (G.root, G.context);
00378 }
00379
00380 static void
00381 ggc_pop_context_1 (x, c)
00382 struct ggc_mem *x;
00383 int c;
00384 {
00385 if (x->context > c)
00386 x->context = c;
00387 if (x->sub[0])
00388 ggc_pop_context_1 (x->sub[0], c);
00389 if (x->sub[1])
00390 ggc_pop_context_1 (x->sub[1], c);
00391 }
00392
00393
00394
00395 void
00396 debug_ggc_tree (p, indent)
00397 struct ggc_mem *p;
00398 int indent;
00399 {
00400 int i;
00401
00402 if (!p)
00403 {
00404 fputs ("(nil)\n", stderr);
00405 return;
00406 }
00407
00408 if (p->sub[0])
00409 debug_ggc_tree (p->sub[0], indent + 1);
00410
00411 for (i = 0; i < indent; ++i)
00412 putc (' ', stderr);
00413 fprintf (stderr, "%lx %p\n", (unsigned long)PTR_KEY (p), p);
00414
00415 if (p->sub[1])
00416 debug_ggc_tree (p->sub[1], indent + 1);
00417 }
00418
00419 #ifdef GGC_BALANCE
00420
00421
00422 #include <math.h>
00423
00424 void
00425 debug_ggc_balance ()
00426 {
00427 size_t nleaf, sumdepth;
00428
00429 nleaf = sumdepth = 0;
00430 tally_leaves (G.root, 0, &nleaf, &sumdepth);
00431
00432 fprintf (stderr, " {B %.2f,%.1f,%.1f}",
00433
00434 (float)nleaf / (float)G.objects,
00435
00436 (float)sumdepth / (float)nleaf,
00437 log ((double) G.objects) / M_LN2);
00438 }
00439 #endif
00440
00441
00442 static void
00443 tally_leaves (x, depth, nleaf, sumdepth)
00444 struct ggc_mem *x;
00445 int depth;
00446 size_t *nleaf;
00447 size_t *sumdepth;
00448 {
00449 if (! x->sub[0] && !x->sub[1])
00450 {
00451 *nleaf += 1;
00452 *sumdepth += depth;
00453 }
00454 else
00455 {
00456 if (x->sub[0])
00457 tally_leaves (x->sub[0], depth + 1, nleaf, sumdepth);
00458 if (x->sub[1])
00459 tally_leaves (x->sub[1], depth + 1, nleaf, sumdepth);
00460 }
00461 }
00462
00463 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
00464 ? (x) \
00465 : ((x) < 1024*1024*10 \
00466 ? (x) / 1024 \
00467 : (x) / (1024*1024))))
00468 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
00469
00470
00471 void
00472 ggc_print_statistics ()
00473 {
00474 struct ggc_statistics stats;
00475 size_t nleaf = 0, sumdepth = 0;
00476
00477
00478 memset (&stats, 0, sizeof (stats));
00479
00480
00481 G.allocated_last_gc = 0;
00482
00483
00484 ggc_print_common_statistics (stderr, &stats);
00485
00486
00487 tally_leaves (G.root, 0, &nleaf, &sumdepth);
00488
00489 fprintf (stderr, "\n\
00490 Total internal data (bytes)\t%ld%c\n\
00491 Number of leaves in tree\t%d\n\
00492 Average leaf depth\t\t%.1f\n",
00493 SCALE(G.objects * offsetof (struct ggc_mem, u)),
00494 LABEL(G.objects * offsetof (struct ggc_mem, u)),
00495 nleaf, (double)sumdepth / (double)nleaf);
00496
00497
00498 fprintf (stderr, "\n\
00499 Total objects allocated\t\t%d\n\
00500 Total memory in GC arena\t%ld%c\n",
00501 G.objects,
00502 SCALE(G.allocated), LABEL(G.allocated));
00503 }