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]

RFA/RFC: Add support for exporting vtables based ondllexport/dllimport attributes


Hi Mark, Hi Jason,

  Please could you examine, and maybe approve, the attached patch.  It
  adds code to gcc/cp/decl2.c to implement the exporting of vtables
  and rtti based on the presence of dllexport and dllimport
  attributes, as specified here:

     http://www.armdevzone.com/EABI/exported_class.txt

  The code was actually developed by Red Hat for Symbian who have been
  using it successfully for a little while now.  I realise that the
  patch is adding a #ifdef controlled conditional piece of code to the
  generic decl2.c file, but I could not think of a clean way for a
  particular back end (or set of backends) to otherwise intercept the
  class exporting code and add the necessary attributes.

  There is also a target specific patch which would enable this code
  and then add functions to actually export the vtables and rtti, but
  there is no point in submitting it until this generic patch (or a
  better replacement) has been accepted.

  I have checked this patch against an i686-pc-linux-gnu port and it
  shows no regressions.  Mind you the #ifdef in the patch was not
  enabled, so this comes as no surprise.
  
Cheers
    Nick

gcc/cp/ChangeLog
2004-05-14  Nick Clifton  <nickc@redhat.com>

	* decl2.c: Add code to export vtables and rtti if required by
	the presence of dllimport/dllexport attributes.  Controlled
	by the definition of DLLEXPORTED_VTABLES:
        (possibly_export_base_class): New function: Decide if a base
	class needs its vtable & rtti exported.
        (export_vtable_and_rtti_p): New function: Decide if a class
	needs its vtable & rtti exported.
        (add_attribute): New function: Add an attribute to a decl or
	type.
        (add_attribute_to_class_vtable_and_rtti): New function: Add an
	attribute to a class and its vtable and rtti.
        (class_needs_attribute_p): New function: Decide if a class
	needs a particular attribute.
        (import_export_class): Use new code to decide if a class and
	its vtable and rtti need to be exported.

Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.707
diff -c -3 -p -r1.707 decl2.c
*** gcc/cp/decl2.c	13 May 2004 06:40:17 -0000	1.707
--- gcc/cp/decl2.c	14 May 2004 16:23:11 -0000
*************** import_export_vtable (tree decl, tree ty
*** 1500,1505 ****
--- 1500,1780 ----
      }
  }
  
