Patchwork [2/3] Handle simple inheritance in gengtype.

login
register
mail settings
Submitter David Malcolm
Date Sept. 20, 2013, 2:05 p.m.
Message ID <1379685919-9437-3-git-send-email-dmalcolm@redhat.com>
Download mbox | patch
Permalink /patch/276476/
State New
Headers show

Comments

David Malcolm - Sept. 20, 2013, 2:05 p.m.
Treat GTY structs that have a "desc" as being the root of an inheritance
hierarchy.  Generate a switch on desc within the marking function with
cases for each subclass, visiting all fields of the type (including
inherited ones).

Don't create marking functions for subclasses, instead using the base
class marking functions.  Use walk_type on them within walk_subclasses
to generate the case within the switch for handling the tag, directly
walking all fields of the type.

	* gengtype.c (output_mangled_typename):  Convert references
	to classes within an inheritance hierarchy to reference the
	ultimate base class, since only it will have gt_ functions.
	(get_string_option): New.
	(walk_subclasses): New.
	(walk_type): Treat GTY structs that have a "desc" as being the
	root of an inheritance hierarchy.  Generate a switch on it
	within the marking function which walks all subclasses, adding
	cases for them via walk_subclasses.  For subclasses, visit all
	fields of the type (including inherited ones).
	(write_func_for_structure): Don't write fns for subclasses, only
	for the ultimate base class within an inheritance hierarchy.
	Subclasses-marking will be handled by the base class marking
	functions.
	(write_types): Likewise.
	(write_local_func_for_structure): Likewise.
	(USED_BY_TYPED_GC_P): Emit allocators for subclasses.
	(write_root): Use the marker function for the ultimate base class.
	* gengtype.h (FOR_ALL_INHERITED_FIELDS): New.
---
 gcc/gengtype.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 gcc/gengtype.h |   5 +++
 2 files changed, 100 insertions(+), 5 deletions(-)
Michael Matz - Sept. 20, 2013, 3:01 p.m.
Hi,

On Fri, 20 Sep 2013, David Malcolm wrote:

> Treat GTY structs that have a "desc" as being the root of an inheritance
> hierarchy.  Generate a switch on desc within the marking function with
> cases for each subclass, visiting all fields of the type (including
> inherited ones).

Yay!  Thanks for working on that.  I miss a change in set_gc_used_type 
to mark base classes.  When you construct a testcase where only derived 
classes are used it should break because the base class marker isn't 
emitted.

Apart from that I think I like it, there's a potential quadratic loop in 
walk_subclasses, but I guess it doesn't really matter for the number of 
gty types we have (and could be changed via a list of all derived classes 
per base class if necessary).

Yes, it needs some updates to the documentation.  Some minor nits:

> @@ -2960,8 +3002,21 @@ walk_type (type_p t, struct walk_type_data *d)
>  	    d->indent += 2;
>  	    oprintf (d->of, "%*s{\n", d->indent, "");
>  	  }
> +	else
> +	  {
> +	    if (desc)
> +	      {

else if (desc)
  {

>  	  }
> +	else
> +	  {
> +	    if (desc)
> +	      {

Same.

> @@ -4076,7 +4162,9 @@ write_local (outf_p output_header, type_p structures, type_p param_structs)
>  	   || ((s)->gc_used == GC_MAYBE_POINTED_TO			\
>  	       && s->u.s.line.file != NULL)				\
>  	   || ((s)->gc_used == GC_USED					\
> -	       && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))))))
> +	       && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))) \
> +	   || (s->u.s.base_class))))
> +
>  
>  

Watch for vertical white space.


Ciao,
Michael.

Patch

diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index a6dc221..a078b44 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -2534,6 +2534,11 @@  output_mangled_typename (outf_p of, const_type_p t)
       case TYPE_LANG_STRUCT:
       case TYPE_USER_STRUCT:
 	{
+	  /* For references to classes within an inheritance hierarchy,
+	     only ever reference the ultimate base class, since only
+	     it will have gt_ functions.  */
+	  while (t->u.s.base_class)
+	    t = t->u.s.base_class;
 	  const char *id_for_tag = filter_type_name (t->u.s.tag);
 	  oprintf (of, "%lu%s", (unsigned long) strlen (id_for_tag),
 		   id_for_tag);
@@ -2596,6 +2601,42 @@  output_escaped_param (struct walk_type_data *d, const char *param,
 	}
 }
 
