Fix memory allocations in ipa-modref.

Pair ggc_delete with ggc_alloc_no_dtor.  I copy same scheme as used by Martin
in ipa-fnsummary, that is creating a static member function create_ggc hidding
the ugly bits and using it in ipa-modref.c.

I also noticed that modref-tree leaks memory on destruction/collapse method and
fixed that.

Bootstrapped/regtested x86_64-linux.

gcc/ChangeLog:

2020-09-24  Jan Hubicka  <hubicka@ucw.cz>

	* ipa-modref-tree.h (modref_base::collapse): Release memory.
	(modref_tree::create_ggc): New member function.
	(modref_tree::colapse): Release memory.
	(modref_tree::~modref_tree): New destructor.
	* ipa-modref.c (modref_summaries::create_ggc): New function.
	(analyze_function): Use create_ggc.
	(modref_summaries::duplicate): Likewise.
	(read_modref_records): Likewise.
	(modref_read): Likewise.
This commit is contained in:
Jan Hubicka 2020-09-24 08:28:09 +02:00
parent 2d5fb576bd
commit c9da53d698
2 changed files with 65 additions and 42 deletions

View file

@ -95,7 +95,15 @@ struct GTY((user)) modref_base_node
void collapse ()
{
size_t i;
modref_ref_node <T> *r;
if (refs)
{
FOR_EACH_VEC_SAFE_ELT (refs, i, r)
ggc_free (r);
vec_free (refs);
}
refs = NULL;
every_ref = true;
}
@ -214,12 +222,36 @@ struct GTY((user)) modref_tree
return NULL;
}
/* Return ggc allocated instance. We explicitly call destructors via
ggc_delete and do not want finalizers to be registered and
called at the garbage collection time. */
static modref_tree<T> *create_ggc (size_t max_bases, size_t max_refs)
{
return new (ggc_alloc_no_dtor<modref_tree<T>> ())
modref_tree<T> (max_bases, max_refs);
}
void collapse ()
{
size_t i;
modref_base_node <T> *n;
if (bases)
{
FOR_EACH_VEC_SAFE_ELT (bases, i, n)
{
n->collapse ();
ggc_free (n);
}
vec_free (bases);
}
bases = NULL;
every_base = true;
}
~modref_tree ()
{
collapse ();
}
};
void modref_c_tests ();

View file

@ -84,6 +84,11 @@ public:
ipa-modref pass execution needs to be analyzed in IPA mode while all
other insertions leads to normal analysis. */
bool ipa;
static modref_summaries *create_ggc (symbol_table *symtab)
{
return new (ggc_alloc_no_dtor<modref_summaries> ())
modref_summaries (symtab);
}
};
/* Global variable holding all modref summaries. */
@ -608,8 +613,7 @@ analyze_function (function *f, bool ipa)
/* Initialize the summary. */
if (!summaries)
summaries = new (ggc_alloc <modref_summaries> ())
modref_summaries (symtab);
summaries = modref_summaries::create_ggc (symtab);
else /* Remove existing summary if we are re-running the pass. */
summaries->remove (cgraph_node::get (f->decl));
@ -633,27 +637,21 @@ analyze_function (function *f, bool ipa)
if (nolto)
{
gcc_assert (!summary->loads);
summary->loads
= new (ggc_alloc <modref_tree<alias_set_type> > ())
modref_records (param_modref_max_bases,
summary->loads = modref_records::create_ggc (param_modref_max_bases,
param_modref_max_refs);
gcc_assert (!summary->stores);
summary->stores
= new (ggc_alloc <modref_tree<alias_set_type> > ())
modref_records (param_modref_max_bases,
summary->stores = modref_records::create_ggc (param_modref_max_bases,
param_modref_max_refs);
}
if (lto)
{
gcc_assert (!summary->loads_lto);
summary->loads_lto
= new (ggc_alloc <modref_tree<tree> > ())
modref_records_lto (param_modref_max_bases,
summary->loads_lto = modref_records_lto::create_ggc
(param_modref_max_bases,
param_modref_max_refs);
gcc_assert (!summary->stores_lto);
summary->stores_lto
= new (ggc_alloc <modref_tree<tree> > ())
modref_records_lto (param_modref_max_bases,
summary->stores_lto = modref_records_lto::create_ggc
(param_modref_max_bases,
param_modref_max_refs);
}
summary->finished = false;
@ -730,34 +728,30 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *,
dst_data->finished = src_data->finished;
if (src_data->stores)
{
dst_data->stores = new (ggc_alloc <modref_tree<alias_set_type> > ())
modref_records
dst_data->stores = modref_records::create_ggc
(src_data->stores->max_bases,
src_data->stores->max_refs);
dst_data->stores->merge (src_data->stores);
}
if (src_data->loads)
{
dst_data->loads = new (ggc_alloc <modref_tree<alias_set_type> > ())
modref_records
dst_data->loads = modref_records::create_ggc
(src_data->loads->max_bases,
src_data->loads->max_refs);
dst_data->loads->merge (src_data->loads);
}
if (src_data->stores_lto)
{
dst_data->stores_lto = new (ggc_alloc <modref_tree<tree> > ())
modref_records_lto
dst_data->stores_lto = modref_records_lto::create_ggc
(src_data->stores_lto->max_bases,
src_data->stores_lto->max_refs);
dst_data->stores_lto->merge (src_data->stores_lto);
}
if (src_data->loads_lto)
{
dst_data->loads_lto = new (ggc_alloc <modref_tree<tree> > ())
modref_records_lto
(src_data->stores_lto->max_bases,
src_data->stores_lto->max_refs);
dst_data->loads_lto = modref_records_lto::create_ggc
(src_data->loads_lto->max_bases,
src_data->loads_lto->max_refs);
dst_data->loads_lto->merge (src_data->loads_lto);
}
}
@ -838,11 +832,9 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in,
/* Decide whether we want to turn LTO data types to non-LTO (i.e. when
LTO re-streaming is not going to happen). */
if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
*lto_ret = new (ggc_alloc <modref_records_lto> ()) modref_records_lto
(max_bases, max_refs);
*lto_ret = modref_records_lto::create_ggc (max_bases, max_refs);
else
*nolto_ret = new (ggc_alloc <modref_records> ()) modref_records
(max_bases, max_refs);
*nolto_ret = modref_records::create_ggc (max_bases, max_refs);
size_t every_base = streamer_read_uhwi (ib);
size_t nbase = streamer_read_uhwi (ib);
@ -1048,8 +1040,7 @@ modref_read (void)
unsigned int j = 0;
if (!summaries)
summaries = new (ggc_alloc <modref_summaries> ())
modref_summaries (symtab);
summaries = modref_summaries::create_ggc (symtab);
((modref_summaries *)summaries)->ipa = true;
while ((file_data = file_data_vec[j++]))