String pool, revised

Zack Weinberg zackw@Stanford.EDU
Sun Oct 29 17:43:00 GMT 2000


On Sun, Oct 29, 2000 at 12:21:23AM -0700, Zack Weinberg wrote:
> This patch replaces garbage-collection for strings with a custom pool
> allocator.  Strings are now stored uniquely and permanently.

This is a revised patch which addresses some of Mark Mitchell's
concerns (see other message in this thread):

- The new file is now called stringpool.c and doesn't have hooks into
  the garbage collector.  (The string allocator function is still
  called ggc_alloc_string, and init_stringpool etc are still declared
  in ggc.h.)
- We use the same hash function cpplib does, instead of a supposedly
  better one off a webpage with copyright issues.  cpplib's simple
  hash turns out to be faster and produce fewer collisions.

Old: 
coll/search     0.8223
  1.59      6.83     0.23   261446     0.00     0.00  alloc_string
  0.76      8.91     0.11        4    27.50    49.21  expand_string_table
  1.45      7.04     0.21   445766     0.00     0.00  calc_hash

New:
coll/search     0.7804
  1.12      7.99     0.16   261445     0.00     0.00  alloc_string
  1.19      7.67     0.17        4    42.50    42.50  expand_string_table
(calc_hash is inline)

- -Wid-clash-<N> works.  However, it is a tad too eager:

$ ./cc1 -Wid-clash-6 <<! >/dev/null
int foobarbaz(int);
int foobarquux(int);
!
stdin:1: warning: "__constructor__" and "__const__" identical in first 6 characters
stdin:1: warning: "__aligned__" and "__alignof__" identical in first 6 characters
stdin:1: warning: "format_arg" and "format" identical in first 6 characters
stdin:1: warning: "__format_arg__" and "__format__" identical in first 6 characters
stdin:2: warning: "foobarquux" and "foobarbaz" identical in first 6 characters
$

Where the last warning is the only one we actually wanted.  This is an
unrelated problem (start_identifier_warnings is being called too
early) and suggests that no one has used -Wid-clash in a long, long
time.  Maybe we could just dump the feature.

Also, thanks to Joseph Myers, the statistics code now doesn't make you
do square roots for it.

	* stringpool.c: New file, implements string pool.
	* Makefile.in (stringpool.o): New rule.
	(OBJS): Add stringpool.o.

> 	* ggc-common.c (ggc_add_string_root, ggc_mark_string_ptr): Delete.
> 	(ggc_alloc_string): Now in stringpool.c.
> 	* ggc-page.c, ggc-simple.c: Do not define or initialize empty_string.
> 	* ggc.h (init_stringpool, ggc_stringpool_statistics): Prototype.
> 	(ggc_alloc_string): Now returns const char *.
> 	* toplev.c (main): Call init_stringpool.
	(compile_file): Call stringpool_statistics if mem_report is set.
	(approx_sqrt): New function.

> 	* tree.c (hash_table, MAX_HASH_TABLE, HASHBITS): Delete.
> 	(built_in_filename): Constify.
> 	(init_obstacks): Don't register hash_table as GC root.
> 	(get_identifier, maybe_get_identifier,
	do_identifier_warnings, start_identifier_warnings,
	set_identifier_size): Now in stringpool.c.

> 	* tree.h (struct tree_string): Constify pointer.
	Prototype approx_sqrt.

> 
> 	* c-common.c (combine_strings): Combine strings into a scratch
> 	buffer, then pass to build_string.
> 
> 	* java/jcf-parse.c (get_constant): Create UCS2 string in
> 	scratch buffer, then pass to build_string.
> 	* java/parse.y (do_merge_string_cste): Merge strings in
> 	scratch buffer, then pass to build_string.
> 
> 	* optabs.c (init_libfuncs),
> 	profile.c (init_edge_profiler, output_func_start_profiler),
> 	stmt.c (init_stmt, expand_asm_operands),
> 	alpha/alpha.c (alpha_need_linkage),
> 	arm/arm.c (arm_encode_call_attribute),
> 	i386/i386.c (load_pic_register),
> 	ia64/ia64.c (ia64_encode_section_info),
> 	pa/pa.c (hppa_encode_label),
> 	rs6000/rs6000.c (rs6000_encode_section_info): 
> 	Create string in scratch buffer, then feed to
> 	ggc_alloc_string.  Don't modify strings in place.
> 
> 	* builtins.c (c_strlen),
> 	c-decl.c (finish_decl),
> 	c-lex.c (process_directive),
> 	c-typeck.c (constructor_asmspec, struct initializer_stack, start_init),
> 	except.c (create_rethrow_ref),
> 	toplev.c (decode_f_option),
> 	varasm.c (in_named_name, assemble_static_space,
> 	struct constant_descriptor, struct pool_constant, force_const_mem),
> 	i386/i386.c (pic_label_name, global_offset_table_name),
> 	rs6000/rs6000.c (rs6000_emit_prologue, rs6000_emit_epilogue),
> 	cp/lex.c (struct impl_files, internal_filename): 
> 	Constify a char *.
> 
> 	* pa/elf.h, pa/pa-protos.h, pa/pa.c, pa/pa.h, pa/som.h: Drop
> 	unused second argument of hppa_encode_label.

===================================================================
Index: Makefile.in
--- Makefile.in	2000/10/28 17:59:04	1.532
+++ Makefile.in	2000/10/30 01:32:15
@@ -733,7 +733,7 @@ OBJS = diagnostic.o version.o tree.o pri
  insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o    \
  profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o	      \
  mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o	      \
- lists.o ggc-common.o $(GGC) simplify-rtx.o ssa.o bb-reorder.o		      \
+ lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o   \
  sibcall.o conflict.o timevar.o ifcvt.o dependence.o dce.o
 
 BACKEND = toplev.o libbackend.a
@@ -1262,6 +1262,9 @@ ggc-simple.o: ggc-simple.c $(CONFIG_H) $
 
 ggc-page.o: ggc-page.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h toplev.h \
 	$(GGC_H) varray.h $(TIMEVAR_H)
+
+stringpool.o: stringpool.c $(CONFIG_H) system.h $(TREE_H) $(OBSTACK_H) \
+	flags.h toplev.h
 
 ggc-none.o: ggc-none.c $(CONFIG_H) $(RTL_H) $(GGC_H)
 
