On Fri, Jun 20, 2014 at 08:41:22AM +0200, Jan Hubicka wrote:
> Hi,
> this patch moves init and fini priorities to symbol table instead of trees.
> They are already in on-side hashtables, but the hashtables are now maintaned
> by symbol table. This is needed for correctness with LTO.
>
> Currently tree merging may load declaration with priority and then ggc_free
> it creating a stale entry in the hashtable. This is usually not problem,
> because
> ctor declarations are usually static, but it is not safe.
>
> I would really like to have template for such a sparse annotations to symbols
> (writting our old school pch friendly hashtable is not a fun) but I am not
> sure
> I can get it done in GGC/PCH safe way. Is user marking working for PCH?
hm, so thinking about this a little more I wonder if you can just use
hash_table, and add a dtor to symtab_node that removes its entry from
the hash table. ggc should invoke your dtor as a finalizer for the node
then.
Trev
>
> Bootstrapped/regtested x86_64-linux, will commit it shortly.
>
> Honza
>
> * cgraph.h (struct symtab_node): Add field in_init_priority_hash
> (set_init_priority, get_init_priority, set_fini_priority,
> get_fini_priority): New methods.
> * tree.c (init_priority_for_decl): Remove.
> (init_ttree): Do not initialize init priority.
> (decl_init_priority_lookup, decl_fini_priority_lookup): Rewrite.
> (decl_priority_info): Remove.
> (decl_init_priority_insert): Rewrite.
> (decl_fini_priority_insert): Rewrite.
> * tree.h (tree_priority_map_eq, tree_priority_map_hash,
> tree_priority_map_marked_p): Remove.
> * lto-cgraph.c (lto_output_node, input_node): Stream init priorities.
> * lto-streamer-out.c (hash_tree): Do not hash priorities.
> * tree-streamer-out.c (pack_ts_decl_with_vis_value_fields): Do
> not output priorities.
> (pack_ts_function_decl_value_fields): Likewise.
> * tree-streamer-in.c (unpack_ts_decl_with_vis_value_fields): Do
> not input priorities.
> (unpack_ts_function_decl_value_fields): Likewise.
> * symtab.c (symbol_priority_map): Declare.
> (init_priority_hash): Declare.
> (symtab_unregister_node): Unregister from priority hash, too.
> (symtab_node::get_init_priority, cgraph_node::get_fini_priority):
> New methods.
> (symbol_priority_map_eq, symbol_priority_map_hash): New functions.
> (symbol_priority_info): New function.
> (symtab_node::set_init_priority, cgraph_node::set_fini_priority):
> New methods.
> * tree-core.h (tree_priority_map): Remove.
>
> * lto.c (compare_tree_sccs_1): Do not compare priorities.
> Index: cgraph.h
> ===================================================================
> --- cgraph.h (revision 211831)
> +++ cgraph.h (working copy)
> @@ -130,6 +130,8 @@ public:
>
> /* Set when symbol has address taken. */
> unsigned address_taken : 1;
> + /* Set when init priority is set. */
> + unsigned in_init_priority_hash : 1;
>
>
> /* Ordering of all symtab entries. */
> @@ -163,6 +165,7 @@ public:
> return x_comdat_group;
> }
>
> + /* Return comdat group as identifier_node. */
> tree get_comdat_group_id ()
> {
> if (x_comdat_group && TREE_CODE (x_comdat_group) != IDENTIFIER_NODE)
> @@ -208,6 +211,9 @@ public:
> /* Set section for symbol and its aliases. */
> void set_section (const char *section);
> void set_section_for_node (const char *section);
> +
> + void set_init_priority (priority_type priority);
> + priority_type get_init_priority ();
> };
>
> enum availability
> @@ -497,6 +503,9 @@ public:
> /* True if this decl calls a COMDAT-local function. This is set up in
> compute_inline_parameters and inline_call. */
> unsigned calls_comdat_local : 1;
> +
> + void set_fini_priority (priority_type priority);
> + priority_type get_fini_priority ();
> };
>
>
> Index: tree.c
> ===================================================================
> --- tree.c (revision 211831)
> +++ tree.c (working copy)
> @@ -219,10 +219,6 @@ static GTY ((if_marked ("tree_decl_map_m
> static GTY ((if_marked ("tree_vec_map_marked_p"), param_is (struct
> tree_vec_map)))
> htab_t debug_args_for_decl;
>
> -static GTY ((if_marked ("tree_priority_map_marked_p"),
> - param_is (struct tree_priority_map)))
> - htab_t init_priority_for_decl;
> -
> static void set_type_quals (tree, int);
> static int type_hash_eq (const void *, const void *);
> static hashval_t type_hash_hash (const void *);
> @@ -573,8 +569,6 @@ init_ttree (void)
>
> value_expr_for_decl = htab_create_ggc (512, tree_decl_map_hash,
> tree_decl_map_eq, 0);
> - init_priority_for_decl = htab_create_ggc (512, tree_priority_map_hash,
> - tree_priority_map_eq, 0);
>
> int_cst_hash_table = htab_create_ggc (1024, int_cst_hash_hash,
> int_cst_hash_eq, NULL);
> @@ -6492,13 +6486,12 @@ tree_decl_map_hash (const void *item)
> priority_type
> decl_init_priority_lookup (tree decl)
> {
> - struct tree_priority_map *h;
> - struct tree_map_base in;
> + symtab_node *snode = symtab_get_node (decl);
>
> - gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
> - in.from = decl;
> - h = (struct tree_priority_map *) htab_find (init_priority_for_decl, &in);
> - return h ? h->init : DEFAULT_INIT_PRIORITY;
> + if (!snode)
> + return DEFAULT_INIT_PRIORITY;
> + return
> + snode->get_init_priority ();
> }
>
> /* Return the finalization priority for DECL. */
> @@ -6506,39 +6499,12 @@ decl_init_priority_lookup (tree decl)
> priority_type
> decl_fini_priority_lookup (tree decl)
> {
> - struct tree_priority_map *h;
> - struct tree_map_base in;
> -
> - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
> - in.from = decl;
> - h = (struct tree_priority_map *) htab_find (init_priority_for_decl, &in);
> - return h ? h->fini : DEFAULT_INIT_PRIORITY;
> -}
> -
> -/* Return the initialization and finalization priority information for
> - DECL. If there is no previous priority information, a freshly
> - allocated structure is returned. */
> -
> -static struct tree_priority_map *
> -decl_priority_info (tree decl)
> -{
> - struct tree_priority_map in;
> - struct tree_priority_map *h;
> - void **loc;
> -
> - in.base.from = decl;
> - loc = htab_find_slot (init_priority_for_decl, &in, INSERT);
> - h = (struct tree_priority_map *) *loc;
> - if (!h)
> - {
> - h = ggc_cleared_alloc<tree_priority_map> ();
> - *loc = h;
> - h->base.from = decl;
> - h->init = DEFAULT_INIT_PRIORITY;
> - h->fini = DEFAULT_INIT_PRIORITY;
> - }
> + cgraph_node *node = cgraph_get_node (decl);
>
> - return h;
> + if (!node)
> + return DEFAULT_INIT_PRIORITY;
> + return
> + node->get_fini_priority ();
> }
>
> /* Set the initialization priority for DECL to PRIORITY. */
> @@ -6546,13 +6512,19 @@ decl_priority_info (tree decl)
> void
> decl_init_priority_insert (tree decl, priority_type priority)
> {
> - struct tree_priority_map *h;
> + struct symtab_node *snode;
>
> - gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
> if (priority == DEFAULT_INIT_PRIORITY)
> - return;
> - h = decl_priority_info (decl);
> - h->init = priority;
> + {
> + snode = symtab_get_node (decl);
> + if (!snode)
> + return;
> + }
> + else if (TREE_CODE (decl) == VAR_DECL)
> + snode = varpool_node_for_decl (decl);
> + else
> + snode = cgraph_get_create_node (decl);
> + snode->set_init_priority (priority);
> }
>
> /* Set the finalization priority for DECL to PRIORITY. */
> @@ -6560,13 +6532,17 @@ decl_init_priority_insert (tree decl, pr
> void
> decl_fini_priority_insert (tree decl, priority_type priority)
> {
> - struct tree_priority_map *h;
> + struct cgraph_node *node;
>
> - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
> if (priority == DEFAULT_INIT_PRIORITY)
> - return;
> - h = decl_priority_info (decl);
> - h->fini = priority;
> + {
> + node = cgraph_get_node (decl);
> + if (!node)
> + return;
> + }
> + else
> + node = cgraph_get_create_node (decl);
> + node->set_fini_priority (priority);
> }
>
> /* Print out the statistics for the DECL_DEBUG_EXPR hash table. */
> Index: tree.h
> ===================================================================
> --- tree.h (revision 211831)
> +++ tree.h (working copy)
> @@ -4345,10 +4345,6 @@ extern unsigned int tree_decl_map_hash (
> #define tree_int_map_hash tree_map_base_hash
> #define tree_int_map_marked_p tree_map_base_marked_p
>
> -#define tree_priority_map_eq tree_map_base_eq
> -#define tree_priority_map_hash tree_map_base_hash
> -#define tree_priority_map_marked_p tree_map_base_marked_p
> -
> #define tree_vec_map_eq tree_map_base_eq
> #define tree_vec_map_hash tree_decl_map_hash
> #define tree_vec_map_marked_p tree_map_base_marked_p
> Index: lto-cgraph.c
> ===================================================================
> --- lto-cgraph.c (revision 211831)
> +++ lto-cgraph.c (working copy)
> @@ -557,6 +557,10 @@ lto_output_node (struct lto_simple_outpu
> streamer_write_uhwi_stream (ob->main_stream,
> node->thunk.virtual_value);
> }
> streamer_write_hwi_stream (ob->main_stream, node->profile_id);
> + if (DECL_STATIC_CONSTRUCTOR (node->decl))
> + streamer_write_hwi_stream (ob->main_stream, DECL_INIT_PRIORITY
> (node->decl));
> + if (DECL_STATIC_DESTRUCTOR (node->decl))
> + streamer_write_hwi_stream (ob->main_stream, DECL_FINI_PRIORITY
> (node->decl));
> }
>
> /* Output the varpool NODE to OB.
> @@ -1210,6 +1214,10 @@ input_node (struct lto_file_decl_data *f
> if (node->alias && !node->analyzed && node->weakref)
> node->alias_target = get_alias_symbol (node->decl);
> node->profile_id = streamer_read_hwi (ib);
> + if (DECL_STATIC_CONSTRUCTOR (node->decl))
> + SET_DECL_INIT_PRIORITY (node->decl, streamer_read_hwi (ib));
> + if (DECL_STATIC_DESTRUCTOR (node->decl))
> + SET_DECL_FINI_PRIORITY (node->decl, streamer_read_hwi (ib));
> return node;
> }
>
> Index: lto-streamer-out.c
> ===================================================================
> --- lto-streamer-out.c (revision 211831)
> +++ lto-streamer-out.c (working copy)
> @@ -827,8 +827,6 @@ hash_tree (struct streamer_tree_cache_d
> | (DECL_CXX_CONSTRUCTOR_P (t) << 1)
> | (DECL_CXX_DESTRUCTOR_P (t) << 2),
> v);
> - if (VAR_OR_FUNCTION_DECL_P (t))
> - v = iterative_hash_host_wide_int (DECL_INIT_PRIORITY (t), v);
> }
>
> if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> @@ -852,8 +850,6 @@ hash_tree (struct streamer_tree_cache_d
> | (DECL_LOOPING_CONST_OR_PURE_P (t) <<
> 15), v);
> if (DECL_BUILT_IN_CLASS (t) != NOT_BUILT_IN)
> v = iterative_hash_host_wide_int (DECL_FUNCTION_CODE (t), v);
> - if (DECL_STATIC_DESTRUCTOR (t))
> - v = iterative_hash_host_wide_int (DECL_FINI_PRIORITY (t), v);
> }
>
> if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c (revision 211831)
> +++ lto/lto.c (working copy)
> @@ -1300,8 +1300,6 @@ compare_tree_sccs_1 (tree t1, tree t2, t
> /* DECL_IN_TEXT_SECTION is set during final asm output only. */
> compare_values (DECL_IN_CONSTANT_POOL);
> }
> - if (VAR_OR_FUNCTION_DECL_P (t1))
> - compare_values (DECL_INIT_PRIORITY);
> }
>
> if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> @@ -1328,8 +1326,6 @@ compare_tree_sccs_1 (tree t1, tree t2, t
> compare_values (DECL_CXX_DESTRUCTOR_P);
> if (DECL_BUILT_IN_CLASS (t1) != NOT_BUILT_IN)
> compare_values (DECL_FUNCTION_CODE);
> - if (DECL_STATIC_DESTRUCTOR (t1))
> - compare_values (DECL_FINI_PRIORITY);
> }
>
> if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> Index: tree-streamer-out.c
> ===================================================================
> --- tree-streamer-out.c (revision 211831)
> +++ tree-streamer-out.c (working copy)
> @@ -256,8 +256,6 @@ pack_ts_decl_with_vis_value_fields (stru
> bp_pack_value (bp, DECL_CXX_CONSTRUCTOR_P (expr), 1);
> bp_pack_value (bp, DECL_CXX_DESTRUCTOR_P (expr), 1);
> }
> - if (VAR_OR_FUNCTION_DECL_P (expr))
> - bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
> }
>
>
> @@ -291,8 +289,6 @@ pack_ts_function_decl_value_fields (stru
> bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
> if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
> bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
> - if (DECL_STATIC_DESTRUCTOR (expr))
> - bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
> }
>
>
> Index: tree-streamer-in.c
> ===================================================================
> --- tree-streamer-in.c (revision 211831)
> +++ tree-streamer-in.c (working copy)
> @@ -288,12 +288,6 @@ unpack_ts_decl_with_vis_value_fields (st
> DECL_CXX_CONSTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> DECL_CXX_DESTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> }
> - if (VAR_OR_FUNCTION_DECL_P (expr))
> - {
> - priority_type p;
> - p = (priority_type) bp_unpack_var_len_unsigned (bp);
> - SET_DECL_INIT_PRIORITY (expr, p);
> - }
> }
>
>
> @@ -336,12 +330,6 @@ unpack_ts_function_decl_value_fields (st
> fatal_error ("target specific builtin not available");
> }
> }
> - if (DECL_STATIC_DESTRUCTOR (expr))
> - {
> - priority_type p;
> - p = (priority_type) bp_unpack_var_len_unsigned (bp);
> - SET_DECL_FINI_PRIORITY (expr, p);
> - }
> }
>
>
> Index: symtab.c
> ===================================================================
> --- symtab.c (revision 211831)
> +++ symtab.c (working copy)
> @@ -64,6 +64,17 @@ static GTY((param_is (section_hash_entry
> /* Hash table used to convert assembler names into nodes. */
> static GTY((param_is (symtab_node))) htab_t assembler_name_hash;
>
> +/* Map from a symbol to initialization/finalization priorities. */
> +struct GTY(()) symbol_priority_map {
> + symtab_node *symbol;
> + priority_type init;
> + priority_type fini;
> +};
> +
> +/* Hash table used to hold init priorities. */
> +static GTY ((param_is (struct symbol_priority_map)))
> + htab_t init_priority_hash;
> +
> /* Linked list of symbol table nodes. */
> symtab_node *symtab_nodes;
>
> @@ -337,6 +348,16 @@ symtab_unregister_node (symtab_node *nod
> }
> if (!is_a <varpool_node *> (node) || !DECL_HARD_REGISTER (node->decl))
> unlink_from_assembler_name_hash (node, false);
> + if (node->in_init_priority_hash)
> + {
> + struct symbol_priority_map in;
> + void **slot;
> + in.symbol = node;
> +
> + slot = htab_find_slot (init_priority_hash, &in, NO_INSERT);
> + if (slot)
> + htab_clear_slot (init_priority_hash, slot);
> + }
> }
>
>
> @@ -1176,6 +1197,122 @@ symtab_node::set_section (const char *se
> symtab_for_node_and_aliases (this, set_section_1, const_cast<char
> *>(section), true);
> }
>
> +/* Return the initialization priority. */
> +
> +priority_type
> +symtab_node::get_init_priority ()
> +{
> + struct symbol_priority_map *h;
> + struct symbol_priority_map in;
> +
> + if (!this->in_init_priority_hash)
> + return DEFAULT_INIT_PRIORITY;
> + in.symbol = this;
> + h = (struct symbol_priority_map *) htab_find (init_priority_hash, &in);
> + return h ? h->init : DEFAULT_INIT_PRIORITY;
> +}
> +
> +/* Return the finalization priority. */
> +
> +priority_type
> +cgraph_node::get_fini_priority ()
> +{
> + struct symbol_priority_map *h;
> + struct symbol_priority_map in;
> +
> + if (!this->in_init_priority_hash)
> + return DEFAULT_INIT_PRIORITY;
> + in.symbol = this;
> + h = (struct symbol_priority_map *) htab_find (init_priority_hash, &in);
> + 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 struct symbol_priority_map *const a = (const struct
> symbol_priority_map *) va,
> + *const b = (const struct 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 struct 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. */
> +
> +static struct symbol_priority_map *
> +symbol_priority_info (struct symtab_node *symbol)
> +{
> + struct symbol_priority_map in;
> + struct symbol_priority_map *h;
> + void **loc;
> +
> + in.symbol = symbol;
> + if (!init_priority_hash)
> + init_priority_hash = htab_create_ggc (512, symbol_priority_map_hash,
> + symbol_priority_map_eq, 0);
> +
> + loc = htab_find_slot (init_priority_hash, &in, INSERT);
> + h = (struct symbol_priority_map *) *loc;
> + if (!h)
> + {
> + h = ggc_cleared_alloc<symbol_priority_map> ();
> + *loc = h;
> + h->symbol = symbol;
> + h->init = DEFAULT_INIT_PRIORITY;
> + h->fini = DEFAULT_INIT_PRIORITY;
> + symbol->in_init_priority_hash = true;
> + }
> +
> + return h;
> +}
> +
> +/* Set initialization priority to PRIORITY. */
> +
> +void
> +symtab_node::set_init_priority (priority_type priority)
> +{
> + struct symbol_priority_map *h;
> +
> + if (is_a <cgraph_node *> (this))
> + gcc_assert (DECL_STATIC_CONSTRUCTOR (this->decl));
> +
> + if (priority == DEFAULT_INIT_PRIORITY)
> + {
> + gcc_assert (get_init_priority() == priority);
> + return;
> + }
> + h = symbol_priority_info (this);
> + h->init = priority;
> +}
> +
> +/* Set fialization priority to PRIORITY. */
> +
> +void
> +cgraph_node::set_fini_priority (priority_type priority)
> +{
> + struct symbol_priority_map *h;
> +
> + gcc_assert (DECL_STATIC_DESTRUCTOR (this->decl));
> +
> + if (priority == DEFAULT_INIT_PRIORITY)
> + {
> + gcc_assert (get_fini_priority() == priority);
> + return;
> + }
> + h = symbol_priority_info (this);
> + h->fini = priority;
> +}
> +
> /* Worker for symtab_resolve_alias. */
>
> static bool
> Index: tree-core.h
> ===================================================================
> --- tree-core.h (revision 211831)
> +++ tree-core.h (working copy)
> @@ -1761,13 +1761,6 @@ struct GTY(()) tree_int_map {
> unsigned int to;
> };
>
> -/* Map from a tree to initialization/finalization priorities. */
> -struct GTY(()) tree_priority_map {
> - struct tree_map_base base;
> - priority_type init;
> - priority_type fini;
> -};
> -
> /* Map from a decl tree to a tree vector. */
> struct GTY(()) tree_vec_map {
> struct tree_map_base base;