C++ PATCH: Memory savings during mangling

Mark Mitchell mark@codesourcery.com
Wed Aug 25 17:28:00 GMT 2004


This patch reduces the memory usage of G++ in two ways: (1) instead of
freeing and reallocating the substitution table for every mangled
name, we just clear it out and reuse it, and (2) mangled names are
built up on the same obstack used for the identifier hash table, so
that we do not have to copy them there (via get_identifier).  I don't
have precise numbers for this patch, but previous measurements showed
that a significant fraction of the calls to ggc_alloc were coming from
the substitution buffer.

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-08-25  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (mangle_type): Remove.
	* mangle.c (globals): GTY it.
	(mangle_obstack): New variable.
	(name_obstack): Likewise.
	(name_base): Likewise.
	(write_char): Adjust accordingly.
	(write_chars): Likewise.
	(write_string): Likewise.
	(start_mangling): Initialize G.substitutions only one.  Add
	ident_p parameter.
	(finish_mangling): Use VARRAY_CLEAR to reclaim
	storage in G.substitutions.  Use obstack_finish.
	(init_mangle): Adjust for changes to variable names above.
	Initialize G.substitutions.
	(mangle_decl_string): Adjust call to start_mangling.
	(get_identifier_nocopy): New function.
	(mangle_decl): Use it.
	(mangle_type_string): Adjust call to start_mangling.
	(mangle_special_for_type): Likewise.
	(mangle_vtt_for_type): Likewise.
	(mangle_ctor_vtbl_for_type): Likewise.
	(mangle_thunk): Likewise.
	(mangle_guard_variable): Likewise.
	(mangle_ref_init_variable): Likewise.

Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1033
diff -c -5 -p -r1.1033 cp-tree.h
*** cp/cp-tree.h	19 Aug 2004 21:34:36 -0000	1.1033
--- cp/cp-tree.h	25 Aug 2004 16:50:21 -0000
*************** extern tree merge_exception_specifiers  
*** 4356,4366 ****
  
  /* in mangle.c */
  extern void init_mangle                         (void);
  extern void mangle_decl                         (tree);
  extern const char *mangle_type_string           (tree);
- extern tree mangle_type                         (tree);
  extern tree mangle_typeinfo_for_type            (tree);
  extern tree mangle_typeinfo_string_for_type     (tree);
  extern tree mangle_vtbl_for_type                (tree);
  extern tree mangle_vtt_for_type                 (tree);
  extern tree mangle_ctor_vtbl_for_type           (tree, tree);
--- 4356,4365 ----
Index: cp/mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.105
diff -c -5 -p -r1.105 mangle.c
*** cp/mangle.c	16 Aug 2004 02:07:58 -0000	1.105
--- cp/mangle.c	25 Aug 2004 16:50:21 -0000
***************
*** 90,115 ****
     && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM			\
         || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL			\
  	   && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
  
  /* Things we only need one of.  This module is not reentrant.  */