===================================================================
Index: builtins.c
--- builtins.c	2000/10/06 14:59:56	1.60
+++ builtins.c	2000/10/30 01:32:15
@@ -200,7 +200,7 @@ c_strlen (src)
 {
   tree offset_node;
   int offset, max;
-  char *ptr;
+  const char *ptr;
 
   src = string_constant (src, &offset_node);
   if (src == 0)
===================================================================
Index: c-common.c
--- c-common.c	2000/10/20 15:59:06	1.180
+++ c-common.c	2000/10/30 01:32:18
@@ -372,7 +372,7 @@ combine_strings (strings)
       if (wide_flag)
 	length = length * wchar_bytes + wide_length;
 
-      p = ggc_alloc_string (NULL, length);
+      p = alloca (length);
 
       /* Copy the individual strings into the new combined string.
 	 If the combined string is wide, convert the chars to ints
@@ -411,9 +411,7 @@ combine_strings (strings)
       else
 	*q = 0;
 
-      value = make_node (STRING_CST);
-      TREE_STRING_POINTER (value) = p;
-      TREE_STRING_LENGTH (value) = length;
+      value = build_string (length, p);
     }
   else
     {
===================================================================
Index: c-decl.c
--- c-decl.c	2000/10/29 05:59:58	1.172
+++ c-decl.c	2000/10/30 01:32:23
@@ -3612,7 +3612,7 @@ finish_decl (decl, init, asmspec_tree)
 {
   register tree type = TREE_TYPE (decl);
   int was_incomplete = (DECL_SIZE (decl) == 0);
-  char *asmspec = 0;
+  const char *asmspec = 0;
 
   /* If a name was specified, get the string.   */
   if (asmspec_tree)
===================================================================
Index: c-lex.c
--- c-lex.c	2000/10/08 21:20:43	1.106
+++ c-lex.c	2000/10/30 01:32:23
@@ -444,7 +444,7 @@ process_directive ()
   int saw_line;
   enum { act_none, act_push, act_pop } action;
   int action_number, l;
-  char *new_file;
+  const char *new_file;
 #ifndef NO_IMPLICIT_EXTERN_C
   int entering_c_header = 0;
 #endif
===================================================================
Index: c-typeck.c
--- c-typeck.c	2000/10/28 00:18:37	1.97
+++ c-typeck.c	2000/10/30 01:32:27
@@ -4905,7 +4905,7 @@ static int require_constant_elements;
 static tree constructor_decl;
 
 /* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
-static char *constructor_asmspec;
+static const char *constructor_asmspec;
 
 /* Nonzero if this is an initializer for a top-level decl.  */
 static int constructor_top_level;
@@ -4950,7 +4950,7 @@ struct initializer_stack
 {
   struct initializer_stack *next;
   tree decl;
-  char *asmspec;
+  const char *asmspec;
   struct constructor_stack *constructor_stack;
   tree elements;
   struct spelling *spelling;
@@ -4975,7 +4975,7 @@ start_init (decl, asmspec_tree, top_leve
   const char *locus;
   struct initializer_stack *p
     = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
-  char *asmspec = 0;
+  const char *asmspec = 0;
 
   if (asmspec_tree)
     asmspec = TREE_STRING_POINTER (asmspec_tree);
===================================================================
Index: except.c
--- except.c	2000/10/13 06:26:24	1.137
+++ except.c	2000/10/30 01:32:29
@@ -500,7 +500,7 @@ create_rethrow_ref (region_num)
      int region_num;
 {
   rtx def;
-  char *ptr;
+  const char *ptr;
   char buf[60];
 
   ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num);
===================================================================
Index: gcc.c
--- gcc.c	2000/10/20 21:14:20	1.173
+++ gcc.c	2000/10/30 01:32:31
@@ -2871,7 +2871,6 @@ process_command (argc, argv)
      const char *const *argv;
 {
   register int i;
-  unsigned int j;
   const char *temp;
   char *temp1;
   const char *spec_lang = 0;
===================================================================
Index: ggc-common.c
--- ggc-common.c	2000/10/01 19:19:24	1.32
+++ ggc-common.c	2000/10/30 01:32:31
@@ -47,7 +47,6 @@ static void ggc_mark_tree_ptr PARAMS ((v
 static void ggc_mark_rtx_varray_ptr PARAMS ((void *));
 static void ggc_mark_tree_varray_ptr PARAMS ((void *));
 static void ggc_mark_tree_hash_table_ptr PARAMS ((void *));
-static void ggc_mark_string_ptr PARAMS ((void *));
 static void ggc_mark_trees PARAMS ((void));
 static boolean ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *,
 						       hash_table_key));
@@ -143,16 +142,6 @@ ggc_add_tree_hash_table_root (base, nelt
 		ggc_mark_tree_hash_table_ptr);
 }
 
-/* Register an array of strings as a GC root.  */
-
-void
-ggc_add_string_root (base, nelt)
-     char **base;
-     int nelt;
-{
-  ggc_add_root (base, nelt, sizeof (char *), ggc_mark_string_ptr);
-}
-
 /* Remove the previously registered GC root at BASE.  */
 
 void
@@ -555,43 +544,6 @@ ggc_mark_tree_hash_table_ptr (elt)
      void *elt;
 {
   ggc_mark_tree_hash_table (*(struct hash_table **) elt);
-}
-
-/* Type-correct function to pass to ggc_add_root.  It just forwards
-   ELT (which is really a char **) to ggc_mark_string.  */
-
-static void
-ggc_mark_string_ptr (elt)
-     void *elt;
-{
-  ggc_mark_string (*(char **) elt);
-}
-
-/* Allocate a gc-able string.  If CONTENTS is null, then the memory will
-   be uninitialized.  If LENGTH is -1, then CONTENTS is assumed to be a
-   null-terminated string and the memory sized accordingly.  Otherwise,
-   the memory is filled with LENGTH bytes from CONTENTS.  */
-
-char *
-ggc_alloc_string (contents, length)
-     const char *contents;
-     int length;
-{
-  char *string;
-
-  if (length < 0)
-    {
-      if (contents == NULL)
-	return NULL;
-      length = strlen (contents);
-    }
-
-  string = (char *) ggc_alloc (length + 1);
-  if (contents != NULL)
-    memcpy (string, contents, length);
-  string[length] = 0;
-
-  return string;
 }
 
 /* Allocate a block of memory, then clear it.  */
===================================================================
Index: ggc-page.c
--- ggc-page.c	2000/08/29 20:57:11	1.30
+++ ggc-page.c	2000/10/30 01:32:31
@@ -99,8 +99,6 @@ Boston, MA 02111-1307, USA.  */
 #define HOST_BITS_PER_PTR  HOST_BITS_PER_LONG
 #endif
 
-/* The "" allocated string.  */
-char *empty_string;
 
 /* A two-level tree is used to look up the page-entry for a given
    pointer.  Two chunks of the pointer's bits are extracted to index
@@ -839,9 +837,6 @@ init_ggc ()
     munmap (p, G.pagesize);
   }
 #endif
-
-  empty_string = ggc_alloc_string ("", 0);
-  ggc_add_string_root (&empty_string, 1);
 }
 
 /* Increment the `GC context'.  Objects allocated in an outer context
===================================================================
Index: ggc-simple.c
--- ggc-simple.c	2000/08/29 20:57:11	1.35
+++ ggc-simple.c	2000/10/30 01:32:32
@@ -52,10 +52,6 @@
 #define GGC_ALWAYS_COLLECT
 #endif
 
-/* Constants for general use.  */
-
-char *empty_string;
-
 #ifndef HOST_BITS_PER_PTR
 #define HOST_BITS_PER_PTR  HOST_BITS_PER_LONG
 #endif
@@ -374,9 +370,6 @@ void 
 init_ggc ()
 {
   G.allocated_last_gc = GGC_MIN_LAST_ALLOCATED;
-
-  empty_string = ggc_alloc_string ("", 0);
-  ggc_add_string_root (&empty_string, 1);
 }
 
 /* Start a new GGC context.  Memory allocated in previous contexts
===================================================================
Index: ggc.h
--- ggc.h	2000/10/13 06:26:26	1.31
+++ ggc.h	2000/10/30 01:32:32
@@ -40,7 +40,7 @@ union  tree_node;
 struct varasm_status;
 
 /* Constants for general use.  */
-extern char *empty_string;
+extern const char empty_string[];
 
 /* Trees that have been marked, but whose children still need marking.  */
 extern varray_type ggc_pending_trees;
@@ -49,12 +49,14 @@ extern varray_type ggc_pending_trees;
 void ggc_add_root PARAMS ((void *base, int nelt, int size, void (*)(void *)));
 void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt));
 void ggc_add_tree_root PARAMS ((union tree_node **, int nelt));
-void ggc_add_string_root PARAMS ((char **, int nelt));
 void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **, int nelt));
 void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **, int nelt));
 void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **, int nelt));
 void ggc_del_root PARAMS ((void *base));
 