+ #ifdef DLLEXPORTED_VTABLES
+ 
+ /* This code implements a specification for exporting the vtable and rtti of
+    classes that have members with the dllexport or dllexport attributes.
+    This specification is defined here:
+    
+    http://www.armdevzone.com/EABI/exported_class.txt
+ 
+    Basically it says that a class's vtable and rtti should be exported if
+    the following rules apply:
+ 
+    - If it has any non-inline non-pure virtual functions,
+      at least one of these need to be declared dllimport
+      OR any of the constructors is declared dllimport.
+ 
+    AND
+    
+    - The class has an inline constructor/destructor and
+      a key-function (placement of vtable uniquely defined) that
+      is defined in this translation unit.
+ 
+    The specification also says that for classes which will have their
+    vtables and rtti exported that their base class(es) might also need a
+    similar exporting if:
+    
+    - Every base class needs to have its vtable & rtti exported
+      as well, if the following the conditions hold true:
+      + The base class has a non-inline declared non-pure virtual function
+      + The base class is polymorphic (has or inherits any virtual functions)
+        or the base class has any virtual base classes
+ */
+ 
+ /* Decide if a base class of a class should also have its vtable and rtti
+    exported.  */
+ 
+ static void
+ possibly_export_base_class (tree base_class)
+ {
+   tree methods;
+   int len;
+ 
+   if (! (TYPE_POLYMORPHIC_P (base_class)
+ 	 || TYPE_USES_VIRTUAL_BASECLASSES (base_class)))
+     return;
+ 
+   methods = CLASSTYPE_METHOD_VEC (base_class);
+   len = methods ? TREE_VEC_LENGTH (methods) : 0;
+ 
+   for (;len --;)
+     {
+       tree member = TREE_VEC_ELT (methods, len);
+ 
+       if (! member)
+ 	continue;
+ 
+       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
+ 	{	  
+ 	  if (TREE_CODE (member) != FUNCTION_DECL)
+ 	    continue;
+ 
+ 	  if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
+ 	    continue;
+ 
+ 	  if (! DECL_VIRTUAL_P (member))
+ 	    continue;
+ 
+ 	  if (DECL_PURE_VIRTUAL_P (member))
+ 	    continue;
+ 
+ 	  if (DECL_INLINE (member))
+ 	    continue;
+ 
+ 	  break;
+ 	}
+ 
+       if (member)
+ 	break;
+     }
+ 
+   if (len < 0)
+     return;
+ 
+   /* FIXME: According to the spec this base class should be exported, but
+      a) how do we do this ? and
+      b) it does not appear to be necessary for compliance with the Symbian OS which so far is the only consumer of this code.  */
+ }
+ 
+ /* Decide if a class needs its vtable and rtti exporting.  */
+ 
+ static bool
+ export_vtable_and_rtti_p (tree ctype)
+ {
+   bool inline_ctor_dtor;
+   bool dllimport_ctor_dtor;
+   bool dllimport_member;
+   tree binfos;
+   tree methods;
+   tree key;
+   int len;
+ 
+   /* Make sure that we are examining a class...  */
+   if (TREE_CODE (ctype) != RECORD_TYPE)
+     return false;
+ 
+   /* If the class does not have a key function it
+      does not need to have its vtable exported.  */
+   if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
+     return false;
+ 
+   /* If the key fn has not been defined then the class should not be
+      exported.  */
+   if (! TREE_ASM_WRITTEN (key))
+     return false;
+ 
+   /* Check the class's member functions.  */
+   inline_ctor_dtor = false;
+   dllimport_ctor_dtor = false;
+   dllimport_member = false;
+ 
+   methods = CLASSTYPE_METHOD_VEC (ctype);
+   len = methods ? TREE_VEC_LENGTH (methods) : 0;
+ 
+   for (;len --;)
+     {
+       tree member = TREE_VEC_ELT (methods, len);
+ 
+       if (! member)
+ 	continue;
+ 
+       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
+ 	{	  
+ 	  if (TREE_CODE (member) != FUNCTION_DECL)
+ 	    continue;
+ 
+ 	  if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
+ 	    {
+ 	      if (DECL_INLINE (member)
+ 		  /* Ignore C++ backend created inline ctors/dtors.  */
+ 		  && (   DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
+ 		      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
+ 		inline_ctor_dtor = true;
+ 
+ 	      if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
+ 		dllimport_ctor_dtor = true;
+ 	    }
+ 	  else
+ 	    {
+ 	      if (DECL_PURE_VIRTUAL_P (member))
+ 		continue;
+ 
+ 	      if (! DECL_VIRTUAL_P (member))
+ 		continue;
+ 
+ 	      if (DECL_INLINE (member))
+ 		continue;
+ 
+ 	      if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
+ 		dllimport_member = true;
+ 	    }
+ 	}
+     }
+ 
+   if (! dllimport_member && ! dllimport_ctor_dtor)
+     return false;
+ 
+   if (! inline_ctor_dtor)
+     return false;
+ 
+   /* Now we must check and possibly export the base classes.  */
+   binfos = TYPE_BINFO_BASETYPES (ctype);
+   len = CLASSTYPE_N_BASECLASSES (ctype);
+ 
+   for (; len --;) 
+     {
+       tree base_binfo;
+       tree basetype;
+ 
+       /* Figure out which base we're looking at.  */
+       base_binfo = TREE_VEC_ELT (binfos, len);
+       basetype = TREE_TYPE (base_binfo);
+ 
+       possibly_export_base_class (basetype);
+     }
+ 
+   return true;
+ }
+ 
+ /* Add the named attribute to the given node.  Copes with both DECLs and
+    TYPEs.  Will only add the attribute if it is not already present.  */
+ 
+ static void
+ add_attribute (tree node, const char * attr_name)
+ {
+   tree attrs;
+   tree attr;
+ 
+   attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node);
+   
+   if (lookup_attribute (attr_name, attrs) != NULL_TREE)
+     return;
+ 
+   attr = get_identifier (attr_name);
+ 
+   (DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node)) = tree_cons (attr, NULL_TREE, attrs);
+ }
+ 
+ /* Add the named attribute to a class and its vtable and rtti.  */
+ 
+ static void
+ add_attribute_to_class_vtable_and_rtti (tree ctype, const char * attr_name)
+ {
+   add_attribute (ctype, attr_name);
+ 
+   /* If the vtable exists then they need annotating as well.  */
+   if (CLASSTYPE_VTABLES (ctype))
+     /* XXX - Do we need to annotate any vtables other than the primary ?  */
+     add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
+   
+   /* If the rtti exists then it needs annotating as well.  */
+   if (TYPE_MAIN_VARIANT (ctype)
+       && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
+     add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
+ 		   attr_name);
+ }
+ 
+ /* Decide if a class needs to have an attribute because
+    one of its member functions has the attribute.  */
+ 
+ static bool
+ class_needs_attribute_p (tree          ctype,
+ 			 const char *  attribute_name)
+ {
+   /* If the key function has the attribute then the class needs it too.  */
+   if (TYPE_POLYMORPHIC_P (ctype)
+       && CLASSTYPE_KEY_METHOD (ctype)
+       && lookup_attribute (attribute_name,
+ 			   DECL_ATTRIBUTES (CLASSTYPE_KEY_METHOD (ctype))))
+     return true;
+ 
+   /* Check the class's member functions.  */
+   if (TREE_CODE (ctype) == RECORD_TYPE)
+     {
+       tree methods = CLASSTYPE_METHOD_VEC (ctype);
+       unsigned int len = methods ? TREE_VEC_LENGTH (methods) : 0;
+ 
+       for (;len --;)
+ 	{
+ 	  tree member = TREE_VEC_ELT (methods, len);
+ 
+ 	  if (! member)
+ 	    continue;
+ 
+ 	  for (member = OVL_CURRENT (member);
+ 	       member;
+ 	       member = OVL_NEXT (member))
+ 	    {
+ 	      if (TREE_CODE (member) != FUNCTION_DECL)
+ 		continue;
+ 
+ 	      if (DECL_PURE_VIRTUAL_P (member))
+ 		continue;
+ 
+ 	      if (! DECL_VIRTUAL_P (member))
+ 		continue;
+ 
+ 	      if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
+ 		return true;
+ 	    }
+ 	}
+     }
+ 
+   return false;      
+ }
+ #endif /* DLLEXPORTED_VTABLES */
+ 
  /* Determine whether or not we want to specifically import or export CTYPE,
     using various heuristics.  */
  
