This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] support ggc hash_map and hash_set


Sorry, somehow I missed this email. Yes, that appears to have fixed it!

Thank you very much,
Alan

Trevor Saunders wrote:
On Tue, Sep 09, 2014 at 03:37:26PM +0100, Alan Lawrence wrote:
Following this, we're seeing ICEs in tests in gcc.dg/pch.exp and g++.dg/pch.exp,
with cross-builds (hosted on x86_64) targetting bare metal AArch64 and ARM
(aarch64-none-elf, aarch64_be-none-elf and arm-none-eabi; I haven't tested
armeb-none-eabi; builds targeting linux are OK), for *release builds only*.

Could you test the below patch? it seems to work for me, but I'm not
familiar with testing cross compilers.

diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index c2a68fd..028b7de 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -1598,8 +1598,9 @@ template<typename D>
 static void
 gt_pch_nx (hash_table<D> *h)
 {
-  gcc_checking_assert (gt_pch_note_object (h->m_entries, h,
-                                          hashtab_entry_note_pointers<D>));
+  bool success ATTRIBUTE_UNUSED
+    = gt_pch_note_object (h->m_entries, h, hashtab_entry_note_pointers<D>);
+  gcc_checking_assert (success);
   for (size_t i = 0; i < h->m_size; i++)
     {
       if (hash_table<D>::is_empty (h->m_entries[i])

       Trev

Affected tests:

gcc.dg/pch.exp: all variants of
./except-1.h
./inline-3.h
gcc.dg/pch/except-1.c
gcc.dg/pch/inline-3.c

g++.dg: all variants of
./array-1.H
./empty.H
./externc-1.H
./local-1.H
./pch.H
./static-1.H
./system-1.H
./system-2.H
./template-1.H
./uninst.H
./wchar-1.H

(These then lead to failures of g++.dg/pch/{array-1,...}.C and corresponding
assembly comparisons).

Sample log:

Executing on host: build/obj/gcc2/gcc/testsuite/g++/../../xg++
-Bbuild/obj/gcc2/gcc/testsuite/g++/../../ ./template-1.H
-fno-diagnostics-show-caret -fdiagnostics-color=never  -nostdinc++
-Ibuild/obj/gcc2/aarch64-none-elf/ilp32/libstdc++-v3/include/aarch64-none-elf
-Ibuild/obj/gcc2/aarch64-none-elf/ilp32/libstdc++-v3/include
-Isrc/gcc/libstdc++-v3/libsupc++ -Isrc/gcc/libstdc++-v3/include/backward
-Isrc/gcc/libstdc++-v3/testsuite/util -fmessage-length=0  -O2 -g
-specs=aem-ve.specs    -mabi=ilp32 -mcmodel=small  -o template-1.H.gch
(timeout = 300)
spawn build/obj/gcc2/gcc/testsuite/g++/../../xg++
-Bbuild/obj/gcc2/gcc/testsuite/g++/../../ ./template-1.H
-fno-diagnostics-show-caret -fdiagnostics-color=never -nostdinc++
-Ibuild/obj/gcc2/aarch64-none-elf/ilp32/libstdc++-v3/include/aarch64-none-elf
-Ibuild/obj/gcc2/aarch64-none-elf/ilp32/libstdc++-v3/include
-Isrc/gcc/libstdc++-v3/libsupc++ -Isrc/gcc/libstdc++-v3/include/backward
-Isrc/gcc/libstdc++-v3/testsuite/util -fmessage-length=0 -O2 -g
-specs=aem-ve.specs -mabi=ilp32 -mcmodel=small -o template-1.H.gch

./template-1.H:5:2: internal compiler error: in relocate_ptrs, at ggc-common.c:435
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
compiler exited with status 1
output is:
./array-1.H:4:2: internal compiler error: in relocate_ptrs, at ggc-common.c:435
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

FAIL: ./array-1.H  -g (internal compiler error)
FAIL: ./array-1.H  -g (test for excess errors)
Excess errors:
./array-1.H:4:2: internal compiler error: in relocate_ptrs, at ggc-common.c:435

--Alan

tsaunders@mozilla.com wrote:
From: Trevor Saunders <tsaunders@mozilla.com>

Hi,

There are still some issues to make this work really nicely, but this part is
probably good enough its worth reviewing.

For one thing you can't use ggc hash_map or set in front ends with some types
or gengtype will decide to put the overloads of the marking routines it
provides in a front end file instead of the one it choose before breaking other
front ends.  However that seems to be an unrelated issue you can trigger it
without using hash_map/set, so we might as well solve it separetly.

I had to have the entry marking functions for set deligate to the traits class
because gcc < 4.9.1 issues clearly bogus errors if you inline the code from the
traits implementation.  We may well want to make map work the same way at some
point to enable some of the special GTY attributes like if_marked, but it
doesn't seem to be necessary right now.

bootstrapped + regtested without regressions on x86_64-unknown-linux-gnu, ok?

Trev

gcc/ChangeLog:

2014-09-01  Trevor Saunders  <tsaunders@mozilla.com>

       * alloc-pool.c: Include coretypes.h.
       * cgraph.h, dbxout.c, dwarf2out.c, except.c, except.h, function.c,
       function.h, symtab.c, tree-cfg.c, tree-eh.c: Use hash_map and
       hash_set instead of htab.
       * ggc-page.c (in_gc): New variable.
       (ggc_free): Do nothing if a collection is taking place.
       (ggc_collect): Set in_gc appropriately.
       * ggc.h (gt_ggc_mx(const char *)): New function.
       (gt_pch_nx(const char *)): Likewise.
       (gt_ggc_mx(int)): Likewise.
       (gt_pch_nx(int)): Likewise.
       * hash-map.h (hash_map::hash_entry::ggc_mx): Likewise.
       (hash_map::hash_entry::pch_nx): Likewise.
       (hash_map::hash_entry::pch_nx_helper): Likewise.
(hash_map::hash_map): Adjust.
(hash_map::create_ggc): New function.
(gt_ggc_mx): Likewise.
(gt_pch_nx): Likewise.
       * hash-set.h (default_hashset_traits::ggc_mx): Likewise.
(default_hashset_traits::pch_nx): Likewise.
(hash_set::hash_entry::ggc_mx): Likewise.
(hash_set::hash_entry::pch_nx): Likewise.
(hash_set::hash_entry::pch_nx_helper): Likewise.
(hash_set::hash_set): Adjust.
(hash_set::create_ggc): New function.
(hash_set::elements): Likewise.
(gt_ggc_mx): Likewise.
(gt_pch_nx): Likewise.
       * hash-table.h (hash_table::hash_table): Adjust.
(hash_table::m_ggc): New member.
       (hash_table::~hash_table): Adjust.
       (hash_table::expand): Likewise.
       (hash_table::empty): Likewise.
(gt_ggc_mx): New function.
       (hashtab_entry_note_pointers): Likewise.
(gt_pch_nx): Likewise.


diff --git a/gcc/alloc-pool.c b/gcc/alloc-pool.c
index 0d31835..bfaa0e4 100644
--- a/gcc/alloc-pool.c
+++ b/gcc/alloc-pool.c
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3.  If not see

#include "config.h"
#include "system.h"
+#include "coretypes.h"
#include "alloc-pool.h"
#include "hash-table.h"
#include "hash-map.h"
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 879899c..030a1c7 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1604,7 +1604,6 @@ struct cgraph_2node_hook_list;

/* Map from a symbol to initialization/finalization priorities.  */
struct GTY(()) symbol_priority_map {
-  symtab_node *symbol;
  priority_type init;
  priority_type fini;
};
@@ -1872,7 +1871,7 @@ public:
  htab_t GTY((param_is (symtab_node))) assembler_name_hash;

  /* Hash table used to hold init priorities.  */
-  htab_t GTY ((param_is (symbol_priority_map))) init_priority_hash;
+  hash_map<symtab_node *, symbol_priority_map> *init_priority_hash;

  FILE* GTY ((skip)) dump_file;

diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 946f1d1..d856bdd 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -2484,12 +2484,9 @@ dbxout_expand_expr (tree expr)
/* Helper function for output_used_types.  Queue one entry from the
   used types hash to be output.  */

-static int
-output_used_types_helper (void **slot, void *data)
+bool
+output_used_types_helper (tree const &type, vec<tree> *types_p)
{
-  tree type = (tree) *slot;
-  vec<tree> *types_p = (vec<tree> *) data;
-
  if ((TREE_CODE (type) == RECORD_TYPE
       || TREE_CODE (type) == UNION_TYPE
       || TREE_CODE (type) == QUAL_UNION_TYPE
@@ -2502,7 +2499,7 @@ output_used_types_helper (void **slot, void *data)
          && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
    types_p->quick_push (TYPE_NAME (type));

-  return 1;
+  return true;
}

/* This is a qsort callback which sorts types and declarations into a
@@ -2544,8 +2541,9 @@ output_used_types (void)
      int i;
      tree type;

-      types.create (htab_elements (cfun->used_types_hash));
-      htab_traverse (cfun->used_types_hash, output_used_types_helper, &types);
+      types.create (cfun->used_types_hash->elements ());
+      cfun->used_types_hash->traverse<vec<tree> *, output_used_types_helper>
+               (&types);

      /* Sort by UID to prevent dependence on hash table ordering.  */
      types.qsort (output_types_sort);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 7c0be86..21afc3f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -18013,17 +18013,15 @@ dwarf2out_abstract_function (tree decl)
   Marks the DIE of a given type in *SLOT as perennial, so it never gets
   marked as unused by prune_unused_types.  */

-static int
-premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+bool
+premark_used_types_helper (tree const &type, void *)
{
-  tree type;
  dw_die_ref die;

-  type = (tree) *slot;
  die = lookup_type_die (type);
  if (die != NULL)
    die->die_perennial_p = 1;
-  return 1;
+  return true;
}

/* Helper function of premark_types_used_by_global_vars which gets called
@@ -18066,7 +18064,7 @@ static void
premark_used_types (struct function *fun)
{
  if (fun && fun->used_types_hash)
-    htab_traverse (fun->used_types_hash, premark_used_types_helper, NULL);
+    fun->used_types_hash->traverse<void *, premark_used_types_helper> (NULL);
}

/* Mark all members of types_used_by_vars_entry as perennial.  */
diff --git a/gcc/except.c b/gcc/except.c
index 1f57c3f..fecc060 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -149,8 +149,13 @@ along with GCC; see the file COPYING3.  If not see
#endif

static GTY(()) int call_site_base;
-static GTY ((param_is (union tree_node)))
-  htab_t type_to_runtime_map;
+
+struct tree_hash_traits : default_hashmap_traits
+{
+  static hashval_t hash (tree t) { return TREE_HASH (t); }
+};
+
+static GTY (()) hash_map<tree, tree, tree_hash_traits> *type_to_runtime_map;

/* Describe the SjLj_Function_Context structure.  */
static GTY(()) tree sjlj_fc_type_node;
@@ -213,9 +218,6 @@ typedef hash_table<action_record_hasher> action_hash_type;
static bool get_eh_region_and_lp_from_rtx (const_rtx, eh_region *,
                                          eh_landing_pad *);

-static int t2r_eq (const void *, const void *);
-static hashval_t t2r_hash (const void *);
-
static void dw2_build_landing_pads (void);

static int collect_one_action_chain (action_hash_type *, eh_region);
@@ -237,7 +239,8 @@ init_eh (void)
  if (! flag_exceptions)
    return;

-  type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL);
+  type_to_runtime_map
+    = hash_map<tree, tree, tree_hash_traits>::create_ggc (31);

  /* Create the SjLj_Function_Context structure.  This should match
     the definition in unwind-sjlj.c.  */
@@ -671,54 +674,28 @@ eh_region_outermost (struct function *ifun, eh_region region_a,
  return region_a;
}

-static int
-t2r_eq (const void *pentry, const void *pdata)
-{
-  const_tree const entry = (const_tree) pentry;
-  const_tree const data = (const_tree) pdata;
-
-  return TREE_PURPOSE (entry) == data;
-}
-
-static hashval_t
-t2r_hash (const void *pentry)
-{
-  const_tree const entry = (const_tree) pentry;
-  return TREE_HASH (TREE_PURPOSE (entry));
-}
-
void
add_type_for_runtime (tree type)
{
-  tree *slot;
-
  /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
  if (TREE_CODE (type) == NOP_EXPR)
    return;

-  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TREE_HASH (type), INSERT);
-  if (*slot == NULL)
-    {
-      tree runtime = lang_hooks.eh_runtime_type (type);
-      *slot = tree_cons (type, runtime, NULL_TREE);
-    }
+  bool existed = false;
+  tree *slot = &type_to_runtime_map->get_or_insert (type, &existed);
+  if (!existed)
+    *slot = lang_hooks.eh_runtime_type (type);
}

tree
lookup_type_for_runtime (tree type)
{
-  tree *slot;
-
  /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
  if (TREE_CODE (type) == NOP_EXPR)
    return type;

-  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TREE_HASH (type), NO_INSERT);
-
  /* We should have always inserted the data earlier.  */
-  return TREE_VALUE (*slot);
+  return *type_to_runtime_map->get (type);
}


@@ -3150,12 +3127,12 @@ output_function_exception_table (const char *fnname)
}

void
-set_eh_throw_stmt_table (struct function *fun, struct htab *table)
+set_eh_throw_stmt_table (function *fun, hash_map<gimple, int> *table)
{
  fun->eh->throw_stmt_table = table;
}

-htab_t
+hash_map<gimple, int> *
get_eh_throw_stmt_table (struct function *fun)
{
  return fun->eh->throw_stmt_table;
diff --git a/gcc/except.h b/gcc/except.h
index 71a8dce..3259151 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -204,7 +204,7 @@ struct GTY(()) eh_status

  /* At the gimple level, a mapping from gimple statement to landing pad
     or must-not-throw region.  See record_stmt_eh_region.  */
-  htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table;
+  hash_map<gimple, int> *GTY(()) throw_stmt_table;

  /* All of the runtime type data used by the function.  These objects
     are emitted to the lang-specific-data-area for the function.  */
@@ -291,8 +291,8 @@ struct GTY(()) throw_stmt_node {
  int lp_nr;
};

-extern struct htab *get_eh_throw_stmt_table (struct function *);
-extern void set_eh_throw_stmt_table (struct function *, struct htab *);
+extern hash_map<gimple, int> *get_eh_throw_stmt_table (struct function *);
+extern void set_eh_throw_stmt_table (function *, hash_map<gimple, int> *);

enum eh_personality_kind {
  eh_personality_none,
diff --git a/gcc/function.c b/gcc/function.c
index 464c6cd..2e46799 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -6093,14 +6093,10 @@ used_types_insert_helper (tree type, struct function *func)
{
  if (type != NULL && func != NULL)
    {
-      void **slot;
-
      if (func->used_types_hash == NULL)
-       func->used_types_hash = htab_create_ggc (37, htab_hash_pointer,
-                                                htab_eq_pointer, NULL);
-      slot = htab_find_slot (func->used_types_hash, type, INSERT);
-      if (*slot == NULL)
-       *slot = type;
+       func->used_types_hash = hash_set<tree>::create_ggc (37);
+
+      func->used_types_hash->add (type);
    }
}

diff --git a/gcc/function.h b/gcc/function.h
index 071f5dd..e71210d 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
#define GCC_FUNCTION_H

#include "hashtab.h"
+#include "hash-set.h"
#include "vec.h"
#include "machmode.h"
#include "tm.h"                        /* For CUMULATIVE_ARGS.  */
@@ -564,7 +565,7 @@ struct GTY(()) function {
  struct language_function * language;

  /* Used types hash table.  */
-  htab_t GTY ((param_is (union tree_node))) used_types_hash;
+  hash_set<tree> *GTY (()) used_types_hash;

  /* Dwarf2 Frame Description Entry, containing the Call Frame Instructions
     used for unwinding.  Only set when either dwarf2 unwinding or dwarf2
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index 3939540..2a9b2d9 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -500,6 +500,10 @@ static struct globals
  } stats;
} G;

+/* True if a gc is currently taking place.  */
+
+static bool in_gc = false;
+
/* The size in bytes required to maintain a bitmap for the objects
   on a page-entry.  */
#define BITMAP_SIZE(Num_objects) \
@@ -1574,6 +1578,9 @@ ggc_get_size (const void *p)
void
ggc_free (void *p)
{
+  if (in_gc)
+    return;
+
  page_entry *pe = lookup_page_table_entry (p);
  size_t order = pe->order;
  size_t size = OBJECT_SIZE (order);
@@ -2139,7 +2146,6 @@ ggc_collect (void)
    MAX (G.allocated_last_gc, (size_t)PARAM_VALUE (GGC_MIN_HEAPSIZE) * 1024);

  float min_expand = allocated_last_gc * PARAM_VALUE (GGC_MIN_EXPAND) / 100;
-
  if (G.allocated < allocated_last_gc + min_expand && !ggc_force_collect)
    return;

@@ -2162,6 +2168,7 @@ ggc_collect (void)

  invoke_plugin_callbacks (PLUGIN_GGC_START, NULL);

+  in_gc = true;
  clear_marks ();
  ggc_mark_roots ();
  ggc_handle_finalizers ();
@@ -2173,6 +2180,7 @@ ggc_collect (void)
  validate_free_objects ();
  sweep_pages ();

+  in_gc = false;
  G.allocated_last_gc = G.allocated;

  invoke_plugin_callbacks (PLUGIN_GGC_END, NULL);
diff --git a/gcc/ggc.h b/gcc/ggc.h
index 1c0fd3d..6280c43 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -337,4 +337,25 @@ ggc_alloc_cleared_gimple_statement_stat (size_t s CXX_MEM_STAT_INFO)
    ggc_internal_cleared_alloc (s PASS_MEM_STAT);
}

+static inline void
+gt_ggc_mx (const char *s)
+{
+  ggc_test_and_set_mark (const_cast<char *> (s));
+}
+
+static inline void
+gt_pch_nx (const char *)
+{
+}
+
+static inline void
+gt_ggc_mx (int)
+{
+}
+
+static inline void
+gt_pch_nx (int)
+{
+}
+
#endif
diff --git a/gcc/hash-map.h b/gcc/hash-map.h
index d2eed33..c65e1e5 100644
--- a/gcc/hash-map.h
+++ b/gcc/hash-map.h
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
#ifndef hash_map_h
#define hash_map_h

+#include <new>
#include "hash-table.h"

/* implement default behavior for traits when types allow it.  */
@@ -103,7 +104,7 @@ private:

template<typename Key, typename Value,
        typename Traits = default_hashmap_traits>
-class hash_map
+class GTY((user)) hash_map
{
  struct hash_entry
  {
@@ -135,10 +136,56 @@ class hash_map

    static void mark_empty (hash_entry &e) { Traits::mark_empty (e); }
    static bool is_empty (const hash_entry &e) { return Traits::is_empty (e); }
+
+    static void ggc_mx (hash_entry &e)
+      {
+       gt_ggc_mx (e.m_key);
+       gt_ggc_mx (e.m_value);
+      }
+
+    static void pch_nx (hash_entry &e)
+      {
+       gt_pch_nx (e.m_key);
+       gt_pch_nx (e.m_value);
+      }
+
+    static void pch_nx (hash_entry &e, gt_pointer_operator op, void *c)
+      {
+       pch_nx_helper (e.m_key, op, c);
+       pch_nx_helper (e.m_value, op, c);
+      }
+
+  private:
+    template<typename T>
+    static void
+      pch_nx_helper (T &x, gt_pointer_operator op, void *cookie)
+       {
+         gt_pch_nx (&x, op, cookie);
+       }
+
+    static void
+      pch_nx_helper (int, gt_pointer_operator, void *)
+       {
+       }
+
+    template<typename T>
+      static void
+      pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie)
+       {
+         op (&x, cookie);
+       }
  };

public:
-  explicit hash_map (size_t n = 13) : m_table (n) {}
+  explicit hash_map (size_t n = 13, bool ggc = false) : m_table (n, ggc) {}
+
+  /* Create a hash_map in ggc memory.  */
+  static hash_map *create_ggc (size_t size)
+    {
+      hash_map *map = ggc_alloc<hash_map> ();
+      new (map) hash_map (size, true);
+      return map;
+    }

  /* If key k isn't already in the map add key k with value v to the map, and
     return false.  Otherwise set the value of the entry for key k to be v and
@@ -208,7 +255,35 @@ public:
    }

private:
+
+  template<typename T, typename U, typename V> friend void gt_ggc_mx (hash_map<T, U, V> *);
+  template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *);
+      template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *);
+
  hash_table<hash_entry> m_table;
};

+/* ggc marking routines.  */
+
+template<typename K, typename V, typename H>
+static inline void
+gt_ggc_mx (hash_map<K, V, H> *h)
+{
+  gt_ggc_mx (&h->m_table);
+}
+
+template<typename K, typename V, typename H>
+static inline void
+gt_pch_nx (hash_map<K, V, H> *h)
+{
+  gt_pch_nx (&h->m_table);
+}
+
+template<typename K, typename V, typename H>
+static inline void
+gt_pch_nx (hash_map<K, V, H> *h, gt_pointer_operator op, void *cookie)
+{
+  op (&h->m_table.m_entries, cookie);
+}
+
#endif
diff --git a/gcc/hash-set.h b/gcc/hash-set.h
index 47bae9e..0a500cb 100644
--- a/gcc/hash-set.h
+++ b/gcc/hash-set.h
@@ -81,6 +81,26 @@ struct default_hashset_traits
  /* Return true if the passed in entry is marked as empty.  */

  template<typename T> static bool is_empty (T *e) { return e == NULL; }
+
+  /* ggc walking routine, mark all objects refered to by this one.  */
+
+  template<typename T>
+  static void
+  ggc_mx (T &x)
+    {
+      extern void gt_ggc_mx (T &);
+      gt_ggc_mx (x);
+    }
+
+  /* pch walking routine, note all objects refered to by this element.  */
+
+  template<typename T>
+  static void
+  pch_nx (T &x)
+    {
+      extern void gt_pch_nx (T &);
+      gt_pch_nx (x);
+    }
};

template<typename Key, typename Traits = default_hashset_traits>
@@ -128,10 +148,50 @@ class hash_set
      {
       return Traits::is_empty (e.m_key);
      }
+
+    static void ggc_mx (hash_entry &e)
+      {
+       Traits::ggc_mx (e.m_key);
+      }
+
+    static void pch_nx (hash_entry &e)
+      {
+       Traits::pch_nx (e.m_key);
+      }
+
+    static void pch_nx (hash_entry &e, gt_pointer_operator op, void *c)
+      {
+       pch_nx_helper (e.m_key, op, c);
+      }
+
+  private:
+    template<typename T>
+    static void
+      pch_nx_helper (T &x, gt_pointer_operator op, void *cookie)
+       {
+         gt_pch_nx (&x, op, cookie);
+       }
+
+    template<typename T>
+      static void
+      pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie)
+       {
+         op (&x, cookie);
+       }
  };

public:
-  explicit hash_set (size_t n = 13) : m_table (n) {}
+  explicit hash_set (size_t n = 13, bool ggc = false) : m_table (n, ggc) {}
+
+  /* Create a hash_set in gc memory with space for at least n elements.  */
+
+  static hash_set *
+    create_ggc (size_t n)
+      {
+       hash_set *set = ggc_alloc<hash_set> ();
+       new (set) hash_set (n, true);
+       return set;
+      }

  /* If key k isn't already in the map add it to the map, and
     return false.  Otherwise return true.  */
@@ -166,8 +226,40 @@ public:
       f ((*iter).m_key, a);
    }

