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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] mark_hook in GTY?


Hello All,

As I suggested in the last part of my (somehow confusing) message
http://gcc.gnu.org/ml/gcc/2006-12/msg00254.html it could be
interesting for some few passes to have the GGC garbage collector call
a post-marking hook, which is called once when a structure is marked.

As a testing example, I wrote the following (otherwise meaningless)
code

     struct basile1_st
     GTY ((mark_hook("basile1_markedhook")))
     {
       struct basile2_st *b2;
       tree ttt;
     };

     struct basile2_st
     GTY ((mark_hook("basile2_markedhook"),chain_next("%h.suiv")))
     {
       struct basile1_st *b1;
       basic_block bbb;
       struct basile2_st* suiv;
     };

     static void
     basile2_markedhook(struct basile2_st* s)
     {
       if (s->b1)
         fprintf(stderr, "youpi basile2!\n");
     }

     static void
     basile1_markedhook(struct basile1_st* s)
     {
       if (s->b2)
         fprintf(stderr, "youpi basile1!\n");
     }  

Then the gt-*.h generated code contains


void
gt_ggc_mx_basile2_st (void *x_p)
{
  struct basile2_st * x = (struct basile2_st *)x_p;
  struct basile2_st * xlimit = x;
  while (ggc_test_and_set_mark (xlimit))
    {
      basile2_markedhook (xlimit);
      xlimit = ((*xlimit).suiv);
    }
  while (x != xlimit)
    {
      gt_ggc_m_10basile1_st ((*x).b1);
      gt_ggc_m_15basic_block_def ((*x).bbb);
      gt_ggc_m_10basile2_st ((*x).suiv);
      x = ((*x).suiv);
    }
}

void
gt_ggc_mx_basile1_st (void *x_p)
{
  struct basile1_st * const x = (struct basile1_st *)x_p;
  if (ggc_test_and_set_mark (x))
    {
      basile1_markedhook (x);
      gt_ggc_m_10basile2_st ((*x).b2);
      gt_ggc_m_9tree_node ((*x).ttt);
    }
}

The only changed behavior of gengtype is related to the mark_hook GTY
option. If you remove it, the output is unchanged from the unpatched
gengtype behavior: The two calls to basile1_markedhook and
basile2_markedhook are not generated if you remove the mark_hook GTY
option. In other words, this patch is unobtrusive, since it does not
change gengtype behavior on every current file in the trunk actually
processed by gengtype (since no current input to gengtype contains any
mark_hook option). But the others (in particular the PCH related)
generated routines remain unchanged.

The intended use of this is for potential future uncommon passes
handling a small amount of ggc-ed data which needs some processing at
the markking stage. For a simple example, imagine that the mark hook
you provide just increments a global counter. Then your pass is able
to have the ggc (GCC garbage collector) count the number of data that
is of the such marked type at a little cost.

Another potential use could be to handle garbage collected bignum-s as
providedf by MPFR, but I don't know if it is worthwhile. The possible
idea would be to set some bit somewhere in the mark hook, and after
the call to the ggc_collect routine, scan all such bits and call
mpfr_clear on the contained mpfr_t. Some experts on the GCC mailing
lists claim (and I believe them) that for this particular use
(handling mpfr_t) such a trick is not useful, but I can imagine some
passes which could use it for other stuff.

The main plus of this patch is that it is completely unobtrusive to
current gcc trunk code. I bootstrapped and checked that all the
gengtype generated *.c and *.h files (including the gt-*.h) remain
unchanged with and without this patch (the only differences are some
**/config.h files and the *gcc/cc1-checksum.c file).

I made a patch to gcc/gengtype.c and documented the option in
gcc/doc/gty.texi

Bootstrapped ok on x86_64-unknown-linux-gnu (AMD64/DEbian/Sid) with
--enable-languages=c

Changelog after my sig, and patch attached to trunk rev 120900

Ok for mainline?

Thanks for reading!  

PS If I submit another patch needing this one, should my next patch
include this one if this one (a very simple patch) has not yet been
accepted?

-- 
Basile STARYNKEVITCH         http://starynkevitch.net/Basile/ 
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359 
8, rue de la Faïencerie, 92340 Bourg La Reine, France
*** opinions {are only mines, sont seulement les miennes} ***

########################################### Changelog
2007-01-17  Basile Starynkevitch  <basile@starynkevitch.net>

	* gcc/doc/gty.texi:  documented the mark_hook option to GTY

	* gcc/gengtype.c: implemented mark_hook option.
	In struct write_types_data added skip_hooks. In functions 
	walk_type, write_func_for_structure generated the mark hook if
	needed. In data ggc_wtd & pch_wtd initialized as needed the
	skip_hooks.

	