+/* Temporary */
+#define ggc_add_string_root(ptr, nelt)  /* nothing */
+
 /* Mark nodes from the gc_add_root callback.  These functions follow
    pointers to mark other objects too.  */
 extern void ggc_mark_rtx_varray PARAMS ((struct varray_head_tag *));
@@ -91,12 +93,8 @@ extern void ggc_mark_rtvec_children PARA
       ggc_mark_rtvec_children (v__);            \
   } while (0)
 
-#define ggc_mark_string(EXPR)			\
-  do {						\
-    const char *s__ = (EXPR);			\
-    if (s__ != NULL)				\
-      ggc_set_mark (s__);			\
-  } while (0)
+/* Temporary */
+#define ggc_mark_string(EXPR)  /* nothing */
 
 #define ggc_mark(EXPR)				\
   do {						\
@@ -112,6 +110,7 @@ extern void ggc_mark_if_gcable PARAMS ((
 
 /* Initialize the garbage collector.   */
 extern void init_ggc PARAMS ((void));
+extern void init_stringpool PARAMS ((void));
 
 /* Start a new GGC context.  Memory allocated in previous contexts
    will not be collected while the new context is active.  */
@@ -138,11 +137,10 @@ void *ggc_alloc_cleared PARAMS ((size_t)
 
 #define ggc_alloc_tree(LENGTH) ((union tree_node *) ggc_alloc (LENGTH))
 
-/* Allocate a gc-able string.  If CONTENTS is null, then the memory will
-   be uninitialized.  If LENGTH is -1, then CONTENTS is assumed to be a
-   null-terminated string and the memory sized accordingly.  Otherwise,
-   the memory is filled with LENGTH bytes from CONTENTS.  */
-char *ggc_alloc_string PARAMS ((const char *contents, int length));
+/* Allocate a gc-able string, and fill it with LENGTH bytes from CONTENTS.
+   If LENGTH is -1, then CONTENTS is assumed to be a
+   null-terminated string and the memory sized accordingly.  */
+const char *ggc_alloc_string PARAMS ((const char *contents, int length));
 
 /* Make a copy of S, in GC-able memory.  */
 #define ggc_strdup(S) ggc_alloc_string((S), -1)
@@ -214,3 +212,4 @@ void ggc_print_common_statistics PARAMS 
 
 /* Print allocation statistics.  */
 extern void ggc_print_statistics PARAMS ((void));
+void stringpool_statistics PARAMS ((void));
===================================================================
Index: optabs.c
--- optabs.c	2000/10/18 21:33:40	1.84
+++ optabs.c	2000/10/30 01:32:38
@@ -4465,8 +4465,7 @@ init_libfuncs (optable, first_mode, last
     {
       register const char *mname = GET_MODE_NAME(mode);
       register unsigned mname_len = strlen (mname);
-      register char *libfunc_name
-	= ggc_alloc_string (NULL, 2 + opname_len + mname_len + 1 + 1);
+      register char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
       register char *p;
       register const char *q;
 
@@ -4478,10 +4477,11 @@ init_libfuncs (optable, first_mode, last
       for (q = mname; *q; q++)
 	*p++ = TOLOWER (*q);
       *p++ = suffix;
-      *p++ = '\0';
+      *p = '\0';
 
       optable->handlers[(int) mode].libfunc
-	= gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+	= gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
+						       p - libfunc_name));
     }
 }
 
===================================================================
Index: profile.c
--- profile.c	2000/10/13 06:26:27	1.47
+++ profile.c	2000/10/30 01:32:38
@@ -1025,9 +1025,9 @@ static void
 init_edge_profiler ()
 {
   /* Generate and save a copy of this so it can be shared.  */
-  char *name = ggc_alloc_string (NULL, 20);
-  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
-  profiler_label = gen_rtx_SYMBOL_REF (Pmode, name);
+  char buf[20];
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
+  profiler_label = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1));
   ggc_add_rtx_root (&profiler_label, 1);
 }
 
@@ -1066,6 +1066,7 @@ output_func_start_profiler ()
 {
   tree fnname, fndecl;
   char *name;
+  char buf[20];
   const char *cfnname;
   rtx table_address;
   enum machine_mode mode = mode_for_size (LONG_TYPE_SIZE, MODE_INT, 0);
@@ -1121,9 +1122,10 @@ output_func_start_profiler ()
   expand_function_start (fndecl, 0);
 
   /* Actually generate the code to call __bb_init_func. */
-  name = ggc_alloc_string (NULL, 20);
-  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
-  table_address = force_reg (Pmode, gen_rtx_SYMBOL_REF (Pmode, name));
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 0);
+  table_address = force_reg (Pmode,
+			     gen_rtx_SYMBOL_REF (Pmode,
+						 ggc_alloc_string (buf, -1)));
   emit_library_call (gen_rtx_SYMBOL_REF 
 		     (Pmode, ggc_alloc_string ("__bb_init_func", 14)), 0,
 		     mode, 1, table_address, Pmode);
===================================================================
Index: stmt.c
--- stmt.c	2000/10/13 06:26:28	1.171
+++ stmt.c	2000/10/30 01:32:41
@@ -394,7 +394,7 @@ struct stmt_status
 static int using_eh_for_cleanups_p = 0;
 
 /* Character strings, each containing a single decimal digit.  */
-static char *digit_strings[10];
+static const char *digit_strings[10];
 
 static int n_occurrences		PARAMS ((int, const char *));
 static void expand_goto_internal	PARAMS ((tree, rtx, rtx));
@@ -598,13 +598,15 @@ void
 init_stmt ()
 {
   int i;
+  char buf[2];
 
   gcc_obstack_init (&stmt_obstack);
 
+  buf[1] = 0;
   for (i = 0; i < 10; i++)
     {
-      digit_strings[i] = ggc_alloc_string (NULL, 1);
-      digit_strings[i][0] = '0' + i;
+      buf[0] = '0' + i;
+      digit_strings[i] = ggc_alloc_string (buf, 1);
     }
   ggc_add_string_root (digit_strings, 10);
 }
@@ -1408,7 +1410,7 @@ expand_asm_operands (string, outputs, in
     {
       tree val = TREE_VALUE (tail);
       tree type = TREE_TYPE (val);
-      char *constraint;
+      const char *constraint;
       char *p;
       int c_len;
       int j;
@@ -1425,8 +1427,8 @@ expand_asm_operands (string, outputs, in
 	 the worst that happens if we get it wrong is we issue an error
 	 message.  */
 
-      c_len = strlen (TREE_STRING_POINTER (TREE_PURPOSE (tail)));
       constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+      c_len = strlen (constraint);
 
       /* Allow the `=' or `+' to not be at the beginning of the string,
 	 since it wasn't explicitly documented that way, and there is a
@@ -1443,19 +1445,25 @@ expand_asm_operands (string, outputs, in
 	  error ("output operand constraint lacks `='");
 	  return;
 	}
+      j = p - constraint;
+      is_inout = *p == '+';
 
-      if (p != constraint)
+      if (j || is_inout)
 	{
-	  j = *p;
-	  bcopy (constraint, constraint+1, p-constraint);
-	  *constraint = j;
-
-	  warning ("output constraint `%c' for operand %d is not at the beginning", j, i);
+	  /* Have to throw away this constraint string and get a new one.  */
+	  char *buf = alloca (c_len + 1);
+	  buf[0] = '=';
+	  if (j)
+	    memcpy (buf + 1, constraint, j);
+	  memcpy (buf + 1 + j, p + 1, c_len - j);  /* not -j-1 - copy null */
+	  constraint = ggc_alloc_string (buf, c_len);
+
+	  if (j)
+	    warning (
+		"output constraint `%c' for operand %d is not at the beginning",
+		*p, i);
 	}
 
-      is_inout = constraint[0] == '+';
-      /* Replace '+' with '='.  */
-      constraint[0] = '=';
       /* Make sure we can specify the matching operand.  */
       if (is_inout && i > 9)
 	{
@@ -1611,7 +1619,7 @@ expand_asm_operands (string, outputs, in
     {
       int j;
       int allows_reg = 0, allows_mem = 0;
-      char *constraint, *orig_constraint;
+      const char *constraint, *orig_constraint;
       int c_len;
       rtx op;
 
@@ -1629,8 +1637,8 @@ expand_asm_operands (string, outputs, in
 	  return;
 	}
 
-      c_len = strlen (TREE_STRING_POINTER (TREE_PURPOSE (tail)));
       constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+      c_len = strlen (constraint);
       orig_constraint = constraint;
 
       /* Make sure constraint has neither `=', `+', nor '&'.  */
@@ -1691,8 +1699,8 @@ expand_asm_operands (string, outputs, in
 		for (j = constraint[j] - '0'; j > 0; --j)
 		  o = TREE_CHAIN (o);
 
-		c_len = strlen (TREE_STRING_POINTER (TREE_PURPOSE (o)));
 		constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
+		c_len = strlen (constraint);
 		j = 0;
 		break;
 	      }
===================================================================
Index: stringpool.c
--- stringpool.c	Tue May  5 13:32:27 1998
+++ stringpool.c	Sun Oct 29 17:32:41 2000
@@ -0,0 +1,394 @@
+/* String pool for GCC.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* String pool allocator.  All strings allocated by ggc_alloc_string are
+   uniquified and stored in an obstack which is never shrunk.  You can
+   associate a tree with a string if you wish; this is used to implement
+   get_identifier.
+
+   We have our own private hash table implementation which is similar
+   to the one in cpphash.c (actually, it's a further refinement of
+   that code).  libiberty's hashtab.c is not used because it requires
+   100% average space overhead per string, which is unacceptable.
+   Also, this algorithm is faster.  */
+
+#include "config.h"
+#include "system.h"
+#include "ggc.h"
+#include "tree.h"
+#include "obstack.h"
+#include "flags.h"
+#include "toplev.h"
+
+/* The "" allocated string.  */
+const char empty_string[] = "";
+
+static struct obstack string_stack;
+
+/* This is the hash entry associated with each string.  It lives in
+   the hash table; only the string lives in the obstack.  Note that
+   the string is not necessarily NUL terminated.  */
+
+struct str_header
+{
+  const char *ptr;
+  tree data;	/* for get_identifier */
+  unsigned int len;
+};
+
+/* This is the hash table structure.  There's only one.  */
+struct str_hash
+{
+  struct str_header *entries;
+  size_t nslots;	/* total slots in the entries array */
+  size_t nelements;	/* number of live elements */
+
+  /* table usage statistics */
+  unsigned int searches;
+  unsigned int collisions;
+};
+#define INITIAL_HASHSIZE (16*1024)
+
+static struct str_hash string_hash = { 0, INITIAL_HASHSIZE, 0, 0, 0 };
+
+enum insert_option { INSERT, NO_INSERT };
+
+static struct str_header *alloc_string PARAMS ((const char *, size_t,
+						enum insert_option));
+static inline unsigned int calc_hash PARAMS ((const unsigned char *, size_t));
+static void mark_string_hash PARAMS ((void *));
+static struct str_header *expand_string_table PARAMS ((struct str_header *));
+
+/* Convenience macro for iterating over the hash table.  E is set to
+   each live entry in turn.  */
+#define FORALL_STRINGS(E) \
+  for (E = string_hash.entries; E < string_hash.entries+string_hash.nslots; E++) \
+    if (E->ptr != NULL)
+      /* block here */
+
+/* Likewise, but tests ->data instead of ->ptr (for cases where we only
+   care about entries with ->data set)  */
+#define FORALL_IDS(E) \
+  for (E = string_hash.entries; E < string_hash.entries+string_hash.nslots; E++) \
+    if (E->data != NULL)
+
+/* 0 while creating built-in identifiers.  */
+static int do_identifier_warnings;
+
+void
+init_stringpool ()
+{
+  gcc_obstack_init (&string_stack);
+  obstack_alignment_mask (&string_stack) = 0; /* no alignment needed for strings */
+    ggc_add_root (&string_hash, 1, sizeof string_hash, mark_string_hash);
+
+  string_hash.entries = (struct str_header *)
+    xcalloc (string_hash.nslots, sizeof (struct str_header));
+}
+
+/* Enable warnings on similar identifiers (if requested).
+   Done after the built-in identifiers are created.  */
+
+void
+start_identifier_warnings ()
+{
+  do_identifier_warnings = 1;
+}
+
+/* Record the size of an identifier node for the language in use.
+   SIZE is the total size in bytes.
+   This is called by the language-specific files.  This must be
+   called before allocating any identifiers.  */
+
+void
+set_identifier_size (size)
+     int size;
+{
+  tree_code_length[(int) IDENTIFIER_NODE]
+    = (size - sizeof (struct tree_common)) / sizeof (tree);
+}
+
+#define HASHSTEP(r, c) ((r) * 67 + (c - 113));
+static inline unsigned int
+calc_hash (str, len)
+     const unsigned char *str;
+     size_t len;
+{
+  size_t n = len;
+  unsigned int r = 0;
+
+  while (n--)
+    r = HASHSTEP (r, *str++);
+
+  return r + len;
+}
+
+/* Internal primitive: allocate a string constant and return its
+   header structure.  If the string hasn't been seen before and the
+   last argument is INSERT, a new entry is added.  */
+static struct str_header *
+alloc_string (contents, length, insert)
+     const char *contents;
+     size_t length;
+     enum insert_option insert;
+{
+  unsigned int hash = calc_hash ((const unsigned char *)contents, length);
+  unsigned int hash2;
+  unsigned int index;
+  size_t sizemask;
+  struct str_header *entry;
+  struct str_header *entries = string_hash.entries;
+
+  sizemask = string_hash.nslots - 1;
+  index = hash & sizemask;
+
+  /* hash2 must be odd, so we're guaranteed to visit every possible
+     location in the table during rehashing.  */
+  hash2 = ((hash * 17) & sizemask) | 1;
+  string_hash.searches++;
+
+  for (;;)
+    {
+      entry = entries + index;
+
+      if (entry->ptr == NULL)
+	break;
+
+      if (entry->len == length
+	  && !memcmp (entry->ptr, contents, length))
+	return entry;
+
+      index = (index + hash2) & sizemask;
+      string_hash.collisions++;
+    }
+
+  if (insert == NO_INSERT)
+    return NULL;
+
+  obstack_grow0 (&string_stack, contents, length);
+  entry->ptr = (const char *) obstack_finish (&string_stack);
+  entry->len = length;
+  entry->data = NULL;
+
+  if (++string_hash.nelements * 4 < string_hash.nslots * 3)
+    return entry;
+
+  /* Must expand the string table.  */
+  return expand_string_table (entry);
+}
+
+static struct str_header *
+expand_string_table (entry)
+     struct str_header *entry;
+{
+  struct str_header *nentries;
+  struct str_header *e, *nentry = NULL;
+  size_t size, sizemask;
+
+  size = string_hash.nslots * 2;
+  nentries = (struct str_header *) xcalloc (size, sizeof (struct str_header));
+  sizemask = size - 1;
+
+  FORALL_STRINGS (e)
+    {
+      unsigned int index, hash, hash2;
+
+      hash = calc_hash ((const unsigned char *) e->ptr, e->len);
+      hash2 = ((hash * 17) & sizemask) | 1;
+      index = hash & sizemask;
+
+      for (;;)
+	{
+	  if (nentries[index].ptr == NULL)
+	    {
+	      nentries[index].ptr = e->ptr;
+	      nentries[index].len = e->len;
+	      nentries[index].data = e->data;
+	      if (e == entry)
+		nentry = nentries + index;
+	      break;
+	    }
+
+	  index = (index + hash2) & sizemask;
+	}
+    }
+
+  free (string_hash.entries);
+  string_hash.entries = nentries;
+  string_hash.nslots = size;
+  return nentry;
+}
+
+/* Allocate and return a string constant.  If the same string constant
+   has been allocated before, that copy is returned this time too.  */
+
+const char *
+ggc_alloc_string (contents, length)
+     const char *contents;
+     int length;
+{
+  struct str_header *str;
+
+  if (length == -1)
+    length = strlen (contents);
+
+  if (length == 0)
+    return empty_string;
+
+  str = alloc_string (contents, length, INSERT);
+  return str->ptr;
+}
+
+/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
+   If an identifier with that name has previously been referred to,
+   the same node is returned this time.  */
+tree
+get_identifier (text)
+     const char *text;
+{
+  tree idp;
+  struct str_header *str;
+  size_t length = strlen (text);
+
+  str = alloc_string (text, length, INSERT);
+  idp = str->data;
+  if (idp == NULL)
+    {
+      if (TREE_CODE_LENGTH (IDENTIFIER_NODE) < 0)
+	abort ();	/* set_identifier_size hasn't been called.  */
+
+      /* If this identifier is longer than the clash-warning length,
+	 do a brute force search of the entire table for clashes.  */
+      if (warn_id_clash && do_identifier_warnings && length >= (size_t) id_clash_len)
+	{
+	  struct str_header *e;
+	  FORALL_IDS (e)
+	    {
+	      if (e->len >= (size_t)id_clash_len
+		  && !strncmp (e->ptr, text, id_clash_len))
+		{
+		  warning ("\"%s\" and \"%s\" identical in first %d characters",
+			   text, e->ptr, id_clash_len);
+		  break;
+		}
+	    }
+	}
+
+      idp = make_node (IDENTIFIER_NODE);
+      IDENTIFIER_LENGTH (idp) = length;
+      IDENTIFIER_POINTER (idp) = str->ptr;
+#ifdef GATHER_STATISTICS
+      id_string_size += length;
+#endif
+      str->data = idp;
+    }
+  return idp;
+}
+
+/* If an identifier with the name TEXT (a null-terminated string) has
+   previously been referred to, return that node; otherwise return
+   NULL_TREE.  */
+
+tree
+maybe_get_identifier (text)
+     const char *text;
+{
+  struct str_header *str;
+  size_t length = strlen (text);
+
+  str = alloc_string (text, length, NO_INSERT);
+  if (str)
+    return str->data;
+  return NULL_TREE;
+}
+
+/* Report some basic statistics about the string pool.  */
+
+#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
+		  ? (x) \
+		  : ((x) < 1024*1024*10 \
+		     ? (x) / 1024 \
+		     : (x) / (1024*1024))))
+#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
+
+void
+stringpool_statistics ()
+{
+  size_t nelts, overhead, headers;
+  size_t total_bytes, longest, sum_of_squares;
+  double exp_len, exp_len2, exp2_len;
+  struct str_header *e;
+
+  total_bytes = longest = sum_of_squares = 0;
+  FORALL_STRINGS (e)
+    {
+      size_t n = e->len;
+
+      total_bytes += n;
+      sum_of_squares += n*n;
+      if (n > longest)
+	longest = n;
+    }
+      
+  nelts = string_hash.nelements;
+  overhead = obstack_memory_used (&string_stack) - total_bytes;
+  headers = string_hash.nslots * sizeof (struct str_header);
+
+  fprintf (stderr,
+"\nString pool\n\
+entries\t\t%lu\n\
+slots\t\t%lu\n\
+bytes\t\t%lu%c (%lu%c overhead)\n\
+table size\t%lu%c\n",
+	   (unsigned long) nelts, (unsigned long) string_hash.nslots,
+	   SCALE (total_bytes), LABEL (total_bytes),
+	   SCALE (overhead), LABEL (overhead),
+	   SCALE (headers), LABEL (headers));
+
+  exp_len = (double)total_bytes / (double)nelts;
+  exp2_len = exp_len * exp_len;
+  exp_len2 = (double)sum_of_squares / (double)nelts;
+
+  fprintf (stderr,
+"coll/search\t%.4f\n\
+ins/search\t%.4f\n\
+avg. entry\t%.2f bytes (+/- %.2f)\n\
+longest entry\t%lu\n",
+	   (double) string_hash.collisions / (double) string_hash.searches,
+	   (double) nelts / (double) string_hash.searches,
+	   exp_len, approx_sqrt (exp_len2 - exp2_len),
+	   (unsigned long) longest);
+}
+#undef SCALE
+#undef LABEL
+
+/* Mark the string hash for GC.  */
+
+static void
+mark_string_hash (arg)
+     void *arg ATTRIBUTE_UNUSED;
+{
+  struct str_header *h;
+
+  FORALL_IDS (h)
+    {
+      ggc_mark_tree (h->data);
+    }
+}
===================================================================
Index: toplev.c
--- toplev.c	2000/10/29 19:34:52	1.392
+++ toplev.c	2000/10/30 01:32:43
@@ -1575,6 +1575,29 @@ floor_log2_wide (x)
   return log;
 }
 
+/* Return the approximate positive square root of a number N.  This is for
+   statistical reports, not code generation.  */
+double
+approx_sqrt (x)
+     double x;
+{
+  double s, d;
+
+  if (x < 0)
+    abort ();   
+  if (x == 0)
+    return 0;
+
+  s = x;
+  do
+    {
+      d = (s * s - x) / (2 * s);
+      s -= d;                   
+    }        
+  while (d > .0001);
+  return s;
+}
+
 static int float_handler_set;
 int float_handled;
 jmp_buf float_handler;
@@ -2513,7 +2536,10 @@ compile_file (name)
     }
 
   if (mem_report)
-    ggc_print_statistics ();
+    {
+      ggc_print_statistics ();
+      stringpool_statistics ();
+    }
 
   /* Free up memory for the benefit of leak detectors.  */
   free_reg_info ();
@@ -4078,7 +4104,7 @@ decode_f_option (arg)
   else if ((option_value
 	    = skip_leading_substring (arg, "stack-limit-symbol=")))
     {
-      char *nm;
+      const char *nm;
       nm = ggc_strdup (option_value);
       stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, nm);
     }
@@ -4550,6 +4576,7 @@ main (argc, argv)
 
   /* Initialize the garbage-collector.  */
   init_ggc ();
+  init_stringpool ();
   ggc_add_root (&input_file_stack, 1, sizeof input_file_stack,
 		mark_file_stack);
   ggc_add_rtx_root (&stack_limit_rtx, 1);
===================================================================
Index: tree.c
--- tree.c	2000/10/26 09:50:33	1.167
+++ tree.c	2000/10/30 01:32:44
@@ -131,14 +131,6 @@ static const char * const tree_node_kind
   "lang_type kinds"
 };
 
