[PATCH]: An almost working copying collector for gcc

Daniel Berlin dberlin@dberlin.org
Wed Dec 11 19:37:00 GMT 2002


It copies (see below), but crashes because we have things we expect to
still point to the same place, but don't.  The things that point to
them don't actually appear to be accessible from the root set, thus, we
never forward them.
It's possible they are only touched from the set of roots added by
ggc_add_root, which need to be changed by hand to DTRT for a copying
collector.

I'm too lazy to finish the segv handler to handle these cases
automatically for us, but one could do so.


It also does properly copy and move rtl and trees, and anything it
*knows* about.

The code gengtype outputs isn't indented properly, and probably could be
written a bit nicer.


It also currently uses a fixed heap of 64meg.
I just wanted to see how much our memory really *is* fragmented, and how
badly it affects our footprint.

One could use this for testing performance loss due to memory
fragmentation (caused by mark and sweep) by ignoring ignoring the gc times
(since it's not generational or particularly written to be superfast) and
seeing if the times on other things change by a noticeable amount.


I'm posting it because it's probably useful to *someone*, possibly at
Apple, RedHat, CodeSourcery, etc, or just really bored, who wants to look
at improving gcc performance

Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.105.4.2
diff -u -3 -p -r1.105.4.2 c-tree.h
--- c-tree.h	17 Sep 2002 22:58:37 -0000	1.105.4.2
+++ c-tree.h	12 Dec 2002 03:19:49 -0000
@@ -46,10 +46,9 @@ struct lang_identifier GTY(())
 };

 /* The resulting tree type.  */
-
-union lang_tree_node
-  GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
-       chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
+union lang_tree_node GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+			  chain_nextp ("(union lang_tree_node **)&TREE_CHAIN (&%h.generic)"),
+		chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
 {
   union tree_node GTY ((tag ("0"),
 			desc ("tree_node_structure (&%h)")))
Index: configure
===================================================================
RCS file: /cvs/gcc/gcc/gcc/configure,v
retrieving revision 1.630.4.11
diff -u -3 -p -r1.630.4.11 configure
--- configure	3 Dec 2002 17:34:46 -0000	1.630.4.11
+++ configure	12 Dec 2002 03:19:51 -0000
@@ -2388,7 +2388,7 @@ EOF
 fi

 # Find some useful tools
-for ac_prog in mawk gawk nawk awk
+for ac_prog in gawk mawk nawk awk
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
@@ -8467,7 +8467,7 @@ if test "${with_gc+set}" = set; then
     ;;
 esac
 else
-  GGC=ggc-page
+  GGC=ggc-copy
 fi


Index: configure.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/configure.in,v
retrieving revision 1.617.4.11
diff -u -3 -p -r1.617.4.11 configure.in
--- configure.in	3 Dec 2002 17:34:49 -0000	1.617.4.11
+++ configure.in	12 Dec 2002 03:19:51 -0000
@@ -2486,7 +2486,7 @@ AC_ARG_WITH(gc,
     AC_MSG_ERROR([$withval is an invalid option to --with-gc])
     ;;
 esac],
-[GGC=ggc-page])
+[GGC=ggc-copy])
 AC_SUBST(GGC)
 echo "Using $GGC for garbage collection."

Index: gengtype.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gengtype.c,v
retrieving revision 1.14.4.6
diff -u -3 -p -r1.14.4.6 gengtype.c
--- gengtype.c	3 Dec 2002 02:25:46 -0000	1.14.4.6
+++ gengtype.c	12 Dec 2002 03:19:57 -0000
@@ -1121,7 +1121,7 @@ open_base_files ()
       "hashtab.h", "splay-tree.h", "bitmap.h", "tree.h", "rtl.h",
       "function.h", "insn-config.h", "expr.h", "hard-reg-set.h",
       "basic-block.h", "cselib.h", "insn-addr.h", "ssa.h", "optabs.h",
-      "libfuncs.h", "debug.h", "ggc.h",
+      "libfuncs.h", "debug.h", "ggc.h", "real.h",
       NULL
     };
     const char *const *ifp;
@@ -1477,8 +1477,8 @@ output_mangled_typename (of, t)
    the current parameter (from an enclosing param_is option).  */

 static void
-write_gc_structure_fields (of, s, val, prev_val, opts, indent, line, bitmap,
-			   param)
+write_copy_gc_structure_fields (of, s, val, prev_val, opts, indent, line, bitmap,
+			        param)
      outf_p of;
      type_p s;
      const char *val;
@@ -1657,8 +1657,8 @@ write_gc_structure_fields (of, s, val, p
 	    char *newval;

 	    newval = xasprintf ("%s%s%s", val, dot, f->name);
-	    write_gc_structure_fields (of, t, newval, val, f->opt, indent,
-				       &f->line, bitmap, param);
+	    write_copy_gc_structure_fields (of, t, newval, val, f->opt, indent,
+			    		    &f->line, bitmap, param);
 	    free (newval);
 	    break;
 	  }