+  /* Return the number of elements in the set.  */
+
+  size_t elements () const { return m_table.elements (); }
+
private:
+
+  template<typename T, typename U> friend void gt_ggc_mx (hash_set<T, U> *);
+  template<typename T, typename U> friend void gt_pch_nx (hash_set<T, U> *);
+      template<typename T, typename U> friend void gt_pch_nx (hash_set<T, U> *, gt_pointer_operator, void *);
+
  hash_table<hash_entry> m_table;
};

+/* ggc marking routines.  */
+
+template<typename K, typename H>
+static inline void
+gt_ggc_mx (hash_set<K, H> *h)
+{
+  gt_ggc_mx (&h->m_table);
+}
+
+template<typename K, typename H>
+static inline void
+gt_pch_nx (hash_set<K, H> *h)
+{
+  gt_pch_nx (&h->m_table);
+}
+
+template<typename K, typename H>
+static inline void
+gt_pch_nx (hash_set<K, H> *h, gt_pointer_operator op, void *cookie)
+{
+  op (&h->m_table.m_entries, cookie);
+}
+
#endif
diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 9c6a34a..4c18786 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -196,8 +196,11 @@ along with GCC; see the file COPYING3.  If not see
#ifndef TYPED_HASHTAB_H
#define TYPED_HASHTAB_H