-/* Hash table for uniquizing IDENTIFIER_NODEs by name.  */
-
-#define MAX_HASH_TABLE 1009
-static tree hash_table[MAX_HASH_TABLE];	/* id hash buckets */
-
-/* 0 while creating built-in identifiers.  */
-static int do_identifier_warnings;
-
 /* Unique id for next decl created.  */
 static int next_decl_uid;
 /* Unique id for next type created.  */
@@ -191,7 +183,7 @@ void (*lang_unsave_expr_now) PARAMS ((tr
    built-in tree nodes.  The variable, which is dynamically allocated,
    should be used; the macro is only used to initialize it.  */
 
-static char *built_in_filename;
+static const char *built_in_filename;
 #define BUILT_IN_FILENAME ("<built-in>")
 
 tree global_trees[TI_MAX];
@@ -204,10 +196,6 @@ init_obstacks ()
 {
   gcc_obstack_init (&permanent_obstack);
 
-  /* Init the hash table of identifiers.  */
-  bzero ((char *) hash_table, sizeof hash_table);
-  ggc_add_tree_root (hash_table, sizeof hash_table / sizeof (tree));
-
   /* Initialize the hash table of types.  */
   type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
 				 type_hash_eq, 0);
@@ -555,133 +543,7 @@ copy_list (list)
     }
   return head;
 }