@@ -1673,7 +1673,7 @@ write_gc_structure_fields (of, s, val, p
 	      else if (UNION_OR_STRUCT_P (t->u.p)
 		       || t->u.p->kind == TYPE_PARAM_STRUCT)
 		{
-		  oprintf (of, "%*sgt_ggc_m_", indent, "");
+		  oprintf (of, "%*s%s%s%s = gt_ggc_c_", indent,"" ,val, dot, f->name);
 		  output_mangled_typename (of, t->u.p);
 		  oprintf (of, " (");
 		  if (needs_cast_p)
@@ -1687,10 +1687,12 @@ write_gc_structure_fields (of, s, val, p
 			       f->name);
 	      break;
 	    }
-	  else if (t->u.p->kind == TYPE_SCALAR
-		   || t->u.p->kind == TYPE_STRING)
-	    oprintf (of, "%*sggc_mark (%s%s%s);\n", indent, "",
-		     val, dot, f->name);
+	  else if (t->u.p->kind == TYPE_STRING)
+		  oprintf (of, "%*s%s%s%s = alloc_and_copy(%s%s%s, strlen(%s%s%s), 0);\n", indent, "", val, dot, f->name, val, dot, f->name, val, dot, f->name);
+	  else if (t->u.p->kind == TYPE_SCALAR)
+
+	    oprintf (of, "%*s%s%s%s = alloc_and_copy (%s%s%s, sizeof (%s%s%s), 0);\n", indent, "",
+		     val, dot, f->name, val, dot, f->name, val, dot, f->name);
 	  else
 	    {
 	      int loopcounter = ++gc_counter;
@@ -1699,8 +1701,8 @@ write_gc_structure_fields (of, s, val, p
 		       val, dot, f->name);
 	      indent += 2;
 	      oprintf (of, "%*ssize_t i%d;\n", indent, "", loopcounter);
-	      oprintf (of, "%*sggc_set_mark (%s%s%s);\n", indent, "",
-		       val, dot, f->name);
+	      oprintf (of, "%*s%s%s%s = alloc_and_copy (%s%s%s, sizeof (%s%s%s), 0);\n", indent, "",
+		       val, dot, f->name, val, dot, f->name, val, dot, f->name);
 	      oprintf (of, "%*sfor (i%d = 0; i%d < (size_t)(", indent, "",
 		       loopcounter, loopcounter);
 	      output_escaped_param (of, length, val, prev_val, "length", line);
@@ -1715,7 +1717,7 @@ write_gc_structure_fields (of, s, val, p

 		    newval = xasprintf ("%s%s%s[i%d]", val, dot, f->name,
 					loopcounter);
-		    write_gc_structure_fields (of, t->u.p, newval, val,
+		    write_copy_gc_structure_fields (of, t->u.p, newval, val,
 					       f->opt, indent, &f->line,
 					       bitmap, param);
 		    free (newval);
@@ -1725,7 +1727,7 @@ write_gc_structure_fields (of, s, val, p
 		  if (UNION_OR_STRUCT_P (t->u.p->u.p)
 		      || t->u.p->u.p->kind == TYPE_PARAM_STRUCT)
 		    {
-		      oprintf (of, "%*sgt_ggc_m_", indent, "");
+		      oprintf (of, "%*s%s%s%s[i%d] = gt_ggc_c_", indent, "", val, dot, f->name, loopcounter);
 		      output_mangled_typename (of, t->u.p->u.p);
 		      oprintf (of, " (%s%s%s[i%d]);\n", val, dot, f->name,
 			       loopcounter);
@@ -1798,7 +1800,12 @@ write_gc_structure_fields (of, s, val, p
 		&& (UNION_OR_STRUCT_P (ta->u.p)
 		    || ta->u.p->kind == TYPE_PARAM_STRUCT))
 	      {
-		oprintf (of, "%*sgt_ggc_m_", indent, "");
+		oprintf (of, "%*s%s%s%s", indent, "", val, dot, f->name);
+		for (ta = t, i = 0;
+		     ta->kind == TYPE_ARRAY;
+		     ta = ta->u.a.p, i++)
+		  oprintf (of, "[i%d_%d]", loopcounter, i);
+		oprintf (of, " = gt_ggc_c_");
 		output_mangled_typename (of, ta->u.p);
 		oprintf (of, " (%s%s%s", val, dot, f->name);
 		for (ta = t, i = 0;
@@ -1823,7 +1830,7 @@ write_gc_structure_fields (of, s, val, p
 		     ta = ta->u.a.p, i++)
 		  sprintf (newval + strlen (newval), "[i%d_%d]",
 			   loopcounter, i);
-		write_gc_structure_fields (of, t->u.p, newval, val,
+		write_copy_gc_structure_fields (of, t->u.p, newval, val,
 					   f->opt, indent, &f->line, bitmap,
 					   param);
 		free (newval);
@@ -1875,7 +1882,7 @@ write_gc_structure_fields (of, s, val, p
    enclosing PARAM_IS option.  */

 static void
-write_gc_marker_routine_for_structure (orig_s, s, param)
+write_copy_gc_marker_routine_for_structure (orig_s, s, param)
      type_p orig_s;
      type_p s;
      type_p * param;
@@ -1884,6 +1891,7 @@ write_gc_marker_routine_for_structure (o
   const char *fn = s->u.s.line.file;
   int i;
   const char *chain_next = NULL;
+  const char *chain_nextp = NULL;
   const char *chain_prev = NULL;
   options_p opt;

@@ -1898,6 +1906,8 @@ write_gc_marker_routine_for_structure (o
   for (opt = s->u.s.opt; opt; opt = opt->next)
     if (strcmp (opt->name, "chain_next") == 0)
       chain_next = (const char *) opt->info;
+    else if (strcmp (opt->name, "chain_nextp") == 0)
+      chain_nextp = (const char *) opt->info;
     else if (strcmp (opt->name, "chain_prev") == 0)
       chain_prev = (const char *) opt->info;

@@ -1905,73 +1915,95 @@ write_gc_marker_routine_for_structure (o
     error_at_line (&s->u.s.line, "chain_prev without chain_next");

   oprintf (f, "\n");
-  oprintf (f, "void\n");
+  oprintf (f, "void *\n");
   if (param == NULL)
-    oprintf (f, "gt_ggc_mx_%s", s->u.s.tag);
+    oprintf (f, "gt_ggc_cx_%s", s->u.s.tag);
   else
     {
-      oprintf (f, "gt_ggc_m_");
+      oprintf (f, "gt_ggc_c_");
       output_mangled_typename (f, orig_s);
     }
   oprintf (f, " (x_p)\n");
   oprintf (f, "      void *x_p;\n");
   oprintf (f, "{\n");
+  oprintf (f, "  bool forwarded = 0;\n");
   oprintf (f, "  %s %s * %sx = (%s %s *)x_p;\n",
 	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
-	   chain_next == NULL ? "const " : "",
+	   chain_next == NULL ? "" : "",
+	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+  oprintf (f, "  %s %s * %snewx = (%s %s *)x_p;\n",
+	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
+	   chain_next == NULL ? "" : "",
 	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
   if (chain_next != NULL)
-    oprintf (f, "  %s %s * xlimit = x;\n",
+    oprintf (f, "  %s %s * xlimit ;\n",
 	     s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
-  if (chain_next == NULL)
-    oprintf (f, "  if (ggc_test_and_set_mark (x))\n");
-  else
+  oprintf (f, "  if (done_already (x)) return x;\n");
+  oprintf (f, "if (x != NULL) {\n");
+    oprintf (f, "  x = alloc_and_copy (x, sizeof (*x), &forwarded);\n");
+    oprintf (f, "  newx = x;\n");
+  oprintf (f, "if (forwarded) return newx;\n");
+  if (chain_next != NULL)
+    oprintf (f, " xlimit = x_p;\n");
+  if (chain_next != NULL)
     {
-      oprintf (f, "  while (ggc_test_and_set_mark (xlimit))\n");
+      oprintf (f, "  while (xlimit && !done_already (xlimit))\n");
+      oprintf (f, "   {\n");
       oprintf (f, "   xlimit = (");
       output_escaped_param (f, chain_next, "*xlimit", "*xlimit",
 			    "chain_next", &s->u.s.line);
       oprintf (f, ");\n");
+      oprintf (f, "}\n");
       if (chain_prev != NULL)
 	{
 	  oprintf (f, "  if (x != xlimit)\n");
 	  oprintf (f, "    for (;;)\n");
 	  oprintf (f, "      {\n");
-	  oprintf (f, "        %s %s * const xprev = (",
+	  oprintf (f, "        %s %s * xprev = (",
 		   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
 	  output_escaped_param (f, chain_prev, "*x", "*x",
 				"chain_prev", &s->u.s.line);
 	  oprintf (f, ");\n");
 	  oprintf (f, "        if (xprev == NULL) break;\n");
 	  oprintf (f, "        x = xprev;\n");
-	  oprintf (f, "        ggc_set_mark (xprev);\n");
 	  oprintf (f, "      }\n");
 	}
       oprintf (f, "  while (x != xlimit)\n");
     }
   oprintf (f, "    {\n");
+  if (chain_next != NULL)
+	  oprintf (f, "  %s %s ** %sxpp;\n",
+	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
+	   chain_next == NULL ? "" : "");

   gc_counter = 0;
-  write_gc_structure_fields (f, s, "(*x)", "not valid postage",
+  write_copy_gc_structure_fields (f, s, "(*x)", "not valid postage",
 			     s->u.s.opt, 6, &s->u.s.line, s->u.s.bitmap,
 			     param);

   if (chain_next != NULL)
     {
-      oprintf (f, "      x = (");
-      output_escaped_param (f, chain_next, "*x", "*x",
-			    "chain_next", &s->u.s.line);
+      oprintf (f, "      xpp = (");
+      output_escaped_param (f, chain_nextp, "*x", "*x",
+			    "chain_nextp", &s->u.s.line);
       oprintf (f, ");\n");
+      oprintf (f, "if (xpp)\n {");
+      oprintf (f, "      *xpp = alloc_and_copy (*xpp, sizeof (*(*xpp)), &forwarded);\n");
+      oprintf (f, "      if (forwarded) break;\n");
+      oprintf (f, " }\n");
+      oprintf (f, "      x = xpp ? *xpp : 0 ;\n");
     }

   oprintf (f, "  }\n");
+  oprintf (f, "  }\n");
+  oprintf (f, " return newx;\n");
   oprintf (f, "}\n");
 }

 /* Write out marker routines for STRUCTURES and PARAM_STRUCTS.  */

 static void
-write_gc_types (structures, param_structs)
+write_copy_gc_types (structures, param_structs)
      type_p structures;
      type_p param_structs;
 {
@@ -1988,13 +2020,9 @@ write_gc_types (structures, param_struct
 	    && s->u.s.line.file == NULL)
 	  continue;

-	oprintf (header_file, "#define gt_ggc_m_");
+	oprintf (header_file, "#define gt_ggc_c_");
 	output_mangled_typename (header_file, s);
-	oprintf (header_file, "(X) do { \\\n");
-	oprintf (header_file,
-		 "  if (X != NULL) gt_ggc_mx_%s (X);\\\n", s->u.s.tag);
-	oprintf (header_file,
-		 "  } while (0)\n");
+	oprintf (header_file, "(X) X != NULL ? gt_ggc_cx_%s (X) : X;\n", s->u.s.tag);

 	for (opt = s->u.s.opt; opt; opt = opt->next)
 	  if (strcmp (opt->name, "ptr_alias") == 0)
@@ -2004,7 +2032,7 @@ write_gc_types (structures, param_struct
 		  || t->kind == TYPE_UNION
 		  || t->kind == TYPE_LANG_STRUCT)
 		oprintf (header_file,
-			 "#define gt_ggc_mx_%s gt_ggc_mx_%s\n",
+			 "#define gt_ggc_cx_%s gt_ggc_cx_%s\n",
 			 s->u.s.tag, t->u.s.tag);
 	      else
 		error_at_line (&s->u.s.line,
@@ -2016,7 +2044,7 @@ write_gc_types (structures, param_struct

 	/* Declare the marker procedure only once.  */
 	oprintf (header_file,
-		 "extern void gt_ggc_mx_%s PARAMS ((void *));\n",
+		 "extern void *gt_ggc_cx_%s PARAMS ((void *));\n",
 		 s->u.s.tag);

 	if (s->u.s.line.file == NULL)
@@ -2030,10 +2058,10 @@ write_gc_types (structures, param_struct
 	  {
 	    type_p ss;
 	    for (ss = s->u.s.lang_struct; ss; ss = ss->next)
-	      write_gc_marker_routine_for_structure (s, ss, NULL);
+	      write_copy_gc_marker_routine_for_structure (s, ss, NULL);
 	  }
 	else
-	  write_gc_marker_routine_for_structure (s, s, NULL);
+	  write_copy_gc_marker_routine_for_structure (s, s, NULL);
       }

   for (s = param_structs; s; s = s->next)
@@ -2043,7 +2071,7 @@ write_gc_types (structures, param_struct
 	type_p stru = s->u.param_struct.stru;

 	/* Declare the marker procedure.  */
-	oprintf (header_file, "extern void gt_ggc_m_");
+	oprintf (header_file, "extern void * gt_ggc_c_");
 	output_mangled_typename (header_file, s);
 	oprintf (header_file, " PARAMS ((void *));\n");

@@ -2058,137 +2086,1192 @@ write_gc_types (structures, param_struct
 	  {
 	    type_p ss;
 	    for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
-	      write_gc_marker_routine_for_structure (s, ss, param);
+	      write_copy_gc_marker_routine_for_structure (s, ss, param);
 	  }
 	else
-	  write_gc_marker_routine_for_structure (s, stru, param);
-      }
-}
-
-/* Write out the 'enum' definition for gt_types_enum.  */
-
-static void
-write_enum_defn (structures, param_structs)
-     type_p structures;
-     type_p param_structs;
-{
-  type_p s;
-
-  oprintf (header_file, "\n/* Enumeration of types known.  */\n");
-  oprintf (header_file, "enum gt_types_enum {\n");
-  for (s = structures; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO
-	|| s->gc_used == GC_MAYBE_POINTED_TO)
-      {
-	if (s->gc_used == GC_MAYBE_POINTED_TO
-	    && s->u.s.line.file == NULL)
-	  continue;
-
-	oprintf (header_file, " gt_ggc_e_");
-	output_mangled_typename (header_file, s);
-	oprintf (header_file, ", \n");
-      }
-  for (s = param_structs; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO)
-      {
-	oprintf (header_file, " gt_e_");
-	output_mangled_typename (header_file, s);
-	oprintf (header_file, ", \n");
+	  write_copy_gc_marker_routine_for_structure (s, stru, param);
       }
-  oprintf (header_file, " gt_types_enum_last\n");
-  oprintf (header_file, "};\n");
 }

-
-/* Mangle FN and print it to F.  */
+/* Write out code to OF which marks the fields of S.  VAL references
+   the current object, PREV_VAL the object containing the current
+   object, OPTS is a list of options to apply, INDENT is the current
+   indentation level, LINE is used to print error messages, BITMAP
+   indicates which languages to print the structure for, and PARAM is
+   the current parameter (from an enclosing param_is option).  */

 static void
-put_mangled_filename (f, fn)
-     outf_p f;
-     const char *fn;
+write_gc_structure_fields (of, s, val, prev_val, opts, indent, line, bitmap,
+			   param)
+     outf_p of;
+     type_p s;
+     const char *val;
+     const char *prev_val;
+     options_p opts;
+     int indent;
+     struct fileloc *line;
+     lang_bitmap bitmap;
+     type_p * param;
 {
-  const char *name = get_output_file_name (fn);
-  for (; *name != 0; name++)
-    if (ISALNUM (*name))
-      oprintf (f, "%c", *name);
-    else
-      oprintf (f, "%c", '_');
-}
+  pair_p f;
+  int seen_default = 0;

-/* Finish off the currently-created root tables in FLP.  PFX, TNAME,
-   LASTNAME, and NAME are all strings to insert in various places in
-   the resulting code.  */
+  if (! s->u.s.line.file)
+    error_at_line (line, "incomplete structure `%s'", s->u.s.tag);
+  else if ((s->u.s.bitmap & bitmap) != bitmap)
+    {
+      error_at_line (line, "structure defined for mismatching languages");
+      error_at_line (&s->u.s.line, "one structure defined here");
+    }
+
+  if (s->kind == TYPE_UNION)
+    {
+      const char *tagexpr = NULL;
+      options_p oo;
+
+      for (oo = opts; oo; oo = oo->next)
+	if (strcmp (oo->name, "desc") == 0)
+	  tagexpr = (const char *)oo->info;
+      if (tagexpr == NULL)
+	{
+	  tagexpr = "1";
+	  error_at_line (line, "missing `desc' option");
+	}

-static void
-finish_root_table (flp, pfx, lastname, tname, name)
-     struct flist *flp;
-     const char *pfx;
-     const char *tname;
-     const char *lastname;
-     const char *name;
-{
-  struct flist *fli2;
-  unsigned started_bitmap = 0;
+      oprintf (of, "%*sswitch (", indent, "");
+      output_escaped_param (of, tagexpr, val, prev_val, "desc", line);
+      oprintf (of, ")\n");
+      indent += 2;
+      oprintf (of, "%*s{\n", indent, "");
+    }

-  for (fli2 = flp; fli2; fli2 = fli2->next)
-    if (fli2->started_p)
-      {
-	oprintf (fli2->f, "  %s\n", lastname);
-	oprintf (fli2->f, "};\n\n");
-      }
+  for (f = s->u.s.fields; f; f = f->next)
+    {
+      const char *tagid = NULL;
+      const char *length = NULL;
+      int skip_p = 0;
+      int default_p = 0;
+      int maybe_undef_p = 0;
+      int use_param_num = -1;
+      int use_params_p = 0;
+      int needs_cast_p = 0;
+      options_p oo;
+      type_p t = f->type;
+      const char *dot = ".";
+
+      for (oo = f->opt; oo; oo = oo->next)
+	if (strcmp (oo->name, "length") == 0)
+	  length = (const char *)oo->info;
+	else if (strcmp (oo->name, "maybe_undef") == 0)
+	  maybe_undef_p = 1;
+	else if (strcmp (oo->name, "tag") == 0)
+	  tagid = (const char *)oo->info;
+	else if (strcmp (oo->name, "special") == 0)
+	  ;
+	else if (strcmp (oo->name, "skip") == 0)
+	  skip_p = 1;
+	else if (strcmp (oo->name, "default") == 0)
+	  default_p = 1;
+	else if (strcmp (oo->name, "desc") == 0)
+	  ;
+ 	else if (strcmp (oo->name, "descbits") == 0)
+	  ;
+ 	else if (strcmp (oo->name, "param_is") == 0)
+	  ;
+	else if (strncmp (oo->name, "use_param", 9) == 0
+		 && (oo->name[9] == '\0' || ISDIGIT (oo->name[9])))
+	  use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0';
+	else if (strcmp (oo->name, "use_params") == 0)
+	  use_params_p = 1;
+	else if (strcmp (oo->name, "dot") == 0)
+	  dot = (const char *)oo->info;
+	else
+	  error_at_line (&f->line, "unknown field option `%s'\n", oo->name);

-  for (fli2 = flp; fli2; fli2 = fli2->next)
-    if (fli2->started_p)
-      {
-	lang_bitmap bitmap = get_base_file_bitmap (fli2->name);
-	int fnum;
+      if (skip_p)
+	continue;

-	for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
-	  if (bitmap & 1)
+      if (use_params_p)
+	{
+	  int pointer_p = t->kind == TYPE_POINTER;
+
+	  if (pointer_p)
+	    t = t->u.p;
+	  t = find_param_structure (t, param);
+	  if (pointer_p)
+	    t = create_pointer (t);
+	}
+
+      if (use_param_num != -1)
+	{
+	  if (param != NULL && param[use_param_num] != NULL)
 	    {
-	      oprintf (base_files[fnum],
-		       "extern const struct %s gt_ggc_%s_",
-		       tname, pfx);
-	      put_mangled_filename (base_files[fnum], fli2->name);
-	      oprintf (base_files[fnum], "[];\n");
+	      type_p nt = param[use_param_num];
+
+	      if (t->kind == TYPE_ARRAY)
+		nt = create_array (nt, t->u.a.len);
+	      else if (length != NULL && t->kind == TYPE_POINTER)
+		nt = create_pointer (nt);
+	      needs_cast_p = (t->kind != TYPE_POINTER
+			      && nt->kind == TYPE_POINTER);
+	      t = nt;
 	    }
-      }
-
-  for (fli2 = flp; fli2; fli2 = fli2->next)
-    if (fli2->started_p)
-      {
-	lang_bitmap bitmap = get_base_file_bitmap (fli2->name);
-	int fnum;
+	  else if (s->kind != TYPE_UNION)
+	    error_at_line (&f->line, "no parameter defined");
+	}
+
+      if (t->kind == TYPE_SCALAR
+	  || (t->kind == TYPE_ARRAY
+	      && t->u.a.p->kind == TYPE_SCALAR))
+	continue;
+
+      seen_default |= default_p;
+
+      if (maybe_undef_p
+	  && (t->kind != TYPE_POINTER
+	      || t->u.p->kind != TYPE_STRUCT))
+	error_at_line (&f->line,
+		       "field `%s' has invalid option `maybe_undef_p'\n",
+		       f->name);
+      if (s->kind == TYPE_UNION)
+	{
+	  if (tagid)
+	    {
+	      oprintf (of, "%*scase %s:\n", indent, "", tagid);
+
+	    }
+	  else if (default_p)
+	    {
+	      oprintf (of, "%*sdefault:\n", indent, "");
+	    }
+	  else
+	    {
+	      error_at_line (&f->line, "field `%s' has no tag", f->name);
+	      continue;
+	    }
+	  indent += 2;
+	}
+
+      switch (t->kind)
+	{
+	case TYPE_STRING:
+	  /* Do nothing; strings go in the string pool.  */
+	  break;
+
+	case TYPE_LANG_STRUCT:
+	  {
+	    type_p ti;
+	    for (ti = t->u.s.lang_struct; ti; ti = ti->next)
+	      if (ti->u.s.bitmap & bitmap)
+		{
+		  t = ti;
+		  break;
+		}
+	    if (ti == NULL)
+	      {
+		error_at_line (&f->line,
+			       "structure not defined for this language");
+		break;
+	      }
+	  }
+	  /* Fall through...  */
+	case TYPE_STRUCT:
+	case TYPE_UNION:
+	  {
+	    char *newval;
+
+	    newval = xasprintf ("%s%s%s", val, dot, f->name);
+	    write_gc_structure_fields (of, t, newval, val, f->opt, indent,
+				       &f->line, bitmap, param);
+	    free (newval);
+	    break;
+	  }
+
+	case TYPE_POINTER:
+	  if (! length)
+	    {
+	      if (maybe_undef_p
+		  && t->u.p->u.s.line.file == NULL)
+		oprintf (of, "%*sif (%s%s%s) abort();\n", indent, "",
+			 val, dot, f->name);
+	      else if (UNION_OR_STRUCT_P (t->u.p)
+		       || t->u.p->kind == TYPE_PARAM_STRUCT)
+		{
+		  oprintf (of, "%*sgt_ggc_m_", indent, "");
+		  output_mangled_typename (of, t->u.p);
+		  oprintf (of, " (");
+		  if (needs_cast_p)
+		    oprintf (of, "(%s %s *)",
+			     UNION_P (t->u.p) ? "union" : "struct",
+			     t->u.p->u.s.tag);
+		  oprintf (of, "%s%s%s);\n", val, dot, f->name);
+		}
+	      else
+		error_at_line (&f->line, "field `%s' is pointer to scalar",
+			       f->name);
+	      break;
+	    }
+	  else if (t->u.p->kind == TYPE_SCALAR
+		   || t->u.p->kind == TYPE_STRING)
+	    oprintf (of, "%*sggc_mark (%s%s%s);\n", indent, "",
+		     val, dot, f->name);
+	  else
+	    {
+	      int loopcounter = ++gc_counter;
+
+	      oprintf (of, "%*sif (%s%s%s != NULL) {\n", indent, "",
+		       val, dot, f->name);
+	      indent += 2;
+	      oprintf (of, "%*ssize_t i%d;\n", indent, "", loopcounter);
+	      oprintf (of, "%*sggc_set_mark (%s%s%s);\n", indent, "",
+		       val, dot, f->name);
+	      oprintf (of, "%*sfor (i%d = 0; i%d < (size_t)(", indent, "",
+		       loopcounter, loopcounter);
+	      output_escaped_param (of, length, val, prev_val, "length", line);
+	      oprintf (of, "); i%d++) {\n", loopcounter);
+	      indent += 2;
+	      switch (t->u.p->kind)
+		{
+		case TYPE_STRUCT:
+		case TYPE_UNION:
+		  {
+		    char *newval;
+
+		    newval = xasprintf ("%s%s%s[i%d]", val, dot, f->name,
+					loopcounter);
+		    write_gc_structure_fields (of, t->u.p, newval, val,
+					       f->opt, indent, &f->line,
+					       bitmap, param);
+		    free (newval);
+		    break;
+		  }
+		case TYPE_POINTER:
+		  if (UNION_OR_STRUCT_P (t->u.p->u.p)
+		      || t->u.p->u.p->kind == TYPE_PARAM_STRUCT)
+		    {
+		      oprintf (of, "%*sgt_ggc_m_", indent, "");
+		      output_mangled_typename (of, t->u.p->u.p);
+		      oprintf (of, " (%s%s%s[i%d]);\n", val, dot, f->name,
+			       loopcounter);
+		    }
+		  else
+		    error_at_line (&f->line,
+				   "field `%s' is array of pointer to scalar",
+				   f->name);
+		  break;
+		default:
+		  error_at_line (&f->line,
+				 "field `%s' is array of unimplemented type",
+				 f->name);
+		  break;
+		}
+	      indent -= 2;
+	      oprintf (of, "%*s}\n", indent, "");
+	      indent -= 2;
+	      oprintf (of, "%*s}\n", indent, "");
+	    }
+	  break;
+
+	case TYPE_ARRAY:
+	  {
+	    int loopcounter = ++gc_counter;
+	    type_p ta;
+	    int i;
+
+	    if (! length &&
+		(strcmp (t->u.a.len, "0") == 0
+		 || strcmp (t->u.a.len, "1") == 0))
+	      error_at_line (&f->line,
+			     "field `%s' is array of size %s",
+			     f->name, t->u.a.len);
+
+	    /* Arrays of scalars can be ignored.  */
+	    for (ta = t; ta->kind == TYPE_ARRAY; ta = ta->u.a.p)
+	      ;
+	    if (ta->kind == TYPE_SCALAR
+		|| ta->kind == TYPE_STRING)
+	      break;
+
+	    oprintf (of, "%*s{\n", indent, "");
+	    indent += 2;
+
+	    for (ta = t, i = 0; ta->kind == TYPE_ARRAY; ta = ta->u.a.p, i++)
+	      {
+		oprintf (of, "%*ssize_t i%d_%d;\n",
+			 indent, "", loopcounter, i);
+		oprintf (of, "%*sconst size_t ilimit%d_%d = (",
+			 indent, "", loopcounter, i);
+		if (i == 0 && length != NULL)
+		  output_escaped_param (of, length, val, prev_val,
+					"length", line);
+		else
+		  oprintf (of, "%s", ta->u.a.len);
+		oprintf (of, ");\n");
+	      }
+
+	    for (ta = t, i = 0; ta->kind == TYPE_ARRAY; ta = ta->u.a.p, i++)
+	      {
+		oprintf (of,
+		 "%*sfor (i%d_%d = 0; i%d_%d < ilimit%d_%d; i%d_%d++) {\n",
+			 indent, "", loopcounter, i, loopcounter, i,
+			 loopcounter, i, loopcounter, i);
+		indent += 2;
+	      }
+
+	    if (ta->kind == TYPE_POINTER
+		&& (UNION_OR_STRUCT_P (ta->u.p)
+		    || ta->u.p->kind == TYPE_PARAM_STRUCT))
+	      {
+		oprintf (of, "%*sgt_ggc_m_", indent, "");
+		output_mangled_typename (of, ta->u.p);
+		oprintf (of, " (%s%s%s", val, dot, f->name);
+		for (ta = t, i = 0;
+		     ta->kind == TYPE_ARRAY;
+		     ta = ta->u.a.p, i++)
+		  oprintf (of, "[i%d_%d]", loopcounter, i);
+		oprintf (of, ");\n");
+	      }
+	    else if (ta->kind == TYPE_STRUCT || ta->kind == TYPE_UNION)
+	      {
+		char *newval;
+		int len;
+
+		len = strlen (val) + strlen (f->name) + 2;
+		for (ta = t; ta->kind == TYPE_ARRAY; ta = ta->u.a.p)
+		  len += sizeof ("[i_]") + 2*6;
+
+		newval = xmalloc (len);
+		sprintf (newval, "%s%s%s", val, dot, f->name);
+		for (ta = t, i = 0;
+		     ta->kind == TYPE_ARRAY;
+		     ta = ta->u.a.p, i++)
+		  sprintf (newval + strlen (newval), "[i%d_%d]",
+			   loopcounter, i);
+		write_gc_structure_fields (of, t->u.p, newval, val,
+					   f->opt, indent, &f->line, bitmap,
+					   param);
+		free (newval);
+	      }
+	    else if (ta->kind == TYPE_POINTER && ta->u.p->kind == TYPE_SCALAR
+		     && use_param_num != -1 && param == NULL)
+	      oprintf (of, "%*sabort();\n", indent, "");
+	    else
+	      error_at_line (&f->line,
+			     "field `%s' is array of unimplemented type",
+			     f->name);
+	    for (ta = t, i = 0; ta->kind == TYPE_ARRAY; ta = ta->u.a.p, i++)
+	      {
+		indent -= 2;
+		oprintf (of, "%*s}\n", indent, "");
+	      }
+
+	    indent -= 2;
+	    oprintf (of, "%*s}\n", indent, "");
+	    break;
+	  }
+
+	default:
+	  error_at_line (&f->line,
+			 "field `%s' is unimplemented type",
+			 f->name);
+	  break;
+	}
+
+      if (s->kind == TYPE_UNION)
+	{
+	  oprintf (of, "%*sbreak;\n", indent, "");
+	  indent -= 2;
+	}
+    }
+  if (s->kind == TYPE_UNION)
+    {
+      if (! seen_default)
+	{
+	  oprintf (of, "%*sdefault:\n", indent, "");
+	  oprintf (of, "%*s  break;\n", indent, "");
+	}
+      oprintf (of, "%*s}\n", indent, "");
+      indent -= 2;
+    }
+}
+
+/* Write out a marker routine for S.  PARAM is the parameter from an
+   enclosing PARAM_IS option.  */
+
+static void
+write_gc_marker_routine_for_structure (orig_s, s, param)
+     type_p orig_s;
+     type_p s;
+     type_p * param;
+{
+  outf_p f;
+  const char *fn = s->u.s.line.file;
+  int i;
+  const char *chain_next = NULL;
+  const char *chain_prev = NULL;
+  options_p opt;
+
+  /* This is a hack, and not the good kind either.  */
+  for (i = NUM_PARAM - 1; i >= 0; i--)
+    if (param && param[i] && param[i]->kind == TYPE_POINTER
+	&& UNION_OR_STRUCT_P (param[i]->u.p))
+      fn = param[i]->u.p->u.s.line.file;
+
+  f = get_output_file_with_visibility (fn);
+
+  for (opt = s->u.s.opt; opt; opt = opt->next)
+    if (strcmp (opt->name, "chain_next") == 0)
+      chain_next = (const char *) opt->info;
+    else if (strcmp (opt->name, "chain_prev") == 0)
+      chain_prev = (const char *) opt->info;
+
+  if (chain_prev != NULL && chain_next == NULL)
+    error_at_line (&s->u.s.line, "chain_prev without chain_next");
+
+  oprintf (f, "\n");
+  oprintf (f, "void\n");
+  if (param == NULL)
+    oprintf (f, "gt_ggc_mx_%s", s->u.s.tag);
+  else
+    {
+      oprintf (f, "gt_ggc_m_");
+      output_mangled_typename (f, orig_s);
+    }
+  oprintf (f, " (x_p)\n");
+  oprintf (f, "      void *x_p;\n");
+  oprintf (f, "{\n");
+  oprintf (f, "  %s %s * %sx = (%s %s *)x_p;\n",
+	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
+	   chain_next == NULL ? "const " : "",
+	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+  if (chain_next != NULL)
+    oprintf (f, "  %s %s * xlimit = x;\n",
+	     s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+  if (chain_next == NULL)
+    oprintf (f, "  if (ggc_test_and_set_mark (x))\n");
+  else
+    {
+      oprintf (f, "  while (ggc_test_and_set_mark (xlimit))\n");
+      oprintf (f, "   xlimit = (");
+      output_escaped_param (f, chain_next, "*xlimit", "*xlimit",
+			    "chain_next", &s->u.s.line);
+      oprintf (f, ");\n");
+      if (chain_prev != NULL)
+	{
+	  oprintf (f, "  if (x != xlimit)\n");
+	  oprintf (f, "    for (;;)\n");
+	  oprintf (f, "      {\n");
+	  oprintf (f, "        %s %s * xprev = (",
+		   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+	  output_escaped_param (f, chain_prev, "*x", "*x",
+				"chain_prev", &s->u.s.line);
+	  oprintf (f, ");\n");
+	  oprintf (f, "        if (xprev == NULL) break;\n");
+	  oprintf (f, "        x = xprev;\n");
+	  oprintf (f, "        ggc_set_mark (xprev);\n");
+	  oprintf (f, "      }\n");
+	}
+      oprintf (f, "  while (x != xlimit)\n");
+    }
+  oprintf (f, "    {\n");
+
+  gc_counter = 0;
+  write_gc_structure_fields (f, s, "(*x)", "not valid postage",
+			     s->u.s.opt, 6, &s->u.s.line, s->u.s.bitmap,
+			     param);
+
+  if (chain_next != NULL)
+    {
+      oprintf (f, "      x = (");
+      output_escaped_param (f, chain_next, "*x", "*x",
+			    "chain_next", &s->u.s.line);
+      oprintf (f, ");\n");
+    }
+
+  oprintf (f, "  }\n");
+  oprintf (f, "}\n");
+}
+
+/* Write out marker routines for STRUCTURES and PARAM_STRUCTS.  */
+
+static void
+write_gc_types (structures, param_structs)
+     type_p structures;
+     type_p param_structs;
+{
+  type_p s;
+
+  oprintf (header_file, "\n/* GC marker procedures.  */\n");
+  for (s = structures; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO
+	|| s->gc_used == GC_MAYBE_POINTED_TO)
+      {
+	options_p opt;
+
+	if (s->gc_used == GC_MAYBE_POINTED_TO
+	    && s->u.s.line.file == NULL)
+	  continue;
+
+	oprintf (header_file, "#define gt_ggc_m_");
+	output_mangled_typename (header_file, s);
+	oprintf (header_file, "(X) do { \\\n");
+	oprintf (header_file,
+		 "  if (X != NULL) gt_ggc_mx_%s (X);\\\n", s->u.s.tag);
+	oprintf (header_file,
+		 "  } while (0)\n");
+
+	for (opt = s->u.s.opt; opt; opt = opt->next)
+	  if (strcmp (opt->name, "ptr_alias") == 0)
+	    {
+	      type_p t = (type_p) opt->info;
+	      if (t->kind == TYPE_STRUCT
+		  || t->kind == TYPE_UNION
+		  || t->kind == TYPE_LANG_STRUCT)
+		oprintf (header_file,
+			 "#define gt_ggc_mx_%s gt_ggc_mx_%s\n",
+			 s->u.s.tag, t->u.s.tag);
+	      else
+		error_at_line (&s->u.s.line,
+			       "structure alias is not a structure");
+	      break;
+	    }
+	if (opt)
+	  continue;
+
+	/* Declare the marker procedure only once.  */
+	oprintf (header_file,
+		 "extern void gt_ggc_mx_%s PARAMS ((void *));\n",
+		 s->u.s.tag);
+
+	if (s->u.s.line.file == NULL)
+	  {
+	    fprintf (stderr, "warning: structure `%s' used but not defined\n",
+		     s->u.s.tag);
+	    continue;
+	  }
+
+	if (s->kind == TYPE_LANG_STRUCT)
+	  {
+	    type_p ss;
+	    for (ss = s->u.s.lang_struct; ss; ss = ss->next)
+	      write_gc_marker_routine_for_structure (s, ss, NULL);
+	  }
+	else
+	  write_gc_marker_routine_for_structure (s, s, NULL);
+      }
+
+  for (s = param_structs; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO)
+      {
+	type_p * param = s->u.param_struct.param;
+	type_p stru = s->u.param_struct.stru;
+
+	/* Declare the marker procedure.  */
+	oprintf (header_file, "extern void gt_ggc_m_");
+	output_mangled_typename (header_file, s);
+	oprintf (header_file, " PARAMS ((void *));\n");
+
+	if (stru->u.s.line.file == NULL)
+	  {
+	    fprintf (stderr, "warning: structure `%s' used but not defined\n",
+		     s->u.s.tag);
+	    continue;
+	  }
+
+	if (stru->kind == TYPE_LANG_STRUCT)
+	  {
+	    type_p ss;
+	    for (ss = stru->u.s.lang_struct; ss; ss = ss->next)
+	      write_gc_marker_routine_for_structure (s, ss, param);
+	  }
+	else
+	  write_gc_marker_routine_for_structure (s, stru, param);
+      }
+}
+
+/* Write out the 'enum' definition for gt_types_enum.  */
+
+static void
+write_enum_defn (structures, param_structs)
+     type_p structures;
+     type_p param_structs;
+{
+  type_p s;
+
+  oprintf (header_file, "\n/* Enumeration of types known.  */\n");
+  oprintf (header_file, "enum gt_types_enum {\n");
+  for (s = structures; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO
+	|| s->gc_used == GC_MAYBE_POINTED_TO)
+      {
+	if (s->gc_used == GC_MAYBE_POINTED_TO
+	    && s->u.s.line.file == NULL)
+	  continue;
+
+	oprintf (header_file, " gt_ggc_e_");
+	output_mangled_typename (header_file, s);
+	oprintf (header_file, ", \n");
+      }
+  for (s = param_structs; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO)
+      {
+	oprintf (header_file, " gt_e_");
+	output_mangled_typename (header_file, s);
+	oprintf (header_file, ", \n");
+      }
+  oprintf (header_file, " gt_types_enum_last\n");
+  oprintf (header_file, "};\n");
+}
+
+
+/* Mangle FN and print it to F.  */
+
+static void
+put_mangled_filename (f, fn)
+     outf_p f;
+     const char *fn;
+{
+  const char *name = get_output_file_name (fn);
+  for (; *name != 0; name++)
+    if (ISALNUM (*name))
+      oprintf (f, "%c", *name);
+    else
+      oprintf (f, "%c", '_');
+}
+
+/* Finish off the currently-created root tables in FLP.  PFX, TNAME,
+   LASTNAME, and NAME are all strings to insert in various places in
+   the resulting code.  */
+
+static void
+finish_copy_root_table (flp, pfx, lastname, tname, name)
+     struct flist *flp;
+     const char *pfx;
+     const char *tname;
+     const char *lastname;
+     const char *name;
+{
+  struct flist *fli2;
+  unsigned started_bitmap = 0;
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+	oprintf (fli2->f, "  %s\n", lastname);
+	oprintf (fli2->f, "};\n\n");
+      }
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+	lang_bitmap bitmap = get_base_file_bitmap (fli2->name);
+	int fnum;
+
+	for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+	  if (bitmap & 1)
+	    {
+	      oprintf (base_files[fnum],
+		       "extern struct %s gt_ggc_%s_",
+		       tname, pfx);
+	      put_mangled_filename (base_files[fnum], fli2->name);
+	      oprintf (base_files[fnum], "[];\n");
+	    }
+      }
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+	lang_bitmap bitmap = get_base_file_bitmap (fli2->name);
+	int fnum;
+
+	fli2->started_p = 0;
+
+	for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+	  if (bitmap & 1)
+	    {
+	      if (! (started_bitmap & (1 << fnum)))
+		{
+		  oprintf (base_files [fnum],
+			   "struct %s * %s[] = {\n",
+			   tname, name);
+		  started_bitmap |= 1 << fnum;
+		}
+	      oprintf (base_files[fnum], "  gt_ggc_%s_", pfx);
+	      put_mangled_filename (base_files[fnum], fli2->name);
+	      oprintf (base_files[fnum], ",\n");
+	    }
+      }
+
+  {
+    unsigned bitmap;
+    int fnum;
+
+    for (bitmap = started_bitmap, fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+      if (bitmap & 1)
+	{
+	  oprintf (base_files[fnum], "  NULL\n");
+	  oprintf (base_files[fnum], "};\n");
+	}
+  }
+}
+
+/* Finish off the currently-created root tables in FLP.  PFX, TNAME,
+   LASTNAME, and NAME are all strings to insert in various places in
+   the resulting code.  */
+
+static void
+finish_root_table (flp, pfx, lastname, tname, name)
+     struct flist *flp;
+     const char *pfx;
+     const char *tname;
+     const char *lastname;
+     const char *name;
+{
+  struct flist *fli2;
+  unsigned started_bitmap = 0;
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+	oprintf (fli2->f, "  %s\n", lastname);
+	oprintf (fli2->f, "};\n\n");
+      }
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+	lang_bitmap bitmap = get_base_file_bitmap (fli2->name);
+	int fnum;
+
+	for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+	  if (bitmap & 1)
+	    {
+	      oprintf (base_files[fnum],
+		       "extern const struct %s gt_ggc_%s_",
+		       tname, pfx);
+	      put_mangled_filename (base_files[fnum], fli2->name);
+	      oprintf (base_files[fnum], "[];\n");
+	    }
+      }
+
+  for (fli2 = flp; fli2; fli2 = fli2->next)
+    if (fli2->started_p)
+      {
+	lang_bitmap bitmap = get_base_file_bitmap (fli2->name);
+	int fnum;

 	fli2->started_p = 0;

-	for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
-	  if (bitmap & 1)
+	for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+	  if (bitmap & 1)
+	    {
+	      if (! (started_bitmap & (1 << fnum)))
+		{
+		  oprintf (base_files [fnum],
+			   "const struct %s * const %s[] = {\n",
+			   tname, name);
+		  started_bitmap |= 1 << fnum;
+		}
+	      oprintf (base_files[fnum], "  gt_ggc_%s_", pfx);
+	      put_mangled_filename (base_files[fnum], fli2->name);
+	      oprintf (base_files[fnum], ",\n");
+	    }
+      }
+
+  {
+    unsigned bitmap;
+    int fnum;
+
+    for (bitmap = started_bitmap, fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
+      if (bitmap & 1)
+	{
+	  oprintf (base_files[fnum], "  NULL\n");
+	  oprintf (base_files[fnum], "};\n");
+	}
+  }
+}
+
+/* Write out to F the table entry and any marker routines needed to
+   mark NAME as TYPE.  The original variable is V, at LINE.
+   HAS_LENGTH is nonzero iff V was a variable-length array.  IF_MARKED
+   is nonzero iff we are building the root table for hash table caches.  */
+
+static void
+write_copy_gc_root (f, v, type, name, has_length, line, if_marked)
+     outf_p f;
+     pair_p v;
+     type_p type;
+     const char *name;
+     int has_length;
+     struct fileloc *line;
+     const char *if_marked;
+{
+  switch (type->kind)
+    {
+    case TYPE_STRUCT:
+      {
+	pair_p fld;
+	for (fld = type->u.s.fields; fld; fld = fld->next)
+	  {
+	    int skip_p = 0;
+	    const char *desc = NULL;
+	    options_p o;
+
+	    for (o = fld->opt; o; o = o->next)
+	      if (strcmp (o->name, "skip") == 0)
+		skip_p = 1;
+	      else if (strcmp (o->name, "desc") == 0)
+		desc = (const char *)o->info;
+	      else
+		error_at_line (line,
+		       "field `%s' of global `%s' has unknown option `%s'",
+			       fld->name, name, o->name);
+
+	    if (skip_p)
+	      continue;
+	    else if (desc && fld->type->kind == TYPE_UNION)
+	      {
+		pair_p validf = NULL;
+		pair_p ufld;
+
+		for (ufld = fld->type->u.s.fields; ufld; ufld = ufld->next)
+		  {
+		    const char *tag = NULL;
+		    options_p oo;
+
+		    for (oo = ufld->opt; oo; oo = oo->next)
+		      if (strcmp (oo->name, "tag") == 0)
+			tag = (const char *)oo->info;
+		    if (tag == NULL || strcmp (tag, desc) != 0)
+		      continue;
+		    if (validf != NULL)
+		      error_at_line (line,
+			   "both `%s.%s.%s' and `%s.%s.%s' have tag `%s'",
+				     name, fld->name, validf->name,
+				     name, fld->name, ufld->name,
+				     tag);
+		    validf = ufld;
+		  }
+		if (validf != NULL)
+		  {
+		    char *newname;
+		    newname = xasprintf ("%s.%s.%s",
+					 name, fld->name, validf->name);
+		    write_copy_gc_root (f, v, validf->type, newname, 0, line,
+				   if_marked);
+		    free (newname);
+		  }
+	      }
+	    else if (desc)
+	      error_at_line (line,
+		     "global `%s.%s' has `desc' option but is not union",
+			     name, fld->name);
+	    else
+	      {
+		char *newname;
+		newname = xasprintf ("%s.%s", name, fld->name);
+		write_copy_gc_root (f, v, fld->type, newname, 0, line, if_marked);
+		free (newname);
+	      }
+	  }
+      }
+      break;
+
+    case TYPE_ARRAY:
+      {
+	char *newname;
+	newname = xasprintf ("%s[0]", name);
+	write_copy_gc_root (f, v, type->u.a.p, newname, has_length, line, if_marked);
+	free (newname);
+      }
+      break;
+
+    case TYPE_POINTER:
+      {
+	type_p ap, tp;
+
+	oprintf (f, "  {\n");
+	oprintf (f, "    &%s,\n", name);
+	oprintf (f, "    1");
+
+	for (ap = v->type; ap->kind == TYPE_ARRAY; ap = ap->u.a.p)
+	  if (ap->u.a.len[0])
+	    oprintf (f, " * (%s)", ap->u.a.len);
+	  else if (ap == v->type)
+	    oprintf (f, " * ARRAY_SIZE (%s)", v->name);
+	oprintf (f, ",\n");
+	oprintf (f, "    sizeof (%s", v->name);
+	for (ap = v->type; ap->kind == TYPE_ARRAY; ap = ap->u.a.p)
+	  oprintf (f, "[0]");
+	oprintf (f, "),\n");
+
+	tp = type->u.p;
+
+	if (! has_length && UNION_OR_STRUCT_P (tp))
+	  {
+	    oprintf (f, "    &gt_ggc_cx_%s\n", tp->u.s.tag);
+	  }
+	else if (! has_length && tp->kind == TYPE_PARAM_STRUCT)
+	  {
+	    oprintf (f, "    &gt_ggc_c_");
+	    output_mangled_typename (f, tp);
+	  }
+	else if (has_length
+		 && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp)))
+	  {
+	    oprintf (f, "    &gt_ggc_ca_%s", name);
+	  }
+	else
+	  {
+	    error_at_line (line,
+			   "global `%s' is pointer to unimplemented type",
+			   name);
+	  }
+	if (if_marked)
+	  oprintf (f, ",\n    &%s", if_marked);
+	oprintf (f, "\n  },\n");
+      }
+      break;
+
+    case TYPE_SCALAR:
+    case TYPE_STRING:
+      break;
+
+    default:
+      error_at_line (line,
+		     "global `%s' is unimplemented type",
+		     name);
+    }
+}
+
+/* Output a table describing the locations and types of VARIABLES.  */
+
+static void
+write_copy_gc_roots (variables)
+     pair_p variables;
+{
+  pair_p v;
+  struct flist *flp = NULL;
+
+  for (v = variables; v; v = v->next)
+    {
+      outf_p f = get_output_file_with_visibility (v->line.file);
+      struct flist *fli;
+      const char *length = NULL;
+      int deletable_p = 0;
+      options_p o;
+
+      for (o = v->opt; o; o = o->next)
+	if (strcmp (o->name, "length") == 0)
+	  length = (const char *)o->info;
+	else if (strcmp (o->name, "deletable") == 0)
+	  deletable_p = 1;
+	else if (strcmp (o->name, "param_is") == 0)
+	  ;
+ 	else if (strncmp (o->name, "param", 5) == 0
+		 && ISDIGIT (o->name[5])
+		 && strcmp (o->name + 6, "_is") == 0)
+	  ;
+	else if (strcmp (o->name, "if_marked") == 0)
+	  ;
+	else
+	  error_at_line (&v->line,
+			 "global `%s' has unknown option `%s'",
+			 v->name, o->name);
+
+      for (fli = flp; fli; fli = fli->next)
+	if (fli->f == f)
+	  break;
+      if (fli == NULL)
+	{
+	  fli = xmalloc (sizeof (*fli));
+	  fli->f = f;
+	  fli->next = flp;
+	  fli->started_p = 0;
+	  fli->name = v->line.file;
+	  flp = fli;
+
+	  oprintf (f, "\n/* GC roots.  */\n\n");
+	}
+
+      if (! deletable_p
+	  && length
+	  && v->type->kind == TYPE_POINTER
+	  && (v->type->u.p->kind == TYPE_POINTER
+	      || v->type->u.p->kind == TYPE_STRUCT))
+	{
+	  oprintf (f, "static void *gt_ggc_ca_%s PARAMS ((void *));\n",
+		   v->name);
+	  oprintf (f, "static void *\ngt_ggc_ca_%s (x_p)\n      void *x_p;\n",
+		   v->name);
+	  oprintf (f, "{\n");
+	  oprintf (f, "  size_t i;\n");
+	  oprintf (f, "  bool forwarded;\n");
+
+	  if (v->type->u.p->kind == TYPE_POINTER)
 	    {
-	      if (! (started_bitmap & (1 << fnum)))
+	      type_p s = v->type->u.p->u.p;
+
+	      oprintf (f, "  %s %s ** x = (%s %s **)x_p;\n",
+		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
+		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+	      oprintf (f, "  if (done_already (x)) return x;\n");
+	      oprintf (f, "  if (x != NULL)\n");
+	      oprintf (f, "    {\n");
+	      oprintf (f, "      x = alloc_and_copy (x, sizeof (*x), &forwarded);\n");
+	      oprintf (f, "      if (forwarded) return x;\n");
+	      oprintf (f, "    for (i = 0; i < (%s); i++)\n", length);
+	      if (! UNION_OR_STRUCT_P (s)
+		  && ! s->kind == TYPE_PARAM_STRUCT)
 		{
-		  oprintf (base_files [fnum],
-			   "const struct %s * const %s[] = {\n",
-			   tname, name);
-		  started_bitmap |= 1 << fnum;
+		  error_at_line (&v->line,
+				 "global `%s' has unsupported ** type",
+				 v->name);
+		  continue;
 		}
-	      oprintf (base_files[fnum], "  gt_ggc_%s_", pfx);
-	      put_mangled_filename (base_files[fnum], fli2->name);
-	      oprintf (base_files[fnum], ",\n");
+
+	      oprintf (f, "      x[i] = gt_ggc_c_");
+	      output_mangled_typename (f, s);
+	      oprintf (f, " (x[i]);\n");
+	      oprintf (f, "}\n");
 	    }
-      }
+	  else
+	    {
+	      type_p s = v->type->u.p;

-  {
-    unsigned bitmap;
-    int fnum;
-
-    for (bitmap = started_bitmap, fnum = 0; bitmap != 0; fnum++, bitmap >>= 1)
-      if (bitmap & 1)
+	      oprintf (f, "  %s %s * x = (%s %s *)x_p;\n",
+		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
+		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+	      oprintf (f, "  if (done_already (x)) return x;\n");
+	      oprintf (f, "  if (x != NULL) { x = alloc_and_copy (x, sizeof (*x), &forwarded);\n");
+	      oprintf (f, "      if (forwarded) return x;\n");
+	      oprintf (f, "    for (i = 0; i < (%s); i++)\n", length);
+	      oprintf (f, "      {\n");
+	      write_copy_gc_structure_fields (f, s, "x[i]", "x[i]",
+					 v->opt, 8, &v->line, s->u.s.bitmap,
+					 NULL);
+	      oprintf (f, "      }\n");
+	      oprintf (f, "  }\n");
+	    }
+
+	  oprintf (f, "return x;\n }\n\n");
+	}
+    }
+
+  for (v = variables; v; v = v->next)
+    {
+      outf_p f = get_output_file_with_visibility (v->line.file);
+      struct flist *fli;
+      int skip_p = 0;
+      int length_p = 0;
+      options_p o;
+
+      for (o = v->opt; o; o = o->next)
+	if (strcmp (o->name, "length") == 0)
+	  length_p = 1;
+	else if (strcmp (o->name, "deletable") == 0
+		 || strcmp (o->name, "if_marked") == 0)
+	  skip_p = 1;
+
+      if (skip_p)
+	continue;
+
+      for (fli = flp; fli; fli = fli->next)
+	if (fli->f == f)
+	  break;
+      if (! fli->started_p)
 	{
-	  oprintf (base_files[fnum], "  NULL\n");
-	  oprintf (base_files[fnum], "};\n");
+	  fli->started_p = 1;
+
+	  oprintf (f, "struct ggc_croot_tab gt_ggc_cr_");
+	  put_mangled_filename (f, v->line.file);
+	  oprintf (f, "[] = {\n");
 	}
-  }
+
+      write_copy_gc_root (f, v, v->type, v->name, length_p, &v->line, NULL);
+    }
+
+  finish_copy_root_table (flp, "cr", "LAST_GGC_ROOT_TAB", "ggc_croot_tab",
+		     "gt_ggc_crtab");
+
+  for (v = variables; v; v = v->next)
+    {
+      outf_p f = get_output_file_with_visibility (v->line.file);
+      struct flist *fli;
+      int skip_p = 1;
+      options_p o;
+
+      for (o = v->opt; o; o = o->next)
+	if (strcmp (o->name, "deletable") == 0)
+	  skip_p = 0;
+	else if (strcmp (o->name, "if_marked") == 0)
+	  skip_p = 1;
+
+      if (skip_p)
+	continue;
+
+      for (fli = flp; fli; fli = fli->next)
+	if (fli->f == f)
+	  break;
+      if (! fli->started_p)
+	{
+	  fli->started_p = 1;
+
+	  oprintf (f, "struct ggc_croot_tab gt_ggc_crd_");
+	  put_mangled_filename (f, v->line.file);
+	  oprintf (f, "[] = {\n");
+	}
+
+      oprintf (f, "  { &%s, 1, sizeof (%s), NULL },\n",
+	       v->name, v->name);
+    }
+
+  finish_copy_root_table (flp, "crd", "LAST_GGC_ROOT_TAB", "ggc_croot_tab",
+		     "gt_ggc_deletable_crtab");
+
+  for (v = variables; v; v = v->next)
+    {
+      outf_p f = get_output_file_with_visibility (v->line.file);
+      struct flist *fli;
+      const char *if_marked = NULL;
+      int length_p = 0;
+      options_p o;
+
+      for (o = v->opt; o; o = o->next)
+	if (strcmp (o->name, "length") == 0)
+	  length_p = 1;
+	else if (strcmp (o->name, "if_marked") == 0)
+	  if_marked = (const char *) o->info;
+
+      if (if_marked == NULL)
+	continue;
+
+      if (v->type->kind != TYPE_POINTER
+	  || v->type->u.p->kind != TYPE_PARAM_STRUCT
+	  || v->type->u.p->u.param_struct.stru != find_structure ("htab", 0))
+	{
+	  error_at_line (&v->line, "if_marked option used but not hash table");
+	  continue;
+	}
+
+      for (fli = flp; fli; fli = fli->next)
+	if (fli->f == f)
+	  break;
+      if (! fli->started_p)
+	{
+	  fli->started_p = 1;
+
+	  oprintf (f, " struct ggc_cache_tab gt_ggc_crc_");
+	  put_mangled_filename (f, v->line.file);
+	  oprintf (f, "[] = {\n");
+	}
+
+      write_copy_gc_root (f, v, v->type->u.p->u.param_struct.param[0],
+		     v->name, length_p, &v->line, if_marked);
+    }
+
+  finish_root_table (flp, "crc", "LAST_GGC_CACHE_TAB", "ggc_cache_tab",
+		     "gt_ggc_cache_crtab");
 }

 /* Write out to F the table entry and any marker routines needed to
@@ -2411,7 +3494,7 @@ write_gc_roots (variables)
 	    {
 	      type_p s = v->type->u.p->u.p;

-	      oprintf (f, "  %s %s ** const x = (%s %s **)x_p;\n",
+	      oprintf (f, "  %s %s ** x = (%s %s **)x_p;\n",
 		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
 		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
 	      oprintf (f, "  if (ggc_test_and_set_mark (x))\n");
@@ -2433,7 +3516,7 @@ write_gc_roots (variables)
 	    {
 	      type_p s = v->type->u.p;

-	      oprintf (f, "  %s %s * const x = (%s %s *)x_p;\n",
+	      oprintf (f, "  %s %s * x = (%s %s *)x_p;\n",
 		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
 		       s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
 	      oprintf (f, "  if (ggc_test_and_set_mark (x))\n");
@@ -2619,6 +3702,8 @@ main(argc, argv)
   write_gc_types (structures, param_structs);
   write_gc_roots (variables);
   write_rtx_next ();
+  write_copy_gc_types (structures, param_structs);
+  write_copy_gc_roots (variables);
   close_output_files ();

   return (hit_error != 0);
Index: ggc-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ggc-common.c,v
retrieving revision 1.54.8.3
diff -u -3 -p -r1.54.8.3 ggc-common.c
--- ggc-common.c	3 Dec 2002 17:34:55 -0000	1.54.8.3
+++ ggc-common.c	12 Dec 2002 03:19:57 -0000
@@ -102,6 +102,48 @@ ggc_htab_delete (slot, info)
 /* Iterate through all registered roots and mark each element.  */

 void
+ggc_copy_roots ()
+{
+  struct ggc_root *x;
+  struct ggc_croot_tab * *rt;
+  struct ggc_croot_tab *rti;
+  struct ggc_cache_tab **ct;
+  struct ggc_cache_tab *cti;
+  size_t i;
+
+  for (rt = gt_ggc_deletable_crtab; *rt; rt++)
+    for (rti = *rt; rti->base != NULL; rti++)
+      memset (rti->base, 0, rti->stride);
+
+  for (rt = gt_ggc_crtab; *rt; rt++)
+    for (rti = *rt; rti->base != NULL; rti++)
+      for (i = 0; i < rti->nelt; i++)
+      {
+	      void **addr = (void **)((char *)rti->base + rti->stride * i);
+	*addr = (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
+      }
+  for (x = roots; x != NULL; x = x->next)
+    {
+      char *elt = x->base;
+      int s = x->size, n = x->nelt;
+      void (*cb) PARAMS ((void *)) = x->cb;
+      int i;
+
+      for (i = 0; i < n; ++i, elt += s)
+	(*cb)(elt);
+    }
+
+  /* Now scan all hash tables that have objects which are to be deleted if
+     they are not already marked.  */
+  for (ct = gt_ggc_cache_rtab; *ct; ct++)
+    for (cti = *ct; cti->base != NULL; cti++)
+      if (*cti->base)
+	htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti);
+}
+
+/* Iterate through all registered roots and mark each element.  */
+
+void
 ggc_mark_roots ()
 {
   struct ggc_root *x;
Index: ggc-copy.c
===================================================================
RCS file: ggc-copy.c
diff -N ggc-copy.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ggc-copy.c	12 Dec 2002 03:19:57 -0000
@@ -0,0 +1,360 @@
+/* "Bag-of-pages" garbage collector for the GNU compiler.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "toplev.h"
+#include "varray.h"
+#include "flags.h"
+#include "ggc.h"
+#include "timevar.h"
+#include "splay-tree.h"
+#include "params.h"
+#include <sys/mman.h>
+static struct globals
+{
+  splay_tree marks;
+  int fromspacesize;
+  char *current;
+  char *start;
+  char *end;
+  char *fromspace;
+  char *tospace;
+
+  /* Data bytes currently allocated.  */
+  size_t allocated;
+
+  /* Data objects currently allocated.  */
+  size_t objects;
+
+  /* Data bytes allocated at time of last GC.  */
+  size_t allocated_last_gc;
+
+  /* Current context level.  */
+  int context;
+} G;
+struct ggc_mem
+{
+  unsigned int size : 24;
+  unsigned int forwarded:1;
+  void *forwardptr;
+  union {
+    HOST_WIDEST_INT i;
+    double d;
+  } u;
+} ;
+void *
+ggc_alloc (size)
+     size_t size;
+{
+  size_t memsize;
+  struct ggc_mem *x;
+  char *place;
+
+  place = G.current;
+  if (G.current + size > G.end)
+    abort();
+  x = (struct ggc_mem *)G.current;
+  x->size = size;
+  memsize = (offsetof (struct ggc_mem, u));
+  G.current += size + memsize;
+
+  G.allocated += size;
+  G.objects += 1;
+  return place + memsize;
+}
+/* Return 1 if P has been marked, zero otherwise.
+   P must have been allocated by the GC allocator; it mustn't point to
+   static objects, stack variables, or memory allocated with malloc.  */
+
+int
+ggc_marked_p (p)
+     const void *p;
+{
+  return splay_tree_lookup (G.marks, (splay_tree_key) p) != 0;
+}
+
+/* Return the size of the gc-able object P.  */
+
+size_t
+ggc_get_size (p)
+     const void *p;
+{
+  struct ggc_mem *x
+    = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
+  return x->size;
+}
+
+
+/* Initialize the ggc-mmap allocator.  */
+void
+init_ggc ()
+{
+  G.marks = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+  G.fromspace = mmap (0, 1024 * 1024 * 64, PROT_WRITE | PROT_READ , MAP_PRIVATE |MAP_ANONYMOUS, -1, 0);
+  G.start = G.fromspace;
+  G.current = G.fromspace;
+  G.end = G.fromspace + (1024 * 1024 * 64);
+}
+
+/* Increment the `GC context'.  Objects allocated in an outer context
+   are never freed, eliminating the need to register their roots.  */
+
+void
+ggc_push_context ()
+{
+#if 0
+  ++G.context_depth;
+
+  /* Die on wrap.  */
+  if (G.context_depth == 0)
+    abort ();
+#endif
+}
+/* Decrement the `GC context'.  All objects allocated since the
+   previous ggc_push_context are migrated to the outer context.  */
+
+void
+ggc_pop_context ()
+{
+#if 0
+  unsigned order, depth;
+
+  depth = --G.context_depth;
+
+  /* Any remaining pages in the popped context are lowered to the new
+     current context; i.e. objects allocated in the popped context and
+     left over are imported into the previous context.  */
+  for (order = 2; order < NUM_ORDERS; order++)
+    {
+      page_entry *p;
+
+      for (p = G.pages[order]; p != NULL; p = p->next)
+	{
+	  if (p->context_depth > depth)
+	    p->context_depth = depth;
+
+	  /* If this page is now in the topmost context, and we'd
+	     saved its allocation state, restore it.  */
+	  else if (p->context_depth == depth && p->save_in_use_p)
+	    {
+	      ggc_recalculate_in_use_p (p);
+	      free (p->save_in_use_p);
+	      p->save_in_use_p = 0;
+	    }
+	}
+    }
+#endif
+}
+int
+ggc_set_mark (p)
+const void *p;
+{
+	if (ggc_marked_p (p))
+		return 1;
+	splay_tree_insert (G.marks, (splay_tree_key) p, 1);
+	return 0;
+}
+/* Top level mark-and-sweep routine.  */
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+
+void segv_handler (int sig, siginfo_t *sip, void *xxx)
+{
+	char *vadr;
+	int writing;
+
+	printf ("SEGV at Addr: 0x%x, 0x%x\n", (int)sip, (int)xxx);
+	fflush(0);
+	vadr = (caddr_t) sip->si_addr;
+	writing = (sip->si_errno & 2);
+	fprintf (stderr, "SEGV addr: %x, %s\n", vadr, writing ? "writing" : "reading");
+}
+void
+ggc_collect ()
+{
+  void *oldfrom;
+  size_t oldfromsize;
+  struct sigaction sa;
+  /* Avoid frequent unnecessary work by skipping collection if the
+     total allocations haven't expanded much since the last
+     collection.  */
+  size_t allocated_last_gc =
+    MAX (G.allocated_last_gc, (size_t)PARAM_VALUE (GGC_MIN_HEAPSIZE) * 1024);
+
+  size_t min_expand = allocated_last_gc * PARAM_VALUE (GGC_MIN_EXPAND) / 100;
+
+  /*if (G.allocated < allocated_last_gc + min_expand)
+    return;*/
+
+  timevar_push (TV_GC);
+  if (!quiet_flag)
+    fprintf (stderr, " {GC %luk -> ", (unsigned long) G.allocated / 1024);
+
+  /* Zero the total allocated bytes.  This will be recalculated in the
+     sweep phase.  */
+  G.allocated = 0;
+
+  splay_tree_delete (G.marks);
+  G.marks = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+  G.allocated = 0;
+  G.objects = 0;
+  oldfromsize= G.fromspacesize;
+  G.fromspacesize = 0;
+  oldfrom = G.fromspace;
+  G.tospace = mmap (0, 64 * 1024 * 1024, PROT_WRITE | PROT_READ , MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  G.fromspace = G.tospace;
+  G.start = G.fromspace;
+  G.current = G.start;
+  G.end = G.start + (64 * 1024 * 1024);
+  G.tospace = NULL;
+  ggc_copy_roots ();
+  munmap (oldfrom, 64 * 1024 * 1024);
+  sa.sa_sigaction = &segv_handler;
+  sigemptyset (&sa.sa_mask);
+  sigaddset(&sa.sa_mask, SIGIO);
+  sigaddset(&sa.sa_mask, SIGALRM);
+  sa.sa_flags = SA_SIGINFO;
+  if (sigaction (SIGSEGV, &sa, NULL))
+  {
+	  printf ("Error assigning signal.\n");
+	  abort();
+  }
+  mprotect (oldfrom, 64 *1024*1024, PROT_NONE);
+  G.allocated_last_gc = G.allocated;
+
+  timevar_pop (TV_GC);
+
+  if (!quiet_flag)
+    fprintf (stderr, "%luk}", (unsigned long) G.allocated / 1024);
+
+}
+void *alloc_and_copy (p, size, forwarded)
+      void *p;
+      size_t size;
+      bool *forwarded;
+{
+  void *newp;
+  struct ggc_mem *x
+    = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
+  if (forwarded)
+    *forwarded = 0;
+  if (p == 0)
+    return 0;
+  if (done_already (p))
+    return p;
+
+  if (x->forwarded)
+    {
+      if (forwarded)
+	*forwarded = 1;
+      return x->forwardptr;
+    }
+  newp = ggc_alloc (ggc_get_size (p));
+  x->forwarded = 1;
+  x->forwardptr = newp;
+  memcpy (newp, p, ggc_get_size (p));
+  return newp;
+}
+
+/* Print allocation statistics.  */
+#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
+ggc_print_statistics ()
+{
+#if 0
+	struct ggc_statistics stats;
+  unsigned int i;
+  size_t total_overhead = 0;
+
+  /* Clear the statistics.  */
+  memset (&stats, 0, sizeof (stats));
+
+  /* Make sure collection will really occur.  */
+  G.allocated_last_gc = 0;
+
+  /* Collect and print the statistics common across collectors.  */
+  ggc_print_common_statistics (stderr, &stats);
+
+  /* Release free pages so that we will not count the bytes allocated
+     there as part of the total allocated memory.  */
+  release_pages ();
+
+  /* Collect some information about the various sizes of
+     allocation.  */
+  fprintf (stderr, "\n%-5s %10s  %10s  %10s\n",
+	   "Size", "Allocated", "Used", "Overhead");
+  for (i = 0; i < NUM_ORDERS; ++i)
+    {
+      page_entry *p;
+      size_t allocated;
+      size_t in_use;
+      size_t overhead;
+
+      /* Skip empty entries.  */
+      if (!G.pages[i])
+	continue;
+
+      overhead = allocated = in_use = 0;
+
+      /* Figure out the total number of bytes allocated for objects of
+	 this size, and how many of them are actually in use.  Also figure
+	 out how much memory the page table is using.  */
+      for (p = G.pages[i]; p; p = p->next)
+	{
+	  allocated += p->bytes;
+	  in_use +=
+	    (OBJECTS_PER_PAGE (i) - p->num_free_objects) * OBJECT_SIZE (i);
+
+	  overhead += (sizeof (page_entry) - sizeof (long)
+		       + BITMAP_SIZE (OBJECTS_PER_PAGE (i) + 1));
+	}
+      fprintf (stderr, "%-5lu %10lu%c %10lu%c %10lu%c\n",
+	       (unsigned long) OBJECT_SIZE (i),
+	       SCALE (allocated), LABEL (allocated),
+	       SCALE (in_use), LABEL (in_use),
+	       SCALE (overhead), LABEL (overhead));
+      total_overhead += overhead;
+    }
+  fprintf (stderr, "%-5s %10lu%c %10lu%c %10lu%c\n", "Total",
+	   SCALE (G.bytes_mapped), LABEL (G.bytes_mapped),
+	   SCALE (G.allocated), LABEL(G.allocated),
+	   SCALE (total_overhead), LABEL (total_overhead));
+#endif
+}
+bool
+done_already (p)
+	void *p;
+{
+	return ((char *)p) >= G.fromspace && ((char *)p) <= G.end;
+}
+
Index: ggc.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ggc.h,v
retrieving revision 1.45.4.2
diff -u -3 -p -r1.45.4.2 ggc.h
--- ggc.h	1 Oct 2002 17:31:48 -0000	1.45.4.2
+++ ggc.h	12 Dec 2002 03:19:57 -0000
@@ -42,10 +42,18 @@ struct ggc_root_tab {
   size_t stride;
   void (*cb) PARAMS ((void *));
 };
+struct ggc_croot_tab {
+  void *base;
+  size_t nelt;
+  size_t stride;
+  void *(*cb) PARAMS ((void *));
+};
 #define LAST_GGC_ROOT_TAB { NULL, 0, 0, NULL }
 /* Pointers to arrays of ggc_root_tab, terminated by NULL.  */
 extern const struct ggc_root_tab * const gt_ggc_rtab[];
 extern const struct ggc_root_tab * const gt_ggc_deletable_rtab[];
+extern  struct ggc_croot_tab * gt_ggc_crtab[];
+extern  struct ggc_croot_tab * gt_ggc_deletable_crtab[];

 /* Structure for hash table cache marking.  */
 struct htab;
@@ -176,3 +184,5 @@ extern void ggc_print_common_statistics
 /* Print allocation statistics.  */
 extern void ggc_print_statistics	PARAMS ((void));
 extern void stringpool_statistics	PARAMS ((void));
+extern void *alloc_and_copy PARAMS ((void *, size_t, bool *));
+extern bool done_already PARAMS ((void *));
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.367.4.8
diff -u -3 -p -r1.367.4.8 rtl.h
--- rtl.h	3 Dec 2002 17:35:00 -0000	1.367.4.8
+++ rtl.h	12 Dec 2002 03:20:00 -0000
@@ -125,7 +125,8 @@ typedef union rtunion_def rtunion;

 /* RTL expression ("rtx").  */

-struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),
+struct rtx_def GTY((chain_nextp ("RTX_NEXTP (&%h)"),
+		    chain_next ("RTX_NEXT (&%h)"),
 		    chain_prev ("RTX_PREV (&%h)")))
 {
   /* The kind of expression this is.  */
@@ -212,6 +213,8 @@ struct rtx_def GTY((chain_next ("RTX_NEX

 #define RTX_NEXT(X) (rtx_next[GET_CODE (X)] == 0 ? NULL			\
 		     : *(rtx *)(((char *)X) + rtx_next[GET_CODE (X)]))
+#define RTX_NEXTP(X) (rtx_next[GET_CODE (X)] == 0 ? NULL			\
+		     : (rtx *)(((char *)X) + rtx_next[GET_CODE (X)]))

 /* FIXME: the "NEXT_INSN (PREV_INSN (X)) == X" condition shouldn't be needed.
  */
@@ -2081,6 +2084,11 @@ extern void expand_dec			PARAMS ((rtx, r
 extern rtx expand_mult_highpart		PARAMS ((enum machine_mode, rtx,
 						unsigned HOST_WIDE_INT, rtx,
 						int, int));
+
+/* In vrp.c */
+#ifdef BUFSIZ
+extern int value_range_prop		PARAMS ((rtx, int, FILE *));
+#endif

 /* In gcse.c */
 #ifdef BUFSIZ
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.744.4.13
diff -u -3 -p -r1.744.4.13 cp-tree.h
--- cp/cp-tree.h	4 Dec 2002 10:16:02 -0000	1.744.4.13
+++ cp/cp-tree.h	12 Dec 2002 03:20:06 -0000
@@ -515,6 +515,7 @@ enum cp_tree_node_structure_enum {

 /* The resulting tree type.  */
 union lang_tree_node GTY((desc ("cp_tree_node_structure (&%h)"),
+	chain_nextp ("(union lang_tree_node **)&TREE_CHAIN (&%h.generic)"),
        chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
 {
   struct tree_common GTY ((tag ("TS_CP_COMMON"))) common;
Index: f/com.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/f/com.c,v
retrieving revision 1.176.4.4
diff -u -3 -p -r1.176.4.4 com.c
--- f/com.c	5 Nov 2002 19:12:28 -0000	1.176.4.4
+++ f/com.c	12 Dec 2002 03:20:13 -0000
@@ -606,7 +606,8 @@ struct lang_identifier GTY(())
 /* The resulting tree type.  */
 union lang_tree_node
   GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
-       chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
+       chain_nextp ("(union lang_tree_node **)&TREE_CHAIN (&%h.generic)"),
+		  chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
 {
   union tree_node GTY ((tag ("0"),
 			desc ("tree_node_structure (&%h)")))
Index: java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.154.4.6
diff -u -3 -p -r1.154.4.6 java-tree.h
--- java/java-tree.h	3 Dec 2002 17:36:03 -0000	1.154.4.6
+++ java/java-tree.h	12 Dec 2002 03:20:14 -0000
@@ -709,6 +709,7 @@ struct lang_identifier GTY(())
 /* The resulting tree type.  */
 union lang_tree_node
   GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+       chain_nextp ("(union lang_tree_node **)&TREE_CHAIN (&%h.generic)"),
        chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
 {
   union tree_node GTY ((tag ("0"),



More information about the Gcc-patches mailing list