+#include "ggc.h"
#include "hashtab.h"

+template<typename, typename, typename> class hash_map;
+template<typename, typename> class hash_set;

/* The ordinary memory allocator.  */
/* FIXME (crowl): This allocator may be extracted for wider sharing later.  */
@@ -998,7 +1001,7 @@ class hash_table<Descriptor, Allocator, true>
  typedef typename Descriptor::compare_type compare_type;

public:
-  hash_table (size_t);
+  explicit hash_table (size_t, bool ggc = false);
  ~hash_table ();

  /* Current size (in entries) of the hash table.  */
@@ -1105,6 +1108,11 @@ public:
    }

private:
+  template<typename T> friend void gt_ggc_mx (hash_table<T> *);
+  template<typename T> friend void gt_pch_nx (hash_table<T> *);
+  template<typename T> friend void hashtab_entry_note_pointers (void *, void *, gt_pointer_operator, void *);
+  template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *);
+  template<typename T, typename U> friend void gt_pch_nx (hash_set<T, U> *, gt_pointer_operator, void *);

  value_type *find_empty_slot_for_expand (hashval_t);
  void expand ();
@@ -1149,18 +1157,26 @@ private:
  /* Current size (in entries) of the hash table, as an index into the
     table of primes.  */
  unsigned int m_size_prime_index;
