/* 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
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
+<http://www.gnu.org/licenses/>. */
/* Generic garbage collection (GC) functions and data, not specific to
any particular GC implementation. */
#include "params.h"
#include "hosthooks.h"
#include "hosthooks-def.h"
+#include "plugin.h"
+#include "vec.h"
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
# define MAP_FAILED ((void *)-1)
#endif
-#ifdef ENABLE_VALGRIND_CHECKING
-# ifdef HAVE_VALGRIND_MEMCHECK_H
-# include <valgrind/memcheck.h>
-# elif defined HAVE_MEMCHECK_H
-# include <memcheck.h>
-# else
-# include <valgrind.h>
-# 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;
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
{
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++)
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));
- ggc_mark_stringpool ();
+ 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));
+ }
+
+ 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. */
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;
}
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);
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;
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;
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. */
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));
}
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;
}
}
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");
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)
if (ret == (void *) MAP_FAILED)
ret = NULL;
else
- munmap (ret, size);
+ munmap ((caddr_t) ret, size);
return ret;
}
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;
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;
}
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);
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);
}
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);
}
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;
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;
{
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);
static int
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;
+ 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));
static int
cmp_statistic (const void *loc1, const void *loc2)
{
- struct loc_descriptor *l1 = *(struct loc_descriptor **) loc1;
- struct loc_descriptor *l2 = *(struct loc_descriptor **) 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) -
}
/* 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)
{
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, "%-48s %10s %10s %10s %10s %10s\n",
"source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
fprintf (stderr, "-------------------------------------------------------\n");
+ ggc_force_collect = false;
#endif
}