Index: gcc/doc/gty.texi
===================================================================
--- gcc/doc/gty.texi	(revision 120900)
+++ gcc/doc/gty.texi	(working copy)
@@ -1,4 +1,4 @@
-@c Copyright (C) 2002, 2003, 2004
+@c Copyright (C) 2002, 2003, 2004, 2007
 @c Free Software Foundation, Inc.
 @c This is part of the GCC manual.
 @c For copying conditions, see the file gcc.texi.
@@ -282,6 +282,16 @@ The routine @code{ggc_marked_p} can be u
 has been marked already; in fact, the usual case is to use
 @code{if_marked ("ggc_marked_p")}.
 
+@findex mark_hook
+@item mark_hook ("@var{hook-routine-name}")
+
+If provided for a structure or union type, the given
+@var{hook-routine-name} (between double-quotes) is the name of a
+routine called when the garbage collector has just marked the data as
+reachable. This routine should not change the data, or call any ggc
+routine. Its only argument is a pointer to the just marked (const)
+structure or union.
+
 @findex maybe_undef
 @item maybe_undef
 
Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 120900)
+++ gcc/gengtype.c	(working copy)
@@ -1382,6 +1382,7 @@ struct write_types_data
   const char *marker_routine;
   const char *reorder_note_routine;
   const char *comment;
+  int skip_hooks;		/* skip hook generation if non zero */
 };
 
 static void output_escaped_param (struct walk_type_data *d,
@@ -1424,6 +1425,7 @@ struct walk_type_data
   options_p opt;
   const char *val;
   const char *prev_val[4];
+
   int indent;
   int counter;
   struct fileloc *line;
@@ -1549,6 +1551,8 @@ walk_type (type_p t, struct walk_type_da
       use_params_p = 1;
     else if (strcmp (oo->name, "desc") == 0)
       desc = oo->info;
+    else if (strcmp (oo->name, "mark_hook") == 0)
+      ;
     else if (strcmp (oo->name, "nested_ptr") == 0)
       nested_ptr_d = (const struct nested_ptr_data *) oo->info;
     else if (strcmp (oo->name, "dot") == 0)
@@ -2039,6 +2043,7 @@ write_func_for_structure (type_p orig_s,
   int i;
   const char *chain_next = NULL;
   const char *chain_prev = NULL;
+  const char *mark_hook_name = NULL;
   options_p opt;
   struct walk_type_data d;
 
@@ -2056,6 +2061,8 @@ write_func_for_structure (type_p orig_s,
       chain_next = opt->info;
     else if (strcmp (opt->name, "chain_prev") == 0)
       chain_prev = opt->info;
+    else if (strcmp (opt->name, "mark_hook") == 0)
+      mark_hook_name = opt->info;
 
   if (chain_prev != NULL && chain_next == NULL)
     error_at_line (&s->u.s.line, "chain_prev without chain_next");
@@ -2111,10 +2118,17 @@ write_func_for_structure (type_p orig_s,
 	  output_type_enum (d.of, orig_s);
 	}
       oprintf (d.of, "))\n");
+      if (mark_hook_name && !wtd->skip_hooks)
+	{
+	  oprintf (d.of, "    {\n");
+	  oprintf (d.of, "      %s (xlimit);\n   ", mark_hook_name);
+	}
       oprintf (d.of, "   xlimit = (");
       d.prev_val[2] = "*xlimit";
       output_escaped_param (&d, chain_next, "chain_next");
       oprintf (d.of, ");\n");
+      if (mark_hook_name && !wtd->skip_hooks)
+	oprintf (d.of, "    }\n");
       if (chain_prev != NULL)
 	{
 	  oprintf (d.of, "  if (x != xlimit)\n");
@@ -2142,7 +2156,10 @@ write_func_for_structure (type_p orig_s,
       oprintf (d.of, "  while (x != xlimit)\n");
     }
   oprintf (d.of, "    {\n");
-
+  if (mark_hook_name && chain_next == NULL && !wtd->skip_hooks)
+    {
+      oprintf (d.of, "      %s(x);\n", mark_hook_name);
+    }
   d.prev_val[2] = "*x";
   d.indent = 6;
   walk_type (s, &d);
@@ -2258,14 +2275,16 @@ write_types (type_p structures, type_p p
 static const struct write_types_data ggc_wtd =
 {
   "ggc_m", NULL, "ggc_mark", "ggc_test_and_set_mark", NULL,
-  "GC marker procedures.  "
+  "GC marker procedures.  ",
+  FALSE
 };
 
 static const struct write_types_data pch_wtd =
 {
   "pch_n", "pch_p", "gt_pch_note_object", "gt_pch_note_object",
   "gt_pch_note_reorder",
-  "PCH type-walking procedures.  "
+  "PCH type-walking procedures.  ",
+  TRUE
 };
 
 /* Write out the local pointer-walking routines.  */

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