X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fggc-common.c;h=28c2b793f22d605d2a06349d8896cca5421b2b3f;hp=3cafc770efd00fa991ed1a88df7c5a2fbe2e4aac;hb=1be3b8e5752db5a415c4690d7331643db4418901;hpb=3a1e1e08c3dced3f10087aeb411c074495adeaa1 diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 3cafc770efd..28c2b793f22 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -1,12 +1,12 @@ /* Simple garbage collection for the GNU compiler. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* Generic garbage collection (GC) functions and data, not specific to any particular GC implementation. */ @@ -31,6 +30,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "params.h" #include "hosthooks.h" #include "hosthooks-def.h" +#include "plugin.h" +#include "vec.h" +#include "timevar.h" #ifdef HAVE_SYS_RESOURCE_H # include @@ -40,7 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA # include # ifdef HAVE_MINCORE /* This is on Solaris. */ -# include +# include # endif #endif @@ -48,22 +50,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA # define MAP_FAILED ((void *)-1) #endif -#ifdef ENABLE_VALGRIND_CHECKING -# ifdef HAVE_VALGRIND_MEMCHECK_H -# include -# elif defined HAVE_MEMCHECK_H -# include -# else -# include -# endif -#else -/* Avoid #ifdef:s when we can help it. */ -#define VALGRIND_DISCARD(x) -#endif - /* When set, ggc_collect will do collection. */ bool ggc_force_collect; +/* When true, protect the contents of the identifier hash table. */ +bool ggc_protect_identifiers = true; + /* Statistics about the allocation. */ static ggc_statistics *ggc_stats; @@ -97,6 +89,63 @@ ggc_htab_delete (void **slot, void *info) return 1; } + +/* This extra vector of dynamically registered root_tab-s is used by + ggc_mark_roots and gives the ability to dynamically add new GGC root + tables, for instance from some plugins; this vector is on the heap + since it is used by GGC internally. */ +typedef const struct ggc_root_tab *const_ggc_root_tab_t; +DEF_VEC_P(const_ggc_root_tab_t); +DEF_VEC_ALLOC_P(const_ggc_root_tab_t, heap); +static VEC(const_ggc_root_tab_t, heap) *extra_root_vec; + +/* Dynamically register a new GGC root table RT. This is useful for + plugins. */ + +void +ggc_register_root_tab (const struct ggc_root_tab* rt) +{ + if (rt) + VEC_safe_push (const_ggc_root_tab_t, heap, extra_root_vec, rt); +} + +/* This extra vector of dynamically registered cache_tab-s is used by + ggc_mark_roots and gives the ability to dynamically add new GGC cache + tables, for instance from some plugins; this vector is on the heap + since it is used by GGC internally. */ +typedef const struct ggc_cache_tab *const_ggc_cache_tab_t; +DEF_VEC_P(const_ggc_cache_tab_t); +DEF_VEC_ALLOC_P(const_ggc_cache_tab_t, heap); +static VEC(const_ggc_cache_tab_t, heap) *extra_cache_vec; + +/* Dynamically register a new GGC cache table CT. This is useful for + plugins. */ + +void +ggc_register_cache_tab (const struct ggc_cache_tab* ct) +{ + if (ct) + VEC_safe_push (const_ggc_cache_tab_t, heap, extra_cache_vec, ct); +} + +/* Scan a hash table that has objects which are to be deleted if they are not + already marked. */ + +static void +ggc_scan_cache_tab (const_ggc_cache_tab_t ctp) +{ + const struct ggc_cache_tab *cti; + + for (cti = ctp; cti->base != NULL; cti++) + if (*cti->base) + { + ggc_set_mark (*cti->base); + htab_traverse_noresize (*cti->base, ggc_htab_delete, + CONST_CAST (void *, (const void *)cti)); + ggc_set_mark ((*cti->base)->entries); + } +} + /* Iterate through all registered roots and mark each element. */ void @@ -104,8 +153,9 @@ ggc_mark_roots (void) { const struct ggc_root_tab *const *rt; const struct ggc_root_tab *rti; + const_ggc_root_tab_t rtp; const struct ggc_cache_tab *const *ct; - const struct ggc_cache_tab *cti; + const_ggc_cache_tab_t ctp; size_t i; for (rt = gt_ggc_deletable_rtab; *rt; rt++) @@ -115,20 +165,31 @@ ggc_mark_roots (void) for (rt = gt_ggc_rtab; *rt; rt++) for (rti = *rt; rti->base != NULL; rti++) for (i = 0; i < rti->nelt; i++) - (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i)); + (*rti->cb) (*(void **)((char *)rti->base + rti->stride * i)); + + for (i = 0; VEC_iterate (const_ggc_root_tab_t, extra_root_vec, i, rtp); i++) + { + for (rti = rtp; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + (*rti->cb) (*(void **) ((char *)rti->base + rti->stride * i)); + } - ggc_mark_stringpool (); + if (ggc_protect_identifiers) + ggc_mark_stringpool (); /* Now scan all hash tables that have objects which are to be deleted if they are not already marked. */ for (ct = gt_ggc_cache_rtab; *ct; ct++) - for (cti = *ct; cti->base != NULL; cti++) - if (*cti->base) - { - ggc_set_mark (*cti->base); - htab_traverse_noresize (*cti->base, ggc_htab_delete, (void *) cti); - ggc_set_mark ((*cti->base)->entries); - } + ggc_scan_cache_tab (*ct); + + for (i = 0; VEC_iterate (const_ggc_cache_tab_t, extra_cache_vec, i, ctp); i++) + ggc_scan_cache_tab (ctp); + + if (! ggc_protect_identifiers) + ggc_purge_stringpool (); + + /* Some plugins may call ggc_set_mark from here. */ + invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL); } /* Allocate a block of memory, then clear it. */ @@ -164,9 +225,9 @@ ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL) old_size as reachable, but that would lose tracking of writes after the end of the object (by small offsets). Discard the handle to avoid handle leak. */ - VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size, - old_size - size)); - VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size)); + VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *) x + size, + old_size - size)); + VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, size)); return x; } @@ -176,7 +237,7 @@ ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL) individually allocated object, we'd access parts of the old object that were marked invalid with the memcpy below. We lose a bit of the initialization-tracking since some of it may be uninitialized. */ - VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size)); + VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, old_size)); memcpy (r, x, old_size); @@ -271,12 +332,12 @@ gt_pch_note_object (void *obj, void *note_ptr_cookie, return 0; } - *slot = xcalloc (sizeof (struct ptr_data), 1); + *slot = XCNEW (struct ptr_data); (*slot)->obj = obj; (*slot)->note_ptr_fn = note_ptr_fn; (*slot)->note_ptr_cookie = note_ptr_cookie; if (note_ptr_fn == gt_pch_p_S) - (*slot)->size = strlen (obj) + 1; + (*slot)->size = strlen ((const char *)obj) + 1; else (*slot)->size = ggc_get_size (obj); (*slot)->type = type; @@ -294,7 +355,8 @@ gt_pch_note_reorder (void *obj, void *note_ptr_cookie, if (obj == NULL || obj == (void *) 1) return; - data = htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj)); + data = (struct ptr_data *) + htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj)); gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie); data->reorder_fn = reorder_fn; @@ -305,13 +367,13 @@ gt_pch_note_reorder (void *obj, void *note_ptr_cookie, static hashval_t saving_htab_hash (const void *p) { - return POINTER_HASH (((struct ptr_data *)p)->obj); + return POINTER_HASH (((const struct ptr_data *)p)->obj); } static int saving_htab_eq (const void *p1, const void *p2) { - return ((struct ptr_data *)p1)->obj == p2; + return ((const struct ptr_data *)p1)->obj == p2; } /* Handy state for the traversal functions. */ @@ -358,8 +420,8 @@ call_alloc (void **slot, void *state_p) static int compare_ptr_data (const void *p1_p, const void *p2_p) { - struct ptr_data *p1 = *(struct ptr_data *const *)p1_p; - struct ptr_data *p2 = *(struct ptr_data *const *)p2_p; + const struct ptr_data *const p1 = *(const struct ptr_data *const *)p1_p; + const struct ptr_data *const p2 = *(const struct ptr_data *const *)p2_p; return (((size_t)p1->new_addr > (size_t)p2->new_addr) - ((size_t)p1->new_addr < (size_t)p2->new_addr)); } @@ -377,7 +439,8 @@ relocate_ptrs (void *ptr_p, void *state_p) if (*ptr == NULL || *ptr == (void *)1) return; - result = htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr)); + result = (struct ptr_data *) + htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr)); gcc_assert (result); *ptr = result->new_addr; } @@ -405,8 +468,8 @@ write_pch_globals (const struct ggc_root_tab * const *tab, } else { - new_ptr = htab_find_with_hash (saving_htab, ptr, - POINTER_HASH (ptr)); + new_ptr = (struct ptr_data *) + htab_find_with_hash (saving_htab, ptr, POINTER_HASH (ptr)); if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f) != 1) fatal_error ("can't write PCH file: %m"); @@ -439,6 +502,7 @@ gt_pch_save (FILE *f) gt_pch_save_stringpool (); + timevar_push (TV_PCH_PTR_REALLOC); saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free); for (rt = gt_ggc_rtab; *rt; rt++) @@ -461,17 +525,22 @@ gt_pch_save (FILE *f) /* Try to arrange things so that no relocation is necessary, but don't try very hard. On most platforms, this will always work, - and on the rest it's a lot of work to do better. + and on the rest it's a lot of work to do better. (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and HOST_HOOKS_GT_PCH_USE_ADDRESS.) */ mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f)); - + ggc_pch_this_base (state.d, mmi.preferred_base); state.ptrs = XNEWVEC (struct ptr_data *, state.count); state.ptrs_i = 0; + htab_traverse (saving_htab, call_alloc, &state); + timevar_pop (TV_PCH_PTR_REALLOC); + + timevar_push (TV_PCH_PTR_SORT); qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data); + timevar_pop (TV_PCH_PTR_SORT); /* Write out all the scalar variables. */ for (rt = gt_pch_scalar_rtab; *rt; rt++) @@ -509,7 +578,7 @@ gt_pch_save (FILE *f) if (this_object_size < state.ptrs[i]->size) { this_object_size = state.ptrs[i]->size; - this_object = xrealloc (this_object, this_object_size); + this_object = XRESIZEVAR (char, this_object, this_object_size); } memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size); if (state.ptrs[i]->reorder_fn != NULL) @@ -642,13 +711,13 @@ mmap_gt_pch_get_address (size_t size, int fd) if (ret == (void *) MAP_FAILED) ret = NULL; else - munmap (ret, size); + munmap ((caddr_t) ret, size); return ret; } /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is present. - Map SIZE bytes of FD+OFFSET at BASE. Return 1 if we succeeded at + Map SIZE bytes of FD+OFFSET at BASE. Return 1 if we succeeded at mapping the data at BASE, -1 if we couldn't. This version assumes that the kernel honors the START operand of mmap @@ -666,7 +735,7 @@ mmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) if (size == 0) return -1; - addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + addr = mmap ((caddr_t) base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset); return addr == base ? 1 : -1; @@ -740,7 +809,7 @@ ggc_min_heapsize_heuristic (void) phys_kbytes /= 8; #if defined(HAVE_GETRLIMIT) && defined (RLIMIT_RSS) - /* Try not to overrun the RSS limit while doing garbage collection. + /* Try not to overrun the RSS limit while doing garbage collection. The RSS limit is only advisory, so no margin is subtracted. */ { struct rlimit rlim; @@ -795,7 +864,7 @@ static htab_t loc_hash; static hashval_t hash_descriptor (const void *p) { - const struct loc_descriptor *d = p; + const struct loc_descriptor *const d = (const struct loc_descriptor *) p; return htab_hash_pointer (d->function) | d->line; } @@ -803,8 +872,8 @@ hash_descriptor (const void *p) static int eq_descriptor (const void *p1, const void *p2) { - const struct loc_descriptor *d = p1; - const struct loc_descriptor *d2 = p2; + const struct loc_descriptor *const d = (const struct loc_descriptor *) p1; + const struct loc_descriptor *const d2 = (const struct loc_descriptor *) p2; return (d->file == d2->file && d->line == d2->line && d->function == d2->function); @@ -823,7 +892,7 @@ struct ptr_hash_entry static hashval_t hash_ptr (const void *p) { - const struct ptr_hash_entry *d = p; + const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p; return htab_hash_pointer (d->ptr); } @@ -831,7 +900,7 @@ hash_ptr (const void *p) static int eq_ptr (const void *p1, const void *p2) { - const struct ptr_hash_entry *p = p1; + const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1; return (p->ptr == p2); } @@ -849,10 +918,10 @@ loc_descriptor (const char *name, int line, const char *function) if (!loc_hash) loc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); - slot = (struct loc_descriptor **) htab_find_slot (loc_hash, &loc, 1); + slot = (struct loc_descriptor **) htab_find_slot (loc_hash, &loc, INSERT); if (*slot) return *slot; - *slot = xcalloc (sizeof (**slot), 1); + *slot = XCNEW (struct loc_descriptor); (*slot)->file = name; (*slot)->line = line; (*slot)->function = function; @@ -887,7 +956,7 @@ ggc_record_overhead (size_t allocated, size_t overhead, void *ptr, static int ggc_prune_ptr (void **slot, void *b ATTRIBUTE_UNUSED) { - struct ptr_hash_entry *p = *slot; + struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot; if (!ggc_marked_p (p->ptr)) { p->loc->collected += p->size; @@ -911,7 +980,7 @@ ggc_free_overhead (void *ptr) { PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), NO_INSERT); - struct ptr_hash_entry *p = *slot; + struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot; p->loc->freed += p->size; htab_clear_slot (ptr_hash, slot); free (p); @@ -919,16 +988,39 @@ ggc_free_overhead (void *ptr) /* Helper for qsort; sort descriptors by amount of memory consumed. */ static int -cmp_statistic (const void *loc1, const void *loc2) +final_cmp_statistic (const void *loc1, const void *loc2) { - struct loc_descriptor *l1 = *(struct loc_descriptor **) loc1; - struct loc_descriptor *l2 = *(struct loc_descriptor **) loc2; - return ((l1->allocated + l1->overhead - l1->freed) - + const struct loc_descriptor *const l1 = + *(const struct loc_descriptor *const *) loc1; + const struct loc_descriptor *const l2 = + *(const struct loc_descriptor *const *) loc2; + long diff; + diff = ((long)(l1->allocated + l1->overhead - l1->freed) - (l2->allocated + l2->overhead - l2->freed)); + return diff > 0 ? 1 : diff < 0 ? -1 : 0; +} + +/* Helper for qsort; sort descriptors by amount of memory consumed. */ +static int +cmp_statistic (const void *loc1, const void *loc2) +{ + const struct loc_descriptor *const l1 = + *(const struct loc_descriptor *const *) loc1; + const struct loc_descriptor *const l2 = + *(const struct loc_descriptor *const *) loc2; + long diff; + + diff = ((long)(l1->allocated + l1->overhead - l1->freed - l1->collected) - + (l2->allocated + l2->overhead - l2->freed - l2->collected)); + if (diff) + return diff > 0 ? 1 : diff < 0 ? -1 : 0; + diff = ((long)(l1->allocated + l1->overhead - l1->freed) - + (l2->allocated + l2->overhead - l2->freed)); + return diff > 0 ? 1 : diff < 0 ? -1 : 0; } /* Collect array of the descriptors from hashtable. */ -struct loc_descriptor **loc_array; +static struct loc_descriptor **loc_array; static int add_statistics (void **slot, void *b) { @@ -941,7 +1033,7 @@ add_statistics (void **slot, void *b) /* Dump per-site memory statistics. */ #endif void -dump_ggc_loc_statistics (void) +dump_ggc_loc_statistics (bool final ATTRIBUTE_UNUSED) { #ifdef GATHER_STATISTICS int nentries = 0; @@ -952,13 +1044,14 @@ dump_ggc_loc_statistics (void) ggc_force_collect = true; ggc_collect (); - loc_array = xcalloc (sizeof (*loc_array), loc_hash->n_elements); + loc_array = XCNEWVEC (struct loc_descriptor *, loc_hash->n_elements); fprintf (stderr, "-------------------------------------------------------\n"); fprintf (stderr, "\n%-48s %10s %10s %10s %10s %10s\n", "source location", "Garbage", "Freed", "Leak", "Overhead", "Times"); fprintf (stderr, "-------------------------------------------------------\n"); htab_traverse (loc_hash, add_statistics, &nentries); - qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic); + qsort (loc_array, nentries, sizeof (*loc_array), + final ? final_cmp_statistic : cmp_statistic); for (i = 0; i < nentries; i++) { struct loc_descriptor *d = loc_array[i]; @@ -999,5 +1092,6 @@ dump_ggc_loc_statistics (void) fprintf (stderr, "%-48s %10s %10s %10s %10s %10s\n", "source location", "Garbage", "Freed", "Leak", "Overhead", "Times"); fprintf (stderr, "-------------------------------------------------------\n"); + ggc_force_collect = false; #endif }