*************** import_export_class (tree ctype)
*** 1553,1558 ****
--- 1828,1883 ----
    if (import_export == -1)
      import_export = 0;
  #endif
+ 
+ #ifdef DLLEXPORTED_VTABLES
+   {
+     const char * attr_name = NULL;
+ 
+     /* If we are exporting the class but it does not have the dllexport
+        attribute then we may need to add it.  Similarly imported classes
+        may need the dllimport attribute.  */   
+     switch (import_export)
+       {
+       case  1: attr_name = "dllexport"; break;
+       case -1: attr_name = "dllimport"; break;
+       default: break;
+       }
+ 
+     if (attr_name
+ 	&& ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype)))
+       {
+ 	if (class_needs_attribute_p (ctype, attr_name))
+ 	  add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
+ 
+ 	/* Classes can be forced to export their vtable and rtti under
+ 	   certain conditions.  */
+ 	if (export_vtable_and_rtti_p (ctype))
+ 	  {
+ 	    add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
+ 
+ 	    /* Make sure that the class and its vtable are exported.  */
+ 	    import_export = 1;
+ 	    if (CLASSTYPE_VTABLES (ctype))
+ 	      DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1;	  
+ 
+ 	    /* Check to make sure that if the class has a key method that it
+ 	       is now on the list of keyed classes.  That way its vtable
+ 	       will be emitted.  */
+ 	    if (CLASSTYPE_KEY_METHOD (ctype))
+ 	      {
+ 		tree class;
+ 
+ 		for (class = keyed_classes; class; class = TREE_CHAIN (class))
+ 		  if (class == ctype)
+ 		    break;
+ 
+ 		if (class == NULL_TREE)
+ 		  keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes);
+ 	      }
+ 	  }
+       }
+   }
+ #endif /* DLLEXPORTED_VTABLES */
  
    if (import_export)
      {

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