+
+  /* if m_entries is stored in ggc memory.  */
+  bool m_ggc;
};

template<typename Descriptor, template<typename Type> class Allocator>
-hash_table<Descriptor, Allocator, true>::hash_table (size_t size) :
-  m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0)
+hash_table<Descriptor, Allocator, true>::hash_table (size_t size, bool ggc) :
+  m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0),
+  m_ggc (ggc)
{
  unsigned int size_prime_index;

  size_prime_index = hash_table_higher_prime_index (size);
  size = prime_tab[size_prime_index].prime;

-  m_entries = Allocator <value_type> ::data_alloc (size);
+  if (!m_ggc)
+    m_entries = Allocator <value_type> ::data_alloc (size);
+  else
+    m_entries = ggc_cleared_vec_alloc<value_type> (size);
+
  gcc_assert (m_entries != NULL);
  m_size = size;
  m_size_prime_index = size_prime_index;
@@ -1173,7 +1189,10 @@ hash_table<Descriptor, Allocator, true>::~hash_table ()
    if (!is_empty (m_entries[i]) && !is_deleted (m_entries[i]))
      Descriptor::remove (m_entries[i]);

-  Allocator <value_type> ::data_free (m_entries);
+  if (!m_ggc)
+    Allocator <value_type> ::data_free (m_entries);
+  else
+    ggc_free (m_entries);
}