! static struct globals
  {
-   /* The name in which we're building the mangled name.  */
-   struct obstack name_obstack;
- 
    /* An array of the current substitution candidates, in the order
       we've seen them.  */
    varray_type substitutions;
  
    /* The entity that is being mangled.  */
!   tree entity;
  
    /* True if the mangling will be different in a future version of the
       ABI.  */
    bool need_abi_warning;
! } G;
  
  /* Indices into subst_identifiers.  These are identifiers used in
     special substitution rules.  */
  typedef enum
  {
--- 90,125 ----
     && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM			\
         || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL			\
  	   && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
  
  /* Things we only need one of.  This module is not reentrant.  */
! typedef struct globals GTY(())
  {
    /* An array of the current substitution candidates, in the order
       we've seen them.  */
    varray_type substitutions;
  
    /* The entity that is being mangled.  */
!   tree GTY ((skip)) entity;
  
    /* True if the mangling will be different in a future version of the
       ABI.  */
    bool need_abi_warning;
! } globals;
! 
! static GTY (()) globals G;
! 
! /* The obstack on which we build mangled names.  */
! static struct obstack *mangle_obstack;
! 
! /* The obstack on which we build mangled names that are not going to
!    be IDENTIFIER_NODEs.  */
! static struct obstack name_obstack;
! 
!   /* The first object on the name_obstack; we use this to free memory
!      allocated on the name_obstack.  */
! static void *name_base;
  
  /* Indices into subst_identifiers.  These are identifiers used in
     special substitution rules.  */
  typedef enum
  {
*************** static void write_local_name (const tree
*** 204,234 ****
  static void dump_substitution_candidates (void);
  static const char *mangle_decl_string (const tree);
  
  /* Control functions.  */
  
! static inline void start_mangling (const tree);
  static inline const char *finish_mangling (const bool);
  static tree mangle_special_for_type (const tree, const char *);
  
  /* Foreign language functions.  */
  
  static void write_java_integer_type_codes (const tree);
  
  /* Append a single character to the end of the mangled
     representation.  */
  #define write_char(CHAR)                                              \
!   obstack_1grow (&G.name_obstack, (CHAR))
  
  /* Append a sized buffer to the end of the mangled representation.  */
  #define write_chars(CHAR, LEN)                                        \
!   obstack_grow (&G.name_obstack, (CHAR), (LEN))
  
  /* Append a NUL-terminated string to the end of the mangled
     representation.  */
  #define write_string(STRING)                                          \
!   obstack_grow (&G.name_obstack, (STRING), strlen (STRING))
  
  /* Nonzero if NODE1 and NODE2 are both TREE_LIST nodes and have the
     same purpose (context, which may be a type) and value (template
     decl).  See write_template_prefix for more information on what this
     is used for.  */
--- 214,244 ----
  static void dump_substitution_candidates (void);
  static const char *mangle_decl_string (const tree);
  
  /* Control functions.  */
  
! static inline void start_mangling (const tree, bool);
  static inline const char *finish_mangling (const bool);
  static tree mangle_special_for_type (const tree, const char *);
  
  /* Foreign language functions.  */
  
  static void write_java_integer_type_codes (const tree);
  
  /* Append a single character to the end of the mangled
     representation.  */
  #define write_char(CHAR)                                              \
!   obstack_1grow (mangle_obstack, (CHAR))
  
  /* Append a sized buffer to the end of the mangled representation.  */
  #define write_chars(CHAR, LEN)                                        \
!   obstack_grow (mangle_obstack, (CHAR), (LEN))
  
  /* Append a NUL-terminated string to the end of the mangled
     representation.  */
  #define write_string(STRING)                                          \
!   obstack_grow (mangle_obstack, (STRING), strlen (STRING))
  
  /* Nonzero if NODE1 and NODE2 are both TREE_LIST nodes and have the
     same purpose (context, which may be a type) and value (template
     decl).  See write_template_prefix for more information on what this
     is used for.  */
*************** write_substitution (const int seq_id)
*** 2399,2414 ****
  }
  
  /* Start mangling ENTITY.  */
  
  static inline void
! start_mangling (const tree entity)
  {
    G.entity = entity;
    G.need_abi_warning = false;
!   VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
!   obstack_free (&G.name_obstack, obstack_base (&G.name_obstack));
  }
  
  /* Done with mangling.  Return the generated mangled name.  If WARN is
     true, and the name of G.entity will be mangled differently in a
     future version of the ABI, issue a warning.  */
--- 2409,2430 ----
  }
  
  /* Start mangling ENTITY.  */
  
  static inline void
! start_mangling (const tree entity, const bool ident_p)
  {
    G.entity = entity;
    G.need_abi_warning = false;
!   if (!ident_p) 
!     {
!       obstack_free (&name_obstack, name_base);
!       mangle_obstack = &name_obstack;
!       name_base = obstack_alloc (&name_obstack, 0);
!     }
!   else
!     mangle_obstack = &ident_hash->stack;
  }
  
  /* Done with mangling.  Return the generated mangled name.  If WARN is
     true, and the name of G.entity will be mangled differently in a
     future version of the ABI, issue a warning.  */
*************** finish_mangling (const bool warn)
*** 2420,2443 ****
      warning ("the mangled name of `%D' will change in a future "
  	     "version of GCC",
  	     G.entity);
  
    /* Clear all the substitutions.  */
!   G.substitutions = 0;
  
    /* Null-terminate the string.  */
    write_char ('\0');
  
!   return (const char *) obstack_base (&G.name_obstack);
  }
  
  /* Initialize data structures for mangling.  */
  
  void
  init_mangle (void)
  {
!   gcc_obstack_init (&G.name_obstack);
  
    /* Cache these identifiers for quick comparison when checking for
       standard substitutions.  */
    subst_identifiers[SUBID_ALLOCATOR] = get_identifier ("allocator");
    subst_identifiers[SUBID_BASIC_STRING] = get_identifier ("basic_string");
--- 2436,2461 ----
      warning ("the mangled name of `%D' will change in a future "
  	     "version of GCC",
  	     G.entity);
  
    /* Clear all the substitutions.  */
!   VARRAY_CLEAR (G.substitutions);
  
    /* Null-terminate the string.  */
    write_char ('\0');
  
!   return (const char *) obstack_finish (mangle_obstack);
  }
  
  /* Initialize data structures for mangling.  */
  
  void
  init_mangle (void)
  {
!   gcc_obstack_init (&name_obstack);
!   name_base = obstack_alloc (&name_obstack, 0);
!   VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
  
    /* Cache these identifiers for quick comparison when checking for
       standard substitutions.  */
    subst_identifiers[SUBID_ALLOCATOR] = get_identifier ("allocator");
    subst_identifiers[SUBID_BASIC_STRING] = get_identifier ("basic_string");
*************** init_mangle (void)
*** 2452,2462 ****
  static const char *
  mangle_decl_string (const tree decl)
  {
    const char *result;
  
!   start_mangling (decl);
  
    if (TREE_CODE (decl) == TYPE_DECL)
      write_type (TREE_TYPE (decl));
    else
      write_mangled_name (decl, true);
--- 2470,2480 ----
  static const char *
  mangle_decl_string (const tree decl)
  {
    const char *result;
  
!   start_mangling (decl, /*ident_p=*/true);
  
    if (TREE_CODE (decl) == TYPE_DECL)
      write_type (TREE_TYPE (decl));
    else
      write_mangled_name (decl, true);
*************** mangle_decl_string (const tree decl)
*** 2465,2507 ****
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
    return result;
  }
  
  /* Create an identifier for the external mangled name of DECL.  */
  
  void
  mangle_decl (const tree decl)
  {
!   tree id = get_identifier (mangle_decl_string (decl));
! 
!   SET_DECL_ASSEMBLER_NAME (decl, id);
  }
  
  /* Generate the mangled representation of TYPE.  */
  
  const char *
  mangle_type_string (const tree type)
  {
    const char *result;
  
!   start_mangling (type);
    write_type (type);
    result = finish_mangling (/*warn=*/false);
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
    return result;
  }
  
- /* Create an identifier for the mangled representation of TYPE.  */
- 
- tree
- mangle_type (const tree type)
- {
-   return get_identifier (mangle_type_string (type));
- }
- 
  /* Create an identifier for the mangled name of a special component
     for belonging to TYPE.  CODE is the ABI-specified code for this
     component.  */
  
  static tree
--- 2483,2527 ----
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
    return result;
  }
  
+ /* Like get_identifier, except that NAME is assumed to have been
+    allocated on the obstack used by the identifier hash table.  */
+ 
+ static inline tree
+ get_identifier_nocopy (const char *name)
+ {
+   hashnode ht_node = ht_lookup (ident_hash, name, 
+ 				strlen (name), HT_ALLOCED);
+   return HT_IDENT_TO_GCC_IDENT (ht_node);
+ }
+ 
  /* Create an identifier for the external mangled name of DECL.  */
  
  void
  mangle_decl (const tree decl)
  {
!   SET_DECL_ASSEMBLER_NAME (decl, 
! 			   get_identifier_nocopy (mangle_decl_string (decl)));
  }
  
  /* Generate the mangled representation of TYPE.  */
  
  const char *
  mangle_type_string (const tree type)
  {
    const char *result;
  
!   start_mangling (type, /*ident_p=*/false);
    write_type (type);
    result = finish_mangling (/*warn=*/false);
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
    return result;
  }
  
  /* Create an identifier for the mangled name of a special component
     for belonging to TYPE.  CODE is the ABI-specified code for this
     component.  */
  
  static tree
*************** mangle_special_for_type (const tree type
*** 2509,2519 ****
  {
    const char *result;
  
    /* We don't have an actual decl here for the special component, so
       we can't just process the <encoded-name>.  Instead, fake it.  */
!   start_mangling (type);
  
    /* Start the mangling.  */
    write_string ("_Z");
    write_string (code);
  
--- 2529,2539 ----
  {
    const char *result;
  
    /* We don't have an actual decl here for the special component, so
       we can't just process the <encoded-name>.  Instead, fake it.  */
!   start_mangling (type, /*ident_p=*/true);
  
    /* Start the mangling.  */
    write_string ("_Z");
    write_string (code);
  
*************** mangle_special_for_type (const tree type
*** 2522,2532 ****
    result = finish_mangling (/*warn=*/false);
  
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
  
!   return get_identifier (result);
  }
  
  /* Create an identifier for the mangled representation of the typeinfo
     structure for TYPE.  */
  
--- 2542,2552 ----
    result = finish_mangling (/*warn=*/false);
  
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
  
!   return get_identifier_nocopy (result);
  }
  
  /* Create an identifier for the mangled representation of the typeinfo
     structure for TYPE.  */
  
*************** mangle_vtt_for_type (const tree type)
*** 2578,2588 ****
  tree
  mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
  {
    const char *result;
  
!   start_mangling (type);
  
    write_string ("_Z");
    write_string ("TC");
    write_type (type);
    write_integer_cst (BINFO_OFFSET (binfo));
--- 2598,2608 ----
  tree
  mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
  {
    const char *result;
  
!   start_mangling (type, /*ident_p=*/true);
  
    write_string ("_Z");
    write_string ("TC");
    write_type (type);
    write_integer_cst (BINFO_OFFSET (binfo));
*************** mangle_ctor_vtbl_for_type (const tree ty
*** 2590,2600 ****
    write_type (BINFO_TYPE (binfo));
  
    result = finish_mangling (/*warn=*/false);
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
!   return get_identifier (result);
  }
  
  /* Mangle a this pointer or result pointer adjustment.
     
     <call-offset> ::= h <fixed offset number> _
--- 2610,2620 ----
    write_type (BINFO_TYPE (binfo));
  
    result = finish_mangling (/*warn=*/false);
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
!   return get_identifier_nocopy (result);
  }
  
  /* Mangle a this pointer or result pointer adjustment.
     
     <call-offset> ::= h <fixed offset number> _
*************** tree
*** 2635,2645 ****
  mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
  	      tree virtual_offset)
  {
    const char *result;
    
!   start_mangling (fn_decl);
  
    write_string ("_Z");
    write_char ('T');
    
    if (!this_adjusting)
--- 2655,2665 ----
  mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
  	      tree virtual_offset)
  {
    const char *result;
    
!   start_mangling (fn_decl, /*ident_p=*/true);
  
    write_string ("_Z");
    write_char ('T');
    
    if (!this_adjusting)
*************** mangle_thunk (tree fn_decl, const int th
*** 2669,2679 ****
    write_encoding (fn_decl);
  
    result = finish_mangling (/*warn=*/false);
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_thunk = %s\n\n", result);
!   return get_identifier (result);
  }
  
  /* This hash table maps TYPEs to the IDENTIFIER for a conversion
     operator to TYPE.  The nodes are IDENTIFIERs whose TREE_TYPE is the
     TYPE.  */
--- 2689,2699 ----
    write_encoding (fn_decl);
  
    result = finish_mangling (/*warn=*/false);
    if (DEBUG_MANGLE)
      fprintf (stderr, "mangle_thunk = %s\n\n", result);
!   return get_identifier_nocopy (result);
  }
  
  /* This hash table maps TYPEs to the IDENTIFIER for a conversion
     operator to TYPE.  The nodes are IDENTIFIERs whose TREE_TYPE is the
     TYPE.  */
*************** mangle_conv_op_name_for_type (const tree
*** 2738,2769 ****
     variable for indicated VARIABLE.  */
  
  tree
  mangle_guard_variable (const tree variable)
  {
!   start_mangling (variable);
    write_string ("_ZGV");
    if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
      /* The name of a guard variable for a reference temporary should refer
         to the reference, not the temporary.  */
      write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
    else
      write_name (variable, /*ignore_local_scope=*/0);
!   return get_identifier (finish_mangling (/*warn=*/false));
  }
  
  /* Return an identifier for the name of a temporary variable used to
     initialize a static reference.  This isn't part of the ABI, but we might
     as well call them something readable.  */
  
  tree
  mangle_ref_init_variable (const tree variable)
  {
!   start_mangling (variable);
    write_string ("_ZGR");
    write_name (variable, /*ignore_local_scope=*/0);
!   return get_identifier (finish_mangling (/*warn=*/false));
  }
  
  
  /* Foreign language type mangling section.  */
  
--- 2758,2789 ----
     variable for indicated VARIABLE.  */
  
  tree
  mangle_guard_variable (const tree variable)
  {
!   start_mangling (variable, /*ident_p=*/true);
    write_string ("_ZGV");
    if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
      /* The name of a guard variable for a reference temporary should refer
         to the reference, not the temporary.  */
      write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
    else
      write_name (variable, /*ignore_local_scope=*/0);
!   return get_identifier_nocopy (finish_mangling (/*warn=*/false));
  }
  
  /* Return an identifier for the name of a temporary variable used to
     initialize a static reference.  This isn't part of the ABI, but we might
     as well call them something readable.  */
  
  tree
  mangle_ref_init_variable (const tree variable)
  {
!   start_mangling (variable, /*ident_p=*/true);
    write_string ("_ZGR");
    write_name (variable, /*ignore_local_scope=*/0);
!   return get_identifier_nocopy (finish_mangling (/*warn=*/false));
  }
  
  
  /* Foreign language type mangling section.  */
  



More information about the Gcc-patches mailing list