-
-#define HASHBITS 30
-
-/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
-   If an identifier with that name has previously been referred to,
-   the same node is returned this time.  */
-
-tree
-get_identifier (text)
-     register const char *text;
-{
-  register int hi;
-  register int i;
-  register tree idp;
-  register int len, hash_len;
-
-  /* Compute length of text in len.  */
-  len = strlen (text);
-
-  /* Decide how much of that length to hash on */
-  hash_len = len;
-  if (warn_id_clash && len > id_clash_len)
-    hash_len = id_clash_len;
-
-  /* Compute hash code */
-  hi = hash_len * 613 + (unsigned) text[0];
-  for (i = 1; i < hash_len; i += 2)
-    hi = ((hi * 613) + (unsigned) (text[i]));
-
-  hi &= (1 << HASHBITS) - 1;
-  hi %= MAX_HASH_TABLE;
-
-  /* Search table for identifier.  */
-  for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
-    if (IDENTIFIER_LENGTH (idp) == len
-	&& IDENTIFIER_POINTER (idp)[0] == text[0]
-	&& !bcmp (IDENTIFIER_POINTER (idp), text, len))
-      /* Return if found.  */
-      return idp;
-
-  /* Not found; optionally warn about a similar identifier.  */
-  if (warn_id_clash && do_identifier_warnings && len >= id_clash_len)
-    for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
-      if (!strncmp (IDENTIFIER_POINTER (idp), text, id_clash_len))
-	{
-	  warning ("`%s' and `%s' identical in first %d characters",
-		   IDENTIFIER_POINTER (idp), text, id_clash_len);
-	  break;
-	}
 
-  if (TREE_CODE_LENGTH (IDENTIFIER_NODE) < 0)
-    abort ();			/* set_identifier_size hasn't been called.  */
-
-  /* Not found, create one, add to chain */
-  idp = make_node (IDENTIFIER_NODE);
-  IDENTIFIER_LENGTH (idp) = len;
-#ifdef GATHER_STATISTICS
-  id_string_size += len;
-#endif
-
-  IDENTIFIER_POINTER (idp) = ggc_alloc_string (text, len);
-
-  TREE_CHAIN (idp) = hash_table[hi];
-  hash_table[hi] = idp;
-  return idp;			/* <-- return if created */
-}
-
-/* If an identifier with the name TEXT (a null-terminated string) has
-   previously been referred to, return that node; otherwise return
-   NULL_TREE.  */
-
-tree
-maybe_get_identifier (text)
-     register const char *text;
-{
-  register int hi;
-  register int i;
-  register tree idp;
-  register int len, hash_len;
-
-  /* Compute length of text in len.  */
-  len = strlen (text);
-
-  /* Decide how much of that length to hash on */
-  hash_len = len;
-  if (warn_id_clash && len > id_clash_len)
-    hash_len = id_clash_len;
-
-  /* Compute hash code */
-  hi = hash_len * 613 + (unsigned) text[0];
-  for (i = 1; i < hash_len; i += 2)
-    hi = ((hi * 613) + (unsigned) (text[i]));
-
-  hi &= (1 << HASHBITS) - 1;
-  hi %= MAX_HASH_TABLE;
-
-  /* Search table for identifier.  */
-  for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
-    if (IDENTIFIER_LENGTH (idp) == len
-	&& IDENTIFIER_POINTER (idp)[0] == text[0]
-	&& !bcmp (IDENTIFIER_POINTER (idp), text, len))
-      return idp;		/* <-- return if found */
-
-  return NULL_TREE;
-}
-
-/* Enable warnings on similar identifiers (if requested).
-   Done after the built-in identifiers are created.  */
-
-void
-start_identifier_warnings ()
-{
-  do_identifier_warnings = 1;
-}
-
-/* Record the size of an identifier node for the language in use.
-   SIZE is the total size in bytes.
-   This is called by the language-specific files.  This must be
-   called before allocating any identifiers.  */
-
-void
-set_identifier_size (size)
-     int size;
-{
-  tree_code_length[(int) IDENTIFIER_NODE]
-    = (size - sizeof (struct tree_common)) / sizeof (tree);
-}
 
 /* Return a newly constructed INTEGER_CST node whose constant value
    is specified by the two ints LOW and HI.
===================================================================
Index: tree.h
--- tree.h	2000/10/23 04:40:25	1.207
+++ tree.h	2000/10/30 01:32:45
@@ -713,7 +713,7 @@ struct tree_string
   struct rtx_def *rtl;	/* acts as link to register transfer language
 				   (rtl) info */
   int length;