/* Similar to find_slot, but without several unwanted side effects:
@@ -1245,7 +1264,12 @@ hash_table<Descriptor, Allocator, true>::expand ()
      nsize = osize;
    }

-  value_type *nentries = Allocator <value_type> ::data_alloc (nsize);
+  value_type *nentries;
+  if (!m_ggc)
+    nentries = Allocator <value_type> ::data_alloc (nsize);
+  else
+    nentries = ggc_cleared_vec_alloc<value_type> (nsize);
+
  gcc_assert (nentries != NULL);
  m_entries = nentries;
  m_size = nsize;
@@ -1269,7 +1293,10 @@ hash_table<Descriptor, Allocator, true>::expand ()
    }
  while (p < olimit);

-  Allocator <value_type> ::data_free (oentries);
+  if (!m_ggc)
+    Allocator <value_type> ::data_free (oentries);
+  else
+    ggc_free (oentries);
}

template<typename Descriptor, template<typename Type> class Allocator>
@@ -1290,8 +1317,17 @@ hash_table<Descriptor, Allocator, true>::empty ()
      int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
      int nsize = prime_tab[nindex].prime;

-      Allocator <value_type> ::data_free (m_entries);
-      m_entries = Allocator <value_type> ::data_alloc (nsize);
+      if (!m_ggc)
+       {
+         Allocator <value_type> ::data_free (m_entries);
+         m_entries = Allocator <value_type> ::data_alloc (nsize);
+       }
+      else
+       {
+         ggc_free (m_entries);
+         m_entries = ggc_cleared_vec_alloc<value_type> (nsize);
+       }
+
      m_size = nsize;
      m_size_prime_index = nindex;
    }
@@ -1519,4 +1555,59 @@ hash_table<Descriptor, Allocator, true>::iterator::operator ++ ()
       (ITER) != (HTAB).end () ? (RESULT = *(ITER) , true) : false; \
       ++(ITER))

+/* ggc walking routines.  */
+
+template<typename E>
+static inline void
+gt_ggc_mx (hash_table<E> *h)
+{
+  typedef hash_table<E> table;
+
+  if (!ggc_test_and_set_mark (h->m_entries))
+    return;
+
+  for (size_t i = 0; i < h->m_size; i++)
+    {
+      if (table::is_empty (h->m_entries[i])
+         || table::is_deleted (h->m_entries[i]))
+       continue;
+
+      E::ggc_mx (h->m_entries[i]);
+    }
+}
+
+template<typename D>
+static inline void
+hashtab_entry_note_pointers (void *obj, void *h, gt_pointer_operator op,
+                            void *cookie)
+{
+  hash_table<D> *map = static_cast<hash_table<D> *> (h);
+  gcc_assert (map->m_entries == obj);
+  for (size_t i = 0; i < map->m_size; i++)
+    {
+      typedef hash_table<D> table;
+      if (table::is_empty (map->m_entries[i])
+         || table::is_deleted (map->m_entries[i]))
+       continue;
+
+      D::pch_nx (map->m_entries[i], op, cookie);
+    }
+}
+
+template<typename D>
+static void
+gt_pch_nx (hash_table<D> *h)
+{
+  gcc_assert (gt_pch_note_object (h->m_entries, h,
+                                 hashtab_entry_note_pointers<D>));
+  for (size_t i = 0; i < h->m_size; i++)
+    {
+      if (hash_table<D>::is_empty (h->m_entries[i])
+         || hash_table<D>::is_deleted (h->m_entries[i]))
+       continue;
+
+      D::pch_nx (h->m_entries[i]);
+    }
+}
+
#endif /* TYPED_HASHTAB_H */
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 739a8e4..792b3b5 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -407,15 +407,7 @@ symtab_node::unregister (void)
  if (!is_a <varpool_node *> (this) || !DECL_HARD_REGISTER (decl))
    symtab->unlink_from_assembler_name_hash (this, false);
  if (in_init_priority_hash)
