1/* Callgraph summary data structure.
2   Copyright (C) 2014-2020 Free Software Foundation, Inc.
3   Contributed by Martin Liska
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#ifndef GCC_SYMBOL_SUMMARY_H
22#define GCC_SYMBOL_SUMMARY_H
23
24/* Base class for function_summary and fast_function_summary classes.  */
25
26template <class T>
27class function_summary_base
28{
29public:
30  /* Default construction takes SYMTAB as an argument.  */
31  function_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO):
32  m_symtab (symtab),
33  m_insertion_enabled (true),
34  m_allocator ("function summary" PASS_MEM_STAT)
35  {}
36
37  /* Basic implementation of insert operation.  */
38  virtual void insert (cgraph_node *, T *) {}
39
40  /* Basic implementation of removal operation.  */
41  virtual void remove (cgraph_node *, T *) {}
42
43  /* Basic implementation of duplication operation.  */
44  virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
45
46  /* Enable insertion hook invocation.  */
47  void enable_insertion_hook ()
48  {
49    m_insertion_enabled = true;
50  }
51
52  /* Enable insertion hook invocation.  */
53  void disable_insertion_hook ()
54  {
55    m_insertion_enabled = false;
56  }
57
58protected:
59  /* Allocates new data that are stored within map.  */
60  T* allocate_new ()
61  {
62    /* Call gcc_internal_because we do not want to call finalizer for
63       a type T.  We call dtor explicitly.  */
64    return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
65		     : m_allocator.allocate () ;
66  }
67
68  /* Release an item that is stored within map.  */
69  void release (T *item)
70  {
71    if (is_ggc ())
72      ggc_delete (item);
73    else
74      m_allocator.remove (item);
75  }
76
77  /* Unregister all call-graph hooks.  */
78  void unregister_hooks ();
79
80  /* Internal summary insertion hook pointer.  */
81  cgraph_node_hook_list *m_symtab_insertion_hook;
82  /* Internal summary removal hook pointer.  */
83  cgraph_node_hook_list *m_symtab_removal_hook;
84  /* Internal summary duplication hook pointer.  */
85  cgraph_2node_hook_list *m_symtab_duplication_hook;
86  /* Symbol table the summary is registered to.  */
87  symbol_table *m_symtab;
88
89  /* Indicates if insertion hook is enabled.  */
90  bool m_insertion_enabled;
91
92private:
93  /* Return true when the summary uses GGC memory for allocation.  */
94  virtual bool is_ggc () = 0;
95
96  /* Object allocator for heap allocation.  */
97  object_allocator<T> m_allocator;
98};
99
100template <typename T>
101void
102function_summary_base<T>::unregister_hooks ()
103{
104  m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
105  m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
106  m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
107}
108
109/* We want to pass just pointer types as argument for function_summary
110   template class.  */
111
112template <class T>
113class function_summary
114{
115private:
116  function_summary();
117};
118
119/* Function summary is a helper class that is used to associate a data structure
120   related to a callgraph node.  Typical usage can be seen in IPA passes which
121   create a temporary pass-related structures.  The summary class registers
122   hooks that are triggered when a new node is inserted, duplicated and deleted.
123   A user of a summary class can ovewrite virtual methods than are triggered by
124   the summary if such hook is triggered.  Apart from a callgraph node, the user
125   is given a data structure tied to the node.
126
127   The function summary class can work both with a heap-allocated memory and
128   a memory gained by garbage collected memory.  */
129
130template <class T>
131class GTY((user)) function_summary <T *>: public function_summary_base<T>
132{
133public:
134  /* Default construction takes SYMTAB as an argument.  */
135  function_summary (symbol_table *symtab, bool ggc = false CXX_MEM_STAT_INFO);
136
137  /* Destructor.  */
138  virtual ~function_summary ();
139
140  /* Traverses all summarys with a function F called with
141     ARG as argument.  */
142  template<typename Arg, bool (*f)(const T &, Arg)>
143  void traverse (Arg a) const
144  {
145    m_map.template traverse <f> (a);
146  }
147
148  /* Getter for summary callgraph node pointer.  If a summary for a node
149     does not exist it will be created.  */
150  T* get_create (cgraph_node *node)
151  {
152    bool existed;
153    T **v = &m_map.get_or_insert (node->get_uid (), &existed);
154    if (!existed)
155      *v = this->allocate_new ();
156
157    return *v;
158  }
159
160  /* Getter for summary callgraph node pointer.  */
161  T* get (cgraph_node *node) ATTRIBUTE_PURE
162  {
163    T **v = m_map.get (node->get_uid ());
164    return v == NULL ? NULL : *v;
165  }
166
167  /* Remove node from summary.  */
168  using function_summary_base<T>::remove;
169  void remove (cgraph_node *node)
170  {
171    int uid = node->get_uid ();
172    T **v = m_map.get (uid);
173    if (v)
174      {
175	m_map.remove (uid);
176	this->release (*v);
177      }
178  }
179
180  /* Return true if a summary for the given NODE already exists.  */
181  bool exists (cgraph_node *node)
182  {
183    return m_map.get (node->get_uid ()) != NULL;
184  }
185
186  /* Symbol insertion hook that is registered to symbol table.  */
187  static void symtab_insertion (cgraph_node *node, void *data);
188
189  /* Symbol removal hook that is registered to symbol table.  */
190  static void symtab_removal (cgraph_node *node, void *data);
191
192  /* Symbol duplication hook that is registered to symbol table.  */
193  static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
194				  void *data);
195
196protected:
197  /* Indication if we use ggc summary.  */
198  bool m_ggc;
199
200private:
201  /* Indication if we use ggc summary.  */
202  virtual bool is_ggc ()
203  {
204    return m_ggc;
205  }
206
207  typedef int_hash <int, 0, -1> map_hash;
208
209  /* Main summary store, where summary ID is used as key.  */
210  hash_map <map_hash, T *> m_map;
211
212  template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
213  template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
214  template <typename U> friend void gt_pch_nx (function_summary <U *> * const &,
215      gt_pointer_operator, void *);
216};
217
218template <typename T>
219function_summary<T *>::function_summary (symbol_table *symtab, bool ggc
220					 MEM_STAT_DECL):
221  function_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc),
222  m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT)
223{
224  this->m_symtab_insertion_hook
225    = this->m_symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
226						 this);
227  this->m_symtab_removal_hook
228    = this->m_symtab->add_cgraph_removal_hook (function_summary::symtab_removal,
229					       this);
230  this->m_symtab_duplication_hook
231    = this->m_symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
232						   this);
233}
234
235template <typename T>
236function_summary<T *>::~function_summary ()
237{
238  this->unregister_hooks ();
239
240  /* Release all summaries.  */
241  typedef typename hash_map <map_hash, T *>::iterator map_iterator;
242  for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
243    this->release ((*it).second);
244}
245
246template <typename T>
247void
248function_summary<T *>::symtab_insertion (cgraph_node *node, void *data)
249{
250  gcc_checking_assert (node->get_uid ());
251  function_summary *summary = (function_summary <T *> *) (data);
252
253  if (summary->m_insertion_enabled)
254    summary->insert (node, summary->get_create (node));
255}
256
257template <typename T>
258void
259function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
260{
261  gcc_checking_assert (node->get_uid ());
262  function_summary *summary = (function_summary <T *> *) (data);
263  summary->remove (node);
264}
265
266template <typename T>
267void
268function_summary<T *>::symtab_duplication (cgraph_node *node,
269					   cgraph_node *node2, void *data)
270{
271  function_summary *summary = (function_summary <T *> *) (data);
272  T *v = summary->get (node);
273
274  if (v)
275    summary->duplicate (node, node2, v, summary->get_create (node2));
276}
277
278template <typename T>
279void
280gt_ggc_mx(function_summary<T *>* const &summary)
281{
282  gcc_checking_assert (summary->m_ggc);
283  gt_ggc_mx (&summary->m_map);
284}
285
286template <typename T>
287void
288gt_pch_nx (function_summary<T *> *const &)
289{
290  gcc_unreachable ();
291}
292
293template <typename T>
294void
295gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *)
296{
297  gcc_unreachable ();
298}
299
300/* Help template from std c++11.  */
301
302template<typename T, typename U>
303struct is_same
304{
305    static const bool value = false;
306};
307
308template<typename T>
309struct is_same<T,T>  //specialization
310{
311   static const bool value = true;
312};
313
314/* We want to pass just pointer types as argument for fast_function_summary
315   template class.  */
316
317template <class T, class V>
318class fast_function_summary
319{
320private:
321  fast_function_summary ();
322};
323
324/* Function vector summary is a fast implementation of function_summary that
325   utilizes vector as primary storage of summaries.  */
326
327template <class T, class V>
328class GTY((user)) fast_function_summary <T *, V>
329  : public function_summary_base<T>
330{
331public:
332  /* Default construction takes SYMTAB as an argument.  */
333  fast_function_summary (symbol_table *symtab CXX_MEM_STAT_INFO);
334
335  /* Destructor.  */
336  virtual ~fast_function_summary ();
337
338  /* Traverses all summarys with a function F called with
339     ARG as argument.  */
340  template<typename Arg, bool (*f)(const T &, Arg)>
341  void traverse (Arg a) const
342  {
343    for (unsigned i = 0; i < m_vector->length (); i++)
344      if ((*m_vector[i]) != NULL)
345	f ((*m_vector)[i], a);
346  }
347
348  /* Getter for summary callgraph node pointer.  If a summary for a node
349     does not exist it will be created.  */
350  T* get_create (cgraph_node *node)
351  {
352    int id = node->get_summary_id ();
353    if (id == -1)
354      id = this->m_symtab->assign_summary_id (node);
355
356    if ((unsigned int)id >= m_vector->length ())
357      {
358	int newlen = this->m_symtab->cgraph_max_summary_id;
359	vec_safe_reserve (m_vector, newlen - m_vector->length ());
360	m_vector->quick_grow_cleared (newlen);
361      }
362
363    if ((*m_vector)[id] == NULL)
364      (*m_vector)[id] = this->allocate_new ();
365
366    return (*m_vector)[id];
367  }
368
369  /* Getter for summary callgraph node pointer.  */
370  T* get (cgraph_node *node) ATTRIBUTE_PURE
371  {
372    return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
373  }
374
375  using function_summary_base<T>::remove;
376  void remove (cgraph_node *node)
377  {
378    if (exists (node))
379      {
380	int id = node->get_summary_id ();
381	this->release ((*m_vector)[id]);
382	(*m_vector)[id] = NULL;
383      }
384  }
385
386  /* Return true if a summary for the given NODE already exists.  */
387  bool exists (cgraph_node *node)
388  {
389    int id = node->get_summary_id ();
390    return (id != -1
391	    && (unsigned int)id < m_vector->length ()
392	    && (*m_vector)[id] != NULL);
393  }
394
395  /* Symbol insertion hook that is registered to symbol table.  */
396  static void symtab_insertion (cgraph_node *node, void *data);
397
398  /* Symbol removal hook that is registered to symbol table.  */
399  static void symtab_removal (cgraph_node *node, void *data);
400
401  /* Symbol duplication hook that is registered to symbol table.  */
402  static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
403				  void *data);
404
405private:
406  virtual bool is_ggc ();
407
408  /* Summary is stored in the vector.  */
409  vec <T *, V> *m_vector;
410
411  template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
412  template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
413  template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
414      gt_pointer_operator, void *);
415};
416
417template <typename T, typename V>
418fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab MEM_STAT_DECL):
419  function_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL)
420{
421  vec_alloc (m_vector, 13 PASS_MEM_STAT);
422  this->m_symtab_insertion_hook
423    = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion,
424						 this);
425  this->m_symtab_removal_hook
426    = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal,
427					       this);
428  this->m_symtab_duplication_hook
429    = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication,
430						   this);
431}
432
433template <typename T, typename V>
434fast_function_summary<T *, V>::~fast_function_summary ()
435{
436  this->unregister_hooks ();
437
438  /* Release all summaries.  */
439  for (unsigned i = 0; i < m_vector->length (); i++)
440    if ((*m_vector)[i] != NULL)
441      this->release ((*m_vector)[i]);
442  vec_free (m_vector);
443}
444
445template <typename T, typename V>
446void
447fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
448{
449  gcc_checking_assert (node->get_uid ());
450  fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
451
452  if (summary->m_insertion_enabled)
453    summary->insert (node, summary->get_create (node));
454}
455
456template <typename T, typename V>
457void
458fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
459{
460  gcc_checking_assert (node->get_uid ());
461  fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
462
463  if (summary->exists (node))
464    summary->remove (node);
465}
466
467template <typename T, typename V>
468void
469fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
470						   cgraph_node *node2,
471						   void *data)
472{
473  fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
474  T *v = summary->get (node);
475
476  if (v)
477    {
478      T *duplicate = summary->get_create (node2);
479      summary->duplicate (node, node2, v, duplicate);
480    }
481}
482
483template <typename T, typename V>
484inline bool
485fast_function_summary<T *, V>::is_ggc ()
486{
487  return is_same<V, va_gc>::value;
488}
489
490template <typename T>
491void
492gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
493{
494}
495
496template <typename T>
497void
498gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
499{
500}
501
502template <typename T>
503void
504gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
505	   void *)
506{
507}
508
509template <typename T>
510void
511gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
512{
513  ggc_test_and_set_mark (summary->m_vector);
514  gt_ggc_mx (summary->m_vector);
515}
516
517template <typename T>
518void
519gt_pch_nx (fast_function_summary<T *, va_gc> *const &)
520{
521  gcc_unreachable ();
522}
523
524template <typename T>
525void
526gt_pch_nx (fast_function_summary<T *, va_gc> *const &, gt_pointer_operator,
527	   void *)
528{
529  gcc_unreachable ();
530}
531
532/* Base class for call_summary and fast_call_summary classes.  */
533
534template <class T>
535class call_summary_base
536{
537public:
538  /* Default construction takes SYMTAB as an argument.  */
539  call_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO):
540  m_symtab (symtab),
541  m_initialize_when_cloning (false),
542  m_allocator ("call summary" PASS_MEM_STAT)
543  {}
544
545  /* Basic implementation of removal operation.  */
546  virtual void remove (cgraph_edge *, T *) {}
547
548  /* Basic implementation of duplication operation.  */
549  virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
550
551protected:
552  /* Allocates new data that are stored within map.  */
553  T* allocate_new ()
554  {
555    /* Call gcc_internal_because we do not want to call finalizer for
556       a type T.  We call dtor explicitly.  */
557    return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
558		     : m_allocator.allocate ();
559  }
560
561  /* Release an item that is stored within map.  */
562  void release (T *item)
563  {
564    if (is_ggc ())
565      ggc_delete (item);
566    else
567      m_allocator.remove (item);
568  }
569
570  /* Unregister all call-graph hooks.  */
571  void unregister_hooks ();
572
573  /* Symbol table the summary is registered to.  */
574  symbol_table *m_symtab;
575
576  /* Internal summary removal hook pointer.  */
577  cgraph_edge_hook_list *m_symtab_removal_hook;
578  /* Internal summary duplication hook pointer.  */
579  cgraph_2edge_hook_list *m_symtab_duplication_hook;
580  /* Initialize summary for an edge that is cloned.  */
581  bool m_initialize_when_cloning;
582
583private:
584  /* Return true when the summary uses GGC memory for allocation.  */
585  virtual bool is_ggc () = 0;
586
587  /* Object allocator for heap allocation.  */
588  object_allocator<T> m_allocator;
589};
590
591template <typename T>
592void
593call_summary_base<T>::unregister_hooks ()
594{
595  m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
596  m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
597}
598
599/* An impossible class templated by non-pointers so, which makes sure that only
600   summaries gathering pointers can be created.  */
601
602template <class T>
603class call_summary
604{
605private:
606  call_summary ();
607};
608
609/* Class to store auxiliary information about call graph edges.  */
610
611template <class T>
612class GTY((user)) call_summary <T *>: public call_summary_base<T>
613{
614public:
615  /* Default construction takes SYMTAB as an argument.  */
616  call_summary (symbol_table *symtab, bool ggc = false
617		CXX_MEM_STAT_INFO)
618  : call_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc),
619    m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT)
620  {
621    this->m_symtab_removal_hook
622      = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal,
623					       this);
624    this->m_symtab_duplication_hook
625      = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication,
626						   this);
627  }
628
629  /* Destructor.  */
630  virtual ~call_summary ();
631
632  /* Traverses all summarys with an edge E called with
633     ARG as argument.  */
634  template<typename Arg, bool (*f)(const T &, Arg)>
635  void traverse (Arg a) const
636  {
637    m_map.template traverse <f> (a);
638  }
639
640  /* Getter for summary callgraph edge pointer.
641     If a summary for an edge does not exist, it will be created.  */
642  T* get_create (cgraph_edge *edge)
643  {
644    bool existed;
645    T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
646    if (!existed)
647      *v = this->allocate_new ();
648
649    return *v;
650  }
651
652  /* Getter for summary callgraph edge pointer.  */
653  T* get (cgraph_edge *edge) ATTRIBUTE_PURE
654  {
655    T **v = m_map.get (edge->get_uid ());
656    return v == NULL ? NULL : *v;
657  }
658
659  /* Remove edge from summary.  */
660  using call_summary_base<T>::remove;
661  void remove (cgraph_edge *edge)
662  {
663    int uid = edge->get_uid ();
664    T **v = m_map.get (uid);
665    if (v)
666      {
667	m_map.remove (uid);
668	this->release (*v);
669      }
670  }
671
672  /* Return true if a summary for the given EDGE already exists.  */
673  bool exists (cgraph_edge *edge)
674  {
675    return m_map.get (edge->get_uid ()) != NULL;
676  }
677
678  /* Symbol removal hook that is registered to symbol table.  */
679  static void symtab_removal (cgraph_edge *edge, void *data);
680
681  /* Symbol duplication hook that is registered to symbol table.  */
682  static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
683				  void *data);
684
685protected:
686  /* Indication if we use ggc summary.  */
687  bool m_ggc;
688
689private:
690  /* Indication if we use ggc summary.  */
691  virtual bool is_ggc ()
692  {
693    return m_ggc;
694  }
695
696  typedef int_hash <int, 0, -1> map_hash;
697
698  /* Main summary store, where summary ID is used as key.  */
699  hash_map <map_hash, T *> m_map;
700
701  template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
702  template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
703  template <typename U> friend void gt_pch_nx (call_summary <U *> * const &,
704      gt_pointer_operator, void *);
705};
706
707template <typename T>
708call_summary<T *>::~call_summary ()
709{
710  this->unregister_hooks ();
711
712  /* Release all summaries.  */
713  typedef typename hash_map <map_hash, T *>::iterator map_iterator;
714  for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
715    this->release ((*it).second);
716}
717
718template <typename T>
719void
720call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
721{
722  call_summary *summary = (call_summary <T *> *) (data);
723  summary->remove (edge);
724}
725
726template <typename T>
727void
728call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
729				       cgraph_edge *edge2, void *data)
730{
731  call_summary *summary = (call_summary <T *> *) (data);
732  T *edge1_summary = NULL;
733
734  if (summary->m_initialize_when_cloning)
735    edge1_summary = summary->get_create (edge1);
736  else
737    edge1_summary = summary->get (edge1);
738
739  if (edge1_summary)
740    summary->duplicate (edge1, edge2, edge1_summary,
741			summary->get_create (edge2));
742}
743
744template <typename T>
745void
746gt_ggc_mx(call_summary<T *>* const &summary)
747{
748  gcc_checking_assert (summary->m_ggc);
749  gt_ggc_mx (&summary->m_map);
750}
751
752template <typename T>
753void
754gt_pch_nx (call_summary<T *> *const &)
755{
756  gcc_unreachable ();
757}
758
759template <typename T>
760void
761gt_pch_nx (call_summary<T *> *const &, gt_pointer_operator, void *)
762{
763  gcc_unreachable ();
764}
765
766/* We want to pass just pointer types as argument for fast_call_summary
767   template class.  */
768
769template <class T, class V>
770class fast_call_summary
771{
772private:
773  fast_call_summary ();
774};
775
776/* Call vector summary is a fast implementation of call_summary that
777   utilizes vector as primary storage of summaries.  */
778
779template <class T, class V>
780class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
781{
782public:
783  /* Default construction takes SYMTAB as an argument.  */
784  fast_call_summary (symbol_table *symtab CXX_MEM_STAT_INFO)
785  : call_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL)
786  {
787    vec_alloc (m_vector, 13 PASS_MEM_STAT);
788    this->m_symtab_removal_hook
789      = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal,
790					       this);
791    this->m_symtab_duplication_hook
792      = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication,
793						   this);
794  }
795
796  /* Destructor.  */
797  virtual ~fast_call_summary ();
798
799  /* Traverses all summarys with an edge F called with
800     ARG as argument.  */
801  template<typename Arg, bool (*f)(const T &, Arg)>
802  void traverse (Arg a) const
803  {
804    for (unsigned i = 0; i < m_vector->length (); i++)
805      if ((*m_vector[i]) != NULL)
806	f ((*m_vector)[i], a);
807  }
808
809  /* Getter for summary callgraph edge pointer.
810     If a summary for an edge does not exist, it will be created.  */
811  T* get_create (cgraph_edge *edge)
812  {
813    int id = edge->get_summary_id ();
814    if (id == -1)
815      id = this->m_symtab->assign_summary_id (edge);
816
817    if ((unsigned)id >= m_vector->length ())
818      {
819	int newlen = this->m_symtab->edges_max_summary_id;
820	m_vector->reserve (newlen - m_vector->length ());
821	m_vector->quick_grow_cleared (newlen);
822      }
823
824    if ((*m_vector)[id] == NULL)
825      (*m_vector)[id] = this->allocate_new ();
826
827    return (*m_vector)[id];
828  }
829
830  /* Getter for summary callgraph edge pointer.  */
831  T* get (cgraph_edge *edge) ATTRIBUTE_PURE
832  {
833    return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
834  }
835
836  /* Remove edge from summary.  */
837  using call_summary_base<T>::remove;
838  void remove (cgraph_edge *edge)
839  {
840    if (exists (edge))
841      {
842	int id = edge->get_summary_id ();
843	this->release ((*m_vector)[id]);
844	(*m_vector)[id] = NULL;
845      }
846  }
847
848  /* Return true if a summary for the given EDGE already exists.  */
849  bool exists (cgraph_edge *edge)
850  {
851    int id = edge->get_summary_id ();
852    return (id != -1
853	    && (unsigned)id < m_vector->length ()
854	    && (*m_vector)[id] != NULL);
855  }
856
857  /* Symbol removal hook that is registered to symbol table.  */
858  static void symtab_removal (cgraph_edge *edge, void *data);
859
860  /* Symbol duplication hook that is registered to symbol table.  */
861  static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
862				  void *data);
863
864private:
865  virtual bool is_ggc ();
866
867  /* Summary is stored in the vector.  */
868  vec <T *, V> *m_vector;
869
870  template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
871  template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
872  template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
873      gt_pointer_operator, void *);
874};
875
876template <typename T, typename V>
877fast_call_summary<T *, V>::~fast_call_summary ()
878{
879  this->unregister_hooks ();
880
881  /* Release all summaries.  */
882  for (unsigned i = 0; i < m_vector->length (); i++)
883    if ((*m_vector)[i] != NULL)
884      this->release ((*m_vector)[i]);
885  vec_free (m_vector);
886}
887
888template <typename T, typename V>
889void
890fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
891{
892  fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
893  summary->remove (edge);
894}
895
896template <typename T, typename V>
897void
898fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
899						 cgraph_edge *edge2, void *data)
900{
901  fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
902  T *edge1_summary = NULL;
903
904  if (summary->m_initialize_when_cloning)
905    edge1_summary = summary->get_create (edge1);
906  else
907    edge1_summary = summary->get (edge1);
908
909  if (edge1_summary)
910    {
911      T *duplicate = summary->get_create (edge2);
912      summary->duplicate (edge1, edge2, edge1_summary, duplicate);
913    }
914}
915
916template <typename T, typename V>
917inline bool
918fast_call_summary<T *, V>::is_ggc ()
919{
920  return is_same<V, va_gc>::value;
921}
922
923template <typename T>
924void
925gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
926{
927}
928
929template <typename T>
930void
931gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
932{
933}
934
935template <typename T>
936void
937gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary ATTRIBUTE_UNUSED,
938	   gt_pointer_operator op ATTRIBUTE_UNUSED,
939	   void *cookie ATTRIBUTE_UNUSED)
940{
941}
942
943template <typename T>
944void
945gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
946{
947  ggc_test_and_set_mark (summary->m_vector);
948  gt_ggc_mx (&summary->m_vector);
949}
950
951template <typename T>
952void
953gt_pch_nx (fast_call_summary<T *, va_gc> *const &)
954{
955  gcc_unreachable ();
956}
957
958template <typename T>
959void
960gt_pch_nx (fast_call_summary<T *, va_gc> *const &, gt_pointer_operator, void *)
961{
962  gcc_unreachable ();
963}
964
965#endif  /* GCC_SYMBOL_SUMMARY_H  */
966