-  char *pointer;
+  const char *pointer;
 };
 
 /* In a COMPLEX_CST node.  */
@@ -1851,6 +1851,10 @@ extern tree integer_types[itk_none];
 #endif
 extern int exact_log2_wide             PARAMS ((unsigned HOST_WIDE_INT));
 extern int floor_log2_wide             PARAMS ((unsigned HOST_WIDE_INT));
+
+/* Approximate positive square root of a host double.  This is for
+   statistical reports, not code generation.  */
+extern double approx_sqrt		PARAMS ((double));
 
 extern char *permalloc			PARAMS ((int));
 extern char *expralloc			PARAMS ((int));
===================================================================
Index: varasm.c
--- varasm.c	2000/10/13 06:26:30	1.136
+++ varasm.c	2000/10/30 01:32:47
@@ -208,7 +208,7 @@ static enum in_section { no_section, in_
 #endif
      
 /* Text of section name when in_section == in_named.  */
-static char *in_named_name;
+static const char *in_named_name;
 
 /* Define functions like text_section for any extra sections.  */
 #ifdef EXTRA_SECTION_FUNCTIONS
@@ -1793,7 +1793,7 @@ assemble_static_space (size)
      int size;
 {
   char name[12];
-  char *namestring;
+  const char *namestring;
   rtx x;
 
 #if 0
@@ -2325,7 +2325,7 @@ struct rtx_const
 struct constant_descriptor
 {
   struct constant_descriptor *next;
-  char *label;
+  const char *label;
   rtx rtl;
   unsigned char contents[1];
 };
@@ -3225,7 +3225,7 @@ struct pool_constant
 
 struct pool_sym
 {
-  char *label;
+  const char *label;
   struct pool_constant *pool;
   struct pool_sym *next;
 };
@@ -3522,7 +3522,7 @@ force_const_mem (mode, x)
   register int hash;
   register struct constant_descriptor *desc;
   char label[256];
-  char *found = 0;
+  const char *found = 0;
   rtx def;
 
   /* If we want this CONST_DOUBLE in the same mode as it is in memory
===================================================================
Index: config/alpha/alpha.c
--- config/alpha/alpha.c	2000/10/20 20:49:27	1.147
+++ config/alpha/alpha.c	2000/10/30 01:32:53
@@ -6232,12 +6232,12 @@ alpha_need_linkage (name, is_local)
   /* Construct a SYMBOL_REF for us to call.  */
   {
     size_t name_len = strlen (name);
-    char *linksym = ggc_alloc_string (NULL, name_len + 6);
-
+    char *linksym = alloca (name_len + 6);
     linksym[0] = '$';
     memcpy (linksym + 1, name, name_len);
     memcpy (linksym + 1 + name_len, "..lk", 5);
-    al->linkage = gen_rtx_SYMBOL_REF (Pmode, linksym);
+    al->linkage = gen_rtx_SYMBOL_REF (Pmode,
+				      ggc_alloc_string (linksym, name_len + 5));
   }
 
   splay_tree_insert (alpha_links, (splay_tree_key) name,
===================================================================
Index: config/arm/arm.c
--- config/arm/arm.c	2000/10/13 15:54:16	1.112
+++ config/arm/arm.c	2000/10/30 01:32:56
@@ -1726,11 +1726,12 @@ arm_encode_call_attribute (decl, flag)
   /* Do not allow weak functions to be treated as short call.  */
   if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
     return;
-  
-  newstr = ggc_alloc_string (NULL, len + 2);
 
-  sprintf (newstr, "%c%s", flag, str);
+  newstr = alloca (len + 2);
+  newstr[0] = flag;
+  strcpy (newstr + 1, str);
 
+  newstr = ggc_alloc_string (newstr, len + 1);
   XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
 }
 
===================================================================
Index: config/i386/i386.c
--- config/i386/i386.c	2000/10/25 17:26:27	1.185
+++ config/i386/i386.c	2000/10/30 01:32:58
@@ -1679,9 +1679,9 @@ ix86_can_use_return_insn_p ()
   return tsize == 0 && nregs == 0;
 }
 
-static char *pic_label_name;
+static const char *pic_label_name;
 static int pic_label_output;
-static char *global_offset_table_name;
+static const char *global_offset_table_name;
 
 /* This function generates code for -fpic that loads %ebx with
    the return address of the caller and then returns.  */
@@ -1737,9 +1737,10 @@ load_pic_register ()
     {
       if (pic_label_name == NULL)
 	{
-	  pic_label_name = ggc_alloc_string (NULL, 32);
+	  char buf[32];
+	  ASM_GENERATE_INTERNAL_LABEL (buf, "LPR", 0);
+	  pic_label_name = ggc_alloc_string (buf, -1);
 	  ggc_add_string_root (&pic_label_name, 1);
-	  ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
 	}
       pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name));
     }
