This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

C++ PATCH: Reduce memory usage



This patch avoids creating DECL_LANG_SPECIFIC for local variables and
types in templates.  (We didn't use to have DECL_LANG_SPECIFIC for
these; I added them to avoid doing name-lookups while instantiation
was happenning, which was ugly.  Now that we never recursively
instantiate templates, we can avoid both the ugliness and the extra
memory usage.)

As a side-effect, we also don't keep local variables in template
instantiations around once the instantiation has been compiled.
(Unfortunately, we do still have to keep them for inline template
instantiations, which is the vast majority.)

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-04-23  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (lang_decl): Remove pretty_function_p.
	(DECL_PRETTY_FUNCTION_P): Use TREE_LANG_FLAG_0, not a bit in the
	language-specific node.
	* decl.c (cp_make_fname_decl): Use build_decl, not
	build_lang_decl, to build the variables.
	(grokvardecl): Don't call build_lang_decl for local variables in
	templates.
	(grokdeclarator): Don't call build_lang_decl for local type
	declarations in templates.
	* lex.c (retrofit_lang_decl): Use ggc_alloc_obj to allocated
	zero'd memory, rather than calling memset.
	* pt.c: Include hashtab.h.
	(local_specializations): New variable.
	(retrieve_local_specialization): Use it.
	(register_local_specialization): Likewise.
	(tsubst_decl): Don't assume local variables have
	DECL_LANG_SPECIFIC.
	(instantiate_decl): Set up local_specializations.
	* Makefile.in (HTAB_H): New variable.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/Makefile.in,v
retrieving revision 1.83
diff -c -p -r1.83 Makefile.in
*** Makefile.in	2000/04/06 00:51:23	1.83
--- Makefile.in	2000/04/24 06:18:58
*************** PARSE_H = $(srcdir)/parse.h
*** 210,215 ****
--- 210,216 ----
  PARSE_C = $(srcdir)/parse.c
  EXPR_H = $(srcdir)/../expr.h ../insn-codes.h
  GGC_H = $(srcdir)/../ggc.h $(srcdir)/../varray.h
+ HTAB_H = $(srcdir)/../../include/hashtab.h
  
  parse.o : $(PARSE_C) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
  	$(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \
*************** xref.o : xref.c $(CXX_TREE_H) $(srcdir)/
*** 295,301 ****
    $(srcdir)/../toplev.h
  pt.o : pt.c $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
    $(srcdir)/../toplev.h $(GGC_H) $(RTL_H) \
!   $(srcdir)/../except.h
  error.o : error.c $(CXX_TREE_H) \
    $(srcdir)/../toplev.h
  errfn.o : errfn.c $(CXX_TREE_H) \
--- 296,302 ----
    $(srcdir)/../toplev.h
  pt.o : pt.c $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
    $(srcdir)/../toplev.h $(GGC_H) $(RTL_H) \
!   $(srcdir)/../except.h $(HTAB_H)
  error.o : error.c $(CXX_TREE_H) \
    $(srcdir)/../toplev.h
  errfn.o : errfn.c $(CXX_TREE_H) \
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.444
diff -c -p -r1.444 cp-tree.h
*** cp-tree.h	2000/04/18 20:21:38	1.444
--- cp-tree.h	2000/04/24 06:19:02
*************** Boston, MA 02111-1307, USA.  */
*** 43,48 ****
--- 43,49 ----
        AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR)
        SCOPE_BEGIN_P (in SCOPE_STMT)
        CTOR_BEGIN_P (in CTOR_STMT)
+       DECL_PRETTY_FUNCTION_P (in VAR_DECL)
     1: IDENTIFIER_VIRTUAL_P.
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
*************** struct lang_decl_flags
*** 1866,1872 ****
    unsigned static_function : 1;
    unsigned pure_virtual : 1;
    unsigned has_in_charge_parm_p : 1;
!   unsigned pretty_function_p : 1;
  
    unsigned mutable_flag : 1;
    unsigned deferred : 1;
--- 1867,1873 ----
    unsigned static_function : 1;
    unsigned pure_virtual : 1;
    unsigned has_in_charge_parm_p : 1;
!   unsigned bitfield : 1;
  
    unsigned mutable_flag : 1;
    unsigned deferred : 1;
*************** struct lang_decl_flags
*** 1876,1887 ****
    unsigned not_really_extern : 1;
    unsigned needs_final_overrider : 1;
  
-   unsigned bitfield : 1;
    unsigned defined_in_class : 1;
    unsigned pending_inline_p : 1;
    unsigned global_ctor_p : 1;
    unsigned global_dtor_p : 1;
!   unsigned dummy : 3;
  
    tree context;
  
