OSDN Git Service

* builtins.c (expand_builtin_compare_and_swap): If target is const0,
[pf3gnuchains/gcc-fork.git] / gcc / ggc-common.c
index a8702a6..3ff64ff 100644 (file)
@@ -1,6 +1,6 @@
 /* Simple garbage collection for the GNU compiler.
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -26,43 +26,21 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "hashtab.h"
 #include "ggc.h"
-#include "toplev.h"
+#include "ggc-internal.h"
+#include "diagnostic-core.h"
 #include "params.h"
 #include "hosthooks.h"
 #include "hosthooks-def.h"
-
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif
-
-#ifdef HAVE_MMAP_FILE
-# include <sys/mman.h>
-# ifdef HAVE_MINCORE
-/* This is on Solaris.  */
-#  include <sys/types.h> 
-# endif
-#endif
-
-#ifndef MAP_FAILED
-# 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
+#include "plugin.h"
+#include "vec.h"
+#include "timevar.h"
 
 /* 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;
 
@@ -77,7 +55,6 @@ static int compare_ptr_data (const void *, const void *);
 static void relocate_ptrs (void *, void *);
 static void write_pch_globals (const struct ggc_root_tab * const *tab,
                               struct traversal_state *state);
-static double ggc_rlimit_bound (double);
 
 /* Maintain global roots that are preserved during GC.  */
 
@@ -96,15 +73,84 @@ 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);
+      }
+}
+
+/* Mark all the roots in the table RT.  */
+
+static void
+ggc_mark_root_tab (const_ggc_root_tab_t rt)
+{
+  size_t i;
+
+  for ( ; rt->base != NULL; rt++)
+    for (i = 0; i < rt->nelt; i++)
+      (*rt->cb) (*(void **) ((char *)rt->base + rt->stride * i));
+}
+
 /* Iterate through all registered roots and mark each element.  */
 
 void
 ggc_mark_roots (void)
 {
   const struct ggc_root_tab *const *rt;
-  const struct ggc_root_tab *rti;
+  const_ggc_root_tab_t rtp, rti;
   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++)
@@ -112,29 +158,34 @@ ggc_mark_roots (void)
       memset (rti->base, 0, rti->stride);
 
   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));
+    ggc_mark_root_tab (*rt);
+
+  FOR_EACH_VEC_ELT (const_ggc_root_tab_t, extra_root_vec, i, rtp)
+    ggc_mark_root_tab (rtp);
 
-  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_EACH_VEC_ELT (const_ggc_cache_tab_t, extra_cache_vec, i, ctp)
+    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.  */
 void *
-ggc_alloc_cleared_stat (size_t size MEM_STAT_DECL)
+ggc_internal_cleared_alloc_stat (size_t size MEM_STAT_DECL)
 {
-  void *buf = ggc_alloc_stat (size PASS_MEM_STAT);
+  void *buf = ggc_internal_alloc_stat (size PASS_MEM_STAT);
   memset (buf, 0, size);
   return buf;
 }
@@ -147,7 +198,7 @@ ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL)
   size_t old_size;
 
   if (x == NULL)
-    return ggc_alloc_stat (size PASS_MEM_STAT);
+    return ggc_internal_alloc_stat (size PASS_MEM_STAT);
 
   old_size = ggc_get_size (x);
 
@@ -163,19 +214,19 @@ 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;
     }
 
-  r = ggc_alloc_stat (size PASS_MEM_STAT);
+  r = ggc_internal_alloc_stat (size PASS_MEM_STAT);
 
   /* Since ggc_get_size returns the size of the pool, not the size of the
      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);
 
@@ -185,19 +236,30 @@ ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL)
   return r;
 }
 
-/* Like ggc_alloc_cleared, but performs a multiplication.  */
 void *
-ggc_calloc (size_t s1, size_t s2)
+ggc_cleared_alloc_htab_ignore_args (size_t c ATTRIBUTE_UNUSED,
+                                   size_t n ATTRIBUTE_UNUSED)
+{
+  gcc_assert (c * n == sizeof (struct htab));
+  return ggc_alloc_cleared_htab ();
+}
+
+/* TODO: once we actually use type information in GGC, create a new tag
+   gt_gcc_ptr_array and use it for pointer arrays.  */
+void *
+ggc_cleared_alloc_ptr_array_two_args (size_t c, size_t n)
 {
-  return ggc_alloc_cleared (s1 * s2);
+  gcc_assert (sizeof (PTR *) == n);
+  return ggc_internal_cleared_vec_alloc (sizeof (PTR *), c);
 }
 
 /* These are for splay_tree_new_ggc.  */
 void *
