PATCH: improve vtable emission

Matt Austern austern@apple.com
Mon Dec 23 15:58:00 GMT 2002


The point of this patch is to reduce the number of dynamic classes
that finish_file has to look at.   Especially in projects that use large
precompiled headers, we don't want finish_file to be traipsing all
over memory.

At present finish_file looks at every dynamic class in the translation
unit; my patch changes it so that it only looks at the dynamic classes
whose vtables we might want to emit.  (Meaning (a) classes whose
key methods we've seen, and (b) classes that have no key methods.)

I'd still like to take this idea farther.  First, I'd like to make sure 
that
finish_file never looks at a class unless we're already certain we
want to emit its vtables.  Second, I'd like to make similar changes
for inline functions, rtti data, etc.  But this is a useful intermediate
result, so may as well start with it.

Tested on linux, with no regressions.  OK to commit?

			--Matt

Index: gcc/cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.502
diff -u -r1.502 class.c
--- gcc/cp/class.c	20 Dec 2002 16:11:41 -0000	1.502
+++ gcc/cp/class.c	23 Dec 2002 23:50:44 -0000
@@ -5200,6 +5200,35 @@
    splay_tree_delete (empty_base_offsets);
  }

+/* Returns the virtual function with which the vtable for TYPE is
+   emitted, or NULL_TREE if that heuristic is not applicable to TYPE.  
*/
+
+static tree
+key_method (tree type)
+{
+  tree method;
+
+  if (TYPE_FOR_JAVA (type)
+      || processing_template_decl
+      || CLASSTYPE_TEMPLATE_INSTANTIATION (type)
+      || CLASSTYPE_INTERFACE_KNOWN (type))
+    return NULL_TREE;
+
+  for (method = TYPE_METHODS (type); method != NULL_TREE;
+       method = TREE_CHAIN (method))
+    if (DECL_VINDEX (method) != NULL_TREE
+	&& ! DECL_DECLARED_INLINE_P (method)
+	&& (! DECL_PURE_VIRTUAL_P (method)
+#if 0
+	    /* This would be nice, but we didn't think of it in time.  */
+	    || DECL_DESTRUCTOR_P (method)
+#endif
+	    ))
+      return method;
+
+  return NULL_TREE;
+}
+
  /* Perform processing required when the definition of T (a class type)
     is complete.  */

@@ -5241,6 +5270,19 @@
       bases and members and add implicitly generated methods.  */
    check_bases_and_members (t);

+  /* Find the key method */
+    if (TYPE_CONTAINS_VPTR_P (t))
+    {
+      CLASSTYPE_KEY_METHOD (t) = key_method (t);
+
+      /* If a polymorphic class has no key method, emit the vtable in
+	 every translation unit where the class definition appear. */
+      if (CLASSTYPE_KEY_METHOD (t) == NULL_TREE && 
!processing_template_decl)
+	{
+	  dynamic_classes = tree_cons (NULL_TREE, t, dynamic_classes);
+	}
+    }
+
    /* Layout the class itself.  */
    layout_class_type (t, &virtuals);

@@ -5318,9 +5360,6 @@
  	  else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
  	    DECL_VINDEX (fndecl) = build_shared_int_cst (vindex);
  	}
-
-      /* Add this class to the list of dynamic classes.  */
-      dynamic_classes = tree_cons (NULL_TREE, t, dynamic_classes);
      }

    finish_struct_bits (t);
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.781
diff -u -r1.781 cp-tree.h
--- gcc/cp/cp-tree.h	22 Dec 2002 21:32:26 -0000	1.781
+++ gcc/cp/cp-tree.h	23 Dec 2002 23:50:44 -0000
@@ -746,7 +746,8 @@
     destructors.  */
  #define vtt_parm_type                   
cp_global_trees[CPTI_VTT_PARM_TYPE]

-/* A TREE_LIST of all of the dynamic classes in the program.  */
+/* A TREE_LIST of the dynamic classes whose vtables may have to be
+   emitted in this translation unit.  */

  #define dynamic_classes                 
cp_global_trees[CPTI_DYNAMIC_CLASSES]

@@ -1163,6 +1164,7 @@
    tree pure_virtuals;
    tree friend_classes;
    tree methods;
+  tree key_method;
    tree decl_list;
    tree template_info;
    tree befriending_classes;
@@ -1282,6 +1284,11 @@
     virtual base classes.  If this is 0 for the root of a type
     hierarchy, then we can use more efficient search techniques.  */
  #define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3 (NODE))