===================================================================
Index: config/ia64/ia64.c
--- config/ia64/ia64.c	2000/10/28 19:42:48	1.58
+++ config/ia64/ia64.c	2000/10/30 01:33:02
@@ -4669,12 +4669,12 @@ ia64_encode_section_info (decl)
 	       && symbol_str[0] != SDATA_NAME_FLAG_CHAR)
 	{
 	  size_t len = strlen (symbol_str);
-	  char *newstr;
+	  char *newstr = alloca (len + 1);
 
-	  newstr = ggc_alloc_string (NULL, len + 1);
 	  *newstr = SDATA_NAME_FLAG_CHAR;
 	  memcpy (newstr + 1, symbol_str, len + 1);
-
+	  
+	  newstr = ggc_alloc_string (newstr, len + 1);
 	  XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
 	}
     }
===================================================================
Index: config/pa/elf.h
--- config/pa/elf.h	2000/05/01 17:30:35	1.7
+++ config/pa/elf.h	2000/10/30 01:33:02
@@ -84,7 +84,7 @@ do {  \
 #define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, RTL) \
   do { fputs ("\t.IMPORT ", FILE);					\
        if (!function_label_operand (RTL, VOIDmode))			\
-	 hppa_encode_label (RTL, 1);					\
+	 hppa_encode_label (RTL);					\
        assemble_name (FILE, XSTR ((RTL), 0));		       		\
        fputs (",ENTRY\n", FILE);					\
      } while (0)
===================================================================
Index: config/pa/pa-protos.h
--- config/pa/pa-protos.h	2000/10/16 16:20:23	1.4
+++ config/pa/pa-protos.h	2000/10/30 01:33:02
@@ -61,7 +61,7 @@ extern void output_global_address PARAMS
 extern void print_operand PARAMS ((FILE *, rtx, int));
 extern rtx legitimize_pic_address PARAMS ((rtx, enum machine_mode, rtx));
 extern struct rtx_def *gen_cmp_fp PARAMS ((enum rtx_code, rtx, rtx));
-extern void hppa_encode_label PARAMS ((rtx, int));
+extern void hppa_encode_label PARAMS ((rtx));
 extern int arith11_operand PARAMS ((rtx, enum machine_mode));
 extern int symbolic_expression_p PARAMS ((rtx));
 extern int hppa_address_cost PARAMS ((rtx));
===================================================================
Index: config/pa/pa.c
--- config/pa/pa.c	2000/10/18 02:12:03	1.82
+++ config/pa/pa.c	2000/10/30 01:33:04
@@ -5939,29 +5939,22 @@ output_call (insn, call_dest, sibcall)
 /* In HPUX 8.0's shared library scheme, special relocations are needed
    for function labels if they might be passed to a function
    in a shared library (because shared libraries don't live in code
-   space), and special magic is needed to construct their address.
+   space), and special magic is needed to construct their address.  */
 
-   For reasons too disgusting to describe storage for the new name
-   is allocated as a ggc string, or as a string on the saveable_obstack
-   (released at function exit) or on the permanent_obstack for things
-   that can never change (libcall names for example). */
-
 void
-hppa_encode_label (sym, permanent)
+hppa_encode_label (sym)
      rtx sym;
-     int permanent;
 {
   const char *str = XSTR (sym, 0);
   int len = strlen (str);
-  char *newstr;
-
-  newstr = ggc_alloc_string (NULL, len + 1);
+  char *newstr = alloca (len + 1);
 
   if (str[0] == '*')
     *newstr++ = *str++;
   strcpy (newstr + 1, str);
   *newstr = '@';
-  XSTR (sym,0) = newstr;
+
+  XSTR (sym,0) = ggc_alloc_string (newstr, len);
 }
 
 int
===================================================================
Index: config/pa/pa.h
--- config/pa/pa.h	2000/10/07 20:53:21	1.94
+++ config/pa/pa.h	2000/10/30 01:33:06
@@ -1494,7 +1494,7 @@ do							\
 	  _rtl = TREE_CST_RTL (DECL);			\
 	SYMBOL_REF_FLAG (XEXP (_rtl, 0)) = 1;		\
 	if (TREE_CODE (DECL) == FUNCTION_DECL)		\
-	  hppa_encode_label (XEXP (DECL_RTL (DECL), 0), 0);\
+	  hppa_encode_label (XEXP (DECL_RTL (DECL), 0));\
       }							\
   }							\
 while (0)
===================================================================
Index: config/pa/som.h
--- config/pa/som.h	2000/06/30 18:14:05	1.12
+++ config/pa/som.h	2000/10/30 01:33:06
@@ -352,7 +352,7 @@ DTORS_SECTION_FUNCTION
 #define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, RTL) \
   do { fputs ("\t.IMPORT ", FILE);					\
        if (!function_label_operand (RTL, VOIDmode))			\
-	 hppa_encode_label (RTL, 1);					\
+	 hppa_encode_label (RTL);					\
        assemble_name (FILE, XSTR ((RTL), 0));		       		\
        fputs (",CODE\n", FILE);						\
      } while (0)