-ggc_splay_alloc (int sz, void *nl)
+ggc_splay_alloc (enum gt_types_enum obj_type ATTRIBUTE_UNUSED, int sz,
+                void *nl)
 {
   gcc_assert (!nl);
-  return ggc_alloc (sz);
+  return ggc_internal_alloc (sz);
 }
 
 void
@@ -270,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;
@@ -293,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;
@@ -357,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));
 }
@@ -376,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;
 }
@@ -400,15 +464,15 @@ write_pch_globals (const struct ggc_root_tab * const *tab,
            {
              if (fwrite (&ptr, sizeof (void *), 1, state->f)
                  != 1)
-               fatal_error ("can't write PCH file: %m");
+               fatal_error ("can%'t write PCH file: %m");
            }
          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");
+               fatal_error ("can%'t write PCH file: %m");
            }
        }
 }
@@ -438,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++)
@@ -452,7 +517,7 @@ gt_pch_save (FILE *f)
 
   /* Prepare the objects for writing, determine addresses and such.  */
   state.f = f;
-  state.d = init_ggc_pch();
+  state.d = init_ggc_pch ();
   state.count = 0;
   htab_traverse (saving_htab, call_count, &state);
 
@@ -460,23 +525,28 @@ 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++)
     for (rti = *rt; rti->base != NULL; rti++)
       if (fwrite (rti->base, rti->stride, 1, f) != 1)
-       fatal_error ("can't write PCH file: %m");
+       fatal_error ("can%'t write PCH file: %m");
 
   /* Write out all the global pointers, after translation.  */
   write_pch_globals (gt_ggc_rtab, &state);
@@ -488,17 +558,17 @@ gt_pch_save (FILE *f)
     long o;
     o = ftell (state.f) + sizeof (mmi);
     if (o == -1)
-      fatal_error ("can't get position in PCH file: %m");
+      fatal_error ("can%'t get position in PCH file: %m");
     mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment;
     if (mmi.offset == mmap_offset_alignment)
       mmi.offset = 0;
     mmi.offset += o;
   }
   if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
-    fatal_error ("can't write PCH file: %m");
+    fatal_error ("can%'t write PCH file: %m");
   if (mmi.offset != 0
       && fseek (state.f, mmi.offset, SEEK_SET) != 0)
-    fatal_error ("can't write padding to PCH file: %m");
+    fatal_error ("can%'t write padding to PCH file: %m");
 
   ggc_pch_prepare_write (state.d, state.f);
 
@@ -508,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)
@@ -553,7 +623,7 @@ gt_pch_restore (FILE *f)
   for (rt = gt_pch_scalar_rtab; *rt; rt++)
     for (rti = *rt; rti->base != NULL; rti++)
       if (fread (rti->base, rti->stride, 1, f) != 1)
-       fatal_error ("can't read PCH file: %m");
+       fatal_error ("can%'t read PCH file: %m");
 
   /* Read in all the global pointers, in 6 easy loops.  */
   for (rt = gt_ggc_rtab; *rt; rt++)
@@ -561,17 +631,17 @@ gt_pch_restore (FILE *f)
       for (i = 0; i < rti->nelt; i++)
        if (fread ((char *)rti->base + rti->stride * i,
                   sizeof (void *), 1, f) != 1)
-         fatal_error ("can't read PCH file: %m");
+         fatal_error ("can%'t read PCH file: %m");
 
   for (rt = gt_pch_cache_rtab; *rt; rt++)
     for (rti = *rt; rti->base != NULL; rti++)
       for (i = 0; i < rti->nelt; i++)
        if (fread ((char *)rti->base + rti->stride * i,
                   sizeof (void *), 1, f) != 1)
-         fatal_error ("can't read PCH file: %m");
+         fatal_error ("can%'t read PCH file: %m");
 
   if (fread (&mmi, sizeof (mmi), 1, f) != 1)