+const char *
+get_string_option (options_p opt, const char *key)
+{
+  for (; opt; opt = opt->next)
+    if (strcmp (opt->name, key) == 0)
+      return opt->info.string;
+  return NULL;
+}
+
+static void
+walk_subclasses (type_p base, struct walk_type_data *d)
+{
+  for (type_p sub = structures; sub != NULL; sub = sub->next)
+    {
+      if (sub->u.s.base_class == base)
+	{
+	  const char *type_tag = get_string_option (sub->u.s.opt, "tag");
+	  oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
+	  d->indent += 2;
+	  oprintf (d->of, "%*s{\n", d->indent, "");
+	  d->indent += 2;
+	  oprintf (d->of, "%*s%s *sub = static_cast <%s *> (x);\n",
+		   d->indent, "", sub->u.s.tag, sub->u.s.tag);
+	  const char *old_val = d->val;
+	  d->val = "(*sub)";
+	  walk_type (sub, d);
+	  d->val = old_val;
+	  d->indent -= 2;
+	  oprintf (d->of, "%*s}\n", d->indent, "");
+	  oprintf (d->of, "%*sbreak;\n", d->indent, "");
+	  d->indent -= 2;
+
+	  walk_subclasses (sub, d);
+	}
+    }
+}
 
 /* Call D->PROCESS_FIELD for every field (or subfield) of D->VAL,
    which is of type T.  Write code to D->OF to constrain execution (at
@@ -2613,6 +2654,7 @@  walk_type (type_p t, struct walk_type_data *d)
 {
   const char *length = NULL;
   const char *desc = NULL;
+  const char *type_tag = NULL;
   int maybe_undef_p = 0;
   int use_param_num = -1;
   int use_params_p = 0;
@@ -2641,7 +2683,7 @@  walk_type (type_p t, struct walk_type_data *d)
     else if (strcmp (oo->name, "dot") == 0)
       ;
     else if (strcmp (oo->name, "tag") == 0)
-      ;
+      type_tag = oo->info.string;
     else if (strcmp (oo->name, "special") == 0)
       ;
     else if (strcmp (oo->name, "skip") == 0)
@@ -2960,8 +3002,21 @@  walk_type (type_p t, struct walk_type_data *d)
 	    d->indent += 2;
 	    oprintf (d->of, "%*s{\n", d->indent, "");
 	  }
+	else
+	  {
+	    if (desc)
+	      {
+		oprintf (d->of, "%*sswitch (", d->indent, "");
+		output_escaped_param (d, desc, "desc");
+		oprintf (d->of, ")\n");
+		d->indent += 2;
+		oprintf (d->of, "%*s{\n", d->indent, "");
+		oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag);
+		d->indent += 2;
+	      }
+	  }
 
-	for (f = t->u.s.fields; f; f = f->next)
+	FOR_ALL_INHERITED_FIELDS (t, f)
 	  {
 	    options_p oo;
 	    int skip_p = 0;
@@ -2999,7 +3054,7 @@  walk_type (type_p t, struct walk_type_data *d)
 	  }
 	endcounter = d->counter;
 
-	for (f = t->u.s.fields; f; f = f->next)
+	FOR_ALL_INHERITED_FIELDS (t, f)
 	  {
 	    options_p oo;
 	    const char *dot = ".";
@@ -3101,11 +3156,29 @@  walk_type (type_p t, struct walk_type_data *d)
 	    oprintf (d->of, "%*sdefault:\n", d->indent, "");
 	    oprintf (d->of, "%*s  break;\n", d->indent, "");
 	  }
+
+	if (desc && !union_p)
+	  {
+		oprintf (d->of, "%*sbreak;\n", d->indent, "");
+		d->indent -= 2;
+          }
 	if (union_p)
 	  {
 	    oprintf (d->of, "%*s}\n", d->indent, "");
 	    d->indent -= 2;
 	  }
+	else
+	  {
+	    if (desc)
+	      {
+		/* Add cases to handle subclasses.  */
+		walk_subclasses (t, d);
+
+		/* End of the switch statement */
+		oprintf (d->of, "%*s}\n", d->indent, "");
+		d->indent -= 2;
+	      }
+	  }
 	if (any_length_seen)
 	  {
 	    d->indent -= 2;
@@ -3451,6 +3524,11 @@  write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   options_p opt;
   struct walk_type_data d;
 
+  /* Don't write fns for subclasses, only for the ultimate base class
+     within an inheritance hierarchy.  */
+  if (s->u.s.base_class)
+    return;
+
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
   for (opt = s->u.s.opt; opt; opt = opt->next)
@@ -3627,7 +3705,10 @@  write_types (outf_p output_header, type_p structures, type_p param_structs,
      emitted afterwards.  This is needed in plugin mode.  */
   oprintf (output_header, "/* Macros and declarations.  */\n");
   for (s = structures; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO)
+    /* Do not emit handlers for derived classes; we only ever deal with
+       the ultimate base class within an inheritance hierarchy.  */
+    if ((s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO)
+        && !s->u.s.base_class)
       {
 	options_p opt;
 
@@ -3932,6 +4013,11 @@  write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param)
 {
   struct walk_type_data d;
 
+  /* Don't write fns for subclasses, only for the ultimate base class
+     within an inheritance hierarchy.  */
+  if (s->u.s.base_class)
+    return;
+
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
   d.process_field = write_types_local_process_field;
@@ -4076,7 +4162,9 @@  write_local (outf_p output_header, type_p structures, type_p param_structs)
 	   || ((s)->gc_used == GC_MAYBE_POINTED_TO			\
 	       && s->u.s.line.file != NULL)				\
 	   || ((s)->gc_used == GC_USED					\
-	       && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))))))
+	       && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))) \
+	   || (s->u.s.base_class))))
+
 
 
 /* Might T contain any non-pointer elements?  */
@@ -4360,6 +4448,8 @@  write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
 
 	if (!has_length && union_or_struct_p (tp))
 	  {
+	    while (tp->u.s.base_class)
+	      tp = tp->u.s.base_class;
 	    const char *id_for_tag = filter_type_name (tp->u.s.tag);
 	    oprintf (f, "    &gt_ggc_mx_%s,\n", id_for_tag);
 	    if (emit_pch)
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 06ebbed..4850723 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -506,4 +506,9 @@  void dbgprint_count_type_at (const char *, int, const char *, type_p);
 #define DBGPRINT_COUNT_TYPE(Msg,Ty) do{/*nodbgprint_count_type*/}while (0)
 #endif /*ENABLE_CHECKING */
 
+#define FOR_ALL_INHERITED_FIELDS(TYPE, FIELD_VAR) \
+  for (type_p sub = (TYPE); sub; sub = sub->u.s.base_class) \
+    for (FIELD_VAR = sub->u.s.fields; FIELD_VAR; FIELD_VAR = FIELD_VAR->next)
+
+
 #endif