ggc-common.c revision 96263
190075Sobrien/* Simple garbage collection for the GNU compiler.
290075Sobrien   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
390075Sobrien
490075SobrienThis file is part of GCC.
590075Sobrien
690075SobrienGCC is free software; you can redistribute it and/or modify it under
790075Sobrienthe terms of the GNU General Public License as published by the Free
890075SobrienSoftware Foundation; either version 2, or (at your option) any later
990075Sobrienversion.
1090075Sobrien
1190075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1290075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1390075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1490075Sobrienfor more details.
1590075Sobrien
1690075SobrienYou should have received a copy of the GNU General Public License
1790075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1890075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
1990075Sobrien02111-1307, USA.  */
2090075Sobrien
2190075Sobrien/* Generic garbage collection (GC) functions and data, not specific to
2290075Sobrien   any particular GC implementation.  */
2390075Sobrien
2490075Sobrien#include "config.h"
2590075Sobrien#include "system.h"
2690075Sobrien#include "rtl.h"
2790075Sobrien#include "tree.h"
2890075Sobrien#include "tm_p.h"
2990075Sobrien#include "hash.h"
3090075Sobrien#include "hashtab.h"
3190075Sobrien#include "varray.h"
3290075Sobrien#include "ggc.h"
3390075Sobrien
3490075Sobrien/* Statistics about the allocation.  */
3590075Sobrienstatic ggc_statistics *ggc_stats;
3690075Sobrien
3790075Sobrien/* The FALSE_LABEL_STACK, declared in except.h, has language-dependent
3890075Sobrien   semantics.  If a front-end needs to mark the false label stack, it
3990075Sobrien   should set this pointer to a non-NULL value.  Otherwise, no marking
4090075Sobrien   will be done.  */
4190075Sobrienvoid (*lang_mark_false_label_stack) PARAMS ((struct label_node *));
4290075Sobrien
4390075Sobrien/* Trees that have been marked, but whose children still need marking.  */
4490075Sobrienvarray_type ggc_pending_trees;
4590075Sobrien
4696263Sobrienstatic void ggc_mark_rtx_children_1 PARAMS ((rtx));
4790075Sobrienstatic void ggc_mark_rtx_ptr PARAMS ((void *));
4890075Sobrienstatic void ggc_mark_tree_ptr PARAMS ((void *));
4990075Sobrienstatic void ggc_mark_rtx_varray_ptr PARAMS ((void *));
5090075Sobrienstatic void ggc_mark_tree_varray_ptr PARAMS ((void *));
5190075Sobrienstatic void ggc_mark_tree_hash_table_ptr PARAMS ((void *));
5290075Sobrienstatic int ggc_htab_delete PARAMS ((void **, void *));
5390075Sobrienstatic void ggc_mark_trees PARAMS ((void));
5490075Sobrienstatic bool ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *,
5590075Sobrien						    hash_table_key));
5690075Sobrien
5790075Sobrien/* Maintain global roots that are preserved during GC.  */
5890075Sobrien
5990075Sobrien/* Global roots that are preserved during calls to gc.  */
6090075Sobrien
6190075Sobrienstruct ggc_root
6290075Sobrien{
6390075Sobrien  struct ggc_root *next;
6490075Sobrien  void *base;
6590075Sobrien  int nelt;
6690075Sobrien  int size;
6790075Sobrien  void (*cb) PARAMS ((void *));
6890075Sobrien};
6990075Sobrien
7090075Sobrienstatic struct ggc_root *roots;
7190075Sobrien
7290075Sobrien/* Add BASE as a new garbage collection root.  It is an array of
7390075Sobrien   length NELT with each element SIZE bytes long.  CB is a
7490075Sobrien   function that will be called with a pointer to each element
7590075Sobrien   of the array; it is the intention that CB call the appropriate
7690075Sobrien   routine to mark gc-able memory for that element.  */
7790075Sobrien
7890075Sobrienvoid
7990075Sobrienggc_add_root (base, nelt, size, cb)
8090075Sobrien     void *base;
8190075Sobrien     int nelt, size;
8290075Sobrien     void (*cb) PARAMS ((void *));
8390075Sobrien{
8490075Sobrien  struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x));
8590075Sobrien
8690075Sobrien  x->next = roots;
8790075Sobrien  x->base = base;
8890075Sobrien  x->nelt = nelt;
8990075Sobrien  x->size = size;
9090075Sobrien  x->cb = cb;
9190075Sobrien
9290075Sobrien  roots = x;
9390075Sobrien}
9490075Sobrien
9590075Sobrien/* Register an array of rtx as a GC root.  */
9690075Sobrien
9790075Sobrienvoid
9890075Sobrienggc_add_rtx_root (base, nelt)
9990075Sobrien     rtx *base;
10090075Sobrien     int nelt;
10190075Sobrien{
10290075Sobrien  ggc_add_root (base, nelt, sizeof (rtx), ggc_mark_rtx_ptr);
10390075Sobrien}
10490075Sobrien
10590075Sobrien/* Register an array of trees as a GC root.  */
10690075Sobrien
10790075Sobrienvoid
10890075Sobrienggc_add_tree_root (base, nelt)
10990075Sobrien     tree *base;
11090075Sobrien     int nelt;
11190075Sobrien{
11290075Sobrien  ggc_add_root (base, nelt, sizeof (tree), ggc_mark_tree_ptr);
11390075Sobrien}
11490075Sobrien
11590075Sobrien/* Register a varray of rtxs as a GC root.  */
11690075Sobrien
11790075Sobrienvoid
11890075Sobrienggc_add_rtx_varray_root (base, nelt)
11990075Sobrien     varray_type *base;
12090075Sobrien     int nelt;
12190075Sobrien{
12290075Sobrien  ggc_add_root (base, nelt, sizeof (varray_type),
12390075Sobrien		ggc_mark_rtx_varray_ptr);
12490075Sobrien}
12590075Sobrien
12690075Sobrien/* Register a varray of trees as a GC root.  */
12790075Sobrien
12890075Sobrienvoid
12990075Sobrienggc_add_tree_varray_root (base, nelt)
13090075Sobrien     varray_type *base;
13190075Sobrien     int nelt;
13290075Sobrien{
13390075Sobrien  ggc_add_root (base, nelt, sizeof (varray_type),
13490075Sobrien		ggc_mark_tree_varray_ptr);
13590075Sobrien}
13690075Sobrien
13790075Sobrien/* Register a hash table of trees as a GC root.  */
13890075Sobrien
13990075Sobrienvoid
14090075Sobrienggc_add_tree_hash_table_root (base, nelt)
14190075Sobrien     struct hash_table **base;
14290075Sobrien     int nelt;
14390075Sobrien{
14490075Sobrien  ggc_add_root (base, nelt, sizeof (struct hash_table *),
14590075Sobrien		ggc_mark_tree_hash_table_ptr);
14690075Sobrien}
14790075Sobrien
14890075Sobrien/* Remove the previously registered GC root at BASE.  */
14990075Sobrien
15090075Sobrienvoid
15190075Sobrienggc_del_root (base)
15290075Sobrien     void *base;
15390075Sobrien{
15490075Sobrien  struct ggc_root *x, **p;
15590075Sobrien
15690075Sobrien  p = &roots, x = roots;
15790075Sobrien  while (x)
15890075Sobrien    {
15990075Sobrien      if (x->base == base)
16090075Sobrien	{
16190075Sobrien	  *p = x->next;
16290075Sobrien	  free (x);
16390075Sobrien	  return;
16490075Sobrien	}
16590075Sobrien      p = &x->next;
16690075Sobrien      x = x->next;
16790075Sobrien    }
16890075Sobrien
16990075Sobrien  abort ();
17090075Sobrien}
17190075Sobrien
17290075Sobrien/* Add a hash table to be scanned when all roots have been processed.  We
17390075Sobrien   delete any entry in the table that has not been marked.  */
17490075Sobrien
17590075Sobrienstruct d_htab_root
17690075Sobrien{
17790075Sobrien  struct d_htab_root *next;
17890075Sobrien  htab_t htab;
17990075Sobrien  ggc_htab_marked_p marked_p;
18090075Sobrien  ggc_htab_mark mark;
18190075Sobrien};
18290075Sobrien
18390075Sobrienstatic struct d_htab_root *d_htab_roots;
18490075Sobrien
18590075Sobrien/* Add X, an htab, to a list of htabs that contain objects which are allocated
18690075Sobrien   from GC memory.  Once all other roots are marked, we check each object in
18790075Sobrien   the htab to see if it has already been marked.  If not, it is deleted.
18890075Sobrien
18990075Sobrien   MARKED_P, if specified, is a function that returns 1 if the entry is to
19090075Sobrien   be considered as "marked".  If not present, the data structure pointed to
19190075Sobrien   by the htab slot is tested.  This function should be supplied if some
19290075Sobrien   other object (such as something pointed to by that object) should be tested
19390075Sobrien   in which case the function tests whether that object (or objects) are
19490075Sobrien   marked (using ggc_marked_p) and returns nonzero if it is.
19590075Sobrien
19690075Sobrien   MARK, if specified, is a function that is passed the contents of a slot
19790075Sobrien   that has been determined to have been "marked" (via the above function)
19890075Sobrien   and marks any other objects pointed to by that object.  For example,
19990075Sobrien   we might have a hash table of memory attribute blocks, which are pointed
20090075Sobrien   to by a MEM RTL but have a pointer to a DECL.  MARKED_P in that case will
20190075Sobrien   not be specified because we want to know if the attribute block is pointed
20290075Sobrien   to by the MEM, but MARK must be specified because if the block has been
20390075Sobrien   marked, we need to mark the DECL.  */
20490075Sobrien
20590075Sobrienvoid
20690075Sobrienggc_add_deletable_htab (x, marked_p, mark)
20790075Sobrien     PTR x;
20890075Sobrien     ggc_htab_marked_p marked_p;
20990075Sobrien     ggc_htab_mark mark;
21090075Sobrien{
21190075Sobrien  struct d_htab_root *r
21290075Sobrien    = (struct d_htab_root *) xmalloc (sizeof (struct d_htab_root));
21390075Sobrien
21490075Sobrien  r->next = d_htab_roots;
21590075Sobrien  r->htab = (htab_t) x;
21690075Sobrien  r->marked_p = marked_p ? marked_p : ggc_marked_p;
21790075Sobrien  r->mark = mark;
21890075Sobrien  d_htab_roots = r;
21990075Sobrien}
22090075Sobrien
22190075Sobrien/* Process a slot of an htab by deleting it if it has not been marked.  */
22290075Sobrien
22390075Sobrienstatic int
22490075Sobrienggc_htab_delete (slot, info)
22590075Sobrien     void **slot;
22690075Sobrien     void *info;
22790075Sobrien{
22890075Sobrien  struct d_htab_root *r = (struct d_htab_root *) info;
22990075Sobrien
23090075Sobrien  if (! (*r->marked_p) (*slot))
23190075Sobrien    htab_clear_slot (r->htab, slot);
23290075Sobrien  else if (r->mark)
23390075Sobrien    (*r->mark) (*slot);
23490075Sobrien
23590075Sobrien  return 1;
23690075Sobrien}
23790075Sobrien
23890075Sobrien/* Iterate through all registered roots and mark each element.  */
23990075Sobrien
24090075Sobrienvoid
24190075Sobrienggc_mark_roots ()
24290075Sobrien{
24390075Sobrien  struct ggc_root *x;
24490075Sobrien  struct d_htab_root *y;
24590075Sobrien
24690075Sobrien  VARRAY_TREE_INIT (ggc_pending_trees, 4096, "ggc_pending_trees");
24790075Sobrien
24890075Sobrien  for (x = roots; x != NULL; x = x->next)
24990075Sobrien    {
25090075Sobrien      char *elt = x->base;
25190075Sobrien      int s = x->size, n = x->nelt;
25290075Sobrien      void (*cb) PARAMS ((void *)) = x->cb;
25390075Sobrien      int i;
25490075Sobrien
25590075Sobrien      for (i = 0; i < n; ++i, elt += s)
25690075Sobrien	(*cb)(elt);
25790075Sobrien    }
25890075Sobrien
25990075Sobrien  /* Mark all the queued up trees, and their children.  */
26090075Sobrien  ggc_mark_trees ();
26190075Sobrien  VARRAY_FREE (ggc_pending_trees);
26290075Sobrien
26390075Sobrien  /* Now scan all hash tables that have objects which are to be deleted if
26490075Sobrien     they are not already marked.  Since these may mark more trees, we need
26590075Sobrien     to reinitialize that varray.  */
26690075Sobrien  VARRAY_TREE_INIT (ggc_pending_trees, 1024, "ggc_pending_trees");
26790075Sobrien
26890075Sobrien  for (y = d_htab_roots; y != NULL; y = y->next)
26990075Sobrien    htab_traverse (y->htab, ggc_htab_delete, (PTR) y);
27090075Sobrien  ggc_mark_trees ();
27190075Sobrien  VARRAY_FREE (ggc_pending_trees);
27290075Sobrien}
27390075Sobrien
27490075Sobrien/* R had not been previously marked, but has now been marked via
27590075Sobrien   ggc_set_mark.  Now recurse and process the children.  */
27690075Sobrien
27790075Sobrienvoid
27890075Sobrienggc_mark_rtx_children (r)
27990075Sobrien     rtx r;
28090075Sobrien{
28196263Sobrien  rtx i, last;
28296263Sobrien
28396263Sobrien  /* Special case the instruction chain.  This is a data structure whose
28496263Sobrien     chain length is potentially unbounded, and which contain references
28596263Sobrien     within the chain (e.g. label_ref and insn_list).  If do nothing here,
28696263Sobrien     we risk blowing the stack recursing through a long chain of insns.
28796263Sobrien
28896263Sobrien     Combat this by marking all of the instructions in the chain before
28996263Sobrien     marking the contents of those instructions.  */
29096263Sobrien
29196263Sobrien  switch (GET_CODE (r))
29296263Sobrien    {
29396263Sobrien    case INSN:
29496263Sobrien    case JUMP_INSN:
29596263Sobrien    case CALL_INSN:
29696263Sobrien    case NOTE:
29796263Sobrien    case CODE_LABEL:
29896263Sobrien    case BARRIER:
29996263Sobrien      for (i = NEXT_INSN (r); ; i = NEXT_INSN (i))
30096263Sobrien	if (! ggc_test_and_set_mark (i))
30196263Sobrien	  break;
30296263Sobrien      last = i;
30396263Sobrien
30496263Sobrien      for (i = NEXT_INSN (r); i != last; i = NEXT_INSN (i))
30596263Sobrien	ggc_mark_rtx_children_1 (i);
30696263Sobrien
30796263Sobrien    default:
30896263Sobrien      break;
30996263Sobrien    }
31096263Sobrien
31196263Sobrien  ggc_mark_rtx_children_1 (r);
31296263Sobrien}
31396263Sobrien
31496263Sobrienstatic void
31596263Sobrienggc_mark_rtx_children_1 (r)
31696263Sobrien     rtx r;
31796263Sobrien{
31890075Sobrien  const char *fmt;
31990075Sobrien  int i;
32090075Sobrien  rtx next_rtx;
32190075Sobrien
32290075Sobrien  do
32390075Sobrien    {
32490075Sobrien      enum rtx_code code = GET_CODE (r);
32590075Sobrien      /* This gets set to a child rtx to eliminate tail recursion.  */
32690075Sobrien      next_rtx = NULL;
32790075Sobrien
32890075Sobrien      /* Collect statistics, if appropriate.  */
32990075Sobrien      if (ggc_stats)
33090075Sobrien	{
33190075Sobrien	  ++ggc_stats->num_rtxs[(int) code];
33290075Sobrien	  ggc_stats->size_rtxs[(int) code] += ggc_get_size (r);
33390075Sobrien	}
33490075Sobrien
33590075Sobrien      /* ??? If (some of) these are really pass-dependent info, do we
33690075Sobrien	 have any right poking our noses in?  */
33790075Sobrien      switch (code)
33890075Sobrien	{
33990075Sobrien	case MEM:
34090075Sobrien	  ggc_mark (MEM_ATTRS (r));
34190075Sobrien	  break;
34290075Sobrien	case JUMP_INSN:
34390075Sobrien	  ggc_mark_rtx (JUMP_LABEL (r));
34490075Sobrien	  break;
34590075Sobrien	case CODE_LABEL:
34690075Sobrien	  ggc_mark_rtx (LABEL_REFS (r));
34790075Sobrien	  break;
34890075Sobrien	case LABEL_REF:
34990075Sobrien	  ggc_mark_rtx (LABEL_NEXTREF (r));
35090075Sobrien	  ggc_mark_rtx (CONTAINING_INSN (r));
35190075Sobrien	  break;
35290075Sobrien	case ADDRESSOF:
35390075Sobrien	  ggc_mark_tree (ADDRESSOF_DECL (r));
35490075Sobrien	  break;
35590075Sobrien	case CONST_DOUBLE:
35690075Sobrien	  ggc_mark_rtx (CONST_DOUBLE_CHAIN (r));
35790075Sobrien	  break;
35890075Sobrien	case NOTE:
35990075Sobrien	  switch (NOTE_LINE_NUMBER (r))
36090075Sobrien	    {
36190075Sobrien	    case NOTE_INSN_RANGE_BEG:
36290075Sobrien	    case NOTE_INSN_RANGE_END:
36390075Sobrien	    case NOTE_INSN_LIVE:
36490075Sobrien	    case NOTE_INSN_EXPECTED_VALUE:
36590075Sobrien	      ggc_mark_rtx (NOTE_RANGE_INFO (r));
36690075Sobrien	      break;
36790075Sobrien
36890075Sobrien	    case NOTE_INSN_BLOCK_BEG:
36990075Sobrien	    case NOTE_INSN_BLOCK_END:
37090075Sobrien	      ggc_mark_tree (NOTE_BLOCK (r));
37190075Sobrien	      break;
37290075Sobrien
37390075Sobrien	    default:
37490075Sobrien	      break;
37590075Sobrien	    }
37690075Sobrien	  break;
37790075Sobrien
37890075Sobrien	default:
37990075Sobrien	  break;
38090075Sobrien	}
38190075Sobrien
38290075Sobrien      for (fmt = GET_RTX_FORMAT (GET_CODE (r)), i = 0; *fmt ; ++fmt, ++i)
38390075Sobrien	{
38490075Sobrien	  rtx exp;
38590075Sobrien	  switch (*fmt)
38690075Sobrien	    {
38790075Sobrien	    case 'e': case 'u':
38890075Sobrien	      exp = XEXP (r, i);
38990075Sobrien	      if (ggc_test_and_set_mark (exp))
39090075Sobrien		{
39190075Sobrien		  if (next_rtx == NULL)
39290075Sobrien		    next_rtx = exp;
39390075Sobrien		  else
39490075Sobrien		    ggc_mark_rtx_children (exp);
39590075Sobrien		}
39690075Sobrien	      break;
39790075Sobrien	    case 'V': case 'E':
39890075Sobrien	      ggc_mark_rtvec (XVEC (r, i));
39990075Sobrien	      break;
40090075Sobrien	    }
40190075Sobrien	}
40290075Sobrien    }
40390075Sobrien  while ((r = next_rtx) != NULL);
40490075Sobrien}
40590075Sobrien
40690075Sobrien/* V had not been previously marked, but has now been marked via
40790075Sobrien   ggc_set_mark.  Now recurse and process the children.  */
40890075Sobrien
40990075Sobrienvoid
41090075Sobrienggc_mark_rtvec_children (v)
41190075Sobrien     rtvec v;
41290075Sobrien{
41390075Sobrien  int i;
41490075Sobrien
41590075Sobrien  i = GET_NUM_ELEM (v);
41690075Sobrien  while (--i >= 0)
41790075Sobrien    ggc_mark_rtx (RTVEC_ELT (v, i));
41890075Sobrien}
41990075Sobrien
42090075Sobrien/* Recursively set marks on all of the children of the
42190075Sobrien   GCC_PENDING_TREES.  */
42290075Sobrien
42390075Sobrienstatic void
42490075Sobrienggc_mark_trees ()
42590075Sobrien{
42690075Sobrien  while (ggc_pending_trees->elements_used)
42790075Sobrien    {
42890075Sobrien      tree t;
42990075Sobrien      enum tree_code code;
43090075Sobrien
43190075Sobrien      t = VARRAY_TOP_TREE (ggc_pending_trees);
43290075Sobrien      VARRAY_POP (ggc_pending_trees);
43390075Sobrien      code = TREE_CODE (t);
43490075Sobrien
43590075Sobrien      /* Collect statistics, if appropriate.  */
43690075Sobrien      if (ggc_stats)
43790075Sobrien	{
43890075Sobrien	  ++ggc_stats->num_trees[(int) code];
43990075Sobrien	  ggc_stats->size_trees[(int) code] += ggc_get_size (t);
44090075Sobrien	}
44190075Sobrien
44290075Sobrien      /* Bits from common.  */
44390075Sobrien      ggc_mark_tree (TREE_TYPE (t));
44490075Sobrien      ggc_mark_tree (TREE_CHAIN (t));
44590075Sobrien
44690075Sobrien      /* Some nodes require special handling.  */
44790075Sobrien      switch (code)
44890075Sobrien	{
44990075Sobrien	case TREE_LIST:
45090075Sobrien	  ggc_mark_tree (TREE_PURPOSE (t));
45190075Sobrien	  ggc_mark_tree (TREE_VALUE (t));
45290075Sobrien	  continue;
45390075Sobrien
45490075Sobrien	case TREE_VEC:
45590075Sobrien	  {
45690075Sobrien	    int i = TREE_VEC_LENGTH (t);
45790075Sobrien
45890075Sobrien	    while (--i >= 0)
45990075Sobrien	      ggc_mark_tree (TREE_VEC_ELT (t, i));
46090075Sobrien	    continue;
46190075Sobrien	  }
46290075Sobrien
46390075Sobrien	case COMPLEX_CST:
46490075Sobrien	  ggc_mark_tree (TREE_REALPART (t));
46590075Sobrien	  ggc_mark_tree (TREE_IMAGPART (t));
46690075Sobrien	  break;
46790075Sobrien
46890075Sobrien	case PARM_DECL:
46990075Sobrien	  ggc_mark_rtx (DECL_INCOMING_RTL (t));
47090075Sobrien	  break;
47190075Sobrien
47290075Sobrien	case FIELD_DECL:
47390075Sobrien	  ggc_mark_tree (DECL_FIELD_BIT_OFFSET (t));
47490075Sobrien	  break;
47590075Sobrien
47690075Sobrien	case IDENTIFIER_NODE:
47790075Sobrien	  lang_mark_tree (t);
47890075Sobrien	  continue;
47990075Sobrien
48090075Sobrien	default:
48190075Sobrien	  break;
48290075Sobrien	}
48390075Sobrien
48490075Sobrien      /* But in general we can handle them by class.  */
48590075Sobrien      switch (TREE_CODE_CLASS (code))
48690075Sobrien	{
48790075Sobrien	case 'd': /* A decl node.  */
48890075Sobrien	  ggc_mark_tree (DECL_SIZE (t));
48990075Sobrien	  ggc_mark_tree (DECL_SIZE_UNIT (t));
49090075Sobrien	  ggc_mark_tree (DECL_NAME (t));
49190075Sobrien	  ggc_mark_tree (DECL_CONTEXT (t));
49290075Sobrien	  ggc_mark_tree (DECL_ARGUMENTS (t));
49390075Sobrien	  ggc_mark_tree (DECL_RESULT_FLD (t));
49490075Sobrien	  ggc_mark_tree (DECL_INITIAL (t));
49590075Sobrien	  ggc_mark_tree (DECL_ABSTRACT_ORIGIN (t));
49690075Sobrien	  ggc_mark_tree (DECL_SECTION_NAME (t));
49790075Sobrien	  ggc_mark_tree (DECL_ATTRIBUTES (t));
49890075Sobrien	  if (DECL_RTL_SET_P (t))
49990075Sobrien	    ggc_mark_rtx (DECL_RTL (t));
50090075Sobrien	  ggc_mark_rtx (DECL_LIVE_RANGE_RTL (t));
50190075Sobrien	  ggc_mark_tree (DECL_VINDEX (t));
50290075Sobrien	  if (DECL_ASSEMBLER_NAME_SET_P (t))
50390075Sobrien	    ggc_mark_tree (DECL_ASSEMBLER_NAME (t));
50490075Sobrien	  if (TREE_CODE (t) == FUNCTION_DECL)
50590075Sobrien	    {
50690075Sobrien	      ggc_mark_tree (DECL_SAVED_TREE (t));
50790075Sobrien	      ggc_mark_tree (DECL_INLINED_FNS (t));
50890075Sobrien	      if (DECL_SAVED_INSNS (t))
50990075Sobrien		ggc_mark_struct_function (DECL_SAVED_INSNS (t));
51090075Sobrien	    }
51190075Sobrien	  lang_mark_tree (t);
51290075Sobrien	  break;
51390075Sobrien
51490075Sobrien	case 't': /* A type node.  */
51590075Sobrien	  ggc_mark_tree (TYPE_SIZE (t));
51690075Sobrien	  ggc_mark_tree (TYPE_SIZE_UNIT (t));
51790075Sobrien	  ggc_mark_tree (TYPE_ATTRIBUTES (t));
51890075Sobrien	  ggc_mark_tree (TYPE_VALUES (t));
51990075Sobrien	  ggc_mark_tree (TYPE_POINTER_TO (t));
52090075Sobrien	  ggc_mark_tree (TYPE_REFERENCE_TO (t));
52190075Sobrien	  ggc_mark_tree (TYPE_NAME (t));
52290075Sobrien	  ggc_mark_tree (TYPE_MIN_VALUE (t));
52390075Sobrien	  ggc_mark_tree (TYPE_MAX_VALUE (t));
52490075Sobrien	  ggc_mark_tree (TYPE_NEXT_VARIANT (t));
52590075Sobrien	  ggc_mark_tree (TYPE_MAIN_VARIANT (t));
52690075Sobrien	  ggc_mark_tree (TYPE_BINFO (t));
52790075Sobrien	  ggc_mark_tree (TYPE_CONTEXT (t));
52890075Sobrien	  lang_mark_tree (t);
52990075Sobrien	  break;
53090075Sobrien
53190075Sobrien	case 'b': /* A lexical block.  */
53290075Sobrien	  ggc_mark_tree (BLOCK_VARS (t));
53390075Sobrien	  ggc_mark_tree (BLOCK_SUBBLOCKS (t));
53490075Sobrien	  ggc_mark_tree (BLOCK_SUPERCONTEXT (t));
53590075Sobrien	  ggc_mark_tree (BLOCK_ABSTRACT_ORIGIN (t));
53690075Sobrien	  break;
53790075Sobrien
53890075Sobrien	case 'c': /* A constant.  */
53990075Sobrien	  ggc_mark_rtx (TREE_CST_RTL (t));
54090075Sobrien	  break;
54190075Sobrien
54290075Sobrien	case 'r': case '<': case '1':
54390075Sobrien	case '2': case 'e': case 's': /* Expressions.  */
54490075Sobrien	  {
54590075Sobrien	    int i = TREE_CODE_LENGTH (TREE_CODE (t));
54690075Sobrien	    int first_rtl = first_rtl_op (TREE_CODE (t));
54790075Sobrien
54890075Sobrien	    while (--i >= 0)
54990075Sobrien	      {
55090075Sobrien		if (i >= first_rtl)
55190075Sobrien		  ggc_mark_rtx ((rtx) TREE_OPERAND (t, i));
55290075Sobrien		else
55390075Sobrien		  ggc_mark_tree (TREE_OPERAND (t, i));
55490075Sobrien	      }
55590075Sobrien	    break;
55690075Sobrien	  }
55790075Sobrien
55890075Sobrien	case 'x':
55990075Sobrien	  lang_mark_tree (t);
56090075Sobrien	  break;
56190075Sobrien	}
56290075Sobrien    }
56390075Sobrien}
56490075Sobrien
56590075Sobrien/* Mark all the elements of the varray V, which contains rtxs.  */
56690075Sobrien
56790075Sobrienvoid
56890075Sobrienggc_mark_rtx_varray (v)
56990075Sobrien     varray_type v;
57090075Sobrien{
57190075Sobrien  int i;
57290075Sobrien
57390075Sobrien  if (v)
57490075Sobrien    for (i = v->num_elements - 1; i >= 0; --i)
57590075Sobrien      ggc_mark_rtx (VARRAY_RTX (v, i));
57690075Sobrien}
57790075Sobrien
57890075Sobrien/* Mark all the elements of the varray V, which contains trees.  */
57990075Sobrien
58090075Sobrienvoid
58190075Sobrienggc_mark_tree_varray (v)
58290075Sobrien     varray_type v;
58390075Sobrien{
58490075Sobrien  int i;
58590075Sobrien
58690075Sobrien  if (v)
58790075Sobrien    for (i = v->num_elements - 1; i >= 0; --i)
58890075Sobrien      ggc_mark_tree (VARRAY_TREE (v, i));
58990075Sobrien}
59090075Sobrien
59190075Sobrien/* Mark the hash table-entry HE.  Its key field is really a tree.  */
59290075Sobrien
59390075Sobrienstatic bool
59490075Sobrienggc_mark_tree_hash_table_entry (he, k)
59590075Sobrien     struct hash_entry *he;
59690075Sobrien     hash_table_key k ATTRIBUTE_UNUSED;
59790075Sobrien{
59890075Sobrien  ggc_mark_tree ((tree) he->key);
59990075Sobrien  return true;
60090075Sobrien}
60190075Sobrien
60290075Sobrien/* Mark all the elements of the hash-table H, which contains trees.  */
60390075Sobrien
60490075Sobrienvoid
60590075Sobrienggc_mark_tree_hash_table (ht)
60690075Sobrien     struct hash_table *ht;
60790075Sobrien{
60890075Sobrien  hash_traverse (ht, ggc_mark_tree_hash_table_entry, /*info=*/0);
60990075Sobrien}
61090075Sobrien
61190075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
61290075Sobrien   *ELT (which is an rtx) to ggc_mark_rtx.  */
61390075Sobrien
61490075Sobrienstatic void
61590075Sobrienggc_mark_rtx_ptr (elt)
61690075Sobrien     void *elt;
61790075Sobrien{
61890075Sobrien  ggc_mark_rtx (*(rtx *) elt);
61990075Sobrien}
62090075Sobrien
62190075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
62290075Sobrien   *ELT (which is a tree) to ggc_mark_tree.  */
62390075Sobrien
62490075Sobrienstatic void
62590075Sobrienggc_mark_tree_ptr (elt)
62690075Sobrien     void *elt;
62790075Sobrien{
62890075Sobrien  ggc_mark_tree (*(tree *) elt);
62990075Sobrien}
63090075Sobrien
63190075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
63290075Sobrien   ELT (which is really a varray_type *) to ggc_mark_rtx_varray.  */
63390075Sobrien
63490075Sobrienstatic void
63590075Sobrienggc_mark_rtx_varray_ptr (elt)
63690075Sobrien     void *elt;
63790075Sobrien{
63890075Sobrien  ggc_mark_rtx_varray (*(varray_type *) elt);
63990075Sobrien}
64090075Sobrien
64190075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
64290075Sobrien   ELT (which is really a varray_type *) to ggc_mark_tree_varray.  */
64390075Sobrien
64490075Sobrienstatic void
64590075Sobrienggc_mark_tree_varray_ptr (elt)
64690075Sobrien     void *elt;
64790075Sobrien{
64890075Sobrien  ggc_mark_tree_varray (*(varray_type *) elt);
64990075Sobrien}
65090075Sobrien
65190075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
65290075Sobrien   ELT (which is really a struct hash_table **) to
65390075Sobrien   ggc_mark_tree_hash_table.  */
65490075Sobrien
65590075Sobrienstatic void
65690075Sobrienggc_mark_tree_hash_table_ptr (elt)
65790075Sobrien     void *elt;
65890075Sobrien{
65990075Sobrien  ggc_mark_tree_hash_table (*(struct hash_table **) elt);
66090075Sobrien}
66190075Sobrien
66290075Sobrien/* Allocate a block of memory, then clear it.  */
66390075Sobrienvoid *
66490075Sobrienggc_alloc_cleared (size)
66590075Sobrien     size_t size;
66690075Sobrien{
66790075Sobrien  void *buf = ggc_alloc (size);
66890075Sobrien  memset (buf, 0, size);
66990075Sobrien  return buf;
67090075Sobrien}
67190075Sobrien
67290075Sobrien/* Print statistics that are independent of the collector in use.  */
67390075Sobrien#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
67490075Sobrien		  ? (x) \
67590075Sobrien		  : ((x) < 1024*1024*10 \
67690075Sobrien		     ? (x) / 1024 \
67790075Sobrien		     : (x) / (1024*1024))))
67890075Sobrien#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
67990075Sobrien
68090075Sobrienvoid
68190075Sobrienggc_print_common_statistics (stream, stats)
68290075Sobrien     FILE *stream;
68390075Sobrien     ggc_statistics *stats;
68490075Sobrien{
68590075Sobrien  int code;
68690075Sobrien
68790075Sobrien  /* Set the pointer so that during collection we will actually gather
68890075Sobrien     the statistics.  */
68990075Sobrien  ggc_stats = stats;
69090075Sobrien
69190075Sobrien  /* Then do one collection to fill in the statistics.  */
69290075Sobrien  ggc_collect ();
69390075Sobrien
69490075Sobrien  /* Total the statistics.  */
69590075Sobrien  for (code = 0; code < MAX_TREE_CODES; ++code)
69690075Sobrien    {
69790075Sobrien      stats->total_num_trees += stats->num_trees[code];
69890075Sobrien      stats->total_size_trees += stats->size_trees[code];
69990075Sobrien    }
70090075Sobrien  for (code = 0; code < NUM_RTX_CODE; ++code)
70190075Sobrien    {
70290075Sobrien      stats->total_num_rtxs += stats->num_rtxs[code];
70390075Sobrien      stats->total_size_rtxs += stats->size_rtxs[code];
70490075Sobrien    }
70590075Sobrien
70690075Sobrien  /* Print the statistics for trees.  */
70790075Sobrien  fprintf (stream, "\n%-17s%10s %16s %10s\n", "Tree",
70890075Sobrien	   "Number", "Bytes", "% Total");
70990075Sobrien  for (code = 0; code < MAX_TREE_CODES; ++code)
71090075Sobrien    if (ggc_stats->num_trees[code])
71190075Sobrien      {
71290075Sobrien	fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
71390075Sobrien		 tree_code_name[code],
71490075Sobrien		 ggc_stats->num_trees[code],
71590075Sobrien		 SCALE (ggc_stats->size_trees[code]),
71690075Sobrien		 LABEL (ggc_stats->size_trees[code]),
71790075Sobrien		 (100 * ((double) ggc_stats->size_trees[code])
71890075Sobrien		  / ggc_stats->total_size_trees));
71990075Sobrien      }
72090075Sobrien  fprintf (stream,
72190075Sobrien	   "%-17s%10u%16ld%c\n", "Total",
72290075Sobrien	   ggc_stats->total_num_trees,
72390075Sobrien	   SCALE (ggc_stats->total_size_trees),
72490075Sobrien	   LABEL (ggc_stats->total_size_trees));
72590075Sobrien
72690075Sobrien  /* Print the statistics for RTL.  */
72790075Sobrien  fprintf (stream, "\n%-17s%10s %16s %10s\n", "RTX",
72890075Sobrien	   "Number", "Bytes", "% Total");
72990075Sobrien  for (code = 0; code < NUM_RTX_CODE; ++code)
73090075Sobrien    if (ggc_stats->num_rtxs[code])
73190075Sobrien      {
73290075Sobrien	fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
73390075Sobrien		 rtx_name[code],
73490075Sobrien		 ggc_stats->num_rtxs[code],
73590075Sobrien		 SCALE (ggc_stats->size_rtxs[code]),
73690075Sobrien		 LABEL (ggc_stats->size_rtxs[code]),
73790075Sobrien		 (100 * ((double) ggc_stats->size_rtxs[code])
73890075Sobrien		  / ggc_stats->total_size_rtxs));
73990075Sobrien      }
74090075Sobrien  fprintf (stream,
74190075Sobrien	   "%-17s%10u%16ld%c\n", "Total",
74290075Sobrien	   ggc_stats->total_num_rtxs,
74390075Sobrien	   SCALE (ggc_stats->total_size_rtxs),
74490075Sobrien	   LABEL (ggc_stats->total_size_rtxs));
74590075Sobrien
74690075Sobrien  /* Don't gather statistics any more.  */
74790075Sobrien  ggc_stats = NULL;
74890075Sobrien}
749