-    {
-      symbol_priority_map in;
-      void **slot;
-      in.symbol = this;
-
-      slot = htab_find_slot (symtab->init_priority_hash, &in, NO_INSERT);
-      if (slot)
-       htab_clear_slot (symtab->init_priority_hash, slot);
-    }
+    symtab->init_priority_hash->remove (this);
}


@@ -1455,14 +1447,10 @@ symtab_node::set_section (const char *section)
priority_type
symtab_node::get_init_priority ()
{
-  symbol_priority_map *h;
-  symbol_priority_map in;
-
  if (!this->in_init_priority_hash)
    return DEFAULT_INIT_PRIORITY;
-  in.symbol = this;
-  h = (symbol_priority_map *) htab_find (symtab->init_priority_hash,
-                                               &in);
+
+  symbol_priority_map *h = symtab->init_priority_hash->get (this);
  return h ? h->init : DEFAULT_INIT_PRIORITY;
}

@@ -1481,35 +1469,12 @@ enum availability symtab_node::get_availability (void)
priority_type
cgraph_node::get_fini_priority ()
{
-  symbol_priority_map *h;
-  symbol_priority_map in;
-
  if (!this->in_init_priority_hash)
    return DEFAULT_INIT_PRIORITY;
-  in.symbol = this;
-  h = (symbol_priority_map *) htab_find (symtab->init_priority_hash,
-                                               &in);
+  symbol_priority_map *h = symtab->init_priority_hash->get (this);
  return h ? h->fini : DEFAULT_INIT_PRIORITY;
}

