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