--- 1877,1887 ----
    unsigned not_really_extern : 1;
    unsigned needs_final_overrider : 1;
  
    unsigned defined_in_class : 1;
    unsigned pending_inline_p : 1;
    unsigned global_ctor_p : 1;
    unsigned global_dtor_p : 1;
!   unsigned dummy : 4;
  
    tree context;
  
*************** struct lang_decl
*** 2106,2112 ****
  /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
     template function.  */
  #define DECL_PRETTY_FUNCTION_P(NODE) \
!   (DECL_LANG_SPECIFIC(NODE)->decl_flags.pretty_function_p)
  
  /* The _TYPE context in which this _DECL appears.  This field holds the
     class where a virtual function instance is actually defined. */
--- 2106,2112 ----
  /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
     template function.  */
  #define DECL_PRETTY_FUNCTION_P(NODE) \
!   (TREE_LANG_FLAG_0 (NODE))
  
  /* The _TYPE context in which this _DECL appears.  This field holds the
     class where a virtual function instance is actually defined. */
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.593
diff -c -p -r1.593 decl.c
*** decl.c	2000/04/18 20:21:39	1.593
--- decl.c	2000/04/24 06:19:11
*************** cp_make_fname_decl (id, name, type_dep)
*** 6550,6556 ****
            (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
  	   domain);
  
!   decl = build_lang_decl (VAR_DECL, id, type);
    TREE_STATIC (decl) = 1;
    TREE_READONLY (decl) = 1;
    DECL_SOURCE_LINE (decl) = 0;
--- 6550,6556 ----
            (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
  	   domain);
  
!   decl = build_decl (VAR_DECL, id, type);
    TREE_STATIC (decl) = 1;
    TREE_READONLY (decl) = 1;
    DECL_SOURCE_LINE (decl) = 0;
*************** grokvardecl (type, declarator, specbits_
*** 8924,8932 ****
        else
  	context = NULL_TREE;
  
!       if (processing_template_decl)
! 	/* If we're in a template, we need DECL_LANG_SPECIFIC so that
! 	   we can call push_template_decl.  */
  	decl = build_lang_decl (VAR_DECL, declarator, type);
        else
  	decl = build_decl (VAR_DECL, declarator, type);
--- 8924,8932 ----
        else
  	context = NULL_TREE;
  
!       if (processing_template_decl && context)
! 	/* For global variables, declared in a template, we need the
! 	   full lang_decl.  */
  	decl = build_lang_decl (VAR_DECL, declarator, type);
        else
  	decl = build_decl (VAR_DECL, declarator, type);
*************** grokdeclarator (declarator, declspecs, d
*** 10917,10930 ****
  	  decl = build_lang_decl (TYPE_DECL, declarator, type);
  	}
        else
! 	{
! 	  /* Make sure this typedef lives as long as its type,
! 	     since it might be used as a template parameter. */
! 	  if (processing_template_decl)
! 	    decl = build_lang_decl (TYPE_DECL, declarator, type);
! 	  else
! 	    decl = build_decl (TYPE_DECL, declarator, type);
! 	}
  
        /* If the user declares "typedef struct {...} foo" then the
  	 struct will have an anonymous name.  Fill that name in now.
--- 10917,10923 ----
  	  decl = build_lang_decl (TYPE_DECL, declarator, type);
  	}
        else
! 	decl = build_decl (TYPE_DECL, declarator, type);
  
        /* If the user declares "typedef struct {...} foo" then the
  	 struct will have an anonymous name.  Fill that name in now.
Index: lex.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/lex.c,v
retrieving revision 1.192
diff -c -p -r1.192 lex.c
*** lex.c	2000/04/11 16:27:38	1.192
--- lex.c	2000/04/24 06:19:17
*************** retrofit_lang_decl (t)
*** 4977,4984 ****
    else
      size = sizeof (struct lang_decl_flags);
  
!   ld = (struct lang_decl *) ggc_alloc (size);
!   memset (ld, 0, size);
  
    DECL_LANG_SPECIFIC (t) = ld;
    if (current_lang_name == lang_name_cplusplus)
--- 4977,4983 ----
    else
      size = sizeof (struct lang_decl_flags);
  
!   ld = (struct lang_decl *) ggc_alloc_obj (size, 1);
  
    DECL_LANG_SPECIFIC (t) = ld;
    if (current_lang_name == lang_name_cplusplus)
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.420
diff -c -p -r1.420 pt.c
*** pt.c	2000/04/11 20:16:35	1.420
--- pt.c	2000/04/24 06:19:23
*************** Boston, MA 02111-1307, USA.  */
*** 43,48 ****
--- 43,49 ----
  #include "rtl.h"
  #include "defaults.h"
  #include "ggc.h"
+ #include "hashtab.h"
  
  /* The type of functions taking a tree, and some additional data, and
     returning an int.  */
*************** static int template_header_count;
*** 72,77 ****
--- 73,79 ----
  static tree saved_trees;
  static varray_type inline_parm_levels;
  static size_t inline_parm_levels_used;
+ static htab_t local_specializations;
  
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free free
*************** static tree build_template_parm_index PA
*** 119,127 ****
  static int inline_needs_template_parms PARAMS ((tree));
  static void push_inline_template_parms_recursive PARAMS ((tree, int));
  static tree retrieve_specialization PARAMS ((tree, tree));
! static tree retrieve_local_specialization PARAMS ((tree, tree));
  static tree register_specialization PARAMS ((tree, tree, tree));
! static tree register_local_specialization PARAMS ((tree, tree, tree));
  static int unregister_specialization PARAMS ((tree, tree));
  static tree reduce_template_parm_level PARAMS ((tree, tree, int));
  static tree build_template_decl PARAMS ((tree, tree));
--- 121,129 ----
  static int inline_needs_template_parms PARAMS ((tree));
  static void push_inline_template_parms_recursive PARAMS ((tree, int));
  static tree retrieve_specialization PARAMS ((tree, tree));
! static tree retrieve_local_specialization PARAMS ((tree));
  static tree register_specialization PARAMS ((tree, tree, tree));
! static tree register_local_specialization PARAMS ((tree, tree));
  static int unregister_specialization PARAMS ((tree, tree));
  static tree reduce_template_parm_level PARAMS ((tree, tree, int));
  static tree build_template_decl PARAMS ((tree, tree));
*************** retrieve_specialization (tmpl, args)
*** 709,724 ****
    return NULL_TREE;
  }
  