-    fatal_error ("can't read PCH file: %m");
+    fatal_error ("can%'t read PCH file: %m");
 
   result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
                                          fileno (f), mmi.offset);
@@ -581,10 +651,10 @@ gt_pch_restore (FILE *f)
     {
       if (fseek (f, mmi.offset, SEEK_SET) != 0
          || fread (mmi.preferred_base, mmi.size, 1, f) != 1)
-       fatal_error ("can't read PCH file: %m");
+       fatal_error ("can%'t read PCH file: %m");
     }
   else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
-    fatal_error ("can't read PCH file: %m");
+    fatal_error ("can%'t read PCH file: %m");
 
   ggc_pch_read (f, mmi.preferred_base);
 
@@ -641,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
@@ -665,13 +735,15 @@ 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;
 }
 #endif /* HAVE_MMAP_FILE */
 
+#if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
+
 /* Modify the bound based on rlimits.  */
 static double
 ggc_rlimit_bound (double limit)
@@ -706,7 +778,7 @@ ggc_rlimit_bound (double limit)
 }
 
 /* Heuristic to set a default for GGC_MIN_EXPAND.  */
-int
+static int
 ggc_min_expand_heuristic (void)
 {
   double min_expand = physmem_total();
@@ -725,7 +797,7 @@ ggc_min_expand_heuristic (void)
 }
 
 /* Heuristic to set a default for GGC_MIN_HEAPSIZE.  */
-int
+static int
 ggc_min_heapsize_heuristic (void)
 {
   double phys_kbytes = physmem_total();
@@ -739,7 +811,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;
@@ -754,7 +826,7 @@ ggc_min_heapsize_heuristic (void)
      the limit, whichever is larger.  If GCC does hit the data limit,
      compilation will fail, so this tries to be conservative.  */
   limit_kbytes = MAX (0, limit_kbytes - MAX (limit_kbytes / 4, 20 * 1024));
-  limit_kbytes = (limit_kbytes * 100) / (110 + ggc_min_expand_heuristic());
+  limit_kbytes = (limit_kbytes * 100) / (110 + ggc_min_expand_heuristic ());
   phys_kbytes = MIN (phys_kbytes, limit_kbytes);
 
   phys_kbytes = MAX (phys_kbytes, 4 * 1024);
@@ -762,13 +834,14 @@ ggc_min_heapsize_heuristic (void)
 
   return phys_kbytes;
 }
+#endif
 
 void
 init_ggc_heuristics (void)
 {
 #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
-  set_param_value ("ggc-min-expand", ggc_min_expand_heuristic());
-  set_param_value ("ggc-min-heapsize", ggc_min_heapsize_heuristic());
+  set_default_param_value (GGC_MIN_EXPAND, ggc_min_expand_heuristic ());
+  set_default_param_value (GGC_MIN_HEAPSIZE, ggc_min_heapsize_heuristic ());
 #endif
 }
 
@@ -794,7 +867,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;
 }
@@ -802,8 +875,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);
@@ -822,7 +895,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);
 }
@@ -830,7 +903,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);
 }
@@ -848,10 +921,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;
@@ -886,7 +959,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;
@@ -910,7 +983,13 @@ 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;
+  /* The pointer might be not found if a PCH read happened between allocation
+     and ggc_free () call.  FIXME: account memory properly in the presence of
+     PCH. */
+  if (!slot)
+      return;
+  p = (struct ptr_hash_entry *) *slot;
   p->loc->freed += p->size;
   htab_clear_slot (ptr_hash, slot);
   free (p);
@@ -920,8 +999,10 @@ ggc_free_overhead (void *ptr)
 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));
@@ -932,8 +1013,10 @@ final_cmp_statistic (const void *loc1, const void *loc2)
 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) -
@@ -946,7 +1029,7 @@ cmp_statistic (const void *loc1, const void *loc2)
 }
 
 /* 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)
 {
@@ -970,7 +1053,7 @@ dump_ggc_loc_statistics (bool final ATTRIBUTE_UNUSED)
   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");
@@ -1018,5 +1101,6 @@ dump_ggc_loc_statistics (bool final ATTRIBUTE_UNUSED)
   fprintf (stderr, "%-48s %10s       %10s       %10s       %10s       %10s\n",
           "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
   fprintf (stderr, "-------------------------------------------------------\n");
+  ggc_force_collect = false;
 #endif
 }