From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19506 invoked by alias); 14 Oct 2014 14:05:36 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 19497 invoked by uid 89); 14 Oct 2014 14:05:35 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.6 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,KAM_STOCKTIP,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-wi0-f182.google.com Received: from mail-wi0-f182.google.com (HELO mail-wi0-f182.google.com) (209.85.212.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 14 Oct 2014 14:05:28 +0000 Received: by mail-wi0-f182.google.com with SMTP id n3so10315171wiv.3 for ; Tue, 14 Oct 2014 07:05:25 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.194.81.6 with SMTP id v6mr5265789wjx.39.1413295525260; Tue, 14 Oct 2014 07:05:25 -0700 (PDT) Received: by 10.194.20.74 with HTTP; Tue, 14 Oct 2014 07:05:25 -0700 (PDT) In-Reply-To: <1409622988-14529-1-git-send-email-tsaunders@mozilla.com> References: <1409622988-14529-1-git-send-email-tsaunders@mozilla.com> Date: Tue, 14 Oct 2014 14:12:00 -0000 Message-ID: Subject: Re: [PATCH] support ggc hash_map and hash_set From: Richard Biener To: tsaunders@mozilla.com Cc: GCC Patches Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2014-10/txt/msg01238.txt.bz2 On Tue, Sep 2, 2014 at 3:56 AM, wrote: > From: Trevor Saunders > > 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? I have just noticed that this (ggc support for hash-table.h) makes it no longer suitable for use from generator programs (trying to merge from trunk on match-and-simplify). If you look at vec.h it has sophisticated guards to block out GGC support if GENERATOR_FILE is defined. Can you try to fix this please? Thanks, Richard. > Trev > > gcc/ChangeLog: > > 2014-09-01 Trevor Saunders > > * 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 *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 *types_p) > { > - tree type = (tree) *slot; > - vec *types_p = (vec *) 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 *, 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 (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 *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_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::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 *table) > { > fun->eh->throw_stmt_table = table; > } > > -htab_t > +hash_map * > 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 *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 *get_eh_throw_stmt_table (struct function *); > +extern void set_eh_throw_stmt_table (function *, hash_map *); > > 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::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 *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 (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 > #include "hash-table.h" > > /* implement default behavior for traits when types allow it. */ > @@ -103,7 +104,7 @@ private: > > template 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 > + 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 > + 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 (); > + 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 friend void gt_ggc_mx (hash_map *); > + template friend void gt_pch_nx (hash_map *); > + template friend void gt_pch_nx (hash_map *, gt_pointer_operator, void *); > + > hash_table m_table; > }; > > +/* ggc marking routines. */ > + > +template > +static inline void > +gt_ggc_mx (hash_map *h) > +{ > + gt_ggc_mx (&h->m_table); > +} > + > +template > +static inline void > +gt_pch_nx (hash_map *h) > +{ > + gt_pch_nx (&h->m_table); > +} > + > +template > +static inline void > +gt_pch_nx (hash_map *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 static bool is_empty (T *e) { return e == NULL; } > + > + /* ggc walking routine, mark all objects refered to by this one. */ > + > + template > + 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 > + static void > + pch_nx (T &x) > + { > + extern void gt_pch_nx (T &); > + gt_pch_nx (x); > + } > }; > > template > @@ -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 > + static void > + pch_nx_helper (T &x, gt_pointer_operator op, void *cookie) > + { > + gt_pch_nx (&x, op, cookie); > + } > + > + template > + 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 (); > + 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 friend void gt_ggc_mx (hash_set *); > + template friend void gt_pch_nx (hash_set *); > + template friend void gt_pch_nx (hash_set *, gt_pointer_operator, void *); > + > hash_table m_table; > }; > > +/* ggc marking routines. */ > + > +template > +static inline void > +gt_ggc_mx (hash_set *h) > +{ > + gt_ggc_mx (&h->m_table); > +} > + > +template > +static inline void > +gt_pch_nx (hash_set *h) > +{ > + gt_pch_nx (&h->m_table); > +} > + > +template > +static inline void > +gt_pch_nx (hash_set *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 class hash_map; > +template 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 > 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 friend void gt_ggc_mx (hash_table *); > + template friend void gt_pch_nx (hash_table *); > + template friend void hashtab_entry_note_pointers (void *, void *, gt_pointer_operator, void *); > + template friend void gt_pch_nx (hash_map *, gt_pointer_operator, void *); > + template friend void gt_pch_nx (hash_set *, 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 class Allocator> > -hash_table::hash_table (size_t size) : > - m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0) > +hash_table::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 ::data_alloc (size); > + if (!m_ggc) > + m_entries = Allocator ::data_alloc (size); > + else > + m_entries = ggc_cleared_vec_alloc (size); > + > gcc_assert (m_entries != NULL); > m_size = size; > m_size_prime_index = size_prime_index; > @@ -1173,7 +1189,10 @@ hash_table::~hash_table () > if (!is_empty (m_entries[i]) && !is_deleted (m_entries[i])) > Descriptor::remove (m_entries[i]); > > - Allocator ::data_free (m_entries); > + if (!m_ggc) > + Allocator ::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::expand () > nsize = osize; > } > > - value_type *nentries = Allocator ::data_alloc (nsize); > + value_type *nentries; > + if (!m_ggc) > + nentries = Allocator ::data_alloc (nsize); > + else > + nentries = ggc_cleared_vec_alloc (nsize); > + > gcc_assert (nentries != NULL); > m_entries = nentries; > m_size = nsize; > @@ -1269,7 +1293,10 @@ hash_table::expand () > } > while (p < olimit); > > - Allocator ::data_free (oentries); > + if (!m_ggc) > + Allocator ::data_free (oentries); > + else > + ggc_free (oentries); > } > > template class Allocator> > @@ -1290,8 +1317,17 @@ hash_table::empty () > int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR)); > int nsize = prime_tab[nindex].prime; > > - Allocator ::data_free (m_entries); > - m_entries = Allocator ::data_alloc (nsize); > + if (!m_ggc) > + { > + Allocator ::data_free (m_entries); > + m_entries = Allocator ::data_alloc (nsize); > + } > + else > + { > + ggc_free (m_entries); > + m_entries = ggc_cleared_vec_alloc (nsize); > + } > + > m_size = nsize; > m_size_prime_index = nindex; > } > @@ -1519,4 +1555,59 @@ hash_table::iterator::operator ++ () > (ITER) != (HTAB).end () ? (RESULT = *(ITER) , true) : false; \ > ++(ITER)) > > +/* ggc walking routines. */ > + > +template > +static inline void > +gt_ggc_mx (hash_table *h) > +{ > + typedef hash_table 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 > +static inline void > +hashtab_entry_note_pointers (void *obj, void *h, gt_pointer_operator op, > + void *cookie) > +{ > + hash_table *map = static_cast *> (h); > + gcc_assert (map->m_entries == obj); > + for (size_t i = 0; i < map->m_size; i++) > + { > + typedef hash_table 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 > +static void > +gt_pch_nx (hash_table *h) > +{ > + gcc_assert (gt_pch_note_object (h->m_entries, h, > + hashtab_entry_note_pointers)); > + for (size_t i = 0; i < h->m_size; i++) > + { > + if (hash_table::is_empty (h->m_entries[i]) > + || hash_table::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 (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::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 (); > - *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 *visited) > { > - struct throw_stmt_node *node = (struct throw_stmt_node *)*slot; > - hash_set *visited = (hash_set *) 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 *eh_table = get_eh_throw_stmt_table (cfun); > + if (eh_table) > + eh_table->traverse *, 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 (); > - 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::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 >