ggc-common.c revision 90075
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
4690075Sobrienstatic void ggc_mark_rtx_ptr PARAMS ((void *));
4790075Sobrienstatic void ggc_mark_tree_ptr PARAMS ((void *));
4890075Sobrienstatic void ggc_mark_rtx_varray_ptr PARAMS ((void *));
4990075Sobrienstatic void ggc_mark_tree_varray_ptr PARAMS ((void *));
5090075Sobrienstatic void ggc_mark_tree_hash_table_ptr PARAMS ((void *));
5190075Sobrienstatic int ggc_htab_delete PARAMS ((void **, void *));
5290075Sobrienstatic void ggc_mark_trees PARAMS ((void));
5390075Sobrienstatic bool ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *,
5490075Sobrien						    hash_table_key));
5590075Sobrien
5690075Sobrien/* Maintain global roots that are preserved during GC.  */
5790075Sobrien
5890075Sobrien/* Global roots that are preserved during calls to gc.  */
5990075Sobrien
6090075Sobrienstruct ggc_root
6190075Sobrien{
6290075Sobrien  struct ggc_root *next;
6390075Sobrien  void *base;
6490075Sobrien  int nelt;
6590075Sobrien  int size;
6690075Sobrien  void (*cb) PARAMS ((void *));
6790075Sobrien};
6890075Sobrien
6990075Sobrienstatic struct ggc_root *roots;
7090075Sobrien
7190075Sobrien/* Add BASE as a new garbage collection root.  It is an array of
7290075Sobrien   length NELT with each element SIZE bytes long.  CB is a
7390075Sobrien   function that will be called with a pointer to each element
7490075Sobrien   of the array; it is the intention that CB call the appropriate
7590075Sobrien   routine to mark gc-able memory for that element.  */
7690075Sobrien
7790075Sobrienvoid
7890075Sobrienggc_add_root (base, nelt, size, cb)
7990075Sobrien     void *base;
8090075Sobrien     int nelt, size;
8190075Sobrien     void (*cb) PARAMS ((void *));
8290075Sobrien{
8390075Sobrien  struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x));
8490075Sobrien
8590075Sobrien  x->next = roots;
8690075Sobrien  x->base = base;
8790075Sobrien  x->nelt = nelt;
8890075Sobrien  x->size = size;
8990075Sobrien  x->cb = cb;
9090075Sobrien
9190075Sobrien  roots = x;
9290075Sobrien}
9390075Sobrien
9490075Sobrien/* Register an array of rtx as a GC root.  */
9590075Sobrien
9690075Sobrienvoid
9790075Sobrienggc_add_rtx_root (base, nelt)
9890075Sobrien     rtx *base;
9990075Sobrien     int nelt;
10090075Sobrien{
10190075Sobrien  ggc_add_root (base, nelt, sizeof (rtx), ggc_mark_rtx_ptr);
10290075Sobrien}
10390075Sobrien
10490075Sobrien/* Register an array of trees as a GC root.  */
10590075Sobrien
10690075Sobrienvoid
10790075Sobrienggc_add_tree_root (base, nelt)
10890075Sobrien     tree *base;
10990075Sobrien     int nelt;
11090075Sobrien{
11190075Sobrien  ggc_add_root (base, nelt, sizeof (tree), ggc_mark_tree_ptr);
11290075Sobrien}
11390075Sobrien
11490075Sobrien/* Register a varray of rtxs as a GC root.  */
11590075Sobrien
11690075Sobrienvoid
11790075Sobrienggc_add_rtx_varray_root (base, nelt)
11890075Sobrien     varray_type *base;
11990075Sobrien     int nelt;
12090075Sobrien{
12190075Sobrien  ggc_add_root (base, nelt, sizeof (varray_type),
12290075Sobrien		ggc_mark_rtx_varray_ptr);
12390075Sobrien}
12490075Sobrien
12590075Sobrien/* Register a varray of trees as a GC root.  */
12690075Sobrien
12790075Sobrienvoid
12890075Sobrienggc_add_tree_varray_root (base, nelt)
12990075Sobrien     varray_type *base;
13090075Sobrien     int nelt;
13190075Sobrien{
13290075Sobrien  ggc_add_root (base, nelt, sizeof (varray_type),
13390075Sobrien		ggc_mark_tree_varray_ptr);
13490075Sobrien}
13590075Sobrien
13690075Sobrien/* Register a hash table of trees as a GC root.  */
13790075Sobrien
13890075Sobrienvoid
13990075Sobrienggc_add_tree_hash_table_root (base, nelt)
14090075Sobrien     struct hash_table **base;
14190075Sobrien     int nelt;
14290075Sobrien{
14390075Sobrien  ggc_add_root (base, nelt, sizeof (struct hash_table *),
14490075Sobrien		ggc_mark_tree_hash_table_ptr);
14590075Sobrien}
14690075Sobrien
14790075Sobrien/* Remove the previously registered GC root at BASE.  */
14890075Sobrien
14990075Sobrienvoid
15090075Sobrienggc_del_root (base)
15190075Sobrien     void *base;
15290075Sobrien{
15390075Sobrien  struct ggc_root *x, **p;
15490075Sobrien
15590075Sobrien  p = &roots, x = roots;
15690075Sobrien  while (x)
15790075Sobrien    {
15890075Sobrien      if (x->base == base)
15990075Sobrien	{
16090075Sobrien	  *p = x->next;
16190075Sobrien	  free (x);
16290075Sobrien	  return;
16390075Sobrien	}
16490075Sobrien      p = &x->next;
16590075Sobrien      x = x->next;
16690075Sobrien    }
16790075Sobrien
16890075Sobrien  abort ();
16990075Sobrien}
17090075Sobrien
17190075Sobrien/* Add a hash table to be scanned when all roots have been processed.  We
17290075Sobrien   delete any entry in the table that has not been marked.  */
17390075Sobrien
17490075Sobrienstruct d_htab_root
17590075Sobrien{
17690075Sobrien  struct d_htab_root *next;
17790075Sobrien  htab_t htab;
17890075Sobrien  ggc_htab_marked_p marked_p;
17990075Sobrien  ggc_htab_mark mark;
18090075Sobrien};
18190075Sobrien
18290075Sobrienstatic struct d_htab_root *d_htab_roots;
18390075Sobrien
18490075Sobrien/* Add X, an htab, to a list of htabs that contain objects which are allocated
18590075Sobrien   from GC memory.  Once all other roots are marked, we check each object in
18690075Sobrien   the htab to see if it has already been marked.  If not, it is deleted.
18790075Sobrien
18890075Sobrien   MARKED_P, if specified, is a function that returns 1 if the entry is to
18990075Sobrien   be considered as "marked".  If not present, the data structure pointed to
19090075Sobrien   by the htab slot is tested.  This function should be supplied if some
19190075Sobrien   other object (such as something pointed to by that object) should be tested
19290075Sobrien   in which case the function tests whether that object (or objects) are
19390075Sobrien   marked (using ggc_marked_p) and returns nonzero if it is.
19490075Sobrien
19590075Sobrien   MARK, if specified, is a function that is passed the contents of a slot
19690075Sobrien   that has been determined to have been "marked" (via the above function)
19790075Sobrien   and marks any other objects pointed to by that object.  For example,
19890075Sobrien   we might have a hash table of memory attribute blocks, which are pointed
19990075Sobrien   to by a MEM RTL but have a pointer to a DECL.  MARKED_P in that case will
20090075Sobrien   not be specified because we want to know if the attribute block is pointed
20190075Sobrien   to by the MEM, but MARK must be specified because if the block has been
20290075Sobrien   marked, we need to mark the DECL.  */
20390075Sobrien
20490075Sobrienvoid
20590075Sobrienggc_add_deletable_htab (x, marked_p, mark)
20690075Sobrien     PTR x;
20790075Sobrien     ggc_htab_marked_p marked_p;
20890075Sobrien     ggc_htab_mark mark;
20990075Sobrien{
21090075Sobrien  struct d_htab_root *r
21190075Sobrien    = (struct d_htab_root *) xmalloc (sizeof (struct d_htab_root));
21290075Sobrien
21390075Sobrien  r->next = d_htab_roots;
21490075Sobrien  r->htab = (htab_t) x;
21590075Sobrien  r->marked_p = marked_p ? marked_p : ggc_marked_p;
21690075Sobrien  r->mark = mark;
21790075Sobrien  d_htab_roots = r;
21890075Sobrien}
21990075Sobrien
22090075Sobrien/* Process a slot of an htab by deleting it if it has not been marked.  */
22190075Sobrien
22290075Sobrienstatic int
22390075Sobrienggc_htab_delete (slot, info)
22490075Sobrien     void **slot;
22590075Sobrien     void *info;
22690075Sobrien{
22790075Sobrien  struct d_htab_root *r = (struct d_htab_root *) info;
22890075Sobrien
22990075Sobrien  if (! (*r->marked_p) (*slot))
23090075Sobrien    htab_clear_slot (r->htab, slot);
23190075Sobrien  else if (r->mark)
23290075Sobrien    (*r->mark) (*slot);
23390075Sobrien
23490075Sobrien  return 1;
23590075Sobrien}
23690075Sobrien
23790075Sobrien/* Iterate through all registered roots and mark each element.  */
23890075Sobrien
23990075Sobrienvoid
24090075Sobrienggc_mark_roots ()
24190075Sobrien{
24290075Sobrien  struct ggc_root *x;
24390075Sobrien  struct d_htab_root *y;
24490075Sobrien
24590075Sobrien  VARRAY_TREE_INIT (ggc_pending_trees, 4096, "ggc_pending_trees");
24690075Sobrien
24790075Sobrien  for (x = roots; x != NULL; x = x->next)
24890075Sobrien    {
24990075Sobrien      char *elt = x->base;
25090075Sobrien      int s = x->size, n = x->nelt;
25190075Sobrien      void (*cb) PARAMS ((void *)) = x->cb;
25290075Sobrien      int i;
25390075Sobrien
25490075Sobrien      for (i = 0; i < n; ++i, elt += s)
25590075Sobrien	(*cb)(elt);
25690075Sobrien    }
25790075Sobrien
25890075Sobrien  /* Mark all the queued up trees, and their children.  */
25990075Sobrien  ggc_mark_trees ();
26090075Sobrien  VARRAY_FREE (ggc_pending_trees);
26190075Sobrien
26290075Sobrien  /* Now scan all hash tables that have objects which are to be deleted if
26390075Sobrien     they are not already marked.  Since these may mark more trees, we need
26490075Sobrien     to reinitialize that varray.  */
26590075Sobrien  VARRAY_TREE_INIT (ggc_pending_trees, 1024, "ggc_pending_trees");
26690075Sobrien
26790075Sobrien  for (y = d_htab_roots; y != NULL; y = y->next)
26890075Sobrien    htab_traverse (y->htab, ggc_htab_delete, (PTR) y);
26990075Sobrien  ggc_mark_trees ();
27090075Sobrien  VARRAY_FREE (ggc_pending_trees);
27190075Sobrien}
27290075Sobrien
27390075Sobrien/* R had not been previously marked, but has now been marked via
27490075Sobrien   ggc_set_mark.  Now recurse and process the children.  */
27590075Sobrien
27690075Sobrienvoid
27790075Sobrienggc_mark_rtx_children (r)
27890075Sobrien     rtx r;
27990075Sobrien{
28090075Sobrien  const char *fmt;
28190075Sobrien  int i;
28290075Sobrien  rtx next_rtx;
28390075Sobrien
28490075Sobrien  do
28590075Sobrien    {
28690075Sobrien      enum rtx_code code = GET_CODE (r);
28790075Sobrien      /* This gets set to a child rtx to eliminate tail recursion.  */
28890075Sobrien      next_rtx = NULL;
28990075Sobrien
29090075Sobrien      /* Collect statistics, if appropriate.  */
29190075Sobrien      if (ggc_stats)
29290075Sobrien	{
29390075Sobrien	  ++ggc_stats->num_rtxs[(int) code];
29490075Sobrien	  ggc_stats->size_rtxs[(int) code] += ggc_get_size (r);
29590075Sobrien	}
29690075Sobrien
29790075Sobrien      /* ??? If (some of) these are really pass-dependent info, do we
29890075Sobrien	 have any right poking our noses in?  */
29990075Sobrien      switch (code)
30090075Sobrien	{
30190075Sobrien	case MEM:
30290075Sobrien	  ggc_mark (MEM_ATTRS (r));
30390075Sobrien	  break;
30490075Sobrien	case JUMP_INSN:
30590075Sobrien	  ggc_mark_rtx (JUMP_LABEL (r));
30690075Sobrien	  break;
30790075Sobrien	case CODE_LABEL:
30890075Sobrien	  ggc_mark_rtx (LABEL_REFS (r));
30990075Sobrien	  break;
31090075Sobrien	case LABEL_REF:
31190075Sobrien	  ggc_mark_rtx (LABEL_NEXTREF (r));
31290075Sobrien	  ggc_mark_rtx (CONTAINING_INSN (r));
31390075Sobrien	  break;
31490075Sobrien	case ADDRESSOF:
31590075Sobrien	  ggc_mark_tree (ADDRESSOF_DECL (r));
31690075Sobrien	  break;
31790075Sobrien	case CONST_DOUBLE:
31890075Sobrien	  ggc_mark_rtx (CONST_DOUBLE_CHAIN (r));
31990075Sobrien	  break;
32090075Sobrien	case NOTE:
32190075Sobrien	  switch (NOTE_LINE_NUMBER (r))
32290075Sobrien	    {
32390075Sobrien	    case NOTE_INSN_RANGE_BEG:
32490075Sobrien	    case NOTE_INSN_RANGE_END:
32590075Sobrien	    case NOTE_INSN_LIVE:
32690075Sobrien	    case NOTE_INSN_EXPECTED_VALUE:
32790075Sobrien	      ggc_mark_rtx (NOTE_RANGE_INFO (r));
32890075Sobrien	      break;
32990075Sobrien
33090075Sobrien	    case NOTE_INSN_BLOCK_BEG:
33190075Sobrien	    case NOTE_INSN_BLOCK_END:
33290075Sobrien	      ggc_mark_tree (NOTE_BLOCK (r));
33390075Sobrien	      break;
33490075Sobrien
33590075Sobrien	    default:
33690075Sobrien	      break;
33790075Sobrien	    }
33890075Sobrien	  break;
33990075Sobrien
34090075Sobrien	default:
34190075Sobrien	  break;
34290075Sobrien	}
34390075Sobrien
34490075Sobrien      for (fmt = GET_RTX_FORMAT (GET_CODE (r)), i = 0; *fmt ; ++fmt, ++i)
34590075Sobrien	{
34690075Sobrien	  rtx exp;
34790075Sobrien	  switch (*fmt)
34890075Sobrien	    {
34990075Sobrien	    case 'e': case 'u':
35090075Sobrien	      exp = XEXP (r, i);
35190075Sobrien	      if (ggc_test_and_set_mark (exp))
35290075Sobrien		{
35390075Sobrien		  if (next_rtx == NULL)
35490075Sobrien		    next_rtx = exp;
35590075Sobrien		  else
35690075Sobrien		    ggc_mark_rtx_children (exp);
35790075Sobrien		}
35890075Sobrien	      break;
35990075Sobrien	    case 'V': case 'E':
36090075Sobrien	      ggc_mark_rtvec (XVEC (r, i));
36190075Sobrien	      break;
36290075Sobrien	    }
36390075Sobrien	}
36490075Sobrien    }
36590075Sobrien  while ((r = next_rtx) != NULL);
36690075Sobrien}
36790075Sobrien
36890075Sobrien/* V had not been previously marked, but has now been marked via
36990075Sobrien   ggc_set_mark.  Now recurse and process the children.  */
37090075Sobrien
37190075Sobrienvoid
37290075Sobrienggc_mark_rtvec_children (v)
37390075Sobrien     rtvec v;
37490075Sobrien{
37590075Sobrien  int i;
37690075Sobrien
37790075Sobrien  i = GET_NUM_ELEM (v);
37890075Sobrien  while (--i >= 0)
37990075Sobrien    ggc_mark_rtx (RTVEC_ELT (v, i));
38090075Sobrien}
38190075Sobrien
38290075Sobrien/* Recursively set marks on all of the children of the
38390075Sobrien   GCC_PENDING_TREES.  */
38490075Sobrien
38590075Sobrienstatic void
38690075Sobrienggc_mark_trees ()
38790075Sobrien{
38890075Sobrien  while (ggc_pending_trees->elements_used)
38990075Sobrien    {
39090075Sobrien      tree t;
39190075Sobrien      enum tree_code code;
39290075Sobrien
39390075Sobrien      t = VARRAY_TOP_TREE (ggc_pending_trees);
39490075Sobrien      VARRAY_POP (ggc_pending_trees);
39590075Sobrien      code = TREE_CODE (t);
39690075Sobrien
39790075Sobrien      /* Collect statistics, if appropriate.  */
39890075Sobrien      if (ggc_stats)
39990075Sobrien	{
40090075Sobrien	  ++ggc_stats->num_trees[(int) code];
40190075Sobrien	  ggc_stats->size_trees[(int) code] += ggc_get_size (t);
40290075Sobrien	}
40390075Sobrien
40490075Sobrien      /* Bits from common.  */
40590075Sobrien      ggc_mark_tree (TREE_TYPE (t));
40690075Sobrien      ggc_mark_tree (TREE_CHAIN (t));
40790075Sobrien
40890075Sobrien      /* Some nodes require special handling.  */
40990075Sobrien      switch (code)
41090075Sobrien	{
41190075Sobrien	case TREE_LIST:
41290075Sobrien	  ggc_mark_tree (TREE_PURPOSE (t));
41390075Sobrien	  ggc_mark_tree (TREE_VALUE (t));
41490075Sobrien	  continue;
41590075Sobrien
41690075Sobrien	case TREE_VEC:
41790075Sobrien	  {
41890075Sobrien	    int i = TREE_VEC_LENGTH (t);
41990075Sobrien
42090075Sobrien	    while (--i >= 0)
42190075Sobrien	      ggc_mark_tree (TREE_VEC_ELT (t, i));
42290075Sobrien	    continue;
42390075Sobrien	  }
42490075Sobrien
42590075Sobrien	case COMPLEX_CST:
42690075Sobrien	  ggc_mark_tree (TREE_REALPART (t));
42790075Sobrien	  ggc_mark_tree (TREE_IMAGPART (t));
42890075Sobrien	  break;
42990075Sobrien
43090075Sobrien	case PARM_DECL:
43190075Sobrien	  ggc_mark_rtx (DECL_INCOMING_RTL (t));
43290075Sobrien	  break;
43390075Sobrien
43490075Sobrien	case FIELD_DECL:
43590075Sobrien	  ggc_mark_tree (DECL_FIELD_BIT_OFFSET (t));
43690075Sobrien	  break;
43790075Sobrien
43890075Sobrien	case IDENTIFIER_NODE:
43990075Sobrien	  lang_mark_tree (t);
44090075Sobrien	  continue;
44190075Sobrien
44290075Sobrien	default:
44390075Sobrien	  break;
44490075Sobrien	}
44590075Sobrien
44690075Sobrien      /* But in general we can handle them by class.  */
44790075Sobrien      switch (TREE_CODE_CLASS (code))
44890075Sobrien	{
44990075Sobrien	case 'd': /* A decl node.  */
45090075Sobrien	  ggc_mark_tree (DECL_SIZE (t));
45190075Sobrien	  ggc_mark_tree (DECL_SIZE_UNIT (t));
45290075Sobrien	  ggc_mark_tree (DECL_NAME (t));
45390075Sobrien	  ggc_mark_tree (DECL_CONTEXT (t));
45490075Sobrien	  ggc_mark_tree (DECL_ARGUMENTS (t));
45590075Sobrien	  ggc_mark_tree (DECL_RESULT_FLD (t));
45690075Sobrien	  ggc_mark_tree (DECL_INITIAL (t));
45790075Sobrien	  ggc_mark_tree (DECL_ABSTRACT_ORIGIN (t));
45890075Sobrien	  ggc_mark_tree (DECL_SECTION_NAME (t));
45990075Sobrien	  ggc_mark_tree (DECL_ATTRIBUTES (t));
46090075Sobrien	  if (DECL_RTL_SET_P (t))
46190075Sobrien	    ggc_mark_rtx (DECL_RTL (t));
46290075Sobrien	  ggc_mark_rtx (DECL_LIVE_RANGE_RTL (t));
46390075Sobrien	  ggc_mark_tree (DECL_VINDEX (t));
46490075Sobrien	  if (DECL_ASSEMBLER_NAME_SET_P (t))
46590075Sobrien	    ggc_mark_tree (DECL_ASSEMBLER_NAME (t));
46690075Sobrien	  if (TREE_CODE (t) == FUNCTION_DECL)
46790075Sobrien	    {
46890075Sobrien	      ggc_mark_tree (DECL_SAVED_TREE (t));
46990075Sobrien	      ggc_mark_tree (DECL_INLINED_FNS (t));
47090075Sobrien	      if (DECL_SAVED_INSNS (t))
47190075Sobrien		ggc_mark_struct_function (DECL_SAVED_INSNS (t));
47290075Sobrien	    }
47390075Sobrien	  lang_mark_tree (t);
47490075Sobrien	  break;
47590075Sobrien
47690075Sobrien	case 't': /* A type node.  */
47790075Sobrien	  ggc_mark_tree (TYPE_SIZE (t));
47890075Sobrien	  ggc_mark_tree (TYPE_SIZE_UNIT (t));
47990075Sobrien	  ggc_mark_tree (TYPE_ATTRIBUTES (t));
48090075Sobrien	  ggc_mark_tree (TYPE_VALUES (t));
48190075Sobrien	  ggc_mark_tree (TYPE_POINTER_TO (t));
48290075Sobrien	  ggc_mark_tree (TYPE_REFERENCE_TO (t));
48390075Sobrien	  ggc_mark_tree (TYPE_NAME (t));
48490075Sobrien	  ggc_mark_tree (TYPE_MIN_VALUE (t));
48590075Sobrien	  ggc_mark_tree (TYPE_MAX_VALUE (t));
48690075Sobrien	  ggc_mark_tree (TYPE_NEXT_VARIANT (t));
48790075Sobrien	  ggc_mark_tree (TYPE_MAIN_VARIANT (t));
48890075Sobrien	  ggc_mark_tree (TYPE_BINFO (t));
48990075Sobrien	  ggc_mark_tree (TYPE_CONTEXT (t));
49090075Sobrien	  lang_mark_tree (t);
49190075Sobrien	  break;
49290075Sobrien
49390075Sobrien	case 'b': /* A lexical block.  */
49490075Sobrien	  ggc_mark_tree (BLOCK_VARS (t));
49590075Sobrien	  ggc_mark_tree (BLOCK_SUBBLOCKS (t));
49690075Sobrien	  ggc_mark_tree (BLOCK_SUPERCONTEXT (t));
49790075Sobrien	  ggc_mark_tree (BLOCK_ABSTRACT_ORIGIN (t));
49890075Sobrien	  break;
49990075Sobrien
50090075Sobrien	case 'c': /* A constant.  */
50190075Sobrien	  ggc_mark_rtx (TREE_CST_RTL (t));
50290075Sobrien	  break;
50390075Sobrien
50490075Sobrien	case 'r': case '<': case '1':
50590075Sobrien	case '2': case 'e': case 's': /* Expressions.  */
50690075Sobrien	  {
50790075Sobrien	    int i = TREE_CODE_LENGTH (TREE_CODE (t));
50890075Sobrien	    int first_rtl = first_rtl_op (TREE_CODE (t));
50990075Sobrien
51090075Sobrien	    while (--i >= 0)
51190075Sobrien	      {
51290075Sobrien		if (i >= first_rtl)
51390075Sobrien		  ggc_mark_rtx ((rtx) TREE_OPERAND (t, i));
51490075Sobrien		else
51590075Sobrien		  ggc_mark_tree (TREE_OPERAND (t, i));
51690075Sobrien	      }
51790075Sobrien	    break;
51890075Sobrien	  }
51990075Sobrien
52090075Sobrien	case 'x':
52190075Sobrien	  lang_mark_tree (t);
52290075Sobrien	  break;
52390075Sobrien	}
52490075Sobrien    }
52590075Sobrien}
52690075Sobrien
52790075Sobrien/* Mark all the elements of the varray V, which contains rtxs.  */
52890075Sobrien
52990075Sobrienvoid
53090075Sobrienggc_mark_rtx_varray (v)
53190075Sobrien     varray_type v;
53290075Sobrien{
53390075Sobrien  int i;
53490075Sobrien
53590075Sobrien  if (v)
53690075Sobrien    for (i = v->num_elements - 1; i >= 0; --i)
53790075Sobrien      ggc_mark_rtx (VARRAY_RTX (v, i));
53890075Sobrien}
53990075Sobrien
54090075Sobrien/* Mark all the elements of the varray V, which contains trees.  */
54190075Sobrien
54290075Sobrienvoid
54390075Sobrienggc_mark_tree_varray (v)
54490075Sobrien     varray_type v;
54590075Sobrien{
54690075Sobrien  int i;
54790075Sobrien
54890075Sobrien  if (v)
54990075Sobrien    for (i = v->num_elements - 1; i >= 0; --i)
55090075Sobrien      ggc_mark_tree (VARRAY_TREE (v, i));
55190075Sobrien}
55290075Sobrien
55390075Sobrien/* Mark the hash table-entry HE.  Its key field is really a tree.  */
55490075Sobrien
55590075Sobrienstatic bool
55690075Sobrienggc_mark_tree_hash_table_entry (he, k)
55790075Sobrien     struct hash_entry *he;
55890075Sobrien     hash_table_key k ATTRIBUTE_UNUSED;
55990075Sobrien{
56090075Sobrien  ggc_mark_tree ((tree) he->key);
56190075Sobrien  return true;
56290075Sobrien}
56390075Sobrien
56490075Sobrien/* Mark all the elements of the hash-table H, which contains trees.  */
56590075Sobrien
56690075Sobrienvoid
56790075Sobrienggc_mark_tree_hash_table (ht)
56890075Sobrien     struct hash_table *ht;
56990075Sobrien{
57090075Sobrien  hash_traverse (ht, ggc_mark_tree_hash_table_entry, /*info=*/0);
57190075Sobrien}
57290075Sobrien
57390075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
57490075Sobrien   *ELT (which is an rtx) to ggc_mark_rtx.  */
57590075Sobrien
57690075Sobrienstatic void
57790075Sobrienggc_mark_rtx_ptr (elt)
57890075Sobrien     void *elt;
57990075Sobrien{
58090075Sobrien  ggc_mark_rtx (*(rtx *) elt);
58190075Sobrien}
58290075Sobrien
58390075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
58490075Sobrien   *ELT (which is a tree) to ggc_mark_tree.  */
58590075Sobrien
58690075Sobrienstatic void
58790075Sobrienggc_mark_tree_ptr (elt)
58890075Sobrien     void *elt;
58990075Sobrien{
59090075Sobrien  ggc_mark_tree (*(tree *) elt);
59190075Sobrien}
59290075Sobrien
59390075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
59490075Sobrien   ELT (which is really a varray_type *) to ggc_mark_rtx_varray.  */
59590075Sobrien
59690075Sobrienstatic void
59790075Sobrienggc_mark_rtx_varray_ptr (elt)
59890075Sobrien     void *elt;
59990075Sobrien{
60090075Sobrien  ggc_mark_rtx_varray (*(varray_type *) elt);
60190075Sobrien}
60290075Sobrien
60390075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
60490075Sobrien   ELT (which is really a varray_type *) to ggc_mark_tree_varray.  */
60590075Sobrien
60690075Sobrienstatic void
60790075Sobrienggc_mark_tree_varray_ptr (elt)
60890075Sobrien     void *elt;
60990075Sobrien{
61090075Sobrien  ggc_mark_tree_varray (*(varray_type *) elt);
61190075Sobrien}
61290075Sobrien
61390075Sobrien/* Type-correct function to pass to ggc_add_root.  It just forwards
61490075Sobrien   ELT (which is really a struct hash_table **) to
61590075Sobrien   ggc_mark_tree_hash_table.  */
61690075Sobrien
61790075Sobrienstatic void
61890075Sobrienggc_mark_tree_hash_table_ptr (elt)
61990075Sobrien     void *elt;
62090075Sobrien{
62190075Sobrien  ggc_mark_tree_hash_table (*(struct hash_table **) elt);
62290075Sobrien}
62390075Sobrien
62490075Sobrien/* Allocate a block of memory, then clear it.  */
62590075Sobrienvoid *
62690075Sobrienggc_alloc_cleared (size)
62790075Sobrien     size_t size;
62890075Sobrien{
62990075Sobrien  void *buf = ggc_alloc (size);
63090075Sobrien  memset (buf, 0, size);
63190075Sobrien  return buf;
63290075Sobrien}
63390075Sobrien
63490075Sobrien/* Print statistics that are independent of the collector in use.  */
63590075Sobrien#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
63690075Sobrien		  ? (x) \
63790075Sobrien		  : ((x) < 1024*1024*10 \
63890075Sobrien		     ? (x) / 1024 \
63990075Sobrien		     : (x) / (1024*1024))))
64090075Sobrien#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
64190075Sobrien
64290075Sobrienvoid
64390075Sobrienggc_print_common_statistics (stream, stats)
64490075Sobrien     FILE *stream;
64590075Sobrien     ggc_statistics *stats;
64690075Sobrien{
64790075Sobrien  int code;
64890075Sobrien
64990075Sobrien  /* Set the pointer so that during collection we will actually gather
65090075Sobrien     the statistics.  */
65190075Sobrien  ggc_stats = stats;
65290075Sobrien
65390075Sobrien  /* Then do one collection to fill in the statistics.  */
65490075Sobrien  ggc_collect ();
65590075Sobrien
65690075Sobrien  /* Total the statistics.  */
65790075Sobrien  for (code = 0; code < MAX_TREE_CODES; ++code)
65890075Sobrien    {
65990075Sobrien      stats->total_num_trees += stats->num_trees[code];
66090075Sobrien      stats->total_size_trees += stats->size_trees[code];
66190075Sobrien    }
66290075Sobrien  for (code = 0; code < NUM_RTX_CODE; ++code)
66390075Sobrien    {
66490075Sobrien      stats->total_num_rtxs += stats->num_rtxs[code];
66590075Sobrien      stats->total_size_rtxs += stats->size_rtxs[code];
66690075Sobrien    }
66790075Sobrien
66890075Sobrien  /* Print the statistics for trees.  */
66990075Sobrien  fprintf (stream, "\n%-17s%10s %16s %10s\n", "Tree",
67090075Sobrien	   "Number", "Bytes", "% Total");
67190075Sobrien  for (code = 0; code < MAX_TREE_CODES; ++code)
67290075Sobrien    if (ggc_stats->num_trees[code])
67390075Sobrien      {
67490075Sobrien	fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
67590075Sobrien		 tree_code_name[code],
67690075Sobrien		 ggc_stats->num_trees[code],
67790075Sobrien		 SCALE (ggc_stats->size_trees[code]),
67890075Sobrien		 LABEL (ggc_stats->size_trees[code]),
67990075Sobrien		 (100 * ((double) ggc_stats->size_trees[code])
68090075Sobrien		  / ggc_stats->total_size_trees));
68190075Sobrien      }
68290075Sobrien  fprintf (stream,
68390075Sobrien	   "%-17s%10u%16ld%c\n", "Total",
68490075Sobrien	   ggc_stats->total_num_trees,
68590075Sobrien	   SCALE (ggc_stats->total_size_trees),
68690075Sobrien	   LABEL (ggc_stats->total_size_trees));
68790075Sobrien
68890075Sobrien  /* Print the statistics for RTL.  */
68990075Sobrien  fprintf (stream, "\n%-17s%10s %16s %10s\n", "RTX",
69090075Sobrien	   "Number", "Bytes", "% Total");
69190075Sobrien  for (code = 0; code < NUM_RTX_CODE; ++code)
69290075Sobrien    if (ggc_stats->num_rtxs[code])
69390075Sobrien      {
69490075Sobrien	fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
69590075Sobrien		 rtx_name[code],
69690075Sobrien		 ggc_stats->num_rtxs[code],
69790075Sobrien		 SCALE (ggc_stats->size_rtxs[code]),
69890075Sobrien		 LABEL (ggc_stats->size_rtxs[code]),
69990075Sobrien		 (100 * ((double) ggc_stats->size_rtxs[code])
70090075Sobrien		  / ggc_stats->total_size_rtxs));
70190075Sobrien      }
70290075Sobrien  fprintf (stream,
70390075Sobrien	   "%-17s%10u%16ld%c\n", "Total",
70490075Sobrien	   ggc_stats->total_num_rtxs,
70590075Sobrien	   SCALE (ggc_stats->total_size_rtxs),
70690075Sobrien	   LABEL (ggc_stats->total_size_rtxs));
70790075Sobrien
70890075Sobrien  /* Don't gather statistics any more.  */
70990075Sobrien  ggc_stats = NULL;
71090075Sobrien}
711