+
+/* The member function with which the vtable will be emitted:
+   the first noninline non-pure-virtual member function.  NULL_TREE
+   if there is no key function or if this is a class template */
+#define CLASSTYPE_KEY_METHOD(NODE) (LANG_TYPE_CLASS_CHECK 
(NODE)->key_method)

  /* Vector member functions defined in this class.  Each element is
     either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD.  All
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.970
diff -u -r1.970 decl.c
--- gcc/cp/decl.c	22 Dec 2002 16:01:26 -0000	1.970
+++ gcc/cp/decl.c	23 Dec 2002 23:50:44 -0000
@@ -14429,6 +14429,22 @@
    if (fndecl == NULL_TREE)
      return error_mark_node;

+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
+      && DECL_VIRTUAL_P (fndecl)
+      && !processing_template_decl)
+    {
+      tree fnclass = DECL_CLASS_CONTEXT (fndecl);
+      if (fndecl == CLASSTYPE_KEY_METHOD (fnclass))
+	{
+	  /* If the function we thought was the key method turns out
+	     to be inline, then the class has no key method.  */
+	  if (DECL_DECLARED_INLINE_P (fndecl))
+	    CLASSTYPE_KEY_METHOD (fnclass) = NULL_TREE;
+
+	  dynamic_classes = tree_cons (NULL_TREE, fnclass, dynamic_classes);
+	}
+    }
+
    nested = function_depth > 1;
    fntype = TREE_TYPE (fndecl);

Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.578
diff -u -r1.578 decl2.c
--- gcc/cp/decl2.c	22 Dec 2002 21:32:26 -0000	1.578
+++ gcc/cp/decl2.c	23 Dec 2002 23:50:44 -0000
@@ -89,7 +89,6 @@
  static tree prune_vars_needing_no_initialization PARAMS ((tree));
  static void write_out_vars PARAMS ((tree));
  static void import_export_class	PARAMS ((tree));
-static tree key_method PARAMS ((tree));
  static tree get_guard_bits PARAMS ((tree));

  /* A list of static class variables.  This is needed, because a
@@ -1586,29 +1585,6 @@
      }
  }

-/* Returns the virtual function with which the vtable for TYPE is
-   emitted, or NULL_TREE if that heuristic is not applicable to TYPE.  
*/
-
-static tree
-key_method (type)
-     tree type;
-{
-  tree method;
-
-  if (TYPE_FOR_JAVA (type)
-      || CLASSTYPE_TEMPLATE_INSTANTIATION (type)
-      || CLASSTYPE_INTERFACE_KNOWN (type))
-    return NULL_TREE;
-
-  for (method = TYPE_METHODS (type); method != NULL_TREE;
-       method = TREE_CHAIN (method))
-    if (DECL_VINDEX (method) != NULL_TREE
-	&& ! DECL_DECLARED_INLINE_P (method)
-	&& ! DECL_PURE_VIRTUAL_P (method))
-      return method;
-
-  return NULL_TREE;
-}

  /* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL,
     based on TYPE and other static flags.
@@ -1642,7 +1618,7 @@
  	 functions in our class, or if we come from a template.  */

        int found = (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
-		   || key_method (type));
+		   || CLASSTYPE_KEY_METHOD (type) != NULL_TREE);

        if (final || ! found)
  	{
@@ -1702,7 +1678,7 @@
    if (import_export == 0
        && TYPE_POLYMORPHIC_P (ctype))
      {
-      tree method = key_method (ctype);
+      tree method = CLASSTYPE_KEY_METHOD (ctype);
        if (method)
  	import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);
      }
@@ -2722,11 +2698,36 @@

        /* Write out virtual tables as required.  Note that writing out
  	 the virtual table for a template class may cause the
-	 instantiation of members of that class.  */
-      for (t = dynamic_classes; t; t = TREE_CHAIN (t))
-	if (maybe_emit_vtables (TREE_VALUE (t)))
+	 instantiation of members of that class.  If we write out
+	 vtables then we remove the class from our list so we don't
+	 have to look at it again. */
+
+      while (dynamic_classes != NULL_TREE
+	     && maybe_emit_vtables (TREE_VALUE (dynamic_classes)))
+	{
  	  reconsider = 1;
-
+	  dynamic_classes = TREE_CHAIN (dynamic_classes);
+	}
+
+      t = dynamic_classes;
+      if (t != NULL_TREE)
+	{
+	  tree next = TREE_CHAIN (t);
+
+	  while (next)
+	    {
+	      if (maybe_emit_vtables (TREE_VALUE (next)))
+		{
+		  reconsider = 1;
+		  TREE_CHAIN (t) = TREE_CHAIN (next);
+		}
+	      else
+		t = next;
+
+	      next = TREE_CHAIN (t);
+	    }
+	}
+
        /* Write out needed type info variables. Writing out one variable
           might cause others to be needed.  */
        if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, 
/*data=*/0))
Index: gcc/cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.638
diff -u -r1.638 pt.c
--- gcc/cp/pt.c	22 Dec 2002 16:01:27 -0000	1.638
+++ gcc/cp/pt.c	23 Dec 2002 23:50:45 -0000
@@ -5463,6 +5463,9 @@
    pop_from_top_level ();
    pop_tinst_level ();

+  if (TYPE_CONTAINS_VPTR_P (type))
+    dynamic_classes = tree_cons (NULL_TREE, type, dynamic_classes);
+
    return type;
  }





More information about the Gcc-patches mailing list