-/* Return true if the from tree in both priority maps are equal.  */
-
-int
-symbol_priority_map_eq (const void *va, const void *vb)
-{
-  const symbol_priority_map *const a = (const symbol_priority_map *) va,
-    *const b = (const symbol_priority_map *) vb;
-  return (a->symbol == b->symbol);
-}
-
-/* Hash a from symbol in a symbol_priority_map.  */
-
-unsigned int
-symbol_priority_map_hash (const void *item)
-{
-  return htab_hash_pointer (((const symbol_priority_map *)item)->symbol);
-}
-
/* Return the initialization and finalization priority information for
   DECL.  If there is no previous priority information, a freshly
   allocated structure is returned.  */
@@ -1517,23 +1482,14 @@ symbol_priority_map_hash (const void *item)
symbol_priority_map *
symtab_node::priority_info (void)
{
-  symbol_priority_map in;
-  symbol_priority_map *h;
-  void **loc;
-
-  in.symbol = this;
  if (!symtab->init_priority_hash)
-    symtab->init_priority_hash = htab_create_ggc (512,
-                                                 symbol_priority_map_hash,
-                                                 symbol_priority_map_eq, 0);
+    symtab->init_priority_hash = hash_map<symtab_node *, symbol_priority_map>::create_ggc (13);

-  loc = htab_find_slot (symtab->init_priority_hash, &in, INSERT);
-  h = (symbol_priority_map *) *loc;
-  if (!h)
+  bool existed;
+  symbol_priority_map *h
+    = &symtab->init_priority_hash->get_or_insert (this, &existed);
+  if (!existed)
    {
-      h = ggc_cleared_alloc<symbol_priority_map> ();
-      *loc = h;
-      h->symbol = this;
      h->init = DEFAULT_INIT_PRIORITY;
      h->fini = DEFAULT_INIT_PRIORITY;
      in_init_priority_hash = true;
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c75516d..e89d76a 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4723,19 +4723,17 @@ verify_node_sharing (tree *tp, int *walk_subtrees, void *data)
}

static bool eh_error_found;
-static int
-verify_eh_throw_stmt_node (void **slot, void *data)
+bool
+verify_eh_throw_stmt_node (const gimple &stmt, const int &,
+                          hash_set<gimple> *visited)
{
-  struct throw_stmt_node *node = (struct throw_stmt_node *)*slot;
-  hash_set<void *> *visited = (hash_set<void *> *) data;
-
-  if (!visited->contains (node->stmt))
+  if (!visited->contains (stmt))
    {
      error ("dead STMT in EH table");
-      debug_gimple_stmt (node->stmt);
+      debug_gimple_stmt (stmt);
      eh_error_found = true;
    }
-  return 1;
+  return true;
}

/* Verify if the location LOCs block is in BLOCKS.  */
@@ -4996,10 +4994,10 @@ verify_gimple_in_cfg (struct function *fn, bool verify_nothrow)
    }

  eh_error_found = false;