! /* Like retrieve_speciailization, but for local declarations.  FN is
!    the function in which we are looking for an instantiation.  */
  
  static tree
! retrieve_local_specialization (tmpl, fn)
       tree tmpl;
-      tree fn;
  {
!   tree s = purpose_member (fn, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
!   return s ? TREE_VALUE (s) : NULL_TREE;
  }
  
  /* Returns non-zero iff DECL is a specialization of TMPL.  */
--- 711,723 ----
    return NULL_TREE;
  }
  
! /* Like retrieve_speciailization, but for local declarations.  */
  
  static tree
! retrieve_local_specialization (tmpl)
       tree tmpl;
  {
!   return (tree) htab_find (local_specializations, tmpl);
  }
  
  /* Returns non-zero iff DECL is a specialization of TMPL.  */
*************** unregister_specialization (spec, tmpl)
*** 885,902 ****
    return 0;
  }
  
! /* Like register_specialization, but for local declarations.  FN is
!    the function in which we are registering SPEC, an instantiation of
!    TMPL.  */
  
  static tree
! register_local_specialization (spec, tmpl, fn)
       tree spec;
       tree tmpl;
-      tree fn;
  {
!   DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
!      = tree_cons (fn, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
  
    return spec;
  }
--- 884,901 ----
    return 0;
  }
  
! /* Like register_specialization, but for local declarations.  We are
!    registering SPEC, an instantiation of TMPL.  */
  
  static tree
! register_local_specialization (spec, tmpl)
       tree spec;
       tree tmpl;
  {
!   void **slot;
! 
!   slot = htab_find_slot (local_specializations, tmpl, INSERT);
!   *slot = spec;
  
    return spec;
  }