===================================================================
Index: config/rs6000/rs6000.c
--- config/rs6000/rs6000.c	2000/10/17 22:17:34	1.152
+++ config/rs6000/rs6000.c	2000/10/30 01:33:11
@@ -5605,7 +5605,7 @@ rs6000_emit_prologue()
     {
       int i;
       char rname[30];
-      char *alloc_rname;
+      const char *alloc_rname;
       rtvec p;
       p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
       
@@ -6058,7 +6058,7 @@ rs6000_emit_epilogue(sibcall)
 	{
 	  int i;
 	  char rname[30];
-	  char *alloc_rname;
+	  const char *alloc_rname;
 
 	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX, 
 		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
@@ -7579,14 +7579,12 @@ rs6000_encode_section_info (decl)
 	{
 	  size_t len1 = (DEFAULT_ABI == ABI_AIX) ? 1 : 2;
 	  size_t len2 = strlen (XSTR (sym_ref, 0));
-	  char *str;
-
-	  str = ggc_alloc_string (NULL, len1 + len2);
+	  char *str = alloca (len1 + len2 + 1);
 	  str[0] = '.';
 	  str[1] = '.';
 	  memcpy (str + len1, XSTR (sym_ref, 0), len2 + 1);
 
-	  XSTR (sym_ref, 0) = str;
+	  XSTR (sym_ref, 0) = ggc_alloc_string (str, len1 + len2);
 	}
     }
   else if (rs6000_sdata != SDATA_NONE
@@ -7626,13 +7624,11 @@ rs6000_encode_section_info (decl)
 	{
 	  rtx sym_ref = XEXP (DECL_RTL (decl), 0);
 	  size_t len = strlen (XSTR (sym_ref, 0));
-	  char *str;
+	  char *str = alloca (len + 1);
 
-	  str = ggc_alloc_string (NULL, len + 1);
 	  str[0] = '@';
 	  memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
-
-	  XSTR (sym_ref, 0) = str;
+	  XSTR (sym_ref, 0) = ggc_alloc_string (str, len);
 	}
     }
 }
===================================================================
Index: cp/lex.c
--- cp/lex.c	2000/10/13 06:26:43	1.218
+++ cp/lex.c	2000/10/30 01:33:15
@@ -131,7 +131,7 @@ extern int *token_count;
 
 struct impl_files
 {
-  char *filename;
+  const char *filename;
   struct impl_files *next;
 };
 
@@ -140,7 +140,7 @@ static struct impl_files *impl_file_chai
 /* The string used to represent the filename of internally generated
    tree nodes.  The variable, which is dynamically allocated, should
    be used; the macro is only used to initialize it.  */
-static char *internal_filename;
+static const char *internal_filename;
 #define INTERNAL_FILENAME ("<internal>")
 
 /* Return something to represent absolute declarators containing a *.
===================================================================
Index: java/jcf-parse.c
--- java/jcf-parse.c	2000/10/19 04:19:09	1.60
+++ java/jcf-parse.c	2000/10/30 01:33:19
@@ -328,29 +328,33 @@ get_constant (jcf, index)
       {
 	tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index));
 	const char *utf8_ptr = IDENTIFIER_POINTER (name);
-	unsigned char *str_ptr;
 	int utf8_len = IDENTIFIER_LENGTH (name);
-	const unsigned char *str = (const unsigned char *)utf8_ptr;
-	int i = utf8_len;
-	int str_len;
+	unsigned char *str_ptr;
+	unsigned char *str;
+	const unsigned char *utf8;
+	int i, str_len;
 
 	/* Count the number of Unicode characters in the string,
 	   while checking for a malformed Utf8 string. */
-	for (str_len = 0; i > 0; str_len++)
+	utf8 = (const unsigned char *) utf8_ptr;
+	i = utf8_len;
+	str_len = 0;
+	while (i > 0)
 	  {
-	    int char_len = UT8_CHAR_LENGTH (*str);
+	    int char_len = UT8_CHAR_LENGTH (*utf8);
 	    if (char_len < 0 || char_len > 3 || char_len > i)
  	      fatal ("bad string constant");
-	    str += char_len;
+	    utf8 += char_len;
 	    i -= char_len;
+	    str_len++;
 	  }
 
-	value = make_node (STRING_CST);
-	TREE_TYPE (value) = build_pointer_type (string_type_node);
-	TREE_STRING_LENGTH (value) = 2 * str_len;
-	TREE_STRING_POINTER (value) = ggc_alloc (2 * str_len);
-	str_ptr = (unsigned char *) TREE_STRING_POINTER (value);
-	str = (const unsigned char *)utf8_ptr;
+	/* Allocate a scratch buffer, convert the string to UCS2, and copy it
+	   into the new space.  */
+	str_ptr = (unsigned char *) alloca (2 * str_len);
+	str = str_ptr;
+	utf8 = (const unsigned char *)utf8_ptr;
+
 	for (i = 0; i < str_len; i++)
 	  {
 	    int char_value;
@@ -358,31 +362,33 @@ get_constant (jcf, index)
 	    switch (char_len)
 	      {
 	      case 1:
-		char_value = *str++;
+		char_value = *utf8++;
 		break;
 	      case 2:
-		char_value = *str++ & 0x1F;
-		char_value = (char_value << 6) | (*str++ & 0x3F);
+		char_value = *utf8++ & 0x1F;
+		char_value = (char_value << 6) | (*utf8++ & 0x3F);
 		break;
 	      case 3:
-		char_value = *str++ & 0x0F;
-		char_value = (char_value << 6) | (*str++ & 0x3F);
-		char_value = (char_value << 6) | (*str++ & 0x3F);
+		char_value = *utf8++ & 0x0F;
+		char_value = (char_value << 6) | (*utf8++ & 0x3F);
+		char_value = (char_value << 6) | (*utf8++ & 0x3F);
 		break;
 	      default:
 		goto bad;
 	      }
 	    if (BYTES_BIG_ENDIAN)
 	      {
-		*str_ptr++ = char_value >> 8;
-		*str_ptr++ = char_value & 0xFF;
+		*str++ = char_value >> 8;
+		*str++ = char_value & 0xFF;
 	      }
 	    else
 	      {
-		*str_ptr++ = char_value & 0xFF;
-		*str_ptr++ = char_value >> 8;
+		*str++ = char_value & 0xFF;
+		*str++ = char_value >> 8;
 	      }
 	  }
+	value = build_string (str - str_ptr, str_ptr);
+	TREE_TYPE (value) = build_pointer_type (string_type_node);
       }
       break;
     default:
===================================================================
Index: java/parse.y
--- java/parse.y	2000/10/25 05:47:28	1.221
+++ java/parse.y	2000/10/30 01:33:25
@@ -13065,11 +13065,7 @@ do_merge_string_cste (cste, string, stri
   const char *old = TREE_STRING_POINTER (cste);
   int old_len = TREE_STRING_LENGTH (cste);
   int len = old_len + string_len;
-  char *new;
-  
-  cste = make_node (STRING_CST);
-  TREE_STRING_LENGTH (cste) = len;
-  new = TREE_STRING_POINTER (cste) = ggc_alloc (len+1);
+  char *new = alloca (len+1);
 
   if (after)
     {
@@ -13082,7 +13078,7 @@ do_merge_string_cste (cste, string, stri
       memcpy (&new [old_len], string, string_len);
     }
   new [len] = '\0';
-  return cste;
+  return build_string (len, new);
 }
 
 /* Tries to merge OP1 (a STRING_CST) and OP2 (if suitable). Return a


More information about the Gcc-patches mailing list