-  if (get_eh_throw_stmt_table (cfun))
-    htab_traverse (get_eh_throw_stmt_table (cfun),
-                  verify_eh_throw_stmt_node,
-                  &visited_stmts);
+  hash_map<gimple, int> *eh_table = get_eh_throw_stmt_table (cfun);
+  if (eh_table)
+    eh_table->traverse<hash_set<gimple> *, verify_eh_throw_stmt_node>
+      (&visited_stmts);

  if (err || eh_error_found)
    internal_error ("verify_gimple failed");
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 6c6faf3..9da8da2 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -77,23 +77,12 @@ typedef union {tree *tp; tree t; gimple g;} treemple;
static void
add_stmt_to_eh_lp_fn (struct function *ifun, gimple t, int num)
{
-  struct throw_stmt_node *n;
-  void **slot;
-
  gcc_assert (num != 0);

-  n = ggc_alloc<throw_stmt_node> ();
-  n->stmt = t;
-  n->lp_nr = num;
-
  if (!get_eh_throw_stmt_table (ifun))
-    set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash,
-                                                   struct_ptr_eq,
-                                                   ggc_free));
+    set_eh_throw_stmt_table (ifun, hash_map<gimple, int>::create_ggc (31));

-  slot = htab_find_slot (get_eh_throw_stmt_table (ifun), n, INSERT);
-  gcc_assert (!*slot);
-  *slot = n;
+  gcc_assert (!get_eh_throw_stmt_table (ifun)->put (t, num));
}

/* Add statement T in the current function (cfun) to EH landing pad NUM.  */
@@ -130,22 +119,14 @@ record_stmt_eh_region (eh_region region, gimple t)
bool
remove_stmt_from_eh_lp_fn (struct function *ifun, gimple t)
{
-  struct throw_stmt_node dummy;
-  void **slot;
-
  if (!get_eh_throw_stmt_table (ifun))
    return false;

-  dummy.stmt = t;
-  slot = htab_find_slot (get_eh_throw_stmt_table (ifun), &dummy,
-                        NO_INSERT);
-  if (slot)
-    {
-      htab_clear_slot (get_eh_throw_stmt_table (ifun), slot);
-      return true;
-    }
-  else
+  if (!get_eh_throw_stmt_table (ifun)->get (t))
    return false;
+
+  get_eh_throw_stmt_table (ifun)->remove (t);
+      return true;
}


@@ -166,14 +147,11 @@ remove_stmt_from_eh_lp (gimple t)
int
lookup_stmt_eh_lp_fn (struct function *ifun, gimple t)
{
-  struct throw_stmt_node *p, n;
-
  if (ifun->eh->throw_stmt_table == NULL)
    return 0;

-  n.stmt = t;
-  p = (struct throw_stmt_node *) htab_find (ifun->eh->throw_stmt_table, &n);
-  return p ? p->lp_nr : 0;
+  int *lp_nr = ifun->eh->throw_stmt_table->get (t);
+  return lp_nr ? *lp_nr : 0;
}

/* Likewise, but always use the current function.  */
--
2.1.0




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]