*************** convert_template_argument (parm, arg, ar
*** 3307,3316 ****
     If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
     provided in ARGLIST, or else trailing parameters must have default
     values.  If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
!    deduction for any unspecified trailing arguments.  
! 
!    The resulting TREE_VEC is allocated on a temporary obstack, and
!    must be explicitly copied if it will be permanent.  */
     
  static tree
  coerce_template_parms (parms, args, in_decl,
--- 3306,3312 ----
     If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
     provided in ARGLIST, or else trailing parameters must have default
     values.  If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
!    deduction for any unspecified trailing arguments.  */
     
  static tree
  coerce_template_parms (parms, args, in_decl,
*************** tsubst_decl (t, args, type, in_decl)
*** 5857,5863 ****
  	  r = TYPE_NAME (type);
  	  break;
  	}
!       else if (!DECL_LANG_SPECIFIC (t))
  	{
  	  /* For a template type parameter, we don't have to do
  	     anything special.  */
--- 5853,5860 ----
  	  r = TYPE_NAME (type);
  	  break;
  	}
!       else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
! 	       || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
  	{
  	  /* For a template type parameter, we don't have to do
  	     anything special.  */
*************** tsubst_decl (t, args, type, in_decl)
*** 5874,5901 ****
  	tree spec;
  	tree tmpl;
  	tree ctx;
  
! 	/* Nobody should be tsubst'ing into non-template variables.  */
! 	my_friendly_assert (DECL_LANG_SPECIFIC (t) 
! 			    && DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
  
  	if (TYPE_P (CP_DECL_CONTEXT (t)))
  	  ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, 
  				  /*complain=*/1,
  				  in_decl, /*entering_scope=*/1);
  	else
! 	  /* Subsequent calls to pushdecl will fill this in.  */
! 	  ctx = NULL_TREE;
  
  	/* Check to see if we already have this specialization.  */
! 	tmpl = DECL_TI_TEMPLATE (t);
! 	gen_tmpl = most_general_template (tmpl);
! 	argvec = tsubst (DECL_TI_ARGS (t), args, /*complain=*/1, in_decl);
! 	if (ctx)
! 	  spec = retrieve_specialization (gen_tmpl, argvec);
  	else
! 	  spec = retrieve_local_specialization (gen_tmpl,
! 						current_function_decl);
  
  	if (spec)
  	  {
--- 5871,5903 ----
  	tree spec;
  	tree tmpl;
  	tree ctx;
+ 	int local_p;
  
! 	/* Assume this is a non-local variable.  */
! 	local_p = 0;
  
  	if (TYPE_P (CP_DECL_CONTEXT (t)))
  	  ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, 
  				  /*complain=*/1,
  				  in_decl, /*entering_scope=*/1);
  	else
! 	  {
! 	    /* Subsequent calls to pushdecl will fill this in.  */
! 	    ctx = NULL_TREE;
! 	    if (!DECL_NAMESPACE_SCOPE_P (t))
! 	      local_p = 1;
! 	  }
  
  	/* Check to see if we already have this specialization.  */
! 	if (!local_p)
! 	  {
! 	    tmpl = DECL_TI_TEMPLATE (t);
! 	    gen_tmpl = most_general_template (tmpl);
! 	    argvec = tsubst (DECL_TI_ARGS (t), args, /*complain=*/1, in_decl);
! 	    spec = retrieve_specialization (gen_tmpl, argvec);
! 	  }
  	else
! 	  spec = retrieve_local_specialization (t);
  
  	if (spec)
  	  {
*************** tsubst_decl (t, args, type, in_decl)
*** 5929,5947 ****
  	if (TREE_CODE (r) == VAR_DECL)
  	  DECL_DEAD_FOR_LOCAL (r) = 0;
  
! 	/* A static data member declaration is always marked external
! 	   when it is declared in-class, even if an initializer is
! 	   present.  We mimic the non-template processing here.  */
! 	if (ctx)
! 	  DECL_EXTERNAL (r) = 1;
  
! 	DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
! 	SET_DECL_IMPLICIT_INSTANTIATION (r);
! 	if (ctx)
! 	  register_specialization (r, gen_tmpl, argvec);
  	else
! 	  register_local_specialization (r, gen_tmpl,
! 					 current_function_decl);
  
  	TREE_CHAIN (r) = NULL_TREE;
  	if (TREE_CODE (r) == VAR_DECL && TREE_CODE (type) == VOID_TYPE)
--- 5931,5950 ----
  	if (TREE_CODE (r) == VAR_DECL)
  	  DECL_DEAD_FOR_LOCAL (r) = 0;
  
! 	if (!local_p)
! 	  {
! 	    /* A static data member declaration is always marked
! 	       external when it is declared in-class, even if an
! 	       initializer is present.  We mimic the non-template
! 	       processing here.  */
! 	    DECL_EXTERNAL (r) = 1;
  
! 	    register_specialization (r, gen_tmpl, argvec);
! 	    DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
! 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
! 	  }
  	else
! 	  register_local_specialization (r, t);
  
  	TREE_CHAIN (r) = NULL_TREE;
  	if (TREE_CODE (r) == VAR_DECL && TREE_CODE (type) == VOID_TYPE)
*************** instantiate_decl (d, defer_ok)
*** 9616,9621 ****
--- 9619,9631 ----
      }
    else if (TREE_CODE (d) == FUNCTION_DECL)
      {
+       /* Set up the list of local specializations.  */
+       my_friendly_assert (local_specializations == NULL, 20000422);
+       local_specializations = htab_create (37, 
+ 					   htab_hash_pointer,
+ 					   htab_eq_pointer,
+ 					   NULL);
+ 
        /* Set up context.  */
        start_function (NULL_TREE, d, NULL_TREE, SF_PRE_PARSED);
        store_parm_decls ();
*************** instantiate_decl (d, defer_ok)
*** 9627,9632 ****
--- 9637,9646 ----
        /* Substitute into the body of the function.  */
        tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
  		   /*complain=*/1, tmpl);
+ 
+       /* We don't need the local specializations any more.  */
+       htab_delete (local_specializations);
+       local_specializations = NULL;
  
        /* Finish the function.  */
        expand_